本例基于springboot,HttpServletRequest传参方式作参数校验,通过自定义拦截器获取HttpServletRequest请求,在拦截器里根据自定义注解做参数校验。代码如下:
首先是两个用于指定校验类型的注解:
@CheckParams和@CheckRule,@CheckParams中有一个CheckRule[]数组,用于实现可指定多个参数的校验规则:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckParams {
CheckRule[] rules();
}
@CheckRule中用于指定校验细则:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckRule {
String attrName();
boolean notNull() default false;
String message() default "参数未通过校验";
CheckType type();
String value() default "";
}
attrName用于指定要校验参数名,用于request取参数。
message用于传递校验失败时,需要传递的错误信息。
type用于指定校验的类型,根据自己的业务指定,如电话号码,邮箱等
value用于指定特殊校验时的值域,如不大于多少,不小于多少等。
CheckType 是根据自己需要校验的类型,列举的枚举值,本例中:
public enum CheckType {
//整数最大值
INT_MAX,
//整数最小值
INT_MIN,
//正则匹配
REGULAR_MATCH,
//邮箱
EMAIL,
//电话号码
PHONE;
}
然后是实际用于校验的工具代码:
public class ParamCheckUtil {
private static final String EMAIL_REGEX = "^([\\w-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([\\w-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
private static final String PHONE_REGEX = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
public static boolean verifyParam(Object verityVaule, boolean notNull, CheckType type, String value) {
if (null == verityVaule) {
return !notNull;
}
switch(type) {
case INT_MAX:
return verifyIntMax(verityVaule, value);
case INT_MIN:
return verifyIntMin(verityVaule, value);
case EMAIL:
return verifyByRegex(verityVaule, EMAIL_REGEX);
case PHONE:
return verifyByRegex(verityVaule, PHONE_REGEX);
case REGULAR_MATCH:
return verifyByRegex(verityVaule, value);
default:
return false;
}
}
public static void main(String args[]) {
String e1 = "dfasfdasfasd";
String e2 = "4329438@qq.com";
String e3 = "sdfsdfsdf@sdf.sdf";
System.out.println(verifyByRegex(e1, EMAIL_REGEX));
System.out.println(verifyByRegex(e2, EMAIL_REGEX));
System.out.println(verifyByRegex(e3, EMAIL_REGEX));
String p1 = "dfjasodfjo23";
String p2 = "3423432";
String p3 = "13545676789";
String p4 = "34543454332";
System.out.println(verifyByRegex(p1, PHONE_REGEX));
System.out.println(verifyByRegex(p2, PHONE_REGEX));
System.out.println(verifyByRegex(p3, PHONE_REGEX));
System.out.println(verifyByRegex(p4, PHONE_REGEX));
}
public static boolean verifyByRegex(Object verityValue, String regex) {
return Pattern.matches(regex,verityValue.toString());
}
public static boolean verifyIntMax(Object verityValue, String value) {
return Integer.parseInt(verityValue.toString()) <= Integer.parseInt(value);
}
public static boolean verifyIntMin(Object verityValue, String value) {
return Integer.parseInt(verityValue.toString()) >= Integer.parseInt(value);
}
}
一切准备就绪,然后就是自定义拦截器和加上拦截器了。
拦截器:
public class ParamCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
CheckParams checkParams = method.getAnnotation(CheckParams.class);
if(checkParams == null || StringUtils.isEmpty(checkParams.rules())) {
return true;
}
for (CheckRule rule: checkParams.rules()) {
//todo (request.getAttribute(rule.attrName()) 改为实际取值
if (!ParamCheckUtil.verifyParam(request.getAttribute(rule.attrName()), rule.notNull(), rule.type(), rule.value())) {
//todo 抛出异常更换为项目所需业务异常
throw new Exception();
}
}
}
return true;
}
}
通过实现HandlerInterceptor 定义自己的拦截器,本例中拦截器重载preHandle方法即可,通过CheckParams checkParams = method.getAnnotation(CheckParams.class);可拿到本调用接口是否增加我们自己的注解,需要作参数校验, 然后根据rule.attrName()拿到我们指定的需要校验的参数名,再到request里去获取,最后根据注解类型进行校验。这里抛出的异常可使用我们@CheckRule中message中的信息做异常信息的传递。
最后,通过@Configuration注解启用我们的拦截器:
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ParamCheckInterceptor());
}
}