1、普通参数接收
(1)@PathVariable
接收url中的参数,可单独接收,也可以通过map接收
属性值:name、value都为绑定地址栏中对应的名称值
/**
* 地址栏访问:http://127.0.0.1:8080/test/zhangsan
* 展示:{"pv":{"text":"zhangsan"},"text":"zhangsan"}
*/
@GetMapping("/test/{text}")
public Map<String,Object> pathVariable(@PathVariable(name = "text") String text,
@PathVariable Map<String,String> pv) {
Map<String,Object> retMap = new HashMap<>();
retMap.put("text",text);
retMap.put("pv",pv);
return retMap;
}
(2)@RequestParam
接收地址栏传参,可单独按名称接收,也可通过map进行统一接收
属性值:name、value接收传参属性值,required是否必传,默认为必传
/**
* 地址栏访问:http://127.0.0.1:8080/test?text=zhangsan&list=lisi,wangwu
* 展示:{"pv":{"text":"zhangsan","list":"lisi,wangwu"},"text":"zhangsan","list":["lisi","wangwu"]}
*/
@GetMapping("/test")
public Map<String,Object> requestParam(@RequestParam(name = "text") String text,
@RequestParam(name = "list") List<String> list,
@RequestParam Map<String,Object> pv) {
Map<String,Object> retMap = new HashMap<>();
retMap.put("text",text);
retMap.put("list",list);
retMap.put("pv",pv);
return retMap;
}
(3)@RequestHeader
接收请求头中的参数,可单独按名称接收,也可通过map进行统一接收
属性值:name、value接收传参属性值,required是否必传,默认为必传
@GetMapping("/header")
public Map<String,Object> requestHeader(@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String,String> header) {
Map<String,Object> retMap = new HashMap<>();
retMap.put("userAgent",userAgent);
retMap.put("header",header);
return retMap;
}
(4)@CookieValue
接收cookie的参数,可单独按名称接收,可接收cookie的值,也可接收为cookie对象
属性值:name、value接收传参属性值,required是否必传,默认为必传
@GetMapping("/cookie")
public Map<String,Object> cookie(@CookieValue("_zs") String _zs,
@CookieValue("_zs") Cookie cookie) {
Map<String,Object> retMap = new HashMap<>();
retMap.put("_zs",_zs);
retMap.put("cookie",cookie);
return retMap;
}
(5)@RequestBody
接收请求体中的内容
属性值:required是否必传,默认为必传
@PostMapping("/body")
public Map<String,Object> body(@RequestBody String body) {
Map<String,Object> retMap = new HashMap<>();
retMap.put("body",body);
return retMap;
}
(6)@RequestAttribute
获取请求域中的值
属性值:name、value接收传参属性值,required是否必传,默认为必传
@GetMapping("/test1")
public String test1(HttpServletRequest request) {
request.setAttribute("site", "zhangsan");
return "forward:/test2";
}
@GetMapping(value = "/test2")
@ResponseBody
public String test2(@RequestAttribute("site") String site) {
return site;
}
(7)@MatrixVariable
获取矩阵变量中的值,必须存在与url路径变量中才能解析,SpringBoot默认不开启矩阵变量解析
属性值:name、value接收传参属性值,required是否必传,默认为必传, pathVar指定路径变量
- 开启矩阵变量解析
对于路径的处理,UrlPathHelper进行解析,其中removeSemicolonContent(移除分号内容)支持矩阵变量的,默认为true,移除不支持
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
/**
* 地址栏访问:http://127.0.0.1:8080/boss/1;age=20/2;age=10
* 展示:{"bossAge":20,"empAge":10}
*/
@GetMapping("/boss/{bossId}/{empId}")
public Map<String,Object> matrixVariable(@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;
}
2、Servlet API
WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId 使用ServletRequestMethodArgumentResolver解析器进行解析
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;
}
3、复杂参数
Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder
/**
* model、Map类型请求响应前会执行以下方法
* @param model
* @param request
* @throws Exception
*/
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
HttpServletRequest request) throws Exception {
//model中的所有数据遍历挨个放在请求域中
model.forEach((name, value) -> {
if (value != null) {
request.setAttribute(name, value);
}
else {
request.removeAttribute(name);
}
});
}
4、自定义POJO参数
可以自动类型转换与格式化,可以级联封装, 使用ServletModelAttributeMethodProcessor解析器进行解析
//判断吧不是这些类型就可处理
public static boolean isSimpleValueType(Class<?> type) {
return Void.class != type &&
Void.TYPE != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type);
}
基本解析原理: WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); WebDataBinder :web数据绑定器,将请求参数的值绑定到指定的JavaBean里面 WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中,参数解析器可使用一下方法往容器中添加自定义的参数转换器
@Configuration
public class MvcConfig implements WebMvcConfigurer {
/**
* 自定义参数转换器
* @param registry
*/
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String , Person>() {
@Override
public Person convert(String s) {
return null;
}
});
}
}
GenericConversionService:在设置每一个值的时候,找它里面的所有converter那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型
5、参数解析原理
(1)根据查询的handlerMapping查询执行的适配器
为当前Handler 找一个适配器 HandlerAdapter;
RequestMappingHandlerAdapter适配器执行目标方法并确定方法参数的每一个值
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
.........
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
.........
}
//循环匹配可执行当前Handler 的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
(2)执行目标方法
通过反射执行目标方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
.........
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
.........
}
//RequestMappingHandlerAdapter
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
........
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
.........
}
//ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
........
}
//InvocableHandlerMethod.class
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//进行参数填充
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Arguments: " + Arrays.toString(args));
}
//执行真正的方法
return this.doInvoke(args);
}
(3)参数解析原理
获取方法中所有的参数项,根据参数项循环查找符合要求的参数解析器,使用参数解析器解析参数
//InvocableHandlerMethod.class
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
/**
* 获取所有的参数信息
*/
MethodParameter[] parameters = this.getMethodParameters();
.......
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
........
/**
* 使用参数解析器进行解析参数值
*/
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
.........
}
}
//HandlerMethodArgumentResolverComposite.class
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
/**
* 循环遍历获取可以处理的参数解析器
*/
HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
} else {
/**
* 执行逻辑,获取参数值
*/
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
//HandlerMethodArgumentResolverComposite.class
//循环从所有参数解析中查找符合的参数解析器
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//从缓存中读取是否存在参数解析器
HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
if (result == null) {
Iterator var3 = this.argumentResolvers.iterator();
while(var3.hasNext()) {
HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, resolver);
break;
}
}
}
return result;
}