在上一篇文章中我们分析了SpringMVC对简单对象和@RequestParam注解的解析过程,这一章中我们继续分析其他形式的参数解析过程。
@RequestMapping("requestAndResponseRequest")
public String requestAndResponseRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("userName" + request.getParameter("userName"));
return "这是一个接收Request和Response的请求";
}
我们的请求处理方法中的两个参数是HttpServletRequest和HttpServletResponse类型,那么SpringMVC在调用requestAndResponseRequest这个方法的时候是怎么解析到这两个参数的值的呢?我们先看HttpServletRequest这个参数,这个参数是ServletRequestMethodArgumentResolver这个类来解析的。在上一篇文章中,我们知道通过调用argumentResolvers.
supportsParameter这个方法来判断HandlerMethodArgumentResolver的实现类是否支持对应的参数的解析,和
resolveArgument方法来实现真正的参数解析。
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) ||
Principal.class.isAssignableFrom(paramType) ||
InputStream.class.isAssignableFrom(paramType) ||
Reader.class.isAssignableFrom(paramType) ||
HttpMethod.class == paramType ||
Locale.class == paramType ||
TimeZone.class == paramType ||
"java.time.ZoneId".equals(paramType.getName()));
}
从上面的代码中我们可以看到如果
参数类型为WebRequest类型、ServletRequest类型、MultipartRequest类型、HttpSession类型、Principal类型、InputStream类型、Reader类型或者HttpMethod类型、Locale类型、TimeZone类型、ZoneId类型则使用这个参数解析器进行参数的解析工作。
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Class> paramType = parameter.getParameterType();
//如果是WebRequest的子类
if (WebRequest.class.isAssignableFrom(paramType)) {
//不是NativeWebRequest的实现类,则抛出异常
if (!paramType.isInstance(webRequest)) {
throw new IllegalStateException(
"Current request is not of type [" + paramType.getName() + "]: " + webRequest);
}
//直接返回传进来的NativeWebRequest
return webRequest;
}
//从传进来的webRequest中获取HttpServletRequest对象
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
//如果是ServletRequest的类型或者为MultipartRequest的类型
if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) {
//判断类型是否一致
Object nativeRequest = webRequest.getNativeRequest(paramType);
if (nativeRequest == null) {
throw new IllegalStateException(
"Current request is not of type [" + paramType.getName() + "]: " + request);
}
return nativeRequest;
}
else if (HttpSession.class.isAssignableFrom(paramType)) {
//从request中得到HttpSession对象
HttpSession session = request.getSession();
if (session != null && !paramType.isInstance(session)) {
throw new IllegalStateException(
"Current session is not of type [" + paramType.getName() + "]: " + session);
}
return session;
}
else if (InputStream.class.isAssignableFrom(paramType)) {
//从request中得到InputStream对象
InputStream inputStream = request.getInputStream();
if (inputStream != null && !paramType.isInstance(inputStream)) {
throw new IllegalStateException(
"Request input stream is not of type [" + paramType.getName() + "]: " + inputStream);
}
return inputStream;
}
else if (Reader.class.isAssignableFrom(paramType)) {
//从request中得到Reader对象
Reader reader = request.getReader();
if (reader != null && !paramType.isInstance(reader)) {
throw new IllegalStateException(
"Request body reader is not of type [" + paramType.getName() + "]: " + reader);
}
return reader;
}
else if (Principal.class.isAssignableFrom(paramType)) {
//从request中得到Reader对象
Principal userPrincipal = request.getUserPrincipal();
if (userPrincipal != null && !paramType.isInstance(userPrincipal)) {
throw new IllegalStateException(
"Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal);
}
return userPrincipal;
}
else if (HttpMethod.class == paramType) {
//从request中得到请求类型的值
return HttpMethod.resolve(request.getMethod());
}
else if (Locale.class == paramType) {
//从Request上下文中获取国际化对象
return RequestContextUtils.getLocale(request);
}
else if (TimeZone.class == paramType) {
//从Request上下文中获取时区对象
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
return (timeZone != null ? timeZone : TimeZone.getDefault());
}
else if ("java.time.ZoneId".equals(paramType.getName())) {
//JDK1.8时区
return ZoneIdResolver.resolveZoneId(request);
}
else {
// Should never happen...
throw new UnsupportedOperationException(
"Unknown parameter type [" + paramType.getName() + "] in " + parameter.getMethod());
}
}
从上面的代码中我们发现最主要的是NativeWebRequest这个对象,我们可以从这个对象中获取到HttpServletRequest,从HttpServletRequest中获取一系列的其他对象的值。我们可以看一下NativeWebRequest这个对象的值是怎么创建的。在RequestMappingHandlerAdapter#invokeHandlerMethod中有这样一段代码:
ServletWebRequest webRequest = new ServletWebRequest(request, response);
在ServletWebRequest这个对象中持有request和response这两个对象的引用。ServletWebRequest的UML类图关系如下:
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class> paramType = parameter.getParameterType();
return (ServletResponse.class.isAssignableFrom(paramType) ||
OutputStream.class.isAssignableFrom(paramType) ||
Writer.class.isAssignableFrom(paramType));
}
ServletResponseMethodArgumentResolver解析的参数类型是:
ServletResponse类型、OutputStream类型和Writer类型。我们再看下一resolveArgument方法中对参数解析的实现:
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
if (mavContainer != null) {
mavContainer.setRequestHandled(true);
}
//从webRequest获取HttpServletResponse对象,我们前面说了webRequest持有HttpServletResponse对象的引用
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
Class> paramType = parameter.getParameterType();
//ServletResponse类型
if (ServletResponse.class.isAssignableFrom(paramType)) {
Object nativeResponse = webRequest.getNativeResponse(paramType);
if (nativeResponse == null) {
throw new IllegalStateException(
"Current response is not of type [" + paramType.getName() + "]: " + response);
}
return nativeResponse;
}//从HttpServletResponse中获取OutputStream对象
else if (OutputStream.class.isAssignableFrom(paramType)) {
return response.getOutputStream();
}//从HttpServletResponse中获取Writer对象
else if (Writer.class.isAssignableFrom(paramType)) {
return response.getWriter();
}
else {
// should not happen
Method method = parameter.getMethod();
throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method);
}
}
这个参数的解析过程和ServletRequestMethodArgumentResolver中对象参数的解析过程如出一辙。我们对HttpServletRequest和HttpServletResponse参数的解析就先到这里了。