测试
准备测试环境
SimpleController.java
@RestController
public class SimpleController {
@ModelAttribute("nickname")
public String init(Model model) {
System.out.println("Controller: SimpleController init 执行");
model.addAttribute("postCode", "225431");
return "Rick";
}
@GetMapping("request")
public Map<String, Object> request(@Validated User user,
BindingResult bindingResult, //必须紧跟@Valid/@Validated对象后面
@RequestParam(required = false) @Validated @Min(18) Integer age,
@RequestParam Map<String, Object> requestParamMap,
@RequestParam("names") List<String> namesList,
String[] names,
@ModelAttribute("postCode") String postCode,
@ModelAttribute("nickname") String nickname,
Map<String, Object> modelMap,
Model model,
HttpServletRequest request) {
System.out.println("Controller: request 执行");
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("requestParamMap", requestParamMap);
resultMap.put("namesList", namesList);
resultMap.put("names", names);
resultMap.put("user", user);
resultMap.put("age", age);
resultMap.put("postCode", postCode);
resultMap.put("nickname", nickname);
resultMap.put("bindingResult", bindingResult.getAllErrors());
modelMap.put("hobby", "swimming");
model.addAttribute("sex", "男");
request.setAttribute("home", "TaiXing");
return resultMap;
}
}
- 请求
http://localhost:8080/request?age=1&names=Jim,Tom&name=Rick
- 返回
{
"names": ["Jim", "Tom"],
"bindingResult": [],
"namesList": ["Jim", "Tom"],
"nickname": "Rick",
"postCode": "225431",
"requestParamMap": {
"age": "1",
"names": "Jim,Tom",
"name": "Rick"
},
"user": {
"age": 1,
"name": "Rick"
},
"age": 1
}
分析
@ModelAttribute
写在方法上,返回值就是model的value,init在每次请求都会执行。init中有2个model属性nickname
postCode
,值分别是“Rick”“225432”- 对象
User
前面加了@Valid/@Validated
解析器ModelAttributeMethodProcessor
会进行字段的验证。如果要收集异常,那么后面紧跟BindingResult。如果没有紧跟,那么如果验证失败将会抛出异常BindException
。
源代码查看ModelAttributeMethodProcessor => validateIfApplicable(binder, parameter)
=> Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann); age
使用RequestParamMethodArgumentResolver
解析,解析后对字段类型由String转换成Integer,该解析器不支持验证,所以虽然加了“@Validated @Min(18)”但是并不会验证requestParamMap
将所有的请求参数值放到requestParamMap中,如果参数是数组,只放第一个- namesList 和 names 是“简单类型” 由
RequestParamMethodArgumentResolver
解析,解析后对字段类型由String转换成对应的类型 postCode
和nickname
参数使用注解@ModelAttribute
表示从model中获取值,这里@ModelAttribute的属性name不要省略model
使用解析器ModelMethodProcessor
;modelMap
使用解析器MapMethodProcessor
。modelMap
和model
是同一个引用。 视图解析器比如ThymeleafView会将model中的值放入request scope中request
使用ServletRequestMethodArgumentResolver
进行解析
自定义参数解析器
系统提供了很多默认的参数处理器
0 = {RequestParamMethodArgumentResolver@8604}
1 = {RequestParamMapMethodArgumentResolver@8605}
2 = {PathVariableMethodArgumentResolver@8606}
3 = {PathVariableMapMethodArgumentResolver@8607}
4 = {MatrixVariableMethodArgumentResolver@8608}
5 = {MatrixVariableMapMethodArgumentResolver@8609}
6 = {ServletModelAttributeMethodProcessor@8610}
7 = {RequestResponseBodyMethodProcessor@8611}
8 = {RequestPartMethodArgumentResolver@8612}
9 = {RequestHeaderMethodArgumentResolver@8613}
10 = {RequestHeaderMapMethodArgumentResolver@8614}
11 = {ServletCookieValueMethodArgumentResolver@8615}
12 = {ExpressionValueMethodArgumentResolver@8616}
13 = {SessionAttributeMethodArgumentResolver@8617}
14 = {RequestAttributeMethodArgumentResolver@8618}
15 = {ServletRequestMethodArgumentResolver@8619}
16 = {ServletResponseMethodArgumentResolver@8620}
17 = {HttpEntityMethodProcessor@8621}
18 = {RedirectAttributesMethodArgumentResolver@8622}
19 = {ModelMethodProcessor@8623}
20 = {MapMethodProcessor@8624}
21 = {ErrorsMethodArgumentResolver@8625}
22 = {SessionStatusMethodArgumentResolver@8626}
23 = {UriComponentsBuilderMethodArgumentResolver@8627}
24 = {PrincipalMethodArgumentResolver@8629}
25 = {RequestParamMethodArgumentResolver@8630}
26 = {ServletModelAttributeMethodProcessor@8631}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return User.class == parameter.getParameterType();
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
User user = new User();
user.setName("Green");
user.setAge(92);
return user;
}
});
}
}
这个参数解析器会在 ServletModelAttributeMethodProcessor
之前执行,非简单对象会先使用自定义的解析器解析。自定义的参数解析器的应用场景,我们可以根据token解析出用户信息放入参数中
GitHub:https://github.com/jkxyx205/spring-boot-learn/tree/master/spring-mvc-argument-resolver