• 参数注解检查方法入参


      springboot 中 @NotNull 等参数检查注解非常实用,优化掉了很多的重复代码。

      在开发老版本 spring 项目时,没有类似注解,所以自己实现一个类似的功能,优化代码结构。

      由于项目中没有使用统一异常处理,注解用于 Service 层,抛出的异常由 Controller 处理。

      首先自定义注解:

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface CheckParams {
    }
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.PARAMETER})
    public @interface NotNull {
        String message() default "";
    
        ParamType type() default ParamType.VALUE;
    }

      @CheckParams 注解用做切点,@NotNull 注解标注参数。切面实现:

    @Aspect
    @Component
    public class ParamsCheckAspect {
        private static final Logger logger = Logger.getLogger(ParamsCheckAspect.class);
    
        ControllerUtils controllerUtils = new ControllerUtils();
    
        //切点
        @Pointcut("@annotation(com.inspur.paramsCheck.annotation.CheckParams)")
        public void CheckParamsAspect() {
        }
    
        //切面
        @Around("CheckParamsAspect()")
        public Object check(ProceedingJoinPoint joinPoint) throws IllegalAccessException, Throwable {
            Object[] args = joinPoint.getArgs();
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            Annotation[][] paramsAnnotation = method.getParameterAnnotations();
            if (null != paramsAnnotation && paramsAnnotation.length != 0) {
                for (int i = 0; i < paramsAnnotation.length; i++) {
                    Annotation[] annotations = paramsAnnotation[i];
                    if (null == annotations || annotations.length == 0) continue;
                    int notNullPoint = -1;
                    if ((notNullPoint = this.indexOf(annotations, NotNull.class.getName())) != -1) {
                        Object arg = args[i];
                        NotNull notNull = (NotNull) annotations[notNullPoint];
                        if (notNull.type() == ParamType.VALUE && isNull(arg)) {
                            throw new LackParamException(notNull.message());
                        }
                        if (notNull.type() == ParamType.BEAN) this.checkBean(arg, new HashSet<Object>());
                    }
                }
            }
            return joinPoint.proceed(args);
        }
    
    
        /**
         * @Author
         * @Date 2021/10/2 下午11:53
         * @Description 递归检查对象完整性
         */
        private void checkBean(Object o, Set<Object> hisSet) throws IllegalAccessException {
            //终止条件,处理循环依赖
            if (hisSet.contains(o)) return;
            hisSet.add(o);
            Class clazz = o.getClass();
            String className = clazz.getSimpleName();
            Field[] fields = o.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(NotNull.class)) continue;
                NotNull notNull = field.getAnnotation(NotNull.class);
                ParamType type = notNull.type();
                if (type == ParamType.VALUE && this.isNull(o, field)) {
                    throw new LackParamException(className + ":" + notNull.message());
                }
                if (type == ParamType.BEAN) {
                    field.setAccessible(true);
                    Object bean = field.get(o);
                    if (null == bean) throw new LackParamException(className + ":" + notNull.message());
                    this.checkBean(bean, hisSet);
                }
            }
        }
    
        private int indexOf(Annotation[] arr, String annotationName) {
            for (int i = 0; i < arr.length; i++) {
                Annotation annotation = arr[i];
                String name = annotation.annotationType().getName();
                if (name.equals(annotationName)) return i;
            }
            return -1;
        }
    
        private boolean isNull(Object obj, Field field) throws IllegalAccessException {
            field.setAccessible(true);
            Object value = field.get(obj);
            return isNull(value);
        }
    
        private boolean isNull(Object obj) {
            return null == obj || obj.toString().length() == 0;
        }
    }

      测试,定义 bean:

    public class selectMachineVisitNumDto  extends BasePo {
        @NotNull(message = "regionCode不可为空")
        private String regionCode;
        @NotNull(message = "machineType不可为空")
        private String machineType;
        @NotNull(message = "startTime不可为空")
        private String startTime;
        @NotNull(message = "endTime不可为空")
        private String endTime;
        @NotNull(type = ParamType.BEAN)
        private TestDto testDto;
    
        public TestDto getTestDto() {
            return testDto;
        }
    
        public void setTestDto(TestDto testDto) {
            this.testDto = testDto;
        }
    
        public String getRegionCode() {
            return regionCode;
        }
    
        public void setRegionCode(String regionCode) {
            this.regionCode = regionCode;
        }
    
        public String getMachineType() {
            return machineType;
        }
    
        public void setMachineType(String machineType) {
            this.machineType = machineType;
        }
    
        public String getStartTime() {
            return startTime;
        }
    
        public void setStartTime(String startTime) {
            this.startTime = startTime;
        }
    
        public String getEndTime() {
            return endTime;
        }
    
        public void setEndTime(String endTime) {
            this.endTime = endTime;
        }
    }
    public class TestDto {
        @NotNull(message = "test不可为空!")
        private String test;
        @NotNull(type = ParamType.BEAN)
        private selectMachineVisitNumDto selectMachineVisitNumDto;
    
        public com.inspur.approval.selfstatistic.dto.selectMachineVisitNumDto getSelectMachineVisitNumDto() {
            return selectMachineVisitNumDto;
        }
    
        public void setSelectMachineVisitNumDto(com.inspur.approval.selfstatistic.dto.selectMachineVisitNumDto selectMachineVisitNumDto) {
            this.selectMachineVisitNumDto = selectMachineVisitNumDto;
        }
    
        public String getTest() {
            return test;
        }
    
        public void setTest(String test) {
            this.test = test;
        }
    
        @Override
        public String toString() {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("test", test);
            jsonObject.put("selectMachineVisitNumDto", selectMachineVisitNumDto.toString());
            return jsonObject.toJSONString();
        }
    }

      两个 bean 之间可形成循环依赖。Service 层,使用 @NotNull 标注参数,@CheckParams 标注方法:

        @CheckParams
        public String getMachineNum(@NotNull(type = ParamType.BEAN) selectMachineVisitNumDto dto, @NotNull(message =
                "name不可为空!") String name) throws Exception {
            JSONObject jsonObject = dto.toJSON();
            return jsonObject.toJSONString();
        }

      Controller 进行异常捕获及处理:

       @RequestMapping("test")
        @ResponseBody
        public String getMachineNum(selectMachineVisitNumDto dto, String name, String test) {
            try {
                TestDto testDto = new TestDto();
                testDto.setTest(test);
                testDto.setSelectMachineVisitNumDto(dto);
                dto.setTestDto(testDto);
                String res = selfStatisticService.getMachineNum(dto, name);
                return controllerUtils.getSuccessJson(res).toJSONString();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                return controllerUtils.getErrorJson(e.getMessage()).toJSONString();
            }
        }

      测试,dto 参数缺失:

      递归检查 TestDto 中参数缺失:

      两个 bean 的参数均完整,测试循环依赖情况的处理:

       可以看到,已经跳出了对两个 dto 的检查,没有陷入循环依赖中。将单独参数 name 补充完整:

    当你看清人们的真相,于是你知道了,你可以忍受孤独
  • 相关阅读:
    File
    多态
    方法重载
    Math
    instanceof
    强制类型转换
    泛型
    springboot热部署
    iOS bug处理
    iOS8-xcode6中添加pch全局引用文件
  • 原文地址:https://www.cnblogs.com/niuyourou/p/15365321.html
Copyright © 2020-2023  润新知