接口方法往往需要對入參做一些校驗,從而判斷入參是否合格,而javax.validation包為我們提供了一些常用的參數校驗注解,使用起來很方便。
下面這個示例是檢驗入參對象中的password是否為空
1. 創建一個User.java
import javax.validation.constraints.NotBlank; public class User { private String username; @NotBlank private String password; private Integer age; }
2. 接口方法
@PostMapping("/user") public User createUser(@Valid @RequestBody User user) { System.out.println(user); user.setAge(100); return user; }
3. 測試代碼
@Test public void testCreateUser() throws Exception { String jsonUser = "{\"username\":\"admin\",\"password\":null}"; mockMvc.perform(MockMvcRequestBuilders.post("/user") .contentType(MediaType.APPLICATION_JSON) .content(jsonUser)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.age").value("100")); }
4. 測試結果
在測試代碼中, 我們的password=null, 所以檢驗不通過,報400。而password不為null ,測試通過,如下
5. BindingResult
在以上的參數校驗中,如果參數校驗不通過,都不通進入接口方法,我們也不好收集錯誤信息.。 不過,spring為我們提供了一個java類BindingResult.java, 借助它即可!
注意: @Valid與BindingResult要配套使用
5.1 接口代碼
@PostMapping("/user") public User createUser(@Valid @RequestBody User user, BindingResult errors) { if (errors.hasErrors()) { errors.getAllErrors().stream().forEach(x-> System.out.println(x.getDefaultMessage())); } System.out.println(user); user.setAge(100); return user; }
5.2 測試代碼及打印結果
5.3 自定義錯誤信息
public class User { private String username; @NotBlank(message = "密碼不能為空") private String password; private Integer age; }
6. 自定義注解
javax.validation默認提供了不少的注解,但是有時候,我們需要按照自己的邏輯去自定義注解。
下面舉個例子,在創建User對象時,先校驗一下數據庫是否存在相同的用戶名username, 代碼如下:
6.1 查詢邏輯
@Service public class UserService { /** * 模擬查詢,檢驗admin用戶名是否存在 * @param username * @return */ public boolean findUserByUsername(String username) { if (StringUtils.equals(username, "admin")) { return false; } return true; } }
6.2 自定義注解及實現
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) // 該注解的具體實例邏輯類 @Constraint(validatedBy = MyValidatorImpl.class) public @interface MyValidator { String message() default "admin用戶已存在"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
import org.springframework.beans.factory.annotation.Autowired; import qinfeng.zheng.mockmvcdemo.service.UserService; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * 實現 ConstraintValidator接口的類,spring會將其弄成一個bean */ public class MyValidatorImpl implements ConstraintValidator<MyValidator, String> { @Autowired private UserService userService; @Override public void initialize(MyValidator anno) { System.out.println("初始化。。。。"); } /** * @param value 需要校驗的參數值 * @param constraintValidatorContext * @return false : 校驗不通過 * true : 校驗通過 */ @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { return userService.findUserByUsername(value); } }
6.3 實體類上注解的使用
public class User { @MyValidator private String username; @NotBlank(message = "密碼不能為空") private String password; private Integer age; }
6.4 校驗接口
@PostMapping("/user") public User createUser(@Valid @RequestBody User user, BindingResult errors) { if (errors.hasErrors()) { errors.getAllErrors().stream().forEach(x-> System.out.println(x.getDefaultMessage())); } System.out.println(user); user.setAge(100); return user; }
6.5 測試代碼