引言
使用SpringMVC作为Controller层进行Web开发时,经常会需要对Controller中的方法进行参数检查。本来SpringMVC自带@Valid和@Validated两个注解可用来检查参数,但只能检查参数是bean的情况,对于参数是String、Long等Java自带类型的就不适用了(但是还可以用@NotNull、@NotBlank、@NotEmpty等),而且有时候这两个注解又突然失效了(没有仔细去调查过原因)。对此,其实我们自己也可以利用Spring的AOP和自定义注解,自己写一个参数校验的功能。
代码示例
注意:本节代码只是一个演示,给出一个可行的思路,并非完整的解决方案。
本项目是一个简单Web项目,使用到了:Spring、SpringMVC、Maven、JDK1.8
项目结构:

自定义注解:
ValidParam.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.lzumetal.ssm.paramcheck.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ValidParam { }
|
NotNull.java:
1 2 3 4 5 6 7 8 9 10 11 12
| package com.lzumetal.ssm.paramcheck.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface NotNull {
String msg() default "字段不能为空"; }
|
NotEmpty.java:
1 2 3 4 5 6 7 8 9 10 11 12
| package com.lzumetal.ssm.paramcheck.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface NotEmpty {
String msg() default "字段不能为空"; }
|
切面类
ParamCheckAspect.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| package com.lzumetal.ssm.paramcheck.aspect;
import com.lzumetal.ssm.paramcheck.annotation.NotEmpty; import com.lzumetal.ssm.paramcheck.annotation.NotNull; import com.lzumetal.ssm.paramcheck.annotation.ValidParam; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.lang.reflect.Field; import java.lang.reflect.Parameter; import java.util.Arrays;
@Aspect @Component public class ParamCheckAspect {
@Before("execution(* com.lzumetal.ssm.paramcheck.controller.*.*(..))") public void paramCheck(JoinPoint joinPoint) throws Exception { Object[] args = joinPoint.getArgs(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Parameter[] parameters = signature.getMethod().getParameters(); for (int i = 0; i < parameters.length; i++) { Parameter parameter = parameters[i]; if (isPrimite(parameter.getType())) { NotNull notNull = parameter.getAnnotation(NotNull.class); if (notNull != null && args[i] == null) { throw new RuntimeException(parameter.toString() + notNull.msg()); } continue; }
if (parameter.getType().isAssignableFrom(HttpServletRequest.class) || parameter.getType().isAssignableFrom(HttpSession.class) || parameter.getType().isAssignableFrom(HttpServletResponse.class) || parameter.getAnnotation(ValidParam.class) == null) { continue; } Class<?> paramClazz = parameter.getType(); Object arg = Arrays.stream(args).filter(ar -> paramClazz.isAssignableFrom(ar.getClass())).findFirst().get(); Field[] declaredFields = paramClazz.getDeclaredFields(); for (Field field : declaredFields) { field.setAccessible(true); NotNull notNull = field.getAnnotation(NotNull.class); if (notNull != null) { Object fieldValue = field.get(arg); if (fieldValue == null) { throw new RuntimeException(field.getName() + notNull.msg()); } } NotEmpty notEmpty = field.getAnnotation(NotEmpty.class); if (notEmpty != null) { if (!String.class.isAssignableFrom(field.getType())) { throw new RuntimeException("NotEmpty Annotation using in a wrong field class"); } String fieldStr = (String) field.get(arg); if (StringUtils.isBlank(fieldStr)) { throw new RuntimeException(field.getName() + notEmpty.msg()); } } } } }
private boolean isPrimite(Class<?> clazz){ return clazz.isPrimitive() || clazz == String.class; }
}
|
参数JavaBean
StudentParam.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.lzumetal.ssm.paramcheck.requestParam;
import com.lzumetal.ssm.paramcheck.annotation.NotEmpty; import com.lzumetal.ssm.paramcheck.annotation.NotNull;
public class StudentParam {
@NotNull private Integer id; private Integer age; @NotEmpty private String name;
}
|
验证参数校验的Controller
TestController.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.lzumetal.ssm.paramcheck.controller;
import com.google.gson.Gson; import com.lzumetal.ssm.paramcheck.annotation.NotNull; import com.lzumetal.ssm.paramcheck.annotation.ValidParam; import com.lzumetal.ssm.paramcheck.requestParam.StudentParam; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class TestController {
private static Gson gson = new Gson();
@ResponseBody @RequestMapping(value = "/test", method = RequestMethod.POST) public StudentParam checkParam(@ValidParam StudentParam param, @NotNull Integer limit) { System.out.println(gson.toJson(param)); System.out.println(limit); return param; }
}
|
本节示例代码已上传至GitHub:https://github.com/liaosilzu2007/ssm-parent.git