1 引入pom依赖:
<!--java验证框架-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
特别注意:
- 如果您已经使用了
spring-boot-starter-web
,那它已经引入了最合适的validation-api
版本 ,不用单独引依赖。 - 低版本的
validation-api
的空校验只有@NotNull ,高版本的请注意区分 @NotNull @NotEmpty @NotBlank 的使用。(本文样例是低版本)
2 简单参数的校验
- 在类上加
org.springframework.validation.annotation.Validated
注解,这里必须是在类上加,在方法或者参数上加,验证会不起作用 - 这个类必须在spring容器里,比如用@Controller @Service之类的注解标记或者在xml注入都行。
/**
* @author: zenghong
* @Date: 2019/4/2 14:16
* @Description: 样例接口
* @RestController 标记为RestController
* @RequestMapping 这个类的公共请求路径
* @Validated 这个注解必须注解在类上面,在方法或者参数上,对于非复杂对象的校验将会失效
*/
@RestController
@RequestMapping("/example")
@Validated
public class ExampleController {
- 然后就可以直接在参数加javax.validated的校验注解了:
/**
* 功能描述: 根据id和name查询example GET 参数为简单对象的示例
*
* @ApiOperation swagger的东西,本项目不强制使用
* @GetMapping 等于 requestMapping + method=GET
* @ResponseBody 标记返回值示一个json
* @NotNull @Size 验证非空,验证长度 ,可查看javax.validation.constraints包下其他的验证注解
* @param:
* @return:
* @author: zenghong
* @date: 2019/4/2 下午2:50
*/
@ApiOperation("根据id查询example")
@GetMapping("getExampleByIdAndName")
@ResponseBody
public BaseResponse<StnExample> getExampleByIdAndName(
@Size(min = 8, max = 10,message = "id 长度应为1~11") @NotNull(message = "id 不能为空") String id,
@Size(min = 8, max = 10,message = "name 长度应为1~64") @NotNull(message = "name 不能为空") String name) {
//日志的打印拼接请使用占位符方式,字符串本身的拼接用 + 没有关系。
log.info("日志打印示例{},{},{}", "参数1", "参数2", id+name);
BaseResponse response = new BaseResponse();
return response;
}
请求结果:
image.png
3 复杂参数校验
- 在需要校验的复杂参数前面加@Validated 注解
/**
* 功能描述: 添加一条记录 - POST 参数为复杂对象的示例
*
* @ApiOperation swagger的东西,本项目不强制使用
* @GetMapping 等于 requestMapping + method=GET
* @ResponseBody 标记返回值示一个json
* @param:
* @return:
* @author: zenghong
* @date: 2019/4/2 下午2:50
*/
@ApiOperation("根据id查询example")
@PostMapping("AddExample")
@ResponseBody
public BaseResponse<StnExample> AddExample(@Validated @RequestBody BaseRequest<StnExample> request) {
log.info("日志打印示例{},{},{}", "参数1", "参数2", request.toString());
BaseResponse response = new BaseResponse();
return response;
}
- 在复杂对象上加校验注解
public class StnExample implements Serializable {
private static final long serialVersionUID = 42L;
/**
* 主键ID
*/
@NotNull(message = "id 不能为空")
private Long id;
/**
* 客户姓名
*/
@NotNull(message = "userName 不能为空")
private String userName;
如果,用到了范型嵌套对象,必须使用@Valid ( javax.validation.Valid )注解,@Validated对此不起作用:
public class BaseRequest<T> implements Serializable {
private static final long serialVersionUID = -4105149695353549745L;
/** 当前页 */
protected Integer pageIndex;
/** 页记录数 */
protected Integer pageSize;
/** 请求体 */
@Valid
protected T body;
请求结果:
image.png
4 全局异常捕获
您应该发现了,默认给出来的异常信息很丑(特别是简单对象校验不过的时候)。咱们应该进行异常捕获,格式化输出。
@ControllerAdvice
@Slf4j
@ResponseBody
public class GlobalExceptionHandler {
/**
*
* 功能描述: 捕获 自定义的业务异常,并处理,该异常由程序员手动抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 上午11:47
*/
@ExceptionHandler(StationException.class)
public BaseResponse handleServiceException(StationException e) {
log.error("业务异常:", e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(e.getErrorCode());
response.setMessage(e.getMessage());
return response;
}
/**
*
* 功能描述: 捕获 HttpMediaTypeNotSupportedException 异常,并处理,该异常由验证框架抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:09
*/
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public BaseResponse handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
log.error("HttpMediaTypeNotSupportedException : ",e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage()+": MediaType 不正确");
return response;
}
/**
*
* 功能描述: 捕获 HttpRequestMethodNotSupportedException 异常,并处理,该异常由验证框架抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:14
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public BaseResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("HttpRequestMethodNotSupportedException : ",e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage()+": 不支持的 http method");
return response;
}
/**
*
* 功能描述: 捕获 HttpMessageNotReadableException 异常,并处理,该异常由验证框架抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:15
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public BaseResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
log.error("HttpMessageNotReadableException : ",e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage()+": 非法的http请求");
return response;
}
/**
*
* 功能描述: 捕获 MissingServletRequestParameterException 异常,并处理,该异常由验证框架抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:18
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
public BaseResponse handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
log.error("MissingServletRequestParameterException : ",e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage()+": 参数缺失");
return response;
}
/**
*
* 功能描述: 捕获 ConstraintViolationException 异常,并处理,该异常由验证框架抛出
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:18
*/
@ExceptionHandler(value = {ConstraintViolationException.class})
public BaseResponse handleResourceNotFoundException(ConstraintViolationException e) {
log.error("ConstraintViolationException : ",e);
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations) {
strBuilder.append(violation.getMessage() + "\n");
}
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage() +": "+ strBuilder.toString());
return response;
}
/**
* 功能描述: 捕获 MethodArgumentNotValidException 异常,并处理,该异常由验证框架抛出
*
* @param: e
* @return: BaseResponse
* @author: zenghong
* @date: 2019/3/12 上午9:11
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public BaseResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("MethodArgumentNotValidException : {}",e);
BindingResult result = e.getBindingResult();
FieldError error = result.getFieldError();
String field = error.getField();
String code = error.getDefaultMessage();
String message = String.format("%s %s", field, code);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.E3000.getCode());
response.setMessage(ResponseStateCode.E3000.getMessage() +": "+ message);
return response;
}
/**
*
* 功能描述: 搂底的异常处理,正常来讲不应该走到这里的,如果走到这里需要特别注意
*
* @param:
* @return: com.jccfc.station.response.BaseResponse
* @author: zenghong
* @date: 2019/4/3 下午2:24
*/
@ExceptionHandler(value = Exception.class)
public BaseResponse defaultErrorHandler(Exception e) {
log.error("发生其他异常,详细信息:", e);
BaseResponse response = new BaseResponse();
response.setState(false);
response.setCode(ResponseStateCode.ERROR.getCode());
response.setMessage(ResponseStateCode.ERROR.getMessage() +": 服务器错误,请稍后重试");
return response;
}
}
说明:具体的实体类和返回码枚举需要换成您自己的。
这个时候的输出:
image.png image.png
网友评论