|
@@ -0,0 +1,366 @@
|
|
|
+package com.gree.mall.manager.config.aop;
|
|
|
+
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
|
+import cn.hutool.core.lang.TypeReference;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.gree.mall.manager.annotation.ZfireField;
|
|
|
+import com.gree.mall.manager.enums.base.BaseEnum;
|
|
|
+import com.gree.mall.manager.helper.ResponseHelper;
|
|
|
+import com.gree.mall.manager.plus.entity.AdminField;
|
|
|
+import com.gree.mall.manager.plus.service.AdminFieldService;
|
|
|
+import com.gree.mall.manager.utils.CommonUtils;
|
|
|
+import com.gree.mall.manager.zfire.bean.ZfireParamBean;
|
|
|
+import io.swagger.annotations.ApiModelProperty;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.poi.ss.formula.functions.T;
|
|
|
+import org.aspectj.lang.JoinPoint;
|
|
|
+import org.aspectj.lang.Signature;
|
|
|
+import org.aspectj.lang.annotation.AfterReturning;
|
|
|
+import org.aspectj.lang.annotation.Aspect;
|
|
|
+import org.aspectj.lang.annotation.Before;
|
|
|
+import org.aspectj.lang.annotation.Pointcut;
|
|
|
+import org.aspectj.lang.reflect.MethodSignature;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.annotation.Order;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.web.context.request.RequestContextHolder;
|
|
|
+import org.springframework.web.context.request.ServletRequestAttributes;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.lang.annotation.Annotation;
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.lang.reflect.ParameterizedType;
|
|
|
+import java.lang.reflect.Type;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Aspect
|
|
|
+@Component
|
|
|
+@Slf4j
|
|
|
+@Order(1)
|
|
|
+public class ZfireFiledAop {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ AdminFieldService adminFieldService;
|
|
|
+
|
|
|
+
|
|
|
+ @Pointcut("@annotation(com.gree.mall.manager.annotation.ZfireList)")
|
|
|
+ public void auth() {}
|
|
|
+
|
|
|
+ @AfterReturning(value = "auth()",returning = "result")
|
|
|
+ public void doAfter(JoinPoint joinPoint, Object result) throws Exception {
|
|
|
+ start(joinPoint,result);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Before("auth()")
|
|
|
+ public void doBefore(JoinPoint joinPoint) {
|
|
|
+ Arrays.stream(joinPoint.getArgs())
|
|
|
+ .filter(ZfireParamBean.class::isInstance)
|
|
|
+ .map(ZfireParamBean.class::cast)
|
|
|
+ .findFirst()
|
|
|
+ .ifPresent(item -> buildReturnTypeClazz(item, joinPoint));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析返回值{@code ResponseHelper<IPage<Obj>>}中的Obj的类型
|
|
|
+ * @param zfireParam
|
|
|
+ * @param joinPoint
|
|
|
+ */
|
|
|
+ private void buildReturnTypeClazz(ZfireParamBean zfireParam, JoinPoint joinPoint) {
|
|
|
+ if (Objects.isNull(zfireParam)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Signature signature = joinPoint.getSignature();
|
|
|
+ if (!(signature instanceof MethodSignature)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ MethodSignature methodSignature = (MethodSignature) signature;
|
|
|
+ Method method = methodSignature.getMethod();
|
|
|
+ Type type = method.getGenericReturnType();
|
|
|
+ if (!(type instanceof ParameterizedType)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ParameterizedType parameterizedType = (ParameterizedType) type;
|
|
|
+ if (!parameterizedType.getRawType().equals(ResponseHelper.class)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
|
|
+ if (actualTypeArguments.length == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Type actualTypeArgument = actualTypeArguments[0];
|
|
|
+ if (!(actualTypeArgument instanceof ParameterizedType)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ParameterizedType parameterizedType1 = (ParameterizedType) actualTypeArgument;
|
|
|
+ Type[] actualTypeArgumentsArrays = parameterizedType1.getActualTypeArguments();
|
|
|
+ if (actualTypeArgumentsArrays.length == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Type actualTypeArg = actualTypeArgumentsArrays[0];
|
|
|
+ if (!(actualTypeArg instanceof Class)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Class<?> clazz = (Class<?>) actualTypeArg;
|
|
|
+ zfireParam.setClazzType(clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * {
|
|
|
+ * moduleId:"菜单id" //不为空
|
|
|
+ * jName:"java字段名" //前端渲染使用的字段名,不为空
|
|
|
+ * label:"字段title" //字段标题
|
|
|
+ * placeholder:"提示语"
|
|
|
+ * type:"输入类型【input/select】"
|
|
|
+ * option:[{
|
|
|
+ * value:"",
|
|
|
+ * name:""
|
|
|
+ * }]
|
|
|
+ * multiple:true //true=多选,false=单选
|
|
|
+ * frontCode:"" //前端预留code,由前端自定义,默认为空
|
|
|
+ * sortNum:1 //排序字段
|
|
|
+ * tbName:"表名" //可能为空(查询组装参数用)
|
|
|
+ * colName:"字段名" //可能为空(查询组装参数用)
|
|
|
+ * }
|
|
|
+ */
|
|
|
+ private void start(JoinPoint joinPoint, Object result) throws Exception {
|
|
|
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
|
+ //Method sourceMethod = getSourceMethod(joinPoint);
|
|
|
+ HttpServletRequest request = attributes.getRequest();
|
|
|
+ //当前菜单ID
|
|
|
+ String moduleId = request.getParameter("moduleId");
|
|
|
+ //当前用户id
|
|
|
+ String adminUserId = CommonUtils.getUserId(request);
|
|
|
+
|
|
|
+ if(!(result instanceof ResponseHelper)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ResponseHelper responseHelper = (ResponseHelper)result;
|
|
|
+ if(responseHelper.getCode() != ResponseHelper.ResponseCode_Success){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Object data = responseHelper.getData();
|
|
|
+ if(!(data instanceof Page)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Page page = (Page) data;
|
|
|
+ List<T> records = page.getRecords();
|
|
|
+ //当前菜单当前用户的配置
|
|
|
+ Map<String, AdminField> fieldMap = adminFieldService.lambdaQuery()
|
|
|
+ .eq(AdminField::getAdminUserId, adminUserId)
|
|
|
+ .eq(AdminField::getModuleId,moduleId)
|
|
|
+ .orderByAsc(AdminField::getSortNum)
|
|
|
+ .list()
|
|
|
+ .stream()
|
|
|
+ .collect(Collectors.toMap(AdminField::getJName, v -> v));
|
|
|
+
|
|
|
+ //返回的内容的对象
|
|
|
+ Object bean = null;
|
|
|
+ if(!CollectionUtils.isEmpty(records)){
|
|
|
+ bean = records.get(0);
|
|
|
+ }else{
|
|
|
+ records = new ArrayList<>();
|
|
|
+ List list1 = this.newInstance(records,responseHelper.typeReference);
|
|
|
+ bean = list1.get(0);
|
|
|
+ // records.getClass().getTypeName();
|
|
|
+ }
|
|
|
+ String typeName = bean.getClass().getTypeName();
|
|
|
+ ZfireField annotation = bean.getClass().getAnnotation(ZfireField.class);
|
|
|
+ String tbName = "";
|
|
|
+ if (Objects.nonNull(annotation)) {
|
|
|
+ tbName = annotation.tbName();
|
|
|
+ }
|
|
|
+
|
|
|
+ List<AdminField> fieldBeans = new ArrayList<>();
|
|
|
+ //反射获取返回对象中的属性
|
|
|
+ Field[] fields = bean.getClass().getDeclaredFields();
|
|
|
+ for(Field field:fields){
|
|
|
+ field.setAccessible(true);
|
|
|
+
|
|
|
+ AdminField fieldBean = this.getTbCol(field, fieldMap, tbName, bean);
|
|
|
+
|
|
|
+ if (Objects.isNull(fieldBean)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ fieldBeans.add(fieldBean);
|
|
|
+ }
|
|
|
+ //排序
|
|
|
+ fieldBeans = fieldBeans.stream()
|
|
|
+ .sorted(Comparator.comparing(AdminField::getSortNum,Comparator.nullsFirst(Integer::compareTo)))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ //填充字段集
|
|
|
+ responseHelper.setFieldBeans(fieldBeans);
|
|
|
+ }
|
|
|
+
|
|
|
+ public AdminField getTbCol(Field field, Map<String, AdminField> fieldMap, String classTbName, Object obj) throws NoSuchFieldException, IllegalAccessException {
|
|
|
+ String fieldName = field.getName();
|
|
|
+ //获取属性类型
|
|
|
+ boolean hide;
|
|
|
+// String typeName = field.getType().getName();
|
|
|
+ AdminField fieldBean = new AdminField();
|
|
|
+ String typeName = field.getType().getTypeName();
|
|
|
+ fieldBean.setJName(fieldName);
|
|
|
+ fieldBean.setColName(xX2x_x(fieldName));
|
|
|
+ //fieldBean.setColName(name);
|
|
|
+ fieldBean.setType("input");
|
|
|
+ fieldBean.setTbName(classTbName);
|
|
|
+ fieldBean.setTiling(true);
|
|
|
+ fieldBean.setIsShow(true);
|
|
|
+ fieldBean.setIsQuery(true);
|
|
|
+ fieldBean.setIsCutting(true);
|
|
|
+
|
|
|
+
|
|
|
+ Annotation[] annotations = field.getAnnotations();
|
|
|
+ for(Annotation annotation : annotations){
|
|
|
+
|
|
|
+ if(annotation instanceof ZfireField){
|
|
|
+ ZfireField zfireField = (ZfireField) annotation;
|
|
|
+ String colName = zfireField.colName();
|
|
|
+ String tbName = zfireField.tbName();
|
|
|
+ String frontCode = zfireField.frontCode();
|
|
|
+ String type = zfireField.type();
|
|
|
+ boolean show = zfireField.isShow();
|
|
|
+ boolean total = zfireField.isTotal();
|
|
|
+ boolean query = zfireField.isQuery();
|
|
|
+ boolean pk = zfireField.pk();
|
|
|
+ hide = zfireField.hide();
|
|
|
+ if (StringUtils.isNotBlank(colName))
|
|
|
+ fieldBean.setColName(colName);
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(tbName))
|
|
|
+ fieldBean.setTbName(tbName);
|
|
|
+
|
|
|
+ fieldBean.setFrontCode(frontCode);
|
|
|
+ fieldBean.setType(type);
|
|
|
+ fieldBean.setSortNum(zfireField.sortNum());
|
|
|
+ fieldBean.setIsShow(show);
|
|
|
+ fieldBean.setHide(hide);
|
|
|
+ fieldBean.setIsTotal(total);
|
|
|
+ fieldBean.setIsQuery(query);
|
|
|
+ fieldBean.setFixed(zfireField.fixed());
|
|
|
+ fieldBean.setPk(pk);
|
|
|
+ fieldBean.setMultiple(zfireField.multiple());
|
|
|
+ fieldBean.setIsCutting(zfireField.isCutting());
|
|
|
+
|
|
|
+ }else if(annotation instanceof ApiModelProperty){
|
|
|
+ ApiModelProperty property = (ApiModelProperty) annotation;
|
|
|
+ fieldBean.setLabel(property.value());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //处理枚举类型
|
|
|
+ Map<String,String> enumMap = Maps.newHashMap();
|
|
|
+ if(field.getType().isEnum()) {
|
|
|
+ for (Object enumO : field.getType().getEnumConstants()) {
|
|
|
+ Class<?> c = enumO.getClass();
|
|
|
+ if (!BaseEnum.class.isAssignableFrom(c)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ BaseEnum baseEnum = (BaseEnum)enumO;
|
|
|
+ if (!hasJsonIgnoreAnnotation((Enum<?>) baseEnum)) {
|
|
|
+ enumMap.put(baseEnum.getKey(), baseEnum.getRemark());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //枚举类型默认为select
|
|
|
+ fieldBean.setType("select");
|
|
|
+ }
|
|
|
+ fieldBean.setEnumMap(JSONObject.toJSONString(enumMap));
|
|
|
+
|
|
|
+ //拿db的配置来覆盖默认的配置
|
|
|
+ if(fieldMap != null) {
|
|
|
+ AdminField adminField = fieldMap.get(fieldName);
|
|
|
+ if (adminField != null) {
|
|
|
+ BeanUtil.copyProperties(adminField, fieldBean, "label","frontCode","type", "hide", "enumMap","isQuery","pk","multiple","jName","colName","tbName","fixed");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(StringUtils.equals(typeName,"java.math.BigDecimal")){
|
|
|
+ fieldBean.setType("amount");
|
|
|
+ }else if(fieldBean.getType().equals("input") && (StringUtils.equals(typeName,"java.util.Date") || StringUtils.equals(typeName,"java.time.LocalDateTime"))){
|
|
|
+ fieldBean.setType("datetime");
|
|
|
+ }else if(StringUtils.equals(typeName,"java.lang.Integer")){
|
|
|
+ fieldBean.setType("number");
|
|
|
+ }
|
|
|
+ if(fieldBean.getSortNum() == null) {
|
|
|
+ fieldBean.setSortNum(999);
|
|
|
+ }
|
|
|
+ return fieldBean;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean hasJsonIgnoreAnnotation(Enum<?> enumValue) throws NoSuchFieldException {
|
|
|
+ Field field = enumValue.getClass().getField(enumValue.name());
|
|
|
+ return field.isAnnotationPresent(JsonIgnore.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Method getSourceMethod(JoinPoint jp) {
|
|
|
+ Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod();
|
|
|
+ try {
|
|
|
+ return jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
|
|
|
+ } catch (NoSuchMethodException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } catch (SecurityException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @author Howe
|
|
|
+ * @Description 将驼峰转为下划线
|
|
|
+ * @param str
|
|
|
+ * @return java.lang.String
|
|
|
+ * @Date 2022/4/22 13:11
|
|
|
+ * @since 1.0.0
|
|
|
+ */
|
|
|
+ public static String xX2x_x(String str) {
|
|
|
+ Pattern compile = Pattern.compile("[A-Z]");
|
|
|
+ Matcher matcher = compile.matcher(str);
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ while(matcher.find()) {
|
|
|
+ matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
|
|
|
+ }
|
|
|
+ matcher.appendTail(sb);
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @author Howe
|
|
|
+ * @Description 将下划线转为驼峰
|
|
|
+ * @param str
|
|
|
+ * @return java.lang.String
|
|
|
+ * @Date 2022/4/22 13:12
|
|
|
+ * @since 1.0.0
|
|
|
+ */
|
|
|
+ public static String x_x2xX(String str) {
|
|
|
+ str = str.toLowerCase();
|
|
|
+ Pattern compile = Pattern.compile("_[a-z]");
|
|
|
+ Matcher matcher = compile.matcher(str);
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ while(matcher.find()) {
|
|
|
+ matcher.appendReplacement(sb, matcher.group(0).toUpperCase().replace("_",""));
|
|
|
+ }
|
|
|
+ matcher.appendTail(sb);
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public <T> List newInstance(List<T> list, TypeReference<T> typeReference) throws IllegalAccessException, InstantiationException {
|
|
|
+ Type tp = typeReference.getClass().getGenericSuperclass();
|
|
|
+ Class<T> type = (Class<T>)((ParameterizedType) tp).getActualTypeArguments()[0];
|
|
|
+ T t = type.newInstance();
|
|
|
+ list.add(t);
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|