JSR 303 输入验证是 Javax.validation 1.0
JSR 349 输入验证是 Javax.validation 1.1
目前Spring默认支持到JSR 349。
JSR 380 输入验证是 javax.Validation 2.0 ,通过添加Hiberante validator 6.x 默认将使用JSR S80验证。
根据Spring官网说明,对JSR 380 从Spring 5.x以后开始支持。但并不全面。经过测试,可以使用。

10.1、JSR380验证
以下使用最新的JSR380做为本次的验证,需要spring5以上版本。
1:可以使用@ExceptionHandler只用于验证一个Controller中的异常。
2:@ControllerAdvice可以用于系统全局异常。
3:BindingResult为错误的具体信息,可以被注入的任意的方法中用于设置错误或是读取错误信息。
4:建议根据不同的请求类型返回不同的响应信息,如,如果Accept为json则应该响应JSON数据。
JSR380的验证包括:

步1、添加验证依赖
<!-- 验证用的包以下是JSR380验证即javax.validation-2.0 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version></dependency><dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version></dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
步2、在spring配置文件中添加validator
<!-- 定义验证器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!--以下属性如果不设置,将默认使用javax.validator-->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/></bean>
<!--方法上基本类型参数的验证-->
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"> <property name="validator" ref="validator"/>
</bean>
<!--用于识别@RequestMapping,并指定验证规则-->
<mvc:annotation-driven validator="validator"/>
1:注意上面的配置中,在annotation-driven中通过validator指定使用LocalValiatorFactoryBean,而LocalValidatorFactoryBean默认将使用 javax.validator:
(见 API源代码)
2:注意上面包含两种不同的验证,其中LocalValidatorFactoryBeaan用于验证JavaBean,而MethodValidationPostProcessor用于验证方法上的其中类型和String.
步3、 JavaBean验证
分为两步:
1:给javaBean添加注解。
2:在Controller的参数上添加@Valid注解。
给JavaBean添加以下注解:
public class StudSaveForm {
private Long id;
@NotBlank(message = "姓名不能为空(name)")
private String name;
@NotNull(message = "年龄不能为空(age)")
private Integer age;
}
在Controller的参数上,添加以下注解:@Valid()
@PostMapping("/save")
@ResponseBody
public Stud save(@Valid()StudSaveForm form) {
log.info("接收到的数据:"+form);
Stud stud = studService.save(form);
return stud;
}
如果验证不成功,将会抛出400 BadRequest 状态码,异常类型:BindException。
步4、方法上接收参数验证(基本类型和 String等包装类型 )
即以下方式:
@RequestMapping("/save2")
@ResponseBody
public Stud save2(@NotBlank(message = "用户名必须输入")String name,@NotNull(message = "年龄必须输入")Integer age){
Stud stud = new Stud();
stud.setName(name);
stud.setAge(age);
return stud;
}
这需要在方法的参数上添加@NotBlank等等注解。然后还需要在类上添加:@Vaidate注解:
@Controller@Slf4j@Validated //注意这个注解
@RequestMapping("example/stud")public class StudController {
..
}
上面的已经添加了,如下的配置,上面的配置才会有效:【 支持方法上的验证】
<!--方法上基本类型参数的验证-->
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"> <property name="validator" ref="validator"/></bean>
然后,测试,如果没有输入name,age的值,请求对应地址,则将抛出异常:ConstraintViolationException
步5、开发异常处理中心
使用@ControllerAdvice可以统一处理异常,以下是具体统一处理的类,它同时根据用户的请求的是ajax还是网页,返回了不同的内容,以下代码主要是两个核心注解:
@ControllerAvice
@ExceptionHandler+[@ResponseStatus 可选]
package cn.ssm.core.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.*;
@Slf4j@ControllerAdvice
public class ExceptionController {
public ExceptionController() {
log.info("异常处理类启动成功..." + this);
}
//这儿所有没有匹配到的异常,在开始时,建议删除
@ExceptionHandler(value = Exception.class)
public String exception(Exception e) {
log.info("异常:" + e.getMessage() + ",异常类型:" + e.getMessage()); e.printStackTrace();
return "abc"; }
/** *
JavaBean验证失败【用于处理JavaBean验证失败】
*/
@ExceptionHandler(value = org.springframework.validation.BindException.class)
public String bindException(BindException bindException, HttpServletRequest request) throws Exception {
List<FieldError> list = bindException.getFieldErrors();
log.info("数据绑定异常:" + bindException.getMessage() + "," + bindException.getCause());
log.info("请求类型为:" + request.getHeader("Accept"));
bindException.printStackTrace();
String accept = request.getHeader("Accept");
if (accept.toLowerCase().contains("/json")) {
//如果包含json
ServletRequestAttributes sra =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = sra.getResponse();
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> map = new HashMap<>();
map.put("result", 1);//错误
for (FieldError fe : list) {
map.put(fe.getField(), fe.getDefaultMessage());
}
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(map);
response.getWriter().print(json);
return null;
}
StringBuilder sb = new StringBuilder();
for (FieldError fe : list) {
sb.append("错误-字段:" + fe.getField() + ",错误:" + fe.getDefaultMessage() + "<br>");
}
request.setAttribute("errorMsg", sb.toString());
return "error/error";
}
/**
* 方法上的基本类型验证失败【用于处理参数验证失败】
*/
@ExceptionHandler(value = ConstraintViolationException.class) public String methodValidation(ConstraintViolationException e,HttpServletRequest request) throws Exception{
Set<ConstraintViolation<?>>
sets = e.getConstraintViolations();
String accept = request.getHeader("Accept");
if (accept.toLowerCase().contains("/json")) {//如果包含json
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = sra.getResponse();
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> map = new HashMap<>();
map.put("result", 1);//错误
for (ConstraintViolation fe : sets) {
String msg = fe.getMessage();
if(map.containsKey("error")){//只有错误信息,没有key
map.put("error",map.get("error")+","+msg);
}else{
map.put("error",msg);
}
}
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(map);
response.getWriter().print(json);
return null;
}
StringBuilder sb = new StringBuilder();
for (ConstraintViolation fe : sets) {
sb.append("错误-字段:" + fe.getMessage()+"<br>");
}
request.setAttribute("errorMsg", sb.toString());
return "error/error";
}}
步6、网页测试结果

Ajax测试结果:

10.2、输入验证的更多细节
1、ResponseStatus验证错误状态码
可以添加 ResponseStatus注解,确定错误的状态码,如下所示:
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = org.springframework.validation.BindException.class)
public String bindException(BindException bindException, HttpServletRequest request) throws Exception {
2、在一个Controller中进行验证
@Controller@Slf4j@Validated@RequestMapping("example/stud")
public class StudController {
@PostMapping("/save")
@ResponseBody
public Stud save(@Valid()StudSaveForm form) {
log.info("接收到的数据:"+form); Stud stud = studService.save(form);
return stud;
}
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
public String exception(Exception e, BindingResult errors, HttpServletRequest request){
log.info("验证错误:"+e.getMessage());
log.info("类型:"+e.getClass());
e.printStackTrace();
int errorCont = errors.getErrorCount();
log.info("错误的数量:"+errorCont);
List<FieldError> list = errors.getFieldErrors();
for(FieldError
error:list){
log.info(error.getField()+","+error.getDefaultMessage()+","+error.getRejectedValue());
}
return "error/error";
}}
10.3、自定义验证器
后续




