SpringBoot-Web开发之请求参数处理
注解获取参数
1. 常用注解
- @PathVariable:获取restful方式的请求参数
- @RequestHeader:获取http请求的header部分信息
- @RequestAttribute:获取域中数据
- @RequestParam:获取请求体的key-value 参数
- @MatrixVariable:请求路径中,分号前为路径,获取分号后的请求参数
- @CookieValue:获取cookie信息
- @RequestBody:获取整个请求体中的数据
- 更多可查看参数解析器-HandlerMethodArgumentResolver
@RestController
public class ParameterTestController {// car/2/owner/zhangsan//cookie的key值在控制台查看请求头@GetMapping("/car/{id}/owner/{username}")public Map<String,Object> getCar(@PathVariable("id") Integer id,@PathVariable("username") String name,@PathVariable Map<String,String> pv,@RequestHeader("User-Agent") String userAgent,@RequestHeader Map<String,String> header,@RequestParam("age") Integer age,@RequestParam("inters") List<String> inters,@RequestParam Map<String,String> params,@CookieValue("_ga") String _ga,@CookieValue("_ga") Cookie cookie){Map<String,Object> map = new HashMap<>();map.put("_ga",_ga);return map;}@PostMapping("/save")public Map postMethod(@RequestBody String content){Map<String,Object> map = new HashMap<>();map.put("content",content);return map;}//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd//2、SpringBoot默认是禁用了矩阵变量的功能// 手动开启:原理。对于路径的处理。UrlPathHelper进行解析。// removeSemicolonContent(移除分号请求内容)//3、矩阵变量必须有url路径变量才能被解析@GetMapping("/cars/{path}")public Map carsSell(@MatrixVariable("low") Integer low,@MatrixVariable("brand") List<String> brand,@PathVariable("path") String path){Map<String,Object> map = new HashMap<>();map.put("low",low);map.put("brand",brand);map.put("path",path);return map;}// /boss/1;age=20/2;age=10@GetMapping("/boss/{bossId}/{empId}")public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){Map<String,Object> map = new HashMap<>();map.put("bossAge",bossAge);map.put("empAge",empAge);return map;}}@Controller
public class RequestController {@GetMapping("/goto")public String goToPage(HttpServletRequest request){request.setAttribute("msg","成功了...");request.setAttribute("code",200);return "forward:/success"; //转发到 /success请求}@ResponseBody@GetMapping("/success")public Map success(@RequestAttribute(value = "msg",required = false) String msg,@RequestAttribute(value = "code",required = false)Integer code,HttpServletRequest request){Object msg1 = request.getAttribute("msg");Map<String,Object> map = new HashMap<>();return map;}
}2. 开启矩阵变量功能
- 方法一:配置类实现接口WebMvcConfigurer,重写方法configurePathMatch
@Configuration(proxyBeanMethods = false)
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper = new UrlPathHelper();//默认true移除支持矩阵变量,故需设为false// 不移除;后面的内容。矩阵变量功能就可以生效urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}
}- 方法二:自定义WebMvcConfigurer的组件
//WebMvcConfigurer定制化SpringMVC的功能
@Bean
public WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer() {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper = new UrlPathHelper();// 不移除;使矩阵变量功能生效urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}};
}Servlet API获取参数
- WebRequest、ServletRequest、MultipartRequest、 HttpSession 等等......
- ServletRequestMethodArgumentResolver类
- 也是存在参数解析器-HandlerMethodArgumentResolver中
@Override
public boolean supportsParameter(MethodParameter parameter) {Class<?> paramType = parameter.getParameterType();return (WebRequest.class.isAssignableFrom(paramType) ||ServletRequest.class.isAssignableFrom(paramType) ||MultipartRequest.class.isAssignableFrom(paramType) ||HttpSession.class.isAssignableFrom(paramType) ||(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||Principal.class.isAssignableFrom(paramType) ||InputStream.class.isAssignableFrom(paramType) ||Reader.class.isAssignableFrom(paramType) ||HttpMethod.class == paramType ||Locale.class == paramType ||TimeZone.class == paramType ||ZoneId.class == paramType);
}复杂参数
- Map、Model(map、model里面的数据会被放在request的请求域==request.setAttribute)
- Errors/BindingResult
- RedirectAttributes( 重定向携带数据)
- ServletResponse(response)
@GetMapping("/params")
public String testParam(Map<String,Object> map,Model model,HttpServletRequest request,HttpServletResponse response){map.put("hello","world666");model.addAttribute("world","hello666");request.setAttribute("message","HelloWorld");Cookie cookie = new Cookie("c1","v1");response.addCookie(cookie);return "forward:/success";
}@ResponseBody
@GetMapping("/success")
public Map success(@RequestAttribute(value = "msg",required = false) String msg,@RequestAttribute(value = "code",required = false)Integer code,HttpServletRequest request){Object msg1 = request.getAttribute("msg");Map<String,Object> map = new HashMap<>();Object hello = request.getAttribute("hello");Object world = request.getAttribute("world");Object message = request.getAttribute("message");return map;
}参数处理过程
- 从DispatcherServlet类中doDispatch()开始
1. HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler())
- HandlerMapping中找到能处理请求的Handler(Controller.method())
- 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter
- 适配器执行目标方法并确定方法参数的每一个值

2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
- 执行目标方法,RequestMappingHandlerAdapter类的handleInternal()
- mav = this.invokeHandlerMethod(request, response, handlerMethod)
3. 参数解析器-HandlerMethodArgumentResolver
- RequestMappingHandlerAdapter类的invokeHandlerMethod()
- 确定将要执行的目标方法的每一个参数的值是什么
- SpringMVC目标方法能写多少种参数类型。取决于参数解析器,当前2.3.4版本查看26种。

- 当前解析器是否支持解析这种参数,支持就调用 resolveArgument()

4. 返回值处理器
- RequestMappingHandlerAdapter类的invokeHandlerMethod()
- 当前2.3.4版本查看15种

5. RequestMappingHandlerAdapter类的invokeHandlerMethod()
- invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0])

- 进入方法,ServletInvocableHandlerMethod类的invokeAndHandle()

- 进入方法,InvocableHandlerMethod类的invokeForRequest()

6. InvocableHandlerMethod类的getMethodArgumentValues()
- 获取到Controller方法上的每一个参数信息
- 使用的参数注解,参数类型等等

- 循环所有参数解析器判断Controller参数的注解是否有对应解析器
- HandlerMethodArgumentResolverComposite类的getArgumentResolver()


- 循环解析获取每一个参数的值
- AbstractNamedValueMethodArgumentResolver类的resolveArgument()


7. 自定义类型参数,封装的POJO
- ServletModelAttributeMethodProcessor ,这个参数处理器支持解析
- 会判断当前类型是否为简单类型


- WebDataBinder:web数据绑定器,利用它里面的 Converters 将请求数据转成指定的数据类型,封装到JavaBean中

- GenericConversionService:在设置每一个值的时候,找它里面的所有converter将这个数据类型(request带来参数的字符串)转换到指定的类型
8. 自定义 Converter作类型转换用
- 只能针对form表单提交数据,不能在restfulApi下生效
@Bean
public WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {//自定义转换类型registry.addConverter(new Converter<String, Pet>() {@Overridepublic Pet convert(String source) {// source获取到的请求内容if(!StringUtils.isEmpty(source)){Pet pet = new Pet();String[] split = source.split(",");pet.setName(split[0]);pet.setAge(Integer.parseInt(split[1]));return pet;}return null;}});}};
}