字典切面实现code动态匹配字典表返回对应的值,解决需要关联查询字典表的问题,可以进一步优化sql执行效率,里面主要整合了 实体,List,项目响应消息实体的字典数据组装。
主要代码如下:
package com.cxm.wechat.common.aop;
import com.alibaba.fastjson.JSON;
import com.cxm.common.annotation.DictInfoAnnotation;
import com.cxm.common.exception.BusinessException;
import com.cxm.commons.constants.Constants;
import com.cxm.commons.utils.DateUtil;
import com.cxm.wechat.service.IDictInfoService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
/**
* 字典切面实现类
* @author zhangliuming
* @date 2019/4/28
*/
@Aspect
@Component
@Log4j2
public class DictInfoAspect {
@Resource
private IDictInfoService dictInfoService;
/**
* 根据改注解实现切点
*/
@Pointcut("@annotation(com.cxm.common.annotation.DictUtilAnnotation)")
public void logPointCut() {
}
/**
* @decription 环绕通知,包围一个连接点的通知
* @author zhangliuming
* @date 2019/4/30
* @param point
* @return
* @throws Throwable
*/
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
// 执行方法获取返回的结果
Object result = point.proceed();
if (result == null){
return null;
}
Class<?> classInfo = null;
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) point.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
// 获取返回值类型
Type type = method.getGenericReturnType();
// 判断获取的类型是否是参数类型
if (type instanceof ParameterizedType) {
// 强制转型为带参数的泛型类型,
Type[] typesto = ((ParameterizedType) type).getActualTypeArguments();
List lists = new ArrayList();
classInfo = Class.forName(typesto[0].getTypeName());
//如果类型为list对象就对其做list数据转换
JSONArray jsonArray = null;
if (((ParameterizedType) type).getRawType().getTypeName().equals(Constants.DataType.JAVA_UTIL_LIST)){
jsonArray = JSONArray.parseArray(JSON.toJSONString(result));
if (jsonArray != null){
//获取list对象
for (int i = 0; i < jsonArray.size(); i++) {
jsonArray.set(i,fieldToValue(classInfo, jsonArray.getJSONObject(i)));
}
result = jsonArrayToListBean(jsonArray, classInfo);
}
} else {
//数据转json
JSONObject jsonResult = JSONObject.parseObject(JSON.toJSONString(result));
List list = (List) jsonResult.get("data");
for (int i = 0; i < list.size(); i++) {
lists.add(fieldToValue(classInfo, (JSONObject) list.get(i)));
}
jsonResult.put("data", lists);
result = jsonObjToClass(jsonResult, result.getClass());
}
}else {
classInfo = result.getClass();
JSONObject jsonResult = JSONObject.parseObject(JSON.toJSONString(result));
Object obj=fieldToValue(classInfo, jsonResult);
//map数据转为原始对象
JSONObject objs = JSONObject.parseObject(JSON.toJSONString(obj));
result = jsonObjToClass(objs, classInfo);
}
long time = System.currentTimeMillis() - beginTime;
log.info("总耗时:" + time);
// 保存日志
return result;
}
/**
* @description 给注解的字段赋值
* @author zhangliuming
* @date 2019/4/29
* @param c
* @param jsonObject
* @return
*/
public Object fieldToValue(Class<?> c, JSONObject jsonObject) {
Field[] field = c.getDeclaredFields();
for (Field f : field) {
DictInfoAnnotation fa = f.getAnnotation(DictInfoAnnotation.class);
//判断是否是加入注解的字段,是给其赋值
if (fa != null) {
try {
String name = f.getName();
String dictCode = String.valueOf(jsonObject.get(name));
if (StringUtils.isEmpty(dictCode)){
jsonObject.put(name, "");
}else {
//根据字典父级编码和code取该字典值
String value = dictInfoService.getValueByParentIdAndCode(fa.parentId(), dictCode);
jsonObject.put(name, value);
}
} catch (BusinessException e){
log.error(e.getErrorMsg());
} catch (Exception e) {
e.printStackTrace();
}
}
}
return jsonObject;
}
/**
* @description jsonObj转为传入的Class对象------反射原理
* @author zhangliuming
* @date 2019/4/30
* @param jsonObject
* @param clz
* @return
* @throws Exception
*/
public Object jsonObjToClass(JSONObject jsonObject, Class<?> clz) throws Exception {
Object obj = clz.newInstance();
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
int mod = field.getModifiers();
if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
field.setAccessible(true);
String filedTypeName = field.getType().getName();
//日期字段类型需要单独处理
if (filedTypeName.equalsIgnoreCase(Constants.DataType.LOCAL_DATE_TIME)) {
String value = (String) jsonObject.get(field.getName());
if (value == null){
field.set(obj, null);
}else {
field.set(obj, DateUtil.str2LocalDateTime(value));
}
} else if(filedTypeName.equalsIgnoreCase(Constants.DataType.LOCAL_DATE)){
String value = (String) jsonObject.get(field.getName());
if (value == null){
field.set(obj, null);
}else {
field.set(obj, DateUtil.str2LocalDate(value));
}
} else if(filedTypeName.equalsIgnoreCase(Constants.DataType.JAVA_UTIL_DATE)){
String value = (String) jsonObject.get(field.getName());
if (value == null){
field.set(obj, null);
}else {
field.set(obj, DateUtil.str2Date(value,DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS));
}
}else {
field.set(obj, jsonObject.get(field.getName()));
}
}
return obj;
}
/**
*
* @description 将jsonArray转换为JavaBean的方法
* @date 2019/4/30
* @author zhangliuming
* @param jsonArray
* @param clz
* @return
* @throws Exception
*/
public JSONArray jsonArrayToListBean(JSONArray jsonArray,Class<?> clz )throws Exception {
JSONArray jsonArray1 = new JSONArray();
// 将jsonArray转换为JavaBean的方法
for (int i = 0; i < jsonArray.size(); i++) {
Object objs = jsonObjToClass(jsonArray.getJSONObject(i), clz);
// 添加进list集合
jsonArray1.add(objs);
}
return jsonArray1;
}
}
package com.cxm.common.annotation;
import org.springframework.core.annotation.Order;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description 字典工具主要用于实现方法级别的切点
* @author zhangliuming
* @date 2019/4/28
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Order(value = -100)//这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
public @interface DictUtilAnnotation {
}
package com.cxm.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description 字典信息自定义注解,标记再需要转换的实体字典列上
* @author zhangliuming
* @date 2019/4/28
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DictInfoAnnotation {
String parentId() default "";
}
切入点作用于实现类重写的方法上即可,如:
如:某实体类的字段上加入注解标识父级code和当前code即可得到该accountStatus字段对应的字典值