添加依赖

 <!-- 参数校验 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0..Final</version>
</dependency>

一.基本类型参数(String)校验

1.注解要写在接口中,实现类会自动继承,如果实现类的某个重写方法没有加上了注解,接口中却没有定义,运行时会产生redefine异常

接口:

User getUserById(@NotNull(message = "uid不能为null") @Min(value = 1,message = "uid不合法") Integer id);
实现类:

@Override
public User getUserById(@NotNull(message = "uid不能为null") @Min(value = 1,message = "uid不合法") Integer id) {
return userMapper.getUserById(id);
}

Controller(restful风格最容易出的问题就是参数为空,只要不传就是404,不要尝试:xxx/getUserById/null,这种写法是400,给url设置null没有意义,解决方式很简单,给Controller增加一个映射路径即可,空参数导致的bind异常可以用在全局异常处理器捕获即可,当然你在web.xml中统一处理404也可以):

 @RequestMapping(value = {"/getUserById/{uid}","/getUserById"})
public @ResponseBody Object getUserById(@PathVariable Integer uid) {
return userService.getUserById(uid);
}

2.提供校验器,自定义异常(可选),全局异常处理器

校验器:

 public class ParamsValidator {

     public static ExecutableValidator getValidator() {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
return validatorFactory.getValidator().forExecutables();
}
}

自定义异常(可选):

 public class ValidParamException extends RuntimeException {
private static final long serialVersionUID = 1L; private Set<ConstraintViolation<Object>> validateResult; public ValidParamException() {
super();
} public ValidParamException(String message) {
super(message);
} public ValidParamException(Set<ConstraintViolation<Object>> validateResult) {
this.validateResult = validateResult;
} public Set<ConstraintViolation<Object>> getValidateResult() {
return validateResult;
} public void setValidateResult(Set<ConstraintViolation<Object>> validateResult) {
this.validateResult = validateResult;
} @Override
public String getMessage() {
return validateResult.iterator().next().getMessage();
} public Map<Object, String> getErrorMap() {
Map<Object, String> map = new HashMap<Object, String>(6);
Iterator<ConstraintViolation<Object>> iterator = validateResult.iterator();
while (iterator.hasNext()) {
ConstraintViolation<Object> cons = iterator.next();
Path propertyPath = cons.getPropertyPath();
String message = cons.getMessage();
map.put(propertyPath, message);
}
return map;
} }

全局异常处理器:

 @ControllerAdvice
@EnableWebMvc
public class GlobalExceptionHandler {
// 单参数校验
@ExceptionHandler(ValidParamException.class)
public @ResponseBody Map<Object, String> validParamException(HttpServletRequest req, ValidParamException vpe) {
return vpe.getErrorMap();
} // 对象类型参数校验
@ExceptionHandler(MethodArgumentNotValidException.class)
public @ResponseBody Map<Object, String> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
String parameterName = ex.getParameter().getParameterName();
Map<Object, String> map = new HashMap<Object, String>(6);
map.put(parameterName, ex.getLocalizedMessage());
return map;
} // pathvariable不传递参数时抛出的异常
@ExceptionHandler(ServletRequestBindingException.class)
public @ResponseBody Map<Object, String> servletRequestBindingException(ServletRequestBindingException ex) {
Map<Object, String> map = new HashMap<Object, String>(6);
map.put("error", ex.getLocalizedMessage());
return map;
}
}

3.使用aop进行拦截

关于aop"失效"的问题有几点说明:

1)如果拦截controller,那么aop的配置要写在springmvc的配置文件中,拦截其他层(如service)写在spring的配置文件中

2)被拦截的类必须也被spring管理否则无法拦截成功

3)开启注解扫描时,springmvc只扫描@Controller类型的注解,其他的如@Service,@Repository注解由spring进行扫描

aop:

 @Component
@Aspect
public class UserAspect { private ExecutableValidator validator = ParamsValidator.getValidator(); @Pointcut("execution (* cn.tele.service.*.*(..))")
private void pt() {
} @Before("pt()")
public void checkParams(JoinPoint jp) { Object target = jp.getTarget();
Object[] params = jp.getArgs();
MethodSignature methodSignature = (MethodSignature) jp.getSignature(); String[] paramNames = methodSignature.getParameterNames();
Method method = methodSignature.getMethod(); Set<ConstraintViolation<Object>> validateResult = validator.validateParameters(target, method, params);
if (!validateResult.isEmpty()) {
throw new ValidParamException(validateResult);
}
} }

4.测试结果:

1)传入-1

2)不传

可以在aop中打印日志啥的

二.对象类型参数校验

1.在javaBean中添加注解,对一些特殊字段进行分组,如id,插入数据时,不需要校验可以为null,而查询,删除,更新等操作必须校验

 @NotNull(message = "uid不能为null",groups = {Query.class,Update.class,Delete.class})
@Min(value = 1,message = "uid不合法")
private Integer uid; @NotBlank(message = "姓名不能为空")
@Size(max = 20,message = "姓名最大长度为50个字符")
private String userName; @NotBlank(message = "性别不能为空")
@Size(max = 20,message = "性别最大长度位20个字符")
private String sex; @NotNull
@Max(value = 70,message = "最大年龄为70岁")
private Integer age; @NotNull
private Integer departmentId; @Value(value = "1")
private Integer state;

分组只是个标记,用接口定义就好

 public interface Query {

 }

2.在参数前添加@Valited注解,该注解支持分组,@Valid不支持,如果你选择的校验位置与上面定义的aop拦截的位置相同,那就会出问题了,

