IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 使用aop和反射对controller方法入参进行格式化(通用版) -> 正文阅读

[Java知识库]使用aop和反射对controller方法入参进行格式化(通用版)

1. 上一篇 [使用aop和反射对controller方法入参进行格式化(简化版)]中,功能已经实现了,但是存在扩展性的问题:

自定义注解和processor的绑定工作在Enum中完成,它的扩展性是非常差的。后面我们将该功能封装为jar包之后,该如何暴露接口来扩展呢(Enum是存在jar包中的,无法动态添加)

2. 摒弃Enum做绑定

  1. FieldFormatterEnum.getFormatters(获取受支持的自定义注解集合)代替方案
@Autowired
Set<? extends AbstractFormatterProcessor> processors;
使用上述代码,在切面类中注入自定义注解的processors集合,将自定义注解和processor的绑定工作在processors中完成.
private Set<Class<? extends Annotation>> getSupportAnnotationTypes() {
        Set<Class<? extends Annotation>> annotations = new HashSet<>();
        this.processors.forEach((i) -> {
            Optional<Class<? extends Annotation>> any = i.getHandleAnnotations().stream().filter(annotations::contains).findAny();
            if (any.isPresent()) {
                log.error("muilti handle processor find for annotaion '{}'", any.get().getName());
//                throw new Exception(String.format("muilti handle processor find for annotaion '%s'", any.get().getName()));
            } else {
                annotations.addAll(i.getHandleAnnotations());
            }
        });
        return annotations;
    }
    上述代码遍历processors获取存放的annotations
  1. FieldFormatterEnum.getProcessorByAnnotation(根据自定义注解获取绑定的processor)代替方案
private Class<? extends AbstractFormatterProcessor> getProcessorByAnnotation(Class<? extends Annotation> annotationType) {
        Optional<? extends AbstractFormatterProcessor> first = processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst();
        if (first.isPresent()) {
            return first.get().getClass();
        } else {
            return null;
        }
    }同样遍历processors获取到对应的processor

3. 由上引发的线程安全问题

AbstractFormatterProcessor子类修改为spring容器中bean,其中的属性就涉及线程安全问题
需要将属性转移到ArgElementMetadata中,下面贴一下修改的代码
  1. 顶级接口FormatterProcessor
public interface FormatterProcessor {

    void format(Object obj, Field field, Annotation annotation) throws Exception;
}
  1. 抽象实现AbstractFormatterProcessor
public abstract class AbstractFormatterProcessor implements FormatterProcessor {

    protected Set<Class<? extends Annotation>> handleAnnotations = new LinkedHashSet<>();

    @PostConstruct
    public void init() {
        this.setHandleAnnotations();
    }

    protected abstract void setHandleAnnotations();

    public Set<Class<? extends Annotation>> getHandleAnnotations() {
        return handleAnnotations;
    }
}
  1. 自定义注解processor
@Component
public class YMDtFormatterProcessor extends AbstractFormatterProcessor {

    @Override
    public void format(Object obj, Field field, Annotation annotation) throws Exception {
        ReflectionUtils.makeAccessible(field);
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        String yoyDtName = "";
        String momDtName = "";
        String pattern = "";
        if (annotation.annotationType().isAssignableFrom(YMDtFormatter.class)) {
            momDtName = ((YMDtFormatter) annotation).momDtName();
            yoyDtName = ((YMDtFormatter) annotation).yoyDtName();
            pattern = ((YMDtFormatter) annotation).pattern();
        }
        Object curValue = field.get(obj);
        String finalYoyDtName = yoyDtName;
        String finalMomDtName = momDtName;
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);

