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/张三
控制器:
@RequestMapping(path = "PathVariable/id/{id}/age/{age}/name/{name}")
public Map PathVariable(@PathVariable("id") Integer id,
@PathVariable("age") Integer age,
@PathVariable("name") String name) {
Map<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("age", age);
map.put("name", name);
return map;
}
Postman:
@RequestParam
样例1
URL:
http://127.0.0.1/RequestParam1?name=张三&age=18
http://127.0.0.1/RequestParam2?name=张三&age=18
控制器
@RequestMapping(path = "RequestParam1")
public String PathVariableTest1(@RequestParam(name = "name") String name,
@RequestParam(name = "age") Integer age) {
return "name -> " + name + "; age -> " + age;
}
@RequestMapping(path = "RequestParam2")
public Map PathVariableTest2(@RequestParam(name = "name") String name,
@RequestParam(name = "age") Integer age) {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
return map;
}
@MatrixVariable
注意
Spring Boot 默认禁用了 @MatrixVariable 矩阵变量功能,如果需要开启:
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除 ; 后面的内容,使得矩阵变量功能可以生效。
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
样例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,捷豹
控制器:
@GetMapping("/car/{path}")
public Map car(@PathVariable("path") String path,
@MatrixVariable("price") Integer low,
@MatrixVariable("brand") List<String> brand,
@MatrixVariable Map<String, String> paramsA,
@MatrixVariable MultiValueMap<String, String> paramsB) {
Map<String, Object> map = new HashMap<>();
map.put("price", low);
map.put("brand", brand);
map.put("path", path);
map.put("paramsA", paramsA);
map.put("paramsB", paramsB);
return map;
}
Postman:
样例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
控制器:
@GetMapping("/boss/{bossId}/employee/{employeeId}")
public Map boss(@MatrixVariable(value = "age", pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age", pathVar = "employeeId") Integer empAge,
@MatrixVariable Map<String, String> paramsA,
@MatrixVariable MultiValueMap<String, String> paramsB) {
Map<String, Object> map = new HashMap<>();
map.put("bossAge", bossAge);
map.put("employeeAge", empAge);
map.put("paramsA", paramsA);
map.put("paramsB", paramsB);
return map;
}
Postman:
开启矩阵变量功能(含原理解析)
开启矩阵变量功能,这就涉及到了定制化 Spring Boot 的东西。
我们来到 Spring MVC 的配置类 WebMvcAutoConfiguration ,所有的自动配置都在这儿。
开启矩阵变量的核心在这儿:
默认的行为:配置了映射
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
if (this.mvcProperties.getPathmatch()
.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
configurer.setPatternParser(new PathPatternParser());
}
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
configurer.setUseRegisteredSuffixPatternMatch(
this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setAlwaysUseFullPath(true);
configurer.setUrlPathHelper(urlPathHelper);
}
});
}
因此,我们需要修改默认的路径匹配规则,这里有一个重要的类 UrlPathHelper 路径帮助器,它里面有一个属性是:
private boolean removeSemicolonContent = true;
默认是 true 。
看一下这个属性的 set 方法:
/**
* Set if ";" (semicolon) content should be stripped from the request URI.
* <p>Default is "true".
*/
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
checkReadOnly();
this.removeSemicolonContent = removeSemicolonContent;
}
可以看到,文档上已经标注了这个属性的功能。如果需要 ;后的内容需要被移除,就把它设置为 true 。
因此,我们需要自定义 Spring MVC 的功能,回顾过去学习的知识:
https://www.yuque.com/jaded/nql9hd/eo2dbg?inner=rQSqY
我们知道,可以使用 @Configuration + webMvcConfigurer 自定义 Spring MVC 的规则。
@Configuration 代表这个东西是容器中的一个组件,只要容器中有一个 webMvcConfigurer 的组件,然我们来定制化它就可以了。
我们来看一下 webMvcConfigurer 是什么:
显然,它是一个接口,这个里面定义了一个方法叫 configurePathMatch ,而 WebMvcAutoConfiguration 自动配置的时候,它给容器里配置了一个组件 WebMvcAutoConfigurationAdapter ,它也实现了 WebMvcConfigurer 这个接口。
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
if (this.mvcProperties.getPathmatch()
.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
configurer.setPatternParser(new PathPatternParser());
}
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
configurer.setUseRegisteredSuffixPatternMatch(
this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setAlwaysUseFullPath(true);
configurer.setUrlPathHelper(urlPathHelper);
}
});
}
它在定义路径映射规则的时候,是默认移除内容的。
所以我们只需要在这儿放一个我们自己定义的 WebMvcConfigurer 。
我们想要自定义它,就是给容器中放一个组件,就有两种写法:
1、使用 @Bean 的方式,给容器中注册一个我们自己写的 WebMvcConfigurer 类型的组件。
2、让配置类实现 WebMvcConfigurer 这个接口,由于 JDK8 有我们接口的默认实现,所以我们无需把接口的每一个方法都实现了,我们只需要实现我们想修改的方法就可以了。
我们只需要修改 configurePathMatch 方法即可。
@Configuration(proxyBeanMethods = false)
public class WebConfig /* implements WebMvcConfigurer */ {
// 方法1
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除 ; 后面的内容,使得矩阵变量功能可以生效。
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
// 方法2
// @Override
// public void configurePathMatch(PathMatchConfigurer configurer) {
// UrlPathHelper urlPathHelper = new UrlPathHelper();
// urlPathHelper.setRemoveSemicolonContent(false);
// configurer.setUrlPathHelper(urlPathHelper);
// }
}
@RequestBody
json传参、xml传参等。
样例1
URL:
http://127.0.0.1/RequestBody1
http://127.0.0.1/RequestBody2
Body:
{"name": "张三","id": 59,"age": 18}
Postman:
@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=张三
控制器:
@RequestMapping(path = "httpServletRequest")
public Map httpServletRequest(HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
map.put("age",request.getParameter("age"));
map.put("name",request.getParameter("name"));
map.put("allParams", request.getParameterMap());
return map;
}
Postman:
复杂参数
Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder
自定义对象参数
可以自动类型转换与格式化,可以级联封装。