添加依赖

 <!-- 参数校验 -->
<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. poj 3280【区间dp】

    poj 3280 题意:给定一个字符串和每个字符删去和增加的代价,求使字符串变成回文串操作所需的最小代价. 题解:哇!开心!终于亲自做对了!做完这两题这个就回了.uva10739  uva 10453 ...

  2. oracle使用profile管理用户口令

    概述:profile是口令限制.资源限制的命令集合,当建立数据时,oracle会自动建立名称为default的profile,当建立用户没有指定profile选项,那么oracle就会将default ...

  3. oracle Sql语句分类

    dml语句:数据操作语句[insert,update,delete] ddl语句:数据定义语言[create table,drop table] dql语句:数据查询语句[select] dtl语句: ...

  4. docker下载容器镜像

    下载镜像的命令非常简单,使用docker pull命令即可. 在docker的镜像索引网站上面,镜像都是按照用户名/镜像名的方式来存储的. 有一组比较特殊的镜像,比如ubuntu这类基础镜像,经过官方 ...

  5. 关于使用JavaMail发送邮件

    import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import javax.activati ...

  6. Datagrid添加右键菜单 标签: 三层EasyUI 2015-08-14 19:57 1029人阅读 评论(22)

    最近的一个项目前台使用的EasyUI,每个界面都有DataGrid控件,按照我们的想法,应该做出来的效果是单击选中,双击可编辑,当然右键也应该出现这些菜单按钮,想的挺好,那么该如何实现呢?一开始不知道 ...

  7. 14-1 jquery的dom操作和事件对象

    一 jquery的操作有,插入,修改,删除,克隆.具体见下方代码实例: <!DOCTYPE html> <html lang="en"> <head& ...

  8. Best Open Source Software

    Best Open Source Software Open Source, Software, Top The promise of open source software is best qua ...

  9. [翻译]Python中yield的解释

    问题: Python中yield关键字的作用是什么?它做了什么? 例如,我想理解以下代码 def node._get_child_candidates(self, distance, min_dist ...

  10. zoj 3859 DoIt is Being Flooded (MFSet && Flood Fill)

    ZOJ :: Problems :: Show Problem 这题开始的时候想不到怎么调整每个grid的实际淹没时间,于是只好找了下watashi的题解,发现这个操作还是挺简单的. ZOJ3354 ...