你的代码会走aop的逻辑然后去用你校验单个参数的校验器去进行校验,这样无法校验出问题,因此推荐放在controller层

 @RequestMapping("/insertUser")
public @ResponseBody String insertUser(@Validated @RequestBody User user) {
Integer count = userService.insertUser(user);
return count ==1 ? "成功增加1条记录" : "增加" + user + "失败";
}

校验指定分组

3.抛出的异常会走上面贴出的全局异常处理器的代码

4.测试

1)正常情况,注意没有id

2)丢失userName

springmvc 参数校验/aop失效/@PathVariable 参数为空的更多相关文章

  1. 更加灵活的参数校验,Spring-boot自定义参数校验注解

    上文我们讨论了如何使用@Min.@Max等注解进行参数校验,主要是针对基本数据类型和级联对象进行参数校验的演示,但是在实际中我们往往需要更为复杂的校验规则,比如注册用户的密码和确认密码进行校验,这个时 ...

  2. Spring Validation最佳实践及其实现原理,参数校验没那么简单!

    之前也写过一篇关于Spring Validation使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂Spring Validation.本文会详细介绍Spring Validation各种场景下 ...

  3. Spring Boot实现通用的接口参数校验

    Spring Boot实现通用的接口参数校验 Harries Blog™ 2018-05-10 2418 阅读 http ACE Spring App API https AOP apache IDE ...

  4. SpringBoot实现通用的接口参数校验

    本文介绍基于Spring Boot和JDK8编写一个AOP,结合自定义注解实现通用的接口参数校验. 缘由 目前参数校验常用的方法是在实体类上添加注解,但对于不同的方法,所应用的校验规则也是不一样的,例 ...

  5. 后端参数校验器v1.0(调用一个方法校验所有参数并得到校验结果,且包括错误原因)

    一:介绍 在写后端时,面对多个参数,比如手机号码.密码等我们常常需要写验证逻辑,当需要验证的参数较多的时候我们会需要写很多的判断语句,这就造成了大量的代码冗余.因此我开发了一套参数验证器,只需要调用参 ...

  6. 接口参数校验之@Valid与BindingResult

    接口方法往往需要对入参做一些校验,从而判断入参是否合格,而javax.validation包为我们提供了一些常用的参数校验注解,使用起来很方便. 下面这个示例是检验入参对象中的password是否为空 ...

  7. 徒手生撸一个验证框架,API 参数校验不再怕!

    你们之中大概率早已练就了代码的拷贝.粘贴,无敌的码农神功,其实做久了业务功能开发,练就这两个无敌神功,那是迟早的事儿.今天先抛一个小问题,来打通你的任督二脉,就是很好奇的问一下:业务功能开发中,输入参 ...

  8. 接口参数校验(不使用hibernate-validator,规避大量if else)

    引言 编写接口时,常用的参数校验使用hibernate-validator注解+@@Validated注解进行参数校验.当遇到一些特殊场景或需求,需要自己对参数进行手动校验时,会出现以下问题: 不可避 ...

  9. Flask开发技巧之参数校验

    Flask开发技巧之参数校验 目录 Flask开发技巧之参数校验 1.请求参数分类 2.解决方案使用到的库 3.针对url查询参数与一般json格式 4.针对复杂json格式数据 本人平时开发中使用的 ...

随机推荐

  1. 中国境内PE\VC\投资公司名单

    中国境内PE\VC\投资公司名单 1.青云创投 2.高盛 3.红杉资本 4.鼎晖创投 5.枫丹国际 6.派杰投资银行 7.凯雷投资 8.长安私人资本 9.格林雷斯 10.汉能资本 11.启明创投 12 ...

  2. 笔记:在 Windows 10 WSL Ubuntu 18.04 安装 Odoo12 (2019-06-09)

    笔记:在 Windows 10 WSL Ubuntu 18.04 安装 Odoo12 原因 为了和服务器一样的运行环境. 使用 Ubuntu 运行 Odoo 运行更快. 方便使用 Windows 10 ...

  3. css3 练习

    css3 文本效果 css3中包含几个新的文本特征 在本章中您将了解一下文本属性 text-shadow box-shadow word-wrap word-break css3 的文本阴影 css3 ...

  4. Javascript 用来验证电话号码的正则

    Javascript 用来验证电话号码的正则 在学习 Javascript 时学习到的. function telephoneCheck(str) { // return /^(1\s?)?(\d{3 ...

  5. Namenode文件系统命名空间映像文件及修改日志

  6. @hdu - 6598@ Harmonious Army

    目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个士兵,每个士兵可以选择加入 A 组或 B 组. 有 m 个 ...

  7. @雅礼集训01/10 - T1@ matrix

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个矩阵.求它的所有子矩阵中本质不同的行的个数之和. inp ...

  8. HZOJ visit

    对于前30%的数据,可以考虑dp,f[i][j][k]表示时间为i,在i,j位置的方案数,枚举转移即可.要注意的是可以走到矩阵外. 对于另外30%数据,考虑推一下式子,设向右走y步,左z,上s,下x. ...

  9. python基础之逻辑题(3)

    Python基础之逻辑题(3) 1.编写一个函数实现将IP地址转换成一个整数 2.求结果:---lambda 3.求a的结果 4.求下面nums的输出 5.求下面片段的输出 6.写出程序的结果:--- ...

  10. php三目运算计算三个数最大值最小值

    文章地址:https://www.cnblogs.com/sandraryan/ $x = 10; $y = 45; $z = 3; //求出三个数字中最大值最小值 //先比较x y,如果x> ...