添加依賴java
1 <!-- 參數校驗 -->
2 <dependency>
3 <groupId>org.hibernate.validator</groupId>
4 <artifactId>hibernate-validator</artifactId>
5 <version>6.0.17.Final</version>
6 </dependency>
一.基本類型參數(String)校驗web
1.註解要寫在接口中,實現類會自動繼承,若是實現類的某個重寫方法沒有加上了註解,接口中卻沒有定義,運行時會產生redefine異常spring
接口:restful
User getUserById(@NotNull(message = "uid不能爲null") @Min(value = 1,message = "uid不合法") Integer id);
實現類:mvc
@Override
public User getUserById(@NotNull(message = "uid不能爲null") @Min(value = 1,message = "uid不合法") Integer id) {
return userMapper.getUserById(id);
}app
Controller(restful風格最容易出的問題就是參數爲空,只要不傳就是404,不要嘗試:xxx/getUserById/null,這種寫法是400,給url設置null沒有意義,解決方式很簡單,給Controller增長一個映射路徑便可,空參數致使的bind異常能夠用在全局異常處理器捕獲便可,固然你在web.xml中統一處理404也能夠):ide
1 @RequestMapping(value = {"/getUserById/{uid}","/getUserById"}) 2 public @ResponseBody Object getUserById(@PathVariable Integer uid) { 3 return userService.getUserById(uid); 4 }
2.提供校驗器,自定義異常(可選),全局異常處理器測試
校驗器:ui
1 public class ParamsValidator { 2 3 public static ExecutableValidator getValidator() { 4 ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); 5 return validatorFactory.getValidator().forExecutables(); 6 } 7 }
自定義異常(可選):this
1 public class ValidParamException extends RuntimeException { 2 private static final long serialVersionUID = 1L; 3 4 private Set<ConstraintViolation<Object>> validateResult; 5 6 public ValidParamException() { 7 super(); 8 } 9 10 public ValidParamException(String message) { 11 super(message); 12 } 13 14 public ValidParamException(Set<ConstraintViolation<Object>> validateResult) { 15 this.validateResult = validateResult; 16 } 17 18 public Set<ConstraintViolation<Object>> getValidateResult() { 19 return validateResult; 20 } 21 22 public void setValidateResult(Set<ConstraintViolation<Object>> validateResult) { 23 this.validateResult = validateResult; 24 } 25 26 @Override 27 public String getMessage() { 28 return validateResult.iterator().next().getMessage(); 29 } 30 31 public Map<Object, String> getErrorMap() { 32 Map<Object, String> map = new HashMap<Object, String>(6); 33 Iterator<ConstraintViolation<Object>> iterator = validateResult.iterator(); 34 while (iterator.hasNext()) { 35 ConstraintViolation<Object> cons = iterator.next(); 36 Path propertyPath = cons.getPropertyPath(); 37 String message = cons.getMessage(); 38 map.put(propertyPath, message); 39 } 40 return map; 41 } 42 43 }
全局異常處理器:
1 @ControllerAdvice 2 @EnableWebMvc 3 public class GlobalExceptionHandler { 4 // 單參數校驗
5 @ExceptionHandler(ValidParamException.class) 6 public @ResponseBody Map<Object, String> validParamException(HttpServletRequest req, ValidParamException vpe) { 7 return vpe.getErrorMap(); 8 } 9
10 // 對象類型參數校驗
11 @ExceptionHandler(MethodArgumentNotValidException.class) 12 public @ResponseBody Map<Object, String> methodArgumentNotValidException(MethodArgumentNotValidException ex) { 13 String parameterName = ex.getParameter().getParameterName(); 14 Map<Object, String> map = new HashMap<Object, String>(6); 15 map.put(parameterName, ex.getLocalizedMessage()); 16 return map; 17 } 18
19 // pathvariable不傳遞參數時拋出的異常
20 @ExceptionHandler(ServletRequestBindingException.class) 21 public @ResponseBody Map<Object, String> servletRequestBindingException(ServletRequestBindingException ex) { 22 Map<Object, String> map = new HashMap<Object, String>(6); 23 map.put("error", ex.getLocalizedMessage()); 24 return map; 25 } 26 }
3.使用aop進行攔截
關於aop"失效"的問題有幾點說明:
1)若是攔截controller,那麼aop的配置要寫在springmvc的配置文件中,攔截其餘層(如service)寫在spring的配置文件中
2)被攔截的類必須也被spring管理不然沒法攔截成功
3)開啓註解掃描時,springmvc只掃描@Controller類型的註解,其餘的如@Service,@Repository註解由spring進行掃描
aop:
1 @Component 2 @Aspect 3 public class UserAspect { 4 5 private ExecutableValidator validator = ParamsValidator.getValidator(); 6 7 @Pointcut("execution (* cn.tele.service.*.*(..))") 8 private void pt() { 9 } 10 11 @Before("pt()") 12 public void checkParams(JoinPoint jp) { 13 14 Object target = jp.getTarget(); 15 Object[] params = jp.getArgs(); 16 MethodSignature methodSignature = (MethodSignature) jp.getSignature(); 17 18 String[] paramNames = methodSignature.getParameterNames(); 19 Method method = methodSignature.getMethod(); 20 21 Set<ConstraintViolation<Object>> validateResult = validator.validateParameters(target, method, params); 22 if (!validateResult.isEmpty()) { 23 throw new ValidParamException(validateResult); 24 } 25 } 26 27 }
4.測試結果:
1)傳入-1
2)不傳
能夠在aop中打印日誌啥的
二.對象類型參數校驗
1.在javaBean中添加註解,對一些特殊字段進行分組,如id,插入數據時,不須要校驗能夠爲null,而查詢,刪除,更新等操做必須校驗
1 @NotNull(message = "uid不能爲null",groups = {Query.class,Update.class,Delete.class}) 2 @Min(value = 1,message = "uid不合法") 3 private Integer uid; 4
5 @NotBlank(message = "姓名不能爲空") 6 @Size(max = 20,message = "姓名最大長度爲50個字符") 7 private String userName; 8
9 @NotBlank(message = "性別不能爲空") 10 @Size(max = 20,message = "性別最大長度位20個字符") 11 private String sex; 12
13 @NotNull 14 @Max(value = 70,message = "最大年齡爲70歲") 15 private Integer age; 16
17 @NotNull 18 private Integer departmentId; 19
20 @Value(value = "1") 21 private Integer state;
分組只是個標記,用接口定義就好
1 public interface Query { 2
3 }
2.在參數前添加@Valited註解,該註解支持分組,@Valid不支持,若是你選擇的校驗位置與上面定義的aop攔截的位置相同,那就會出問題了,
你的代碼會走aop的邏輯而後去用你校驗單個參數的校驗器去進行校驗,這樣沒法校驗出問題,所以推薦放在controller層
1 @RequestMapping("/insertUser") 2 public @ResponseBody String insertUser(@Validated @RequestBody User user) { 3 Integer count = userService.insertUser(user); 4 return count ==1 ? "成功增長1條記錄" : "增長" + user + "失敗"; 5 }
校驗指定分組
3.拋出的異常會走上面貼出的全局異常處理器的代碼
4.測試
1)正常狀況,注意沒有id
2)丟失userName