        Arrays.stream(declaredFields).forEach(i->{
            if (StringUtils.isNotEmpty(finalYoyDtName) && finalYoyDtName.equals(i.getName())) {
                ReflectionUtils.makeAccessible(i);
                try {
                    Calendar now = Calendar.getInstance();
                    now.setTime(sdf.parse(String.valueOf(curValue)));
                    now.add(Calendar.MONTH, -1);
                    i.set(obj, sdf.format(now.getTime()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (StringUtils.isNotEmpty(finalMomDtName) && finalMomDtName.equals(i.getName())) {
                ReflectionUtils.makeAccessible(i);
                try {
                    Calendar now = Calendar.getInstance();
                    now.setTime(sdf.parse(String.valueOf(curValue)));
                    now.add(Calendar.YEAR, -1);
                    i.set(obj, sdf.format(now.getTime()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void setHandleAnnotations() {
        this.handleAnnotations.add(YMDtFormatter.class);
    }
}
  1. 自定义注解包装类ArgElementMetadata
@Data
@Accessors(chain = true)
public class ArgElementMetadata {
    /**
     * 集合处理优先级使用
     */
    private Integer order;

    /**
     * 属性字段
     */
    private Field arg;

    /**
     * 注入对象
     */
    private Object object;
    /**
     * 字段注解信息
     */
    private Annotation annotation;

    private AbstractFormatterProcessor processor;

    public void format() throws IllegalAccessException {
        this.processor.format(this.object,this.arg,this.annotation);
    }

}
  1. 切面VoAspect
@Slf4j
@Aspect
@Component
public class VoAspect {

    @Autowired
    Set<? extends AbstractFormatterProcessor> processors;

    @Around("execution(public * *..controller.*.*(..))")
//    TODO 切入具体参数注解
//            " && @args(cn.com.gome.bdc.data.platform.merchant.web.annotation.vo.EnableFormat)" +
    public Object VoFormat(ProceedingJoinPoint pjp) throws Throwable {
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        HashSet<Integer> positions = new HashSet<>();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Annotation[] annotations = parameterAnnotations[i];
            for (int j = 0; j < annotations.length; j++) {
                Annotation annotation = annotations[j];
                if (annotation.annotationType().isAssignableFrom(EnableFormat.class)) {
                    positions.add(i);
                    break;
                }
            }
        }
        Object vo;
        if (positions.size() > 0) {
            Object[] args = pjp.getArgs();
            for (Integer position : positions) {
                vo = args[position];
//            vo格式化
                Field[] fields = vo.getClass().getDeclaredFields();

                Set<Class<? extends Annotation>> supportAnnotations = getSupportAnnotationTypes();
                List<ArgElementMetadata> metadatas = new ArrayList<>();

                List<ArgElementMetadata> finalMetadatas = metadatas;
                Object finalVo = vo;
                Arrays.stream(fields).forEach(i -> {
                    Annotation[] filedAnnotations = i.getDeclaredAnnotations();
                    Arrays.stream(filedAnnotations).forEach(j -> {
                        if (supportAnnotations.contains(j.annotationType())) {
                            try {
                                buildArgMetadata(finalVo, i, j, finalMetadatas);
                            } catch (Exception e) {
                                log.error(e.getMessage());
                            }
                        }
                    });
                });

                metadatas = metadatas.stream().sorted(Comparator.comparingInt(ArgElementMetadata::getOrder)).collect(Collectors.toList());

                for (ArgElementMetadata metadata : metadatas) {
                    metadata.format();
                }
                args[position] = vo;
            }
            return pjp.proceed(args);
        } else {
            return pjp.proceed();
        }
    }

    private Set<Class<? extends Annotation>> getSupportAnnotationTypes() {
        Set<Class<? extends Annotation>> annotations = new HashSet<>();
        this.processors.forEach((i) -> {
            Optional<Class<? extends Annotation>> any = i.getHandleAnnotations().stream().filter(annotations::contains).findAny();
            if (any.isPresent()) {
                log.error("muilti handle processor find for annotaion '{}'", any.get().getName());
            } else {
                annotations.addAll(i.getHandleAnnotations());
            }
        });
        return annotations;
    }

    private void buildArgMetadata(Object vo, Field i, Annotation j, List<ArgElementMetadata> metadatas) throws Exception {
        final int[] order = new int[1];
        Arrays.stream(j.getClass().getDeclaredMethods()).filter(k -> "order".equals(k.getName())).findFirst()
                .ifPresent(g -> {
                    try {
                        order[0] = Integer.parseInt(String.valueOf(
                                g.invoke(j)
                        ));
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                });
        Class<? extends AbstractFormatterProcessor> processorClass = getProcessorByAnnotation(j.annotationType());
        if (Objects.isNull(processorClass)) {
            return;
        }
        metadatas.add(new ArgElementMetadata()
                .setOrder(order[0] > 0 ? order[0] : 5)
                .setArg(i).setProcessor(getProcessorBeanByAnnotation(j.annotationType())).setObject(vo).setAnnotation(j)
        );
    }

    private Class<? extends AbstractFormatterProcessor> getProcessorByAnnotation(Class<? extends Annotation> annotationType) {
        Optional<? extends AbstractFormatterProcessor> first = processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst();
        if (first.isPresent()) {
            return first.get().getClass();
        } else {
            return null;
        }
    }

    private AbstractFormatterProcessor getProcessorBeanByAnnotation(Class<? extends Annotation> annotationType) {
        return processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst().orElse(null);
    }
}

4. 遗留

暂不支持集合属性的格式化
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:21:20  更:2022-03-24 00:23:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:44:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码