真· 使用注解通过AOP实现JSR303且不仅限于JSR303

#真· 使用注解通过AOP实现JSR303且不仅限于JSR303

前言, 首先JSR303是一种校验, 如果只是对于参数校验进行处理的话, 那么JSR是提供了放发扩展的, 所以只需要去继承它对应的类来做就好了

eg: 这里是Demo

那么下方的代码能做的是不仅限于JSR303校验的事情还可以对于特定的参数或者对象属性进行操作

下方代码例子实现的业务就是如果controller中传参包含的String对象字符串前后用空格的话,则根据注解参数进行对应处理

这里写代码的时候使用的是ruoyi的框架, 所以有一些包名需要根据你项目情况进行一下更改

  • 上代码 AOP

    package com.ruoyi.web.controller.system;
    
    import com.ruoyi.common.annotation.StringTrim;
    import com.ruoyi.common.annotation.StringTrimConstant;
    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 java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author 405
     */
    @Aspect
    @Component
    public class StringTrimMethodAOP {
        @Pointcut(value = "@annotation(com.ruoyi.web.controller.system.StringTrimMethod)")
        public void stringTrimMethodAOP() {
        }
    
        @Around("stringTrimMethodAOP()")
        public Object stringTrimMethodAOP(ProceedingJoinPoint joinPoint) throws Throwable {
            // 获取入参
            Object[] objects = joinPoint.getArgs();
    
            // 获取方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
    
            //参数注解,1维是参数,2维是注解
            Annotation[][] annotations = method.getParameterAnnotations();
    
            // 遍历一维annotations
            for (int i = 0; i < annotations.length; i++) {
                Object object = objects[i];
                Annotation[] param = annotations[i];
                //参数为空,直接下一个参数
                if (object == null || param.length == 0) {
                    continue;
                }
                // String和其他Object的不同处理方式
                if (object instanceof String) {
                    objects[i] = trimString(object, param);
                } else {
                    object = trimParam(object);
                }
    
            }
            return joinPoint.proceed(objects);
        }
    
    
        private Object trimString(Object object, Annotation[] param) {
            Map map = new HashMap(1);
            for (Annotation annotation : param) {
                //这里判断当前注解是否为StringTrim.class
                if (annotation.annotationType().equals(StringTrim.class)) {
                    //获取被代理的对象
                    InvocationHandler invo = Proxy.getInvocationHandler(annotation);
                    map = (Map) getFieldValue(invo, "memberValues");
                    if (map == null) {
                        return object;
                    }
                }
            }
            trimSwitch(object, map.get("value"));
            return object;
        }
    
        private Object trimParam(Object object) throws IllegalAccessException {
            Class<?> clazz = object.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Class<?> fieldClazz = field.getType();
                if (fieldClazz != String.class) {
                    // TODO 应该抛出异常对于非String无效
                    continue;
                }
                StringTrim stringTrim = field.getAnnotation(StringTrim.class);
                if (stringTrim == null) {
                    continue;
                }
                // 去除private权限
                field.setAccessible(true);
                Object o = field.get(object);
                if (o == null) {
                    continue;
                }
                field.set(object, String.valueOf(trimSwitch(o, stringTrim.value())));
            }
            return object;
        }
    
        private static <T> Object getFieldValue(T object, String property) {
            if (object != null && property != null) {
                Class<T> currClass = (Class<T>) object.getClass();
                try {
                    Field field = currClass.getDeclaredField(property);
                    field.setAccessible(true);
                    return field.get(object);
                } catch (NoSuchFieldException e) {
                    throw new IllegalArgumentException(currClass + " has no property: " + property);
                } catch (IllegalArgumentException e) {
                    throw e;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    
        private Object trimSwitch(Object o, Object key) {
            switch (String.valueOf(key)) {
                case StringTrimConstant.BEFORE:
                    o = trimBefore(o.toString());
                    break;
                case StringTrimConstant.END:
                    o = trimEnd(o.toString());
                    break;
                case StringTrimConstant.TRIM:
                    o = o.toString().trim();
                    break;
                default:
                    break;
            }
            return o;
        }
    
        private String trimBefore(String str) {
            int len = str.length();
            int st = 0;
            char[] val = str.toCharArray();
    
            while ((st < len) && (val[st] <= ' ')) {
                st++;
            }
            return ((st > 0) || (len < str.length())) ? str.substring(st, len) : str;
        }
    
        private String trimEnd(String str) {
            int len = str.length();
            int st = 0;
            char[] val = str.toCharArray();
    
            while ((st < len) && (val[len - 1] <= ' ')) {
                len--;
            }
            return ((st > 0) || (len < str.length())) ? str.substring(st, len) : str;
        }
    
    
    }
    
  • StringTrimMethod注解

    package com.ruoyi.web.controller.system;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.ElementType.PARAMETER;
    import static java.lang.annotation.ElementType.TYPE;
    
    /**
     * 使用在方法上
     * 配合 StringTrim
     *
     * @author 405
     */
    @Documented
    @Target(value = {METHOD, TYPE, PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface StringTrimMethod {
    }
    
    
  • StringTrim注解

    package com.ruoyi.common.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    import static java.lang.annotation.ElementType.CONSTRUCTOR;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.ElementType.PARAMETER;
    import static java.lang.annotation.ElementType.TYPE_USE;
    
    /**
     * 使用在方法上
     * 根据状态去除首尾空格
     *
     * @author 405
     */
    @Documented
    @Target(value = {METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface StringTrim {
        String value() default StringTrimConstant.TRIM;
    }
    
  • StringTrim注解的三种常量

    package com.ruoyi.common.annotation;
    
    /**
     * @author 405
     */
    public interface StringTrimConstant {
        /**
         * 字符串前端空格去除枚举
         */
        String BEFORE = "BEFORE";
        /**
         * 字符串后端空格去除枚举
         */
        String END = "END";
    
        /**
         * 字符串两端空格去除枚举
         */
        String TRIM = "TRIM";
    
    }
    
  • 进阶使用StringTrim合并@NotBlank

    package com.ruoyi.common.annotation;
    
    import org.springframework.core.annotation.AliasFor;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    import javax.validation.constraints.NotBlank;
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    import static java.lang.annotation.ElementType.CONSTRUCTOR;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.ElementType.PARAMETER;
    import static java.lang.annotation.ElementType.TYPE_USE;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    /**
     * @StringTrim
     * @NotBlank
     * 两个注解的合并注解
     * 需要注意配合两注解使用的@StringTrimMethod与@Validated注解是否正常配合使用否则会不生效
     *
     * @author 405
     */
    @Documented
    @Constraint(validatedBy = {})
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @StringTrim
    @NotBlank
    public @interface StringTrimNotBlank {
        @AliasFor(annotation = StringTrim.class) String value() default StringTrimConstant.TRIM;
    
        @AliasFor(annotation = NotBlank.class) String message() default "{javax.validation.constraints.StringTrimNotBlank.message}";
    
        @AliasFor(annotation = NotBlank.class) Class<?>[] groups() default {};
    
        @AliasFor(annotation = NotBlank.class) Class<? extends Payload>[] payload() default {};
    }
    

具体使用情况暂时没有时间补充如有使用问题可以评论区留言

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

社畜阿藏405

挣点钱不丢人吧?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值