泛型反序列化
/**
* 字符串转换成对象 支持多级转换以及泛型等 比如 UCRoot<List<Hospital>> 、List<Hospital> 等
* eg:
*
* @param jsonStr
* @param types
* @return
*/
public static Object parseObject(String jsonStr, Type[] types) {
if (isBlank(jsonStr) || ArrayUtils.isEmpty(types)) {
return null;
}
if (types.length == 1) {
if (jsonStr.startsWith("[{")) {
return JSONObject.parseArray(jsonStr, (Class) types[0]);
} else {
return JSONObject.parseObject(jsonStr, types[0]);
}
}
ParameterizedTypeImpl beforeType = null;
if (types != null && types.length > 0) {
for (int i = types.length - 1; i > 0; i--) {
beforeType = new ParameterizedTypeImpl(new Type[]{beforeType == null ? types[i] : beforeType}, null, types[i - 1]);
}
}
return JSONObject.parseObject(jsonStr, beforeType);
}
1.注解
import java.lang.annotation.*;
/**
* 是否启用自定义的 线程缓存
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CacheAopFitter {
String value() default "";
int timeout() default 15; //缓存时间(单位:秒)
/**
* 缓存类型 1:线程缓存 2:内存缓存 3:Redis缓存
*
* @return
*/
CacheUtils.CacheType cacheType() default CacheUtils.CacheType.Redis;
/**
* list 或者泛型 如果是 List 可以省略掉 List.class 反序列化时会判断是否是list类型
* eg UCRoot<List<Pharmacy>>:[UCRoot.class,List.class,Pharmacy.class] 、 List<Pharmacy>:[List.class,Pharmacy.class]
*
* @return
*/
Class[] classes() default {};
}
2 aop拦截器
import cn.ucmed.baseline.d2d.service.Cache.RedisService;
import com.ucmed.common.util.CommonUtil;
import lombok.extern.log4j.Log4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* AOP 对静态的方法没用
* 药事获取用户中心的数据都是 使用静态方法(aop没有生效) 暂时不修改
*/
@Aspect
@Component
@Log4j
public class CacheAop {
@Autowired
RedisService redisService;
//控制器切点
@Pointcut("@annotation(cn.ucmed.baseline.d2d.aop.CacheAopFitter) || @within(cn.ucmed.baseline.d2d.aop.CacheAopFitter)")
public void cachePoint() {
}
@Around("cachePoint()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//获取注解参数
CacheUtils.MyAnnotation myAnnotation = CacheUtils.getAnnotation(joinPoint);
Object object = null;
//生成key
String key = "";
if (myAnnotation.cacheType == CacheUtils.CacheType.ThreadLocal) {
key = CacheUtils.createKey(joinPoint);
//获取缓存的值
object = CacheUtils.getByKey(key);
} else if (myAnnotation.cacheType == CacheUtils.CacheType.Memory) {
key = CacheUtils.createKeyForMemory(joinPoint);
//获取缓存的值
object = CacheUtils.getByKeyForMemory(key);
} else if (myAnnotation.cacheType == CacheUtils.CacheType.Redis) {
key = CacheUtils.createKeyForRedis(joinPoint);
//获取缓存的值
object = redisService.getObject(key, myAnnotation.getClasses());
}
//判断是否存在 如果有这直接返回
if (object != null) return object;
Object value = joinPoint.proceed();
//缓存结果
if (value != null) {
if (myAnnotation.cacheType == CacheUtils.CacheType.ThreadLocal) {
CacheUtils.setValueByKey(key, value, myAnnotation);
} else if (myAnnotation.cacheType == CacheUtils.CacheType.Memory) {
CacheUtils.setValueByKeyForMemory(key, value, myAnnotation);
} else if (myAnnotation.cacheType == CacheUtils.CacheType.Redis) {
redisService.setObject(key, value, myAnnotation.timeout);
}
}
//返回结果
return value;
}
}
3工具类
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Description
* @auther machunsen
* @create 2019-07-22 15:31:12
*/
@Log4j
public class CacheUtils {
//线程缓存
private static ThreadLocal<Map<String, MyValue>> localStorage = ThreadLocal.withInitial(HashMap::new);
//内存缓存
private static Map<String, MyValue> memoryCache = new ConcurrentHashMap<>();
//上一次清理时间
private static String cacheLastClearTime = "YSFWPT_cacheLastClearTime";
//清理缓存间隔
private static Long clearCacheInterval = 30 * 60 * 1000L;
//region ThreadLocal缓存
public static Map<String, MyValue> get() {
return localStorage.get();
}
public static void set(Map<String, MyValue> map) {
localStorage.set(map);
}
/**
* 移除本地变量
*/
public static void remove() {
localStorage.remove();
}
/**
* 根据key 获取缓存的值
*
* @param key
* @return
*/
public static Object getByKey(String key) {
Map<String, MyValue> map = getMyCache();
return getValueByKey(map, key);
}
/**
* 设置缓存的值
*
* @param key
* @param value
*/
public static void setValueByKey(String key, Object value, MyAnnotation myAnnotation) {
Map<String, MyValue> map = getMyCache();
setValue(map, key, value, myAnnotation);
}
/**
* 获取缓存map
*
* @return
*/
private static Map<String, MyValue> getMyCache() {
Map<String, MyValue> map = localStorage.get();
if (map == null) {
localStorage.set(new HashMap<>());
}
return map;
}
//endregion
//region 内存缓存
public static Object getByKeyForMemory(String key) {
return getValueByKey(memoryCache, key);
}
public static void setValueByKeyForMemory(String key, Object value, MyAnnotation myAnnotation) {
setValue(memoryCache, key, value, myAnnotation);
}
//endregion
private static Object getValueByKey(Map<String, MyValue> map, String key) {
if (map == null) return null;
//判断是否需要清空缓存
MyValue myValue = map.get(cacheLastClearTime);
boolean needInitStartTime = false;
if (myValue != null) {
//如果大于清除间隔则清除缓存
if (System.currentTimeMillis() - myValue.startTime > clearCacheInterval) {
map.clear();
return null;
}
} else {
needInitStartTime = true;
}
//出事化清除间隔的开始时间
if (needInitStartTime) {
map.put(cacheLastClearTime, new MyValue());
}
//获取值
myValue = map.get(key);
if (myValue != null) {
//如果超时了则移除
if (System.currentTimeMillis() - myValue.startTime > myValue.getMyAnnotation().getTimeout() * 1000) {
map.remove(key);
} else {
return myValue.getValue();
}
}
return null;
}
private static void setValue(Map<String, MyValue> map, String key, Object value, MyAnnotation myAnnotation) {
if (map == null) return;
MyValue myValue = new MyValue();
myValue.setValue(value);
myValue.setMyAnnotation(myAnnotation);
map.put(key, myValue);
}
/**
* 生成 key
*
* @param joinPoint
* @return
*/
static String createKey(ProceedingJoinPoint joinPoint) {
//类名
String className = joinPoint.getTarget().getClass().getName();
//方法名
String methodName = joinPoint.getSignature().getName();
//参数对象
Object[] methodArgs = joinPoint.getArgs();
String key = className + "." + methodName + Thread.currentThread().getId() + MD5(JSONObject.toJSONString(methodArgs));
return key;
}
static String createKeyForMemory(ProceedingJoinPoint joinPoint) {
//类名
String className = joinPoint.getTarget().getClass().getName();
//方法名
String methodName = joinPoint.getSignature().getName();
//参数对象
Object[] methodArgs = joinPoint.getArgs();
String key = className + "." + methodName + MD5(JSONObject.toJSONString(methodArgs));
return key;
}
static String createKeyForRedis(ProceedingJoinPoint joinPoint) {
//类名
String className = joinPoint.getTarget().getClass().getName();
//方法名
String methodName = joinPoint.getSignature().getName();
//参数对象
Object[] methodArgs = joinPoint.getArgs();
String key = className + "." + methodName + JSONObject.toJSONString(methodArgs);
key = methodName + "_" + MD5(key);
return key;
}
/**
* md5 方法
*
* @param plainText
* @return
*/
private static String MD5(String plainText) {
//定义一个字节数组
byte[] secretBytes = null;
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
//对字符串进行加密
md.update(plainText.getBytes());
//获得加密后的数据
secretBytes = md.digest();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
//将加密后的数据转换为16进制数字
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
/**
* 获取注解中的参数
*
* @param joinPoint
* @return
*/
public static CacheUtils.MyAnnotation getAnnotation(ProceedingJoinPoint joinPoint) {
CacheUtils.MyAnnotation myAnnotation = new CacheUtils.MyAnnotation();
CacheAopFitter cacheAopFitter = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CacheAopFitter.class);
if (cacheAopFitter == null) {
cacheAopFitter = joinPoint.getTarget().getClass().getAnnotation(CacheAopFitter.class);
}
if (cacheAopFitter != null) {
myAnnotation.setTimeout(cacheAopFitter.timeout());
myAnnotation.setValue(cacheAopFitter.value());
myAnnotation.setCacheType(cacheAopFitter.cacheType());
if (!ArrayUtils.isEmpty(cacheAopFitter.classes())) {
myAnnotation.setClasses(cacheAopFitter.classes());
} else {
try {
Class classzz = Class.forName(joinPoint.getSignature().toLongString().split(" ")[1]);
myAnnotation.setClasses(new Class[]{classzz});
} catch (Exception ex) {
log.error("缓存转换类型失败", ex);
}
}
}
return myAnnotation;
}
// /**
// * 缓存类
// */
// @Data
// public static class MyCahce {
//
// private Map<String, MyValue> map = new HashMap<>();
// private MyAnnotation myAnnotation = new MyAnnotation();
// }
/**
* 值对象
*/
@Data
public static class MyValue {
private Object value;
private Long startTime = System.currentTimeMillis();
MyAnnotation myAnnotation;
}
/**
* 缓存的类型 线程缓存和内存缓存不适合缓存比较大的数据
* 比较大的数据可以使用redis缓存
*/
public static enum CacheType {
/**
* 线程缓存
*/
ThreadLocal,
/**
* 直接缓存在内存中 ConcurrentHashMap中
*/
Memory,
/**
* //使用redis 如果返回值是泛型 使用redis不能反序列化,导致获取失败
*/
Redis;
}
/**
* 缓存类
*/
@Data
public static class MyAnnotation {
String value = "";
int timeout = 15;//超时时间
CacheType cacheType = CacheType.Redis; //缓存类型
//返回值类型
Class[] classes;
}
}
[转载]fastjson反序列化多层嵌套泛型类与java中的Type类型