自定义正则表达式校验注解

news/2025/2/12 12:13:04/

1. 解释

自定义注解,通过正则表达式来校验请求相关参数,也可用于校验是否可空等

2. 自定义注解

1. @Check

自定义@Check 注解用来当做AOP切点

package net.lesscoding.aop;import java.lang.annotation.*;/*** @author eleven* @date 2022/11/30 11:56* @description*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Check {public String value() default "";
}

2. @CheckProperties

自定义 @CheckProperties注解用来检验请求上的多个参数

package net.lesscoding.aop;import net.lesscoding.aop.CheckProperty;import java.lang.annotation.*;/*** @author eleven* @date 2022/11/30 15:23* @description*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckProperties {/**** 属性名* @return {@code String}*/String value() default "";/*** 检查的属性值** @return {@code CheckProperty[]}*/CheckProperty[] checks() default {};/***  下标* @return int*/int index() default 0;
}

3. @CheckProperty

自定义注解@CheckProperty用来校验单个属性

package net.lesscoding.aop;import net.lesscoding.enums.TimeType;import java.lang.annotation.*;/*** @author eleven* @date 2022/11/30 10:30* @description 只允许在属性和参数上添加*/
@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckProperty {/** 注解描述 */public String value() default "";/** 报错提示信息 */public String message() default "";/** 正则表达式 */public String regexp() default "";/** 校验的下标 */public int index() default -1;/** 时间格式 */public String pattern() default "";/** 时间类型 */public TimeType timetype() default TimeType.NON_TIME;/** notNull */public boolean notNull() default false;/** notBlank */public boolean notBlank() default false;
}

3. 其他相关类

1. 时间类型枚举类

这个类现在还没有用到,时间类型一般接收过来的时候就会有 @@JsonFormat@DateTimeFormat注解约束类型,所以现在用不到

package net.lesscoding.enums;/*** @author eleven* @date 2022/12/5 10:05* @description*/
public enum TimeType {/*** LocalTime*/LOCAL_TIME,/*** LocalDateTime*/LOCAL_DATETIME,/*** LocalTime*/LOCAL_DATE,/*** Date 类型*/DATE,/*** Timestamp*/TIMESTAMP,/*** 非时间类型*/NON_TIME;
}

2. 注解处理类

如果方法上有@Check注解 ,则进行下边的操作

  1. 首先校验方法参数里是否有@CheckProperty注解,有的话则校验相关参数是否符合要求
  2. 校验方法上是否有@CheckProperties注解,有的话按个校验里边的@CheckProperty注解判断参数是否符合正则表达式(适用于一个接口有好多个参数的情况
  3. 如果方法上没有@CheckProperties注解,但是有@CheckProperty注解,校验相关的参数是否符合
  4. 方法上只有@Check注解,但是传入的实体类的属性上有@CheckProperty挨个校验方法参数是否符合
package net.lesscoding.aop;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import net.lesscoding.enums.TimeType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** @author eleven* @date 2022/11/30 11:17* @description*/
@Aspect
@Component
@Slf4j
public class CheckAspect {private long methodIntervalMs = 0L;@Pointcut("@annotation(net.lesscoding.aop.Check)")public void checkPointCut() {}@Before(value = "checkPointCut()")public void test(JoinPoint joinPoint) throws Exception {Check check = getAnnotationCheck(joinPoint);//获取方法,此处可将signature强转为MethodSignatureMethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();checkArgsAnnotation(joinPoint,method);checkOverMethodAnnotation(joinPoint,method);checkInField(joinPoint);}/*** 校验在类属性里的注解* @param joinPoint     切点* @param method        方法*/private void checkInField(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs();for (Object arg : args) {Class<?> argClass = arg.getClass();Field[] declaredFields = argClass.getDeclaredFields();for (int i = 0; i < declaredFields.length; i++) {Field field = declaredFields[i];CheckProperty checkProperty = field.getAnnotation(CheckProperty.class);if (checkProperty == null){continue;}Object argByFiled = getArgByFiled(field, arg);checkArg(checkProperty,arg.getClass(),field.getName(),argByFiled);}}}/*** 根据类定义的field获取值* @param field     类属性* @param arg       参数* @return  Object*/protected Object getArgByFiled(Field field,Object arg){try{PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(),arg.getClass());Method readMethod = propertyDescriptor.getReadMethod();Object invoke = readMethod.invoke(arg);return invoke;}catch (Exception e){e.printStackTrace();}return new Object();}/*** 校验方法上的注解* @param joinPoint*/protected void checkOverMethodAnnotation(JoinPoint joinPoint,Method method) {Parameter[] parameters = method.getParameters();Object[] args = joinPoint.getArgs();// 判断多个注解配置CheckProperties checkProperties = method.getAnnotation(CheckProperties.class);if(checkProperties != null){CheckProperty[] checkArr = checkProperties.checks();if(checkArr.length == 0){return;}for (int i = 0; i < checkArr.length; i++) {CheckProperty checkProperty = checkArr[i];int index = checkProperty.index();Parameter parameter = parameters[index != -1 ? index : i];Object arg = args[index != -1 ? index : i];checkArg(checkProperty, parameter, arg);}}// 校验 @CheckProperty 注解CheckProperty checkProperty = method.getAnnotation(CheckProperty.class);if(checkProperty != null){int index = checkProperty.index();Parameter parameter = parameters[index != -1 ? index : 0];Object arg = args[index != -1 ? index : 0];checkArg(checkProperty,parameter,arg);}}/*** 检查方法参数里的注解* @param joinPoint AOP切点*/protected void checkArgsAnnotation(JoinPoint joinPoint, Method method){// 获取参数Parameter[] parameters = method.getParameters();//参数注解,1维是参数,2维是注解Annotation[][] annotations = method.getParameterAnnotations();Object[] args = joinPoint.getArgs();for (int i = 0; i < annotations.length; i++) {Annotation[] annotation = annotations[i];List<Annotation> paramsAnnotation = new ArrayList<>(Arrays.asList(annotation));int finalI = i;paramsAnnotation.stream().forEach(item -> {Class<? extends Annotation> annotationType = item.annotationType();if(annotationType.getName().endsWith(".CheckProperty")){CheckProperty checkProperty = (CheckProperty)item;checkArg(checkProperty,parameters[finalI],args[finalI]);}});}}/*** 校验属性* @param checkProperty     注解内容* @param parameter         参数描述* @param arg               参数*/protected void checkArg(CheckProperty checkProperty,Parameter parameter,Object arg){checkArg(checkProperty,parameter.getType(),parameter.getName(),arg);}/*** 校验属性* @param checkProperty     注解* @param type              参数类型* @param argName           参数名称* @param arg               参数*/protected void checkArg(CheckProperty checkProperty,Class type ,String argName,Object arg){// 获取提示信息String message = checkProperty.message();String regexp = checkProperty.regexp();if(checkProperty.notNull()){if(null == arg ) {throw new IllegalArgumentException(String.format("参数[%s]不能为空: %s", argName, message));}}String argStr = String.valueOf(arg);if(checkProperty.notBlank() && type.equals(String.class)){if(StrUtil.isBlank(argStr)){throw new IllegalArgumentException(String.format("参数[%s]不能为空: %s", argName, message));}}if(StrUtil.isNotBlank(regexp)){if(!ReUtil.isMatch(regexp,argStr)){throw new IllegalArgumentException(String.format("参数 [ %s ] :: [ %s ] 不合法,%s",argName,argStr,checkProperty.message()));}}}/*** 环绕通知,可以用来计算方法耗时* @param joinPoint* @throws Exception*///@Around(value = "checkPointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 定义返回对象、得到方法需要的参数Object[] args = joinPoint.getArgs();TimeInterval timer = DateUtil.timer();Object obj = joinPoint.proceed(args);MethodSignature signature = (MethodSignature) joinPoint.getSignature();String methodName = signature.getDeclaringTypeName() + "." + signature.getName();log.info("----------{}方法开始执行----------",methodName);// 打印耗时的信息methodIntervalMs = timer.intervalMs();log.info("----------{}执行耗时{}ms----------", methodName, methodIntervalMs);log.info("----------{}返回参数----------\n{}", methodName, new Gson().toJson(obj));return obj;}/*** 是否存在注解,如果存在就获取*/private Check getAnnotationCheck(JoinPoint joinPoint) throws Exception {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {return method.getAnnotation(Check.class);}return null;}
}

3. 通用返回类

package net.lesscoding.common;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author eleven* @date 2022/11/30 12:12* @description*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {private Integer code;private String message;private Object data;
}

4. 测试类

package net.lesscoding.entity;import lombok.Data;
import net.lesscoding.aop.CheckProperty;/*** @author eleven* @date 2022/11/30 10:34* @description*/
@Data
public class TestEntity {@CheckProperty(message = "超过字符串最大长度",regexp = "\\w{0,12}")private String strTest;@CheckProperty(message = "超过最大长度4",regexp = "\\d{0,4}")private Integer intTest;private Double doubleTest;}

5. 正则表达式常量类

package net.lesscoding.consts;/*** @author eleven* @date 2022/11/30 10:38* @description* 相关正则表达式可以参考* https://jex.im/regulex/#!flags=&re=%5E(a%7Cb)*%3F%24* https://regexr.com/*/
public class RegexpConst {/*** 最大长度32*/public static final String STR_MAX_LENGTH_32 = "\\w{0,32}";/*** 整数最大长度4*/public static final String INTEGER_MAX_LENGTH_4 = "\\d{0,4}";/*** 无符号整数最大长度4*/public static final String UNSIGNED_INTEGER_MAX_LENGTH_4 = "-*\\d{0,4}";/*** 两位小数*/public static final String DECIMAL_PLACE_2 = "\\d+.\\d{0,2}";}

4. 测试接口

package net.lesscoding.controller;import net.lesscoding.aop.Check;
import net.lesscoding.aop.CheckProperties;
import net.lesscoding.aop.CheckProperty;
import net.lesscoding.common.Result;
import net.lesscoding.consts.RegexpConst;
import net.lesscoding.entity.TestEntity;
import org.springframework.web.bind.annotation.*;/*** @author eleven* @date 2022/11/30 12:09* @description*/
@RestController
@RequestMapping("/check")
public class CheckTestController {@GetMapping("/inArgs")@Checkpublic Result inArgs(@CheckProperty(message = "长度超过32位",regexp = RegexpConst.STR_MAX_LENGTH_32) @RequestParam("str") String str,@CheckProperty(message = "长度超过4位",regexp = RegexpConst.INTEGER_MAX_LENGTH_4) @RequestParam("index") Integer index){return new Result(200,"success",str + " :: " +  index);}@GetMapping("/overMethodsMulti")@Check@CheckProperties(checks = {@CheckProperty(message = "长度超过32位",regexp = RegexpConst.STR_MAX_LENGTH_32,index = 0),@CheckProperty(message = "长度超过4位",regexp = RegexpConst.INTEGER_MAX_LENGTH_4,index = 1)})public Result overMethodsMulti( String str, Integer index){return new Result(200,"success",str + " :: " + index);}@GetMapping("/overMethods")@Check@CheckProperty(message = "长度超过32位",regexp = RegexpConst.STR_MAX_LENGTH_32,index = 0)public Result overMethods( String str,Integer index){return new Result(200,"success",str + " :: " + index);}@GetMapping("/inFields")@Checkpublic Result inFields(TestEntity testEntity){return new Result(200,"success",testEntity);}@PostMapping("/inFields")@Checkpublic Result inFieldsPost(@RequestBody TestEntity testEntity){return new Result(200,"success",testEntity);}
}

http://www.ppmy.cn/news/2378.html

相关文章

认知电子战 | 认知电子战简介

认知电子战简介 概念研究现状自适应电子战行为学习项目(BLADE,2010)自适应雷达对抗项目(ARC,2012)认知干扰机项目(CJ,2010)极端射频频谱条件下的通信项目(CommEx,2010)美国海军的认知电子战计划(2013)各项目进展情况系统组成认知侦察模块对抗措施合成模块智能干扰…

Ansys Lumerical | 行波马赫曾德尔调制器的仿真设计与优化

说明 本案例将Lumerical和HFSS在行波MZM调制器建模中的功能与optiSLang相结合&#xff0c;提供了强大的优化能力以寻找最佳性能设计。 下载 联系工作人员获取附件 综述 本案例建立在已有的硅波导建模实例&#xff08;Ansys Lumerical 行波 Mach-Zehnder 调制器仿真分析&#x…

Leica Infinity三维映射环境数据

Leica Infinity三维映射环境数据 Leica Infinity是软件工程师和该领域专家的名字&#xff0c;以及您的工作计划信息。该软件被设计和呈现为一个强大的产品&#xff0c;并且来自六边形组。Leica Infinity产品的居民试图用新的眼光创造新的数据处理。使用此软件&#xff0c;您可以…

【2022秋线上作业-第六次-第13-15周】判断题+选择题

判断题 1.希尔排序是稳定的算法。 F 解析&#xff1a; 希尔排序是非稳定排序算法。 不稳定的排序算法&#xff1a;堆排序、快速排序、希尔排序、直接选择排序 稳定的排序算法&#xff1a;基数排序、冒泡排序、直接插入排序、折半排序、归并排序 2.在散列表中&#xff0c;所谓同…

Java入门笔记

目录Java入门笔记快捷键基础准备环境准备Java编译运行流程TODO自定义模板基础语法变量原理标识符标识符命名规则数据类型整数型浮点型类型转换引用数据类型面向对象类和对象判断一个对象是不是某个类方法传参可变参数基本数据类型传参字符串数据类型传参引用数据类型传参静态属…

学习下c++原来它和Java有很多相似的地方

Java和CJava和C区别简单学习下C语法C 是什么&#xff1f;C工作原理&#xff1a;C标识符C基本数据类型C关键字封装&#xff0c;继承&#xff0c;多态简单回顾下Java语法Java的基础语法&#xff1a;Java注释Java标识符Java修饰符Java 接口和继承Java8 新增的特性Java和C区别 Java…

DeepLab V3学习笔记

DeepLab V3遇到的问题和解决方法相关工作DeepLab V3中的两种模型结构cascaded modelASPP model相对于DeepLab V2的优化Multi-grid MethodASPP的改进消融实验cascaded model消融实验ASPP model消融实验和其他网络的对比实验总结网络模型图遇到的问题和解决方法 对于DeepLab系列…

三种设置session有效时间的方法

session的默认有效时间是30分钟(min) 方法一&#xff1a;使用java函数&#xff1a;session.setMaxInactiveInterval() 举例&#xff1a;设置的有效期是30分钟(min) session.setMaxInactiveInterval(30 * 60); //30分*60秒 注意&#xff1a;以秒(s)为单位。 如果设置的值为零…