springmvc 參數校驗/aop失效/@PathVariable 參數爲空

添加依賴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 }
View Code

自定義異常(可選):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 }
View Code

全局異常處理器:

 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 }
View Code

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

相關文章
相關標籤/搜索