定制设计自定义注解结合AOP之实战应用

定制设计自定义注解结合之实战应用

背景介绍

定制设计最近在项目中写了一个定制设计公共的上传文件接口,定制设计项目中有多个业务场景定制设计会使用到上传文件,定制设计每个场景对上传的文件类型,定制设计文件大小有不同的要求。
按常规操作,我们可以在Controller层提供多个接口,然后在每个接口里写if去校验;或者是在一个接口里定义类型去区分不同的业务场景,再分别写if去校验;总而言之,就是要写if去校验。
然后呢,我就不想写if校验,觉得重复代码太多,不够优雅。于是考虑能否通过类似@RequestParam这样的注解,入参上加上一个简单注解就能实现校验。
好了,废话不多说,开始干吧。

步骤流程

首先贴一下项目目录结构

1. 定义注解

如果小伙伴们对如何自定义注解存在疑惑的话,请先阅读这篇文章

  • 定义用于参数上的注解
package com.example.demo.aop.annotation;import java.lang.annotation.*;/** * @author Dong */@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FileParam {    /**     * 文件后缀     */    public String[] suffix() default {"doc", "xls", "ppt", "png", "txt"};    /**     * 文件大小     */    public int size() default 1024;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 定义用于方法上的注解
package com.example.demo.aop.annotation;import java.lang.annotation.*;/** * @author Dong */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FileValid {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.将注解应用于方法和参数

package com.example.demo.controller;import com.example.demo.aop.annotation.FileParam;import com.example.demo.aop.annotation.FileValid;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * @author Dong */@RestController@RequestMapping("/file")@Slf4jpublic class AopTestController {    @PostMapping("/upload")    @FileValid    public String upload(@FileParam(suffix = {"doc"}) MultipartFile file, HttpServletRequest request, HttpServletResponse response) {        log.info("in the method ...");        return "success";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

到这里之后,你运行项目会发现,并没有什么卵用啊,是不是很气,气就对了
所以你应该认识到,如果只是有注解,对项目其实是不起任何作用的,因为它只是相当于一个标记,真正要让它起作用,那就得写一个能识别这些注解,并且在识别到这些注解之后能做出一系列操作的处理器。这就是Java里面强大的反射,或者是Spring的AOP。
如果小伙伴们对AOP不是很了解的话,可以参考这篇文章

3.定义切面

package com.example.demo.aop.aspect;import com.example.demo.aop.annotation.FileParam;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.Arrays;/** * @author Dong */@Component@Aspect@Slf4jpublic class FileValidAspect {    @Pointcut("@annotation(com.example.demo.aop.annotation.FileValid)")    public void pointcut() {    }    @Around("pointcut()")    public Object around(ProceedingJoinPoint pjp) {        // 参数值        Object[] args = pjp.getArgs();        // 方法        Method method = ((MethodSignature) pjp.getSignature()).getMethod();//        String name = pjp.getSignature().getName();//        Method method1 = null;//        try {//            method1 = pjp.getTarget().getClass().getMethod(name, MultipartFile.class, HttpServletRequest.class, HttpServletResponse.class);//        } catch (NoSuchMethodException e) {//            e.printStackTrace();//        }        // 参数列表        Parameter[] mParameters = method.getParameters();        for (int i = 0; i < mParameters.length; i++) {            // 判断参数上是否修饰了注解            if (mParameters[i].isAnnotationPresent(FileParam.class)) {                // 获取注解进而得到注解上的参数值                Annotation annotation = mParameters[i].getAnnotation(FileParam.class);                String[] suffixs = ((FileParam) annotation).suffix();                int size = ((FileParam) annotation).size();                log.info("suffixs: {}, size: {}", suffixs, size);                // 实际文件大小                long rSize = 0L;                // 实际文件后缀                String suffix = null;                if (args[i] instanceof MultipartFile) {                    MultipartFile temp = ((MultipartFile) args[i]);                    rSize = temp.getSize();                    suffix = temp.getOriginalFilename().split("\\.")[1];                    log.info("suffix: {}, size: {}", suffix, rSize);                }                if (rSize > size) {                    return String.format("文件大小:%sByte,超过限定大小:%sByte", rSize, size);                }                if (!Arrays.asList(suffixs).contains(suffix)) {                    return String.format("不支持文件上传类型:%s", suffix);                }            }        }        try {            return pjp.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }        return "error";    }    @Before("pointcut()")    public void before() {        log.info("before ...");    }    @AfterReturning("pointcut()")    public void afterReturning() {        log.info("afterReturning ...");    }    @After("pointcut()")    public void after() {        log.info("after ...");    }    @AfterThrowing("pointcut()")    public void afterThrowing() {        log.info("afterThrowing ...");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

4.测试结果

到此呢,我们整个实战的代码就撸完了,下面跑项目看结果

致谢

最后感谢几位大佬的美文:
1.
2.
3.

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发