一体化平台初始化仓库

This commit is contained in:
xlj
2026-02-09 13:04:45 +08:00
parent dd6040b580
commit daa67be814
48 changed files with 3747 additions and 0 deletions

32
cdaxxt-common/pom.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>integration-platform-access</artifactId>
<groupId>com.tobacco.mp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdaxxt-common</artifactId>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,14 @@
package com.tobacco.mp.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 【允许已登录的社会用户访问的接口】使用该注解(无效)
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthOperation {
}

View File

@ -0,0 +1,14 @@
package com.tobacco.mp.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 【需要记录操作日志】使用该注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogOperation {
}

View File

@ -0,0 +1,14 @@
package com.tobacco.mp.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 【需要开放第三方对接的接口】使用该注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OpenOperation {
}

View File

@ -0,0 +1,14 @@
package com.tobacco.mp.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 【不需要登录就能访问的接口】使用该注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassOperation {
}

View File

@ -0,0 +1,24 @@
package com.tobacco.mp.constant;
/**
* 基础常量信息
*/
public class Constant {
/********************************************缓存key***********************************************/
public static final String LOGIN_VERIFY_CODE = "LoginVerifyCode:";
public static final String JWT_USER = "JwtUser:";
/*************************************************************************************************/
public static final String DEFAULT_IP = "0.0.0.0";
/** 开放的API */
public static final String OPEN_API = "OPENAPI";
/** 开放的应用 */
public static final String OPEN_APP = "OPENAPP";
}

View File

@ -0,0 +1,35 @@
package com.tobacco.mp.constant;
/**
* @Author XiongLiJian
* @Date 2021/6/4 9:31
* @Description 符号工具类
* @Version 1.0
**/
public class Symbol {
/** 符号:[-] */
public static final String ACROSS = "-";
/** 符号:[_] */
public static final String LOW_ACROSS = "_";
/** 符号[.] */
public static final String POINT = ".";
/** 符号[:] */
public static final String COLON = ":";
/** 逗号[,] */
public static final String COMMA = ",";
/** 斜杠 */
public static final String SLASH = "/";
/** 逗号[@] */
public static final String A2 = "@";
/** 符号[;] */
public static final String SEMICOLON = ";";
}

View File

@ -0,0 +1,48 @@
package com.tobacco.mp.enums;
/**
* 响应码管理
* @Author: XiongLiJian
* @Date: 2020/12/29 09:14
*/
public enum ResponseCodeEnum {
NORMAL(200, "ok"),
REQUEST_PARAM_ERROR(400, "请求参数错误!"),
SYSTEM_NO_LOGIN(401, "系统未登录!"),
USER_ALREADY_DISABLED(402, "该用户已被禁用!"),
NO_ACCESS_PERMISSION(403, "没有访问权限!"),
REQUEST_RESOURCE_NO_EXIST(404, "请求的资源不存在!"),
REQUEST_METHOD_ERROR(405, "请求方式错误"),
SYSTEM_ERROR(500, "系统错误"),
SYSTEM_TIP(501, "系统提示"),
;
/** 响应码 */
private Integer code;
/** 响应信息 */
private String msg;
ResponseCodeEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

View File

@ -0,0 +1,41 @@
package com.tobacco.mp.enums;
/**
* @Author XiongLiJian
* @Date 2021/12/29 9:25
* @Description 消息提示
* @Version 1.0
**/
public enum TipEnum {
BATCH_DELETE_DATA_ERROR("批量删除解析错误!"),
FILE_NOT_SURE("请指定一个文件进行操作!"),
SYSTEM_ERROR("系统出现错误!"),
USERNAME_NOT_EXIST("用户名不存在!"),
PLEASE_WAIT_REPEAT_LOGIN("该账号今天重复多次密码错误请30分钟后重新登录"),
ACCOUNT_PASSWORD_ERROR("账号或密码错误!"),
ACCESS_FILE_ERROR("权限模板文件解析异常!"),
ACCESS_API_ERROR("权限映射解析异常!"),
ROLE_PERSON_NUM_EXSIT("角色下存在人员无法删除!"),
DATA_SHEET_IMPORT_ERROR("数据导入解析错误!"),
USERNAME_IS_REPEAT("该用户名已存在!"),
NOT_MODIFY_SYSTEM_ROLE("不能操作系统超级管理员!"),
CHECK_CODE_REPEAT("请不要频繁生成校验码!"),
;
private String msg;
TipEnum(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

View File

@ -0,0 +1,32 @@
package com.tobacco.mp.exception;
import com.tobacco.mp.enums.ResponseCodeEnum;
import com.tobacco.mp.enums.TipEnum;
import lombok.Data;
/**
* @Author XiongLiJian
* @Date 2021/6/3 17:53
* @Description 服务器异常
* @Version 1.0
**/
@Data
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = 6165589759025169495L;
private Integer code = ResponseCodeEnum.SYSTEM_TIP.getCode();
private String message;
public ServiceException(TipEnum tipEnum) {
super(tipEnum.getMsg());
this.message = tipEnum.getMsg();
}
public ServiceException(String message) {
super(message);
this.message = message;
}
}

View File

@ -0,0 +1,54 @@
package com.tobacco.mp.model;
import com.tobacco.mp.enums.ResponseCodeEnum;
import lombok.Data;
@Data
public class Json<T> {
private boolean success;
private Integer code;
private String message;
private T data;
public static Json success() {
return success(null);
}
public static Json success(Object data) {
Json json = new Json();
json.setSuccess(true);
json.setCode(ResponseCodeEnum.NORMAL.getCode());
json.setMessage(ResponseCodeEnum.NORMAL.getMsg());
json.setData(data);
return json;
}
public static Json fail(ResponseCodeEnum responseCodeEnum) {
Json json = new Json();
json.setSuccess(false);
json.setCode(responseCodeEnum.getCode());
json.setMessage(responseCodeEnum.getMsg());
return json;
}
public static Json fail(Integer code, String message) {
Json json = new Json();
json.setCode(code);
json.setMessage(message);
json.setSuccess(false);
return json;
}
public static Json fail(String message) {
Json json = new Json();
json.setCode(ResponseCodeEnum.SYSTEM_TIP.getCode());
json.setMessage(message);
json.setSuccess(false);
return json;
}
}

View File

@ -0,0 +1,93 @@
package com.tobacco.mp.model;
import lombok.Data;
import java.io.Serializable;
import java.util.Objects;
@Data
@SuppressWarnings("unused")
public class ResponseResult<T> implements Serializable {
/** 调用成功编码 */
private static final int SUCCESS_CODE = 10000;
/** 调用失败编码 */
private static final int FAIL_CODE = -1;
/** 编号 */
private int code = SUCCESS_CODE;
/** 消息 */
private String message;
/** 数据 */
private T data;
public ResponseResult() {
}
public ResponseResult(T data) {
this.message = "OK";
this.data = data;
}
public ResponseResult(int code, String msg) {
this.code = code;
this.message = msg;
this.data = null;
}
public ResponseResult(int code, String msg, T data) {
this.code = code;
this.message = msg;
this.data = data;
}
public static <T> ResponseResult<T> success() {
return new ResponseResult(SUCCESS_CODE, "OK", null);
}
public static <T> ResponseResult<T> success(int code, String message, T data) {
return new ResponseResult(code, message, data);
}
public static <T> ResponseResult<T> success(String message, T data) {
return new ResponseResult(SUCCESS_CODE, message, data);
}
public static <T> ResponseResult<T> success(T data) {
return new ResponseResult(SUCCESS_CODE, "OK", data);
}
public static <T> ResponseResult<T> fail(String message) {
return new ResponseResult(FAIL_CODE, message, (Object)null);
}
public static <T> ResponseResult<T> fail(int code, String message) {
return new ResponseResult(code, message, (Object)null);
}
public static <T> ResponseResult<T> fail(int code, String message, T t) {
return new ResponseResult(code, message, t);
}
public boolean isSuccess() {
return SUCCESS_CODE == code;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) {
return false;
}
ResponseResult<?> that = (ResponseResult<?>) o;
return Objects.equals(code, that.code) && Objects.equals(message, that.message) && Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(code, message, data);
}
}

View File

@ -0,0 +1,172 @@
package com.tobacco.mp.utils;
import com.tobacco.mp.annotation.AuthOperation;
import com.tobacco.mp.annotation.OpenOperation;
import com.tobacco.mp.annotation.PassOperation;
import com.tobacco.mp.constant.Constant;
import com.tobacco.mp.constant.Symbol;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import java.lang.reflect.Method;
import java.util.*;
@Slf4j
@Component
public class AnnotationUtil {
@Autowired
RedisUtils redisUtils;
private final String RESOURCE_PATTERN = "com/tobacco/mp/**/controller/*.class";
public static List<String> PASS_API;
public static List<String> AUTH_API;
/**
* 加载自定义注解
*/
public void loadCustomAnnotation() {
Map<String, List<String>> mapApis = getAccessAnnotations(RESOURCE_PATTERN);
// 获取开放给第三方的接口数据
if (mapApis.get(OpenOperation.class.getName()) != null) {
redisUtils.set(Constant.OPEN_API, StringUtils.toString(mapApis.get(OpenOperation.class.getName())));
}
// 不需要登录就能访问的接口
PASS_API = mapApis.get(PassOperation.class.getName());
if (PASS_API == null) {
PASS_API = new ArrayList<>();
}
// 允许已登录的社会用户访问的接口
AUTH_API = mapApis.get(AuthOperation.class.getName());
if (AUTH_API == null) {
AUTH_API = new ArrayList<>();
}
}
/**
* 获取指定路径下OpenOperation注解下的uri接口
* @return
*/
private Map<String, List<String>> getAccessAnnotations(String resourcePattern) {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Map<String, List<String>> map = new HashMap<>();
try {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourcePattern;
Resource[] resources = resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
for (Resource resource : resources) {
// 读取类信息
MetadataReader reader = readerfactory.getMetadataReader(resource);
// 扫描到的class
String classname = reader.getClassMetadata().getClassName();
Class<?> clazz = Class.forName(classname);
Method[] methods = clazz.getMethods();
for (Method method: methods) {
OpenOperation openAnno = method.getAnnotation(OpenOperation.class);
// 判断是否有指定主解
if (openAnno != null) {
// 获取注解的方法与接口请求注解
String api = getApi(clazz, method);
List<String> openApi = map.get(OpenOperation.class.getName());
if (CollectionUtils.isEmpty(openApi)) {
openApi = new ArrayList<>();
map.put(OpenOperation.class.getName(), openApi);
}
openApi.add(api);
}
AuthOperation authAnno = method.getAnnotation(AuthOperation.class);
// 判断是否有指定主解
if (authAnno != null) {
// 获取注解的方法与接口请求注解
String api = getApi(clazz, method);
List<String> authApi = map.get(AuthOperation.class.getName());
if (CollectionUtils.isEmpty(authApi)) {
authApi = new ArrayList<>();
map.put(AuthOperation.class.getName(), authApi);
}
authApi.add(api);
}
PassOperation passAnno = method.getAnnotation(PassOperation.class);
// 判断是否有指定主解
if (passAnno != null) {
// 获取注解的方法与接口请求注解
String api = getApi(clazz, method);
List<String> passApi = map.get(PassOperation.class.getName());
if (CollectionUtils.isEmpty(passApi)) {
passApi = new ArrayList<>();
map.put(PassOperation.class.getName(), passApi);
}
passApi.add(api);
}
}
}
} catch (Exception e) {
}
return map;
}
/**
* 获取api接口
* @param
* @param
*/
private String getApi(Class<?> clazz, Method method) {
RequestMapping request = clazz.getDeclaredAnnotation(RequestMapping.class);
if (request != null) {
String api = request.value().length > 0 ? request.value()[0] : "";
if (!api.contains(Symbol.SLASH)) {
api = Symbol.SLASH + api;
}
String name = "";
// 获取方法的接口路由
GetMapping getAnn = method.getAnnotation(GetMapping.class);
if (getAnn != null) {
name = getAnn.value().length > 0 ? getAnn.value()[0] : "";
if (!name.contains(Symbol.SLASH)) {
name = Symbol.SLASH + name;
}
}
PostMapping postAnn = method.getAnnotation(PostMapping.class);
if (postAnn != null) {
name = postAnn.value().length > 0 ? postAnn.value()[0] : "";
if (!name.contains(Symbol.SLASH)) {
name = Symbol.SLASH + name;
}
}
DeleteMapping deleteAnn = method.getAnnotation(DeleteMapping.class);
if (deleteAnn != null) {
name = deleteAnn.value().length > 0 ? deleteAnn.value()[0] : "";
if (!name.contains(Symbol.SLASH)) {
name = Symbol.SLASH + name;
}
}
PutMapping putAnn = method.getAnnotation(PutMapping.class);
if (putAnn != null) {
name = putAnn.value().length > 0 ? putAnn.value()[0] : "";
if (!name.contains(Symbol.SLASH)) {
name = Symbol.SLASH + name;
}
}
api += name;
return api;
}
return UUID.randomUUID().toString();
}
}

View File

@ -0,0 +1,108 @@
package com.tobacco.mp.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class JWTUtil {
// 公钥
public static String PUBLIC_KEY_STR = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwHOi7T3dx95MADXlRPkLeFS+08f7dGg6RxbG5gug+yQLnw1ARNDYx6zK0gtHU+qmUlBCVqHS5vqAt73ydDKUGY9IgdMcxWtbPj456wF7W86xDv6EfiV/G9ZRVvPWmgNUxw1RXtQa91sIuyCxp4xIFd43wROxWUbmN+Omiv2ZYqYBquSdmzslL1dDypPCZ53ZCs1aY6TodbhndySp8E7YAhw8o+F2uGPW9p1Xz1w4hIZBo10b49rOpR5h0t2U4OloBbAC8Too6Smb5ZdYseUZLLD+PW1O0l7uMBlmJuqjPXRUxuTwXUO+EA4Z/ymBXalE4Zi3uEomISqWajSDPOG4pwIDAQAB";
/**
* 从Base64编码的字符串加载公钥
* @param publicKeyStr Base64编码的公钥字符串
* @return PublicKey对象
*/
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
// 移除PEM格式的标记
String publicKeyPEM = publicKeyStr
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
// Base64解码
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
// 创建公钥规范
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
// 根据算法获取KeyFactory
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
/**
* 验证JWT令牌
* @param token JWT令牌字符串
* @param publicKey 公钥
* @return Claims 声明信息
*/
public static Claims verifyJWT(String token, PublicKey publicKey) {
return Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(token).getBody();
}
/**
* 验证令牌签名信息
* @param token 令牌
* @param publicKeyStr 公钥字符串
* @return
*/
public static Claims verifyJWTToken(String token, String publicKeyStr) {
try {
// 加载公钥
PublicKey publicKey = loadPublicKey(publicKeyStr);
// 验证JWT
return Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(token).getBody();
} catch (io.jsonwebtoken.security.SignatureException e) {
throw new RuntimeException("无效的签名", e);
} catch (io.jsonwebtoken.ExpiredJwtException e) {
throw new RuntimeException("令牌已过期", e);
} catch (io.jsonwebtoken.MalformedJwtException e) {
throw new RuntimeException("无效的令牌格式", e);
} catch (Exception e) {
throw new RuntimeException("令牌验证失败", e);
}
}
/**
* 读取txt文件的内容
* @param file 想要读取的文件对象
* @return 返回文件内容
*/
public static String readTxt(File file) {
StringBuilder result = new StringBuilder();
try {
// 构造一个BufferedReader类来读取文件
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
// 使用readLine方法一次读一行
while ((s = br.readLine()) != null) {
result.append(System.lineSeparator()+s);
}
br.close();
} catch(Exception e) {
e.printStackTrace();
}
return result.toString();
}
public static void main(String[] args) {
String publicKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwHOi7T3dx95MADXlRPkLeFS+08f7dGg6RxbG5gug+yQLnw1ARNDYx6zK0gtHU+qmUlBCVqHS5vqAt73ydDKUGY9IgdMcxWtbPj456wF7W86xDv6EfiV/G9ZRVvPWmgNUxw1RXtQa91sIuyCxp4xIFd43wROxWUbmN+Omiv2ZYqYBquSdmzslL1dDypPCZ53ZCs1aY6TodbhndySp8E7YAhw8o+F2uGPW9p1Xz1w4hIZBo10b49rOpR5h0t2U4OloBbAC8Too6Smb5ZdYseUZLLD+PW1O0l7uMBlmJuqjPXRUxuTwXUO+EA4Z/ymBXalE4Zi3uEomISqWajSDPOG4pwIDAQAB";
String jwtToken = "eyJhbGciOiJSUzI1NiJ9.eyJlbXBsb3llZUpvYklkIjoiNjIxMzI1MDMwNzAwMDAwMDAwMSIsIm1hbmFnZVVuaXRJZCI6IjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDExNjIwNTAxIiwib3JpZ2luQXBwIjoiYzQ1Y2I1YzMwZDQzNGMyNDlkZWYyZGNiMzM2ODg4NGQiLCJ0YXJnZXRDbGllbnRzIjoiNmY5MzhkYTBlMjI5MTFmMGJjNzFiYzE2OTUwYTU1ZmIiLCJlbXBsb3llZUlkIjoiMDAwMDAwMDAwMDAwMDAwMDEwNjIwNTAxMDAwMDA0MjIiLCJ1c2VyVHlwZSI6IjAwMDAwMSIsInVzZXJOYW1lIjoi5p2c5YevIiwib3JnVW5pdElkIjoiMDAwMDAwMDAwMDAwMDAwMDAwMDAxMTYyMDUwMTAxMDciLCJnbXRDcmVhdGUiOiIyMDI1LTEyLTI2IDA4OjAxOjA5IiwidXNlcklkIjoiNjIxMzIzMDIyMzAwMDAwMDAzNDAwMDAiLCJhY2NvdW50IjoiRFVLQUkifQ.LzvpEPcGBeOnfV0tcO9yl11PeWuGQR0lzrRAmdUAcSGhvL-J_UF57P4_Q64qfMrzotoSEiVKiCErs4XcgexDFg4WIpx-wbZWdaQ7zIaFMWY-4eVe3R8Th72ABohwuQ7YRFJuWuNE21m3olfqbnbQ1DztDlsWrjd0l6LohrycK9A0teCAlP4Hhjl9kjT2UrRnMFVep1t5dTz8oPSE4KXNjseG8aTBGYbg304JYFQSfkdn3rB6ucp9FG0b9HGrpw1kCdq16m2VXGmKlqGizrOFw30SEZ9z9dABWiNMZjt3AqhY1ByNFtx0bNY-51DOdfVHeWTUDqItuwOak86r-ZVH_w";
try {
Claims claims = verifyJWTToken(jwtToken, publicKeyStr);
String account = claims.get("account", String.class);
System.out.println("验证成功!");
System.out.println("account: " + account);
System.out.println("过期时间: " + claims.getExpiration());
} catch (Exception e) {
System.err.println("验证失败: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,80 @@
package com.tobacco.mp.utils;
import com.alibaba.fastjson.JSON;
import java.util.*;
public class Maps {
/**
* json去除key-value处理
* @param json
* @return
*/
public static String jsonRemoveKey(String json, String key) {
Map map = JSON.parseObject(json);
Iterator<Map.Entry<String, Object>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Object> entry = iter.next();
if (entry.getKey() != null && entry.getKey().equals(key)) {
map.remove(key);
break;
}
}
return JSON.toJSONString(map);
}
/**
* 默认采用HashMap
* @param args
* @return
*/
public static Map<Object,Object> map(Object ... args){
Map<Object,Object> map = new HashMap<Object, Object>();
fillMap(map, args);
return map;
}
/**
* 默认采用HashMap
* @param args
* @return
*/
public static <K,V> Map<K,V> map(Class<K> kClazz,Class<V> vClassz,Object ... args){
Map<K,V> map = new HashMap<K, V>();
if (args.length % 2 == 0){
for (int i = 0;i < args.length; i+=2){
map.put((K)args[i], (V)args[i+1]);
}
}
return map;
}
public static Map<Object,Object> treemap(Object ... args){
Map<Object,Object> map = new TreeMap<Object, Object>();
fillMap(map, args);
return map;
}
public static <T,V> Map<T,V> copy(Map<T,V> source){
if (source == null){
return Collections.emptyMap();
}
if (source instanceof LinkedHashMap){
return new LinkedHashMap<T,V>(source);
} else if (source instanceof TreeMap){
return new TreeMap<T,V>(source);
} else {
return new HashMap<T,V>(source);
}
}
private static void fillMap(Map target,Object ... args){
if (args.length % 2 == 0){
for (int i = 0;i < args.length; i+=2){
target.put(args[i], args[i+1]);
}
}
}
}

View File

@ -0,0 +1,249 @@
package com.tobacco.mp.utils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
*
*/
public final class Objects {
public static <T> List<T> take(List list, String name, Class<T> clazz) {
try {
List<T> values = new ArrayList<>();
for (Object item : list) {
Object valueObj = PropertyUtils.getProperty(item, name);
T value = (T) valueObj;
if (value != null) {
values.add(value);
}
}
return values;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static <I, T> Map<I, T> index(List<T> list, String name, Class<I> clazz) {
try {
Map<I, T> index = new HashMap<>();
for (T t : list) {
Object valueObj = PropertyUtils.getProperty(t, name);
I key = (I) valueObj;
index.put(key, t);
}
return index;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
/**
* @param target
* @param source
* @param mapKey 默认两个对象之间通过mapKey关联即source中对应的是idtarget中对应的对象的属性是mapKey.replace("Id")
*/
public static void orm(List target, List source, String mapKey) {
try {
String defaultID = "id";
Map<Object, Object> index = index(source, defaultID, Object.class);
String name = mapKey.substring(0, mapKey.length() - defaultID.length());
for (Object t : target) {
Object mapValue = PropertyUtils.getProperty(t, mapKey);
Object value = index.get(mapValue);
PropertyUtils.setProperty(t, name, value);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static void orm(List target, List source, String mapKey, String name) {
try {
String defaultID = "id";
Map<Object, Object> index = index(source, defaultID, Object.class);
for (Object t : target) {
Object mapValue = PropertyUtils.getProperty(t, mapKey);
if(mapValue != null) {
Object value = index.get(Long.parseLong(mapValue.toString()));
PropertyUtils.setProperty(t, name, value);
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static boolean isEmpty(Object value) {
if (value == null) {
return true;
}
if (value instanceof Integer) {
return value.equals(Integer.valueOf(0));
} else if (value instanceof String) {
return StringUtils.isEmpty(value.toString());
}
return false;
}
public static Map<Object, List> group(List list, String prop) {
try {
Map<Object, List> groupIndex = new HashMap<>();
for (Object item : list) {
Object value = PropertyUtils.getProperty(item, prop);
if (value != null) {
List group = groupIndex.get(value);
if (group == null) {
group = new LinkedList();
groupIndex.put(value, group);
}
group.add(item);
}
}
return groupIndex;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
/**
* list去重
* @param list
* @return
*/
public static List removeDuplicate(List list) {
for ( int i = 0 ; i < list.size() - 1 ; i ++ ) {
for ( int j = list.size() - 1 ; j > i; j -- ) {
if (list.get(j).equals(list.get(i))) {
list.remove(j);
}
}
}
return list;
}
/**
* 检查一个列表对象是否有数据
* @param objs
* @return
*/
public static <T> boolean checkObjFieldIsData(Collection<T> objs, String...keys) {
try {
for (T obj : objs) {
if (checkObjField(obj, keys)) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 检查一个列表对象是否有数据
* @param objs false 表示
* @return
*/
public static <T> boolean checkObjFieldIsData(Map<String, List<T>> objs, String...keys) {
try {
Iterator<Map.Entry<String, List<T>>> iter = objs.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, List<T>> entry = iter.next();
for (Object obj : entry.getValue()) {
if (checkObjField(obj, keys)) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 去掉设备类型没有在线率的统计
* @param map
*/
public static <T> void deleteNullDeviceType(Map<Integer, List<T>> map, String...keys) {
List<Integer> eventTypes = new ArrayList<>();
Iterator<Map.Entry<Integer, List<T>>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer, List<T>> entry = iter.next();
boolean result = checkObjFieldIsData(entry.getValue(), keys);
if (!result) {
eventTypes.add(entry.getKey());
}
}
for (Integer s: eventTypes) {
map.remove(s);
}
}
/**
* 检测对象是否有数据
* @param obj
* @return
* @throws IllegalAccessException
*/
private static boolean checkObjField(Object obj, String...keys) throws IllegalAccessException{
for (Field f : obj.getClass().getDeclaredFields()) {
f.setAccessible(true);
if (keys != null) {
boolean isCheck = true;
for (String key : keys) {
if (key.equals(f.getName())) {
isCheck = false;
break;
}
}
if (!isCheck) {
continue;
}
}
if (obj instanceof String && f.get(obj) != null) {
if (!"".equals(String.valueOf(f.get(obj)))) {
return true;
}
} else if (obj instanceof Number && f.get(obj) != null) {
if (!"0".equals(String.valueOf(f.get(obj)))) {
return true;
}
} else if (f.get(obj) != null) {
if (!"0".equals(String.valueOf(f.get(obj)))) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,163 @@
package com.tobacco.mp.utils;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.MessageDigest;
import java.security.SecureRandom;
/**
* 加密加盐工具
*/
public class PasswordUtil {
public static final String ALGORITHM = "PBEWITHMD5andDES";
public static final int ITERATION_COUNT = 100;
public static final String PRIVATE_KRY = "MD5";
public static byte[] initSalt() throws Exception {
// 实例化安全随机数
SecureRandom random = new SecureRandom();
return random.generateSeed(8);
}
/**
* md5加密处理
* @param s
* @return
*/
private static String md5(String s) {
try {
// MessageDigest是封装md5算法的工具对象还支持SHA算法
MessageDigest md = MessageDigest.getInstance("MD5");
// 通过digest拿到的任意字符串,得到的bates都是等长的
byte[] bytes = md.digest(s.getBytes(StandardCharsets.UTF_8));
return toHex(bytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 二进制转十六进制
* @param bytes 二进制数据
* @return
*/
private static String toHex(byte[] bytes) {
// 把二进制转换成十六进制字符串
char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
StringBuilder ret = new StringBuilder(bytes.length * 2);
// 循环判断是为了补位操作
for (int i = 0; i < bytes.length; i++) {
ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
}
return ret.toString();
}
/**
* 对密码进行加密加盐操作
* @param password
* @return
*/
public static String encode(String password, String salt) {
//加密
String hexPwd = md5(password);
//加盐操作
StringBuilder builder = new StringBuilder(hexPwd);
builder.insert(18, salt);
//返回加密加盐后的字符串
return builder.toString();
}
/**
* 校对密码是否匹配匹配则返回true
* @param password
* @param dbPassword
* @return
*/
public static boolean match(String password, String dbPassword) {
StringBuilder builder = new StringBuilder(dbPassword);
//去盐操作生成md5加密后原始字符
builder.replace(18, 26, "");
//加密新密码生成md5加密字符
password = md5(password);
//校对加密字符与原始字符是否匹配
return password.equals(builder.toString());
}
/***
* 转换密钥函数
* @param password 密码
* @return 密钥
*/
private static Key toKey(String password) throws Exception {
//密钥材料
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
//实例化
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
//生成密钥
return factory.generateSecret(keySpec);
}
/***
* @Deprecated 加密函数
* @param data 待加密数据
*/
public static String newEncrypt(String data, String salt) throws Exception {
// 盐加密转换为数组类型
byte[] saltByte = salt.getBytes();
// 通过私钥拿到密钥
Key key = toKey(PRIVATE_KRY);
// 创建算法实体类
PBEParameterSpec spec = new PBEParameterSpec(saltByte, ITERATION_COUNT);
// 创建加密实体类
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 通过私钥和算法类初始化加密构造
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
// 方法需要数组 这里直接封装好了
return DatatypeConverter.printBase64Binary(cipher.doFinal(data.getBytes()));
}
/***
* @Deprecated 解密函数
* @param encrypt 待解密数据
*/
public static String newDecrypt(String encrypt, String salt) {
try {
// 盐加密转换为数组类型
byte[] saltByte = salt.getBytes();
// 通过私钥拿到密钥
Key key = toKey(PRIVATE_KRY);
// 创建算法实体类
PBEParameterSpec spec = new PBEParameterSpec(saltByte, ITERATION_COUNT);
// 创建加密实体类
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 通过私钥和算法类初始化加密构造
cipher.init(Cipher.DECRYPT_MODE, key, spec);
// 方法需要数组 这里直接封装好了
byte[] decode = DatatypeConverter.parseBase64Binary(encrypt);
return new String(cipher.doFinal(decode));
} catch (Exception e) {
e.printStackTrace();
return salt;
}
}
public static void main(String[] args) throws Exception {
// String salt = RandomUtil.generateString(8);
// String salt = "UhHoJ6Z8";
// String password = "123456";
// System.err.println("盐值:" + salt);
// System.err.println("密码:" + newEncrypt(password, salt));
// System.err.println(newDecrypt("qYc/bjJN5cI+bQjFQaEoMA==","WZIpOlpa"));
System.err.println(newDecrypt("fihwsY8n4KDkh0wCaKrZpQ==", "sUio5KqE"));
}
}

View File

@ -0,0 +1,95 @@
package com.tobacco.mp.utils;
import java.util.Random;
/**
* 随机数工具
*/
public class RandomUtil {
public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String LETTERCHAR = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* 返回一个定长的随机字符串(只包含大小写字母、数字)
* @param length 随机字符串长度
* @return 随机字符串
*/
public static String generateString(int length) {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
return sb.toString();
}
/**
* 返回一个定长的随机纯字母字符串(只包含大小写字母)
* @param length 随机字符串长度
* @return 随机字符串
*/
public static String generateMixString(int length) {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(ALLCHAR.charAt(random.nextInt(LETTERCHAR.length())));
}
return sb.toString();
}
/**
* 返回一个定长的随机纯大写字母字符串(只包含大小写字母)
* @param length 随机字符串长度
* @return 随机字符串
*/
public static String generateLowerString(int length) {
return generateMixString(length).toLowerCase();
}
/**
* 返回一个定长的随机纯小写字母字符串(只包含大小写字母)
* @param length 随机字符串长度
* @return 随机字符串
*/
public static String generateUpperString(int length) {
return generateMixString(length).toUpperCase();
}
/**
* 生成一个定长的纯0字符串
* @param length 字符串长度
* @return 纯0字符串
*/
public static String generateZeroString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append('0');
}
return sb.toString();
}
/**
* 根据数字生成一个定长的字符串长度不够前面补0
* @param num 数字
* @param fixdLenth 字符串长度
* @return 定长的字符串
*/
public static String toFixdLengthString(long num, int fixdLenth) {
StringBuilder sb = new StringBuilder();
String strNum = String.valueOf(num);
if (fixdLenth - strNum.length() >= 0) {
sb.append(generateZeroString(fixdLenth - strNum.length()));
} else {
throw new RuntimeException("将数字" + num + "转化为长度为" + fixdLenth + "的字符串发生异常!");
}
sb.append(strNum);
return sb.toString();
}
public static void main(String[] args) {
System.out.println("定长的随机字符串(只包含大小写字母、数字):" + generateString(10));
}
}

View File

@ -0,0 +1,317 @@
package com.tobacco.mp.utils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Redis工具
*/
@Component(value = "redisUtils")
public class RedisUtils {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 设置过期时间
* @param key
* @param expireTime
* @param unit
*/
public void setExpire(String key, Long expireTime, TimeUnit unit) {
redisTemplate.expire(key, expireTime, unit);
}
/**
* 递增
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
/**
* 获取redis中缓存信息
* @return
*/
public List<String> getRedisCacheMessage() {
List<String> list = new ArrayList<>();
Set<String> keys = redisTemplate.keys("*");
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
}