【註解】用註解來優雅校驗
阿新 • • 發佈:2019-01-22
前言
現在公司中 Springboot 框架中欄位校驗使用Assert
但遇到要校驗多個欄位,一個欄位多重限制,那麼這時候Assert
便變得很笨重,且不優雅
這時候JSR 303
和JSR 349
閃亮登場 (~ ̄▽ ̄)~
一、最佳實踐
配置
版本:Spring boot 2.0
如果開發web,spring-boot-starter-web
包中就有hibernate-validate
包。
當然,不匯入這個包,匯入spring-boot-starter-validation
也可以
(1)整合配置
為了能與原先
web
配置(攔截器、過濾器等)統一管理,希望他們能在同一檔案或同一資料夾下。
-
為了能使用 Spring MVC 部分特性,可能會選擇使用繼承(
extend
)WebMvcConfigurerAdapter
,然而這個已經過時了@Deprecated
-
突然發現還有個
WebMvcConfigurationSupport
,也要extend
,欣喜若狂。然而發現繼承這個會將配置完全交給 Spring MVC,這樣會與自定義的配置和Spring boot的某些配置相沖突。 -
最後種,引用(
implements
)WebMvcConfigurer
,解決了我的需求。同時我發現
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer
o(╥﹏╥)o
- 使用
JSR 303
校驗,我可能需要:
- 快速失敗功能(即:遇到錯誤直接返回,而不是把所有的都校驗一般,這樣減少CPU資源使用)
- 我想讓其在方法之間傳遞引數時候也能生效
這樣我的配置大概形成了:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor ()).addPathPatterns("/**");
}
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
return registrationBean;
}
@Bean
public TimeInterceptor timeInterceptor() {
return new TimeInterceptor();
}
// 設定校驗器
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator());
return processor;
}
// 設定模式
@Bean
public Validator validator(){
// failFast(true)啟動快速失敗
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).
configure().
failFast(true).
buildValidatorFactory();
return validatorFactory.getValidator();
}
}
(2)異常捕獲
@ControllerAdvice
public class RestExceptionHandler {
/**
* 校驗JSR-303
* @param exception
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public ServerResponse validate(ConstraintViolationException exception) {
log.error(exception.getMessage());
exception.printStackTrace();
Iterator iter = exception.getConstraintViolations().iterator();
ConstraintViolation constraintViolation = (ConstraintViolation) iter.next();
// ServerResponse.createByErrorCodeMessage 為自己配置的返回包裝體
return ServerResponse.createByErrorCodeMessage(Const.HttpStatusCode.BAD_REQUEST.getCode(),
constraintViolation.getConstraintDescriptor().getMessageTemplate());
}
}
(3)常用搭配
- 字串
String
@Length
和@Size
均可
@NotBlank(message = "請填寫專案名稱")
@Length(min = 3, max = 50, message = "專案名稱長度大於3且小於50")
private String projectName;
- 整型
Integer
@Range
和@Max
@Min
都可
@NotNull(message = "請選擇專案背景")
@Digits(integer = 1, fraction = 0, message = "請選擇專案背景")
@Range(min = 0, max = 3, message = "請重新選擇專案背景")
private Integer projectType;
- 用於小數
BigDecimal
@NotNull(message = "請填寫融資金額")
@Digits(integer = 10, fraction = 5, message = "請填寫正確的金額")
private BigDecimal amount;
- Boolean 校驗
@AssertTrue 驗證 Boolean 物件是否為 true
@AssertFalse 驗證 Boolean 物件是否為 false
- 物件資料校驗
@Valid
可校驗物件裡面的屬性,同時可遞迴校驗
@Valid
Person person;
二、實際運用
(1)Controller
層使用
controller層
校驗物件引數
@RequestMapping(value = "/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public User getUser(@Valid User user, BindingResult errors) {
if (errors.hasErrors()) {
errors.getAllErrors().stream().forEach(
error -> System.out.println(error.getDefaultMessage())
);
}
user.setUsername("Donald");
return user;
}
}
User物件
@Data
public class User {
@NotBlank(message = "使用者類中使用者名稱不能為空")
private String username;
@NotBlank(message = "密碼不能為空")
private String password;
@NotNull(message = "生日不能為空")
private Date birthday;
}
(2) Service
層使用
@Validated
是 Spring boot 對@Valid
的增強
UserService.java
@Validated
public interface UserService {
public List<User> getUserListByName(@NotBlank(message = "使用者名稱不能為空")
@Length(min = 3, max = 10, message = "使用者名稱長度大於3小於10")String username,
@Valid User user);
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Override
public List<User> getUserListByName(String username, User _user) {
List<User> users = new ArrayList<>();
User user = new User();
users.add(user);
return users;
}
}