SpringBoot
配合Hibernate-Validator
參數校驗(學習筆記2020.3.25)
前言:
在
RESTful Web Services
的接口服務中,會有各種各樣的入參,我們不可能完全不做任何校驗就直接進入到業務處理的環節,通常我們會有一個基礎的數據驗證的機制,待這些驗證過程完畢,結果無誤後,參數纔會進入到正式的業務處理中。而數據驗證又分爲兩種,一種是無業務關聯的規則性驗證,一種是根據現有數據進行的聯動性數據驗證(簡單來說,參數的合理性,需要查數據庫)。而Hibernate-Validator
則適合做無業務關聯(不需要對比數據庫)的規則性驗證。
1. 快速入門
1.1 引入依賴
創建
springboot
工程,如果是SpringBoot
工程的話,Hibernate-Validator
已經包含在spring-boot-starter-web
裏面。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果是普通
Spring
工程,則引入:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
</dependency>
Hibernate-Validator
的主要使用的方式就是註解的形式,並且是“零配置”的,無需配置也可以使用。
1.2方法參數的校驗
@RestController
@Validated //加上開啓驗證器
public class UserController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@GetMapping("/getUser")
public User getUser(@NotNull(message = "名字不能爲空") String name,
@NotNull(message = "年齡不能爲空")@Min(value = 1L,message = "年齡最小1") Integer age, @NotNull(message = "性別不能爲空") String sex){
log.info("成功訪問到了,參數是{},{},{}",name,age,sex);
return new User(name, age, sex);
}
}
然後啓動項目,進行訪問。 效果爲下圖。
這樣的效果並不好,後端會輸出大量錯誤日記,並且前臺提示會亂碼。
1.3 使用全局異常處理器
使用全局異常處理器來捕獲
ConstraintViolationException
@RestControllerAdvice
public class ViolationException {
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ExceptionResult exceptionResult(ConstraintViolationException exception){
StringBuilder builder = new StringBuilder();
for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
String[] split = violation.getPropertyPath().toString().split("\\.");
builder.append(split[1])
.append(violation.getMessage()).append(",");
}
return new ExceptionResult(builder.deleteCharAt(builder.length()-1).toString(), HttpStatus.BAD_REQUEST.value());
}
}
請求過去後返回的結果:
{"message":"age年齡不能爲空,name名字不能爲空,sex性別不能爲空","code":400}
如果想返回自定義錯誤頁面, 加上模板依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>參數錯誤頁面error.html</title>
</head>
<body>
<div>
<span>
錯誤信息: <span th:text="${message}"></span>
</span> </p>
<span>
錯誤狀態碼: <span th:text="${code}"></span>
</span>
</div>
</body>
</html>
異常處理器:
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ModelAndView ResultErrorHtml(ConstraintViolationException exception,
HttpServletResponse response){
StringBuilder builder = new StringBuilder();
for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
String[] split = violation.getPropertyPath().toString().split("\\.");
builder.append(split[1])
.append(violation.getMessage()).append(",");
}
ModelAndView view = new ModelAndView();
view.setViewName("error");
view.addObject("message", builder.deleteCharAt(builder.length()-1).toString());
view.addObject("code", HttpStatus.BAD_REQUEST.value());
return view;
}
1.4 實體類的校驗
方法參數校驗,少參數的情況下還是很方便的,但是做多參數的情況下就要用到實體類來進行校驗了。
public class User implements Serializable {
@NotNull(message = "名字不能爲空")
private String name;
@NotNull(message = "年齡不能爲空")
private Integer age;
@NotNull(message = "性別不能爲空")
private String sex;
@NotNull(message = "生日不能爲空")
private String birthday;
.......省略
}
控制層
api
方法使用註解@Valid
來進行校驗標記好的實體類
@GetMapping("/getUsers")
public User getUsers(@Valid User user){
log.info("成功訪問到了,參數是{}",user);
return user;
}
訪問後控制檯會出現以下信息。
Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 4 errors
Field error in object 'user' on field 'sex': rejected value [null]; codes [NotNull.user.sex,NotNull.sex,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.sex,sex]; arguments []; default message [sex]]; default message [性別不能爲空]
這個時候叫需要在全局異常處理器進行添加一個異常類型
BindException
注意別導錯異常類型包。
@ExceptionHandler(value = BindException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ExceptionResult bindExceptionResult(BindException exception){
StringBuilder builder = new StringBuilder();
for (FieldError fieldError : exception.getFieldErrors()) {
builder.append(fieldError.getField())
.append(fieldError.getDefaultMessage()).append(",");
}
return new ExceptionResult(builder.deleteCharAt(builder.length()-1).toString(), HttpStatus.BAD_REQUEST.value());
}
註解說明:
-
@NotNull
: 註釋元素一定不能null 。 -
@Null
: 帶註釋的元素必須爲null 。 -
@NotBlank
: 該註釋元素不能爲null ,且必須含有至少一個非空白字符。 接受CharSequence
。 -
@NotEmpty
: 註釋元素不能是null也不空。支持的類型包括CharSequence , Collection , Map, 數組
-
@Size
: 該註釋元素大小必須在指定的邊界之間(含), 支持的類型包括CharSequence , Collection , Map, 數組
-
@Max
: 帶註釋的元素必須是一個數字,其值必須小於或等於指定的最大值。支持的類型包括:BigDecimal
BigInteger
byte , short , int , long
,和他們各自的包裝
需要注意的是double和float不支持,由於舍入誤差(有些供應商可能提供一些近似的支持)。 -
@Min
: 帶註釋的元素必須是一個數字,其值必須大於或等於指定的最小值。支持的類型與@Max一樣
-
@Email
: 該字符串必須是一個結構完整的電子郵件地址。 是什麼使一個有效的電子郵件地址確切的語義留給Bean驗證 -
@Past
: 註釋元素必須是在過去的瞬間,日期或時間。 null元素被認爲是有效的。 -
@PastOrPresent
: 帶註釋的元素必須是在過去或在現在瞬間,日期或時間。 -
@AssertFalse
:註釋元素一定是假的@AssertTrue
: 註釋元素一定是真的。 -
@Range(min = 18,max = 60,message = "只能填報年齡在18~60歲的")
其他的註解解析
項目代碼
1