pom 文件引入

使用 Validation 前,要先在 pom 中引入相关依赖:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-validation</artifactId>
  4. </dependency>

创建分组

在很多时候,同一个模型可能会在多处被用到,但每处的校验场景又不一定相同。如:新增信息 和 修改信息,参数可能都是 user 模型,在新增时 user 中 name 字段不能为空;在修改时 user 中 name 字段可以为空。这样我们可以用 groups 来实现,同一个模型在不同场景下,动态校验模型中的不同字段。因此先创建 Insert 和 Update 两个分组

  1. package com.test.tools.validation;
  2. public interface Insert {}
  1. package com.test.tools.validation;
  2. public interface Update {}

在实体类中添加校验信息

  1. package com.test.tools.entity;
  2. import com.test.tools.validation.Insert;
  3. import lombok.Data;
  4. import javax.validation.constraints.Email;
  5. import javax.validation.constraints.NotBlank;
  6. import javax.validation.constraints.NotNull;
  7. @Data
  8. public class DiffyEntity implements java.io.Serializable{
  9. @NotBlank(message = "稳定版本的ip地址不能为空",groups = Insert.class)
  10. protected String primaryIp;
  11. @NotBlank(message = "稳定版本的端口不能为空",groups = Insert.class)
  12. protected String primaryPort;
  13. @NotBlank(message = "候选版本的ip地址不能为空",groups = Insert.class)
  14. protected String candidateIp;
  15. @NotBlank(message = "候选版本的端口不能为空",groups = Insert.class)
  16. protected String candidatePort;
  17. @NotBlank(message = "邮箱不能为空",groups = Insert.class)
  18. @Email(message = "邮箱地址不合法")
  19. protected String email;
  20. }

通过约束性的注解,可以对参数进行验证,并通过 groups 进行分组校验。

  • groups = Insert.class 则当前验证规则作用于 Insert 分组
  • groups = Update.class 则当前验证规则作用于 Update 分组

    约束性注解说明

    | 注解 | 作用 | 使用方法 | | —- | —- | —- | | @NotNull | 不能为null,可以是空 | @NotNull(message=””) | | @Null | 必须是null | @Null(message=””) | | @Email | 必须是email格式 | @Email(message=””) | | @Length | 长度必须在指定范围内 | @Length(min = 5, max = 10, message=””) | | @NotBlank | 字符串不能为null
    字符串trim()后也不能等于”” | @NotBlank(message=””) | | @NotEmpty | 不能为null
    集合、数组、map等size()不能为0;
    字符串trim()后可以等于”” | @NotEmpty(message=””) | | @Range | 值必须在指定范围内 | @Range(min = 100, max = 200, message=””) | | @URL | 必须是一个URL | @URL(message=””) | | @Pattern | 必须满足指定的正则表达式 | @Pattern(regexp = “\\d+”, message=””) | | @Max | 最大不得超过此最大值 | @Max(value = 200, message=””) | | @Min | 最大不得小于此最小值 | @Min(value = 200, message=””) | | @Future | 日期必须在当前日期的未来 | @Future(message=””) | | @Past | 日期必须在当前日期的过去 | @Past(message=””) | | @Digits | 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内 | @Digits(integer = 5, fraction = 3, message=””) | | @DecimalMax | 设置不能超过最大值 | @DecimalMax(value = “12.3”,message=””) | | @DecimalMin | 设置不能超过最小值 | @DecimalMax(value = “12.3”,message=””) | | @AssertFalse | 可以为null,如果不为null的话必须为false | @AssertFalse(message=””) | | @AssertTrue | 可以为null,如果不为null的话必须为true | @AssertTrue(message=””) |

在Controller中使用@Validated注解

在 Controller 接口方法参数之前使用 @Validated 注解启用参数验证,可以赋值不同的分组名称进行分组验证,比如上面的 Insert.class 和 Update.class,分组验证可以用来处理不同接口需要校验不同参数的情况。验证不通过会返回前端 JSON 数据,处理方式有两种:使用 BindingResult 全局异常处理

BindingResult 处理

  1. @PostMapping("/post/diffy")
  2. public JsonResult save(@Validated(Insert.class) @RequestBody DiffyEntity diffyEntity, BindingResult bindingResult) {
  3. if (bindingResult.hasErrors()) {
  4. return JsonResult.fail(bindingResult.getFieldErrors().get(0).getDefaultMessage());
  5. }
  6. return diffyService.save(diffyEntity);
  7. }

全局异常处理

我用的是全局的异常处理,且接口返回的是json数据,因此先创建一个JsonResult,用于返回统一格式给到前端

  1. package com.test.tools.vo;
  2. public class JsonResult {
  3. private int code;
  4. private Object data;
  5. private String msg;
  6. public JsonResult() {
  7. }
  8. public JsonResult(int code, Object data) {
  9. this.code = code;
  10. this.data = data;
  11. }
  12. public JsonResult(int code, Object data, String msg) {
  13. this.code = code;
  14. this.data = data;
  15. this.msg = msg;
  16. }
  17. public static JsonResult buildSuccess(Object data){
  18. return new JsonResult(200,data);
  19. }
  20. public static JsonResult warn(String msg){
  21. return new JsonResult(-1,"",msg);
  22. }
  23. public static JsonResult fail(String msg){
  24. return new JsonResult(-1,"",msg);
  25. }
  26. public String getMsg() {
  27. return msg;
  28. }
  29. public void setMsg(String msg) {
  30. this.msg = msg;
  31. }
  32. public int getCode() {
  33. return code;
  34. }
  35. public void setCode(int code) {
  36. this.code = code;
  37. }
  38. public Object getData() {
  39. return data;
  40. }
  41. public void setData(Object data) {
  42. this.data = data;
  43. }
  44. }

然后再创建一个全局异常处理的类 GlobalExceptionHandler,处理一些通用的异常

  1. package com.test.tools.exception;
  2. import com.test.tools.vo.JsonResult;
  3. import org.apache.catalina.connector.ClientAbortException;
  4. import org.springframework.dao.DataAccessResourceFailureException;
  5. import org.springframework.dao.EmptyResultDataAccessException;
  6. import org.springframework.dao.InvalidDataAccessApiUsageException;
  7. import org.springframework.http.converter.HttpMessageNotReadableException;
  8. import org.springframework.transaction.CannotCreateTransactionException;
  9. import org.springframework.web.HttpRequestMethodNotSupportedException;
  10. import org.springframework.web.bind.MethodArgumentNotValidException;
  11. import org.springframework.web.bind.MissingServletRequestParameterException;
  12. import org.springframework.web.bind.annotation.ControllerAdvice;
  13. import org.springframework.web.bind.annotation.ExceptionHandler;
  14. import org.springframework.web.bind.annotation.ResponseBody;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.validation.UnexpectedTypeException;
  17. import java.sql.SQLTransientConnectionException;
  18. @ControllerAdvice
  19. public class GlobalExceptionHandler {
  20. // 声明要捕获的异常
  21. @ExceptionHandler(Error.class)
  22. @ResponseBody
  23. public JsonResult defaultError(HttpServletRequest request, Error e) {
  24. if (e instanceof NoClassDefFoundError) {
  25. return JsonResult.fail("找不到类错误" + e.getMessage());
  26. }
  27. // 未知错误
  28. e.printStackTrace();
  29. return JsonResult.fail("项目运行异常, 请联系技术人员...");
  30. }
  31. // 声明要捕获的异常
  32. @ExceptionHandler(Exception.class)
  33. @ResponseBody
  34. public JsonResult defaultException(HttpServletRequest request, Exception e) {
  35. // 请求方式有误
  36. if (e instanceof HttpRequestMethodNotSupportedException) {
  37. return JsonResult.warn("请求方式POST/GET有误");
  38. }
  39. /**
  40. * @Validated 进行接口参数校验统一处理
  41. */
  42. if (e instanceof MethodArgumentNotValidException) {
  43. MethodArgumentNotValidException exception = (MethodArgumentNotValidException)e;
  44. return JsonResult.warn(exception.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
  45. }
  46. /**
  47. * 缺少参数异常
  48. */
  49. if (e instanceof MissingServletRequestParameterException) {
  50. return JsonResult.warn("缺少请求参数");
  51. }
  52. /**
  53. * 接口请求不对
  54. */
  55. if (e instanceof InvalidDataAccessApiUsageException) {
  56. return JsonResult.warn("请检查接口请求是否缺少参数");
  57. }
  58. // 参数格式有误,比如int类型输入了abc
  59. if (e instanceof HttpMessageNotReadableException) {
  60. return JsonResult.warn("参数格式异常:" + e.getMessage());
  61. }
  62. if (e instanceof NumberFormatException) {
  63. return JsonResult.warn("参数格式异常" + e.getMessage());
  64. }
  65. /**
  66. * 没有匹配到的数据
  67. */
  68. if (e instanceof EmptyResultDataAccessException) {
  69. return JsonResult.warn("数据不存在, 请检查参数是否正确");
  70. }
  71. /**
  72. * 前面的都是警告,不输出错误信息
  73. */
  74. e.printStackTrace();
  75. // id用了@NotBlank
  76. if (e instanceof UnexpectedTypeException) {
  77. return JsonResult.fail("请求参数类型异常" + e.getMessage());
  78. }
  79. // 数据库异常
  80. if (e instanceof DataAccessResourceFailureException) {
  81. return JsonResult.fail("数据库连接异常");
  82. }
  83. if (e instanceof SQLTransientConnectionException) {
  84. return JsonResult.fail("数据库连接异常");
  85. }
  86. if (e instanceof CannotCreateTransactionException) {
  87. return JsonResult.fail("数据库连接异常");
  88. }
  89. if (e instanceof ClientAbortException) {
  90. return JsonResult.fail("中止了一个已建立的连接");
  91. }
  92. // 空指针异常
  93. if (e instanceof NullPointerException) {
  94. e.printStackTrace();
  95. return JsonResult.fail("空指针异常");
  96. }
  97. // 未知错误
  98. return JsonResult.fail("服务器处理异常, 请联系技术人员...");
  99. }
  100. }

最后在 Controller 中,使用 @Validated 注解启用参数验证

  1. @PostMapping(path = "/post/diffy")
  2. public JsonResult add(@Validated(Insert.class) @RequestBody DiffyEntity diffyEntity,Exception e){
  3. // 异常处理,包括参数异常
  4. if (e instanceof MethodArgumentNotValidException) {
  5. MethodArgumentNotValidException exception = (MethodArgumentNotValidException)e;
  6. return JsonResult.warn(exception.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
  7. }
  8. // 保存提交记录
  9. diffyService.addCommitLog(diffyEntity);
  10. // 返回启动命令
  11. JsonResult jsonResult = new JsonResult(200,diffyService.getStartCommand(),"success");
  12. return jsonResult;
  13. }

利用 postman 验证一下效果
1646563151(1).jpg