Spring MVC 在底层处理 Web 请求接收的传参类型,大概分为了4类。

注解

@PathVariable、@RequestParam、@MatrixVariable、@RequestBody、@RequestHeader、@CookieValue、@ModelAttribute

@PathVariable

路径变量

样例1

URL:
http://127.0.0.1/PathVariable/id/59/age/18/name/张三

控制器:

  1. @RequestMapping(path = "PathVariable/id/{id}/age/{age}/name/{name}")
  2. public Map PathVariable(@PathVariable("id") Integer id,
  3. @PathVariable("age") Integer age,
  4. @PathVariable("name") String name) {
  5. Map<String, Object> map = new HashMap<>();
  6. map.put("id", id);
  7. map.put("age", age);
  8. map.put("name", name);
  9. return map;
  10. }

Postman:
image.png

@RequestParam

请求参数

样例1

URL:
http://127.0.0.1/RequestParam1?name=张三&age=18
http://127.0.0.1/RequestParam2?name=张三&age=18

控制器

  1. @RequestMapping(path = "RequestParam1")
  2. public String PathVariableTest1(@RequestParam(name = "name") String name,
  3. @RequestParam(name = "age") Integer age) {
  4. return "name -> " + name + "; age -> " + age;
  5. }
  1. @RequestMapping(path = "RequestParam2")
  2. public Map PathVariableTest2(@RequestParam(name = "name") String name,
  3. @RequestParam(name = "age") Integer age) {
  4. Map<String, Object> map = new HashMap<>();
  5. map.put("name", name);
  6. map.put("age", age);
  7. return map;
  8. }

@MatrixVariable

注意

Spring Boot 默认禁用了 @MatrixVariable 矩阵变量功能,如果需要开启:

  1. @Bean
  2. public WebMvcConfigurer webMvcConfigurer() {
  3. return new WebMvcConfigurer() {
  4. @Override
  5. public void configurePathMatch(PathMatchConfigurer configurer) {
  6. UrlPathHelper urlPathHelper = new UrlPathHelper();
  7. // 不移除 ; 后面的内容,使得矩阵变量功能可以生效。
  8. urlPathHelper.setRemoveSemicolonContent(false);
  9. configurer.setUrlPathHelper(urlPathHelper);
  10. }
  11. };
  12. }

样例1

请求URL:
http://127.0.0.1/car/1;price=34;brand=byd;brand=捷豹
http://127.0.0.1/car/1;price=34;brand=byd,捷豹

控制器:

  1. @GetMapping("/car/{path}")
  2. public Map car(@PathVariable("path") String path,
  3. @MatrixVariable("price") Integer low,
  4. @MatrixVariable("brand") List<String> brand,
  5. @MatrixVariable Map<String, String> paramsA,
  6. @MatrixVariable MultiValueMap<String, String> paramsB) {
  7. Map<String, Object> map = new HashMap<>();
  8. map.put("price", low);
  9. map.put("brand", brand);
  10. map.put("path", path);
  11. map.put("paramsA", paramsA);
  12. map.put("paramsB", paramsB);
  13. return map;
  14. }

Postman:
image.png

样例2

请求URL:
http://127.0.0.1/boss/1;age=20/employee/2;age=10
http://127.0.0.1/boss/1;age=35;name=老板A/employee/2;age=20;name=打工人A

控制器:

  1. @GetMapping("/boss/{bossId}/employee/{employeeId}")
  2. public Map boss(@MatrixVariable(value = "age", pathVar = "bossId") Integer bossAge,
  3. @MatrixVariable(value = "age", pathVar = "employeeId") Integer empAge,
  4. @MatrixVariable Map<String, String> paramsA,
  5. @MatrixVariable MultiValueMap<String, String> paramsB) {
  6. Map<String, Object> map = new HashMap<>();
  7. map.put("bossAge", bossAge);
  8. map.put("employeeAge", empAge);
  9. map.put("paramsA", paramsA);
  10. map.put("paramsB", paramsB);
  11. return map;
  12. }

Postman:
image.pngimage.png

开启矩阵变量功能(含原理解析)

开启矩阵变量功能,这就涉及到了定制化 Spring Boot 的东西。

我们来到 Spring MVC 的配置类 WebMvcAutoConfiguration ,所有的自动配置都在这儿。

开启矩阵变量的核心在这儿:
image.png

默认的行为:配置了映射

  1. @Override
  2. public void configurePathMatch(PathMatchConfigurer configurer) {
  3. if (this.mvcProperties.getPathmatch()
  4. .getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
  5. configurer.setPatternParser(new PathPatternParser());
  6. }
  7. configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
  8. configurer.setUseRegisteredSuffixPatternMatch(
  9. this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
  10. this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
  11. String servletUrlMapping = dispatcherPath.getServletUrlMapping();
  12. if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
  13. UrlPathHelper urlPathHelper = new UrlPathHelper();
  14. urlPathHelper.setAlwaysUseFullPath(true);
  15. configurer.setUrlPathHelper(urlPathHelper);
  16. }
  17. });
  18. }

因此,我们需要修改默认的路径匹配规则,这里有一个重要的类 UrlPathHelper 路径帮助器,它里面有一个属性是:

  1. private boolean removeSemicolonContent = true;

默认是 true 。

看一下这个属性的 set 方法:

  1. /**
  2. * Set if ";" (semicolon) content should be stripped from the request URI.
  3. * <p>Default is "true".
  4. */
  5. public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
  6. checkReadOnly();
  7. this.removeSemicolonContent = removeSemicolonContent;
  8. }

可以看到,文档上已经标注了这个属性的功能。如果需要 ;后的内容需要被移除,就把它设置为 true 。

因此,我们需要自定义 Spring MVC 的功能,回顾过去学习的知识:
https://www.yuque.com/jaded/nql9hd/eo2dbg?inner=rQSqY

我们知道,可以使用 @Configuration + webMvcConfigurer 自定义 Spring MVC 的规则。

@Configuration 代表这个东西是容器中的一个组件,只要容器中有一个 webMvcConfigurer 的组件,然我们来定制化它就可以了。

我们来看一下 webMvcConfigurer 是什么:
image.png
显然,它是一个接口,这个里面定义了一个方法叫 configurePathMatch ,而 WebMvcAutoConfiguration 自动配置的时候,它给容器里配置了一个组件 WebMvcAutoConfigurationAdapter ,它也实现了 WebMvcConfigurer 这个接口。

  1. public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer
  2. @Override
  3. public void configurePathMatch(PathMatchConfigurer configurer) {
  4. if (this.mvcProperties.getPathmatch()
  5. .getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
  6. configurer.setPatternParser(new PathPatternParser());
  7. }
  8. configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
  9. configurer.setUseRegisteredSuffixPatternMatch(
  10. this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
  11. this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
  12. String servletUrlMapping = dispatcherPath.getServletUrlMapping();
  13. if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
  14. UrlPathHelper urlPathHelper = new UrlPathHelper();
  15. urlPathHelper.setAlwaysUseFullPath(true);
  16. configurer.setUrlPathHelper(urlPathHelper);
  17. }
  18. });
  19. }

它在定义路径映射规则的时候,是默认移除内容的。

所以我们只需要在这儿放一个我们自己定义的 WebMvcConfigurer 。

我们想要自定义它,就是给容器中放一个组件,就有两种写法:
1、使用 @Bean 的方式,给容器中注册一个我们自己写的 WebMvcConfigurer 类型的组件。
2、让配置类实现 WebMvcConfigurer 这个接口,由于 JDK8 有我们接口的默认实现,所以我们无需把接口的每一个方法都实现了,我们只需要实现我们想修改的方法就可以了。

我们只需要修改 configurePathMatch 方法即可。

  1. @Configuration(proxyBeanMethods = false)
  2. public class WebConfig /* implements WebMvcConfigurer */ {
  3. // 方法1
  4. @Bean
  5. public WebMvcConfigurer webMvcConfigurer() {
  6. return new WebMvcConfigurer() {
  7. @Override
  8. public void configurePathMatch(PathMatchConfigurer configurer) {
  9. UrlPathHelper urlPathHelper = new UrlPathHelper();
  10. // 不移除 ; 后面的内容,使得矩阵变量功能可以生效。
  11. urlPathHelper.setRemoveSemicolonContent(false);
  12. configurer.setUrlPathHelper(urlPathHelper);
  13. }
  14. };
  15. }
  16. // 方法2
  17. // @Override
  18. // public void configurePathMatch(PathMatchConfigurer configurer) {
  19. // UrlPathHelper urlPathHelper = new UrlPathHelper();
  20. // urlPathHelper.setRemoveSemicolonContent(false);
  21. // configurer.setUrlPathHelper(urlPathHelper);
  22. // }
  23. }

@RequestBody

json传参、xml传参等。

样例1

URL:
http://127.0.0.1/RequestBody1
http://127.0.0.1/RequestBody2

Body:

  1. {"name": "张三","id": 59,"age": 18}

Postman:
image.pngimage.png

@RequestHeader

@CookieValue

@ModelAttribute

Servlet API

HttpServletRequest、WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId

HttpServletRequest

URL:
127.0.0.1/httpServletRequest?age=18&name=张三

控制器:

  1. @RequestMapping(path = "httpServletRequest")
  2. public Map httpServletRequest(HttpServletRequest request) {
  3. Map<String, Object> map = new HashMap<>();
  4. map.put("age",request.getParameter("age"));
  5. map.put("name",request.getParameter("name"));
  6. map.put("allParams", request.getParameterMap());
  7. return map;
  8. }

Postman:
image.png

复杂参数

MapModel(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder

自定义对象参数

可以自动类型转换与格式化,可以级联封装。