#真· 使用注解通过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 {}; }
具体使用情况暂时没有时间补充如有使用问题可以评论区留言