使用 Servlet API 作为入参
MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数:
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream
OutputStream
Reader
Writer
示例
1. 添加JSP页面
<li>使用 Servlet API作为入参 <ul> <li><a href="user/testServletAPI">使用 Servlet API作为入参</a></li> <li><a href="user/testServletAPI2">使用 Servlet API作为入参</a></li> </ul> </li>
2. 添加处理器类
/** * 可以使用Servlet原生的API作为目标方法的参数 具体支持以下类型 * * HttpServletRequest * HttpServletResponse * HttpSession * java.security.Principal * Locale * InputStream * OutputStream * Reader * Writer * */ @RequestMapping("testServletAPI") public String testServletAPI(HttpServletRequest request,HttpServletResponse response) { System.out.println("------testServletAPI HttpServletRequest: " + request + "------"); System.out.println("------testServletAPI HttpServletResponse: " + response + "------"); return LOGIN; } @RequestMapping("testServletAPI2") public void testServletAPI2(Writer writer) throws IOException { System.out.println("------testServletAPI2 Writer: " + writer + "------"); StringBuffer sb = new StringBuffer(); sb.append("<html><body>"); sb.append("<br/><a href='/org.rabbitx.web.spring4mvc/index.jsp'>Back TO Home Page</a>"); sb.append("</body></html>"); writer.write(sb.toString()); }
原理分析
1. 在 testServletAPI方法中打断点并使用debug模式启动服务器;
2. 在浏览器端点击对应连接启动调试;
3. 在调试窗口选中AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker(HandlerMethodInvoker).invokeHandlerMethod(Method, Object, NativeWebRequest, ExtendedModelMap) line: 175
其中,resolveHandlerArguments为解析处理参数方法。
4. 进入resolveHandlerArguments方法;
5. 找到resolveHandlerArguments方法中resolveCommonArgument方法并进入;
6. 找到resolveCommonArgument方法中resolveStandardArgument方法并进入;
7. 在方法resolveStandardArgument上使用Ctrl+T快捷键并选择"ServletHandlerMethodInvoker"进入;
8. 查看方法resolveStandardArgument可以知道SpringMVC本质上还是从原生ServletAPI中获取相应的对象;
@Override protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); if (ServletRequest.class.isAssignableFrom(parameterType) || MultipartRequest.class.isAssignableFrom(parameterType)) { Object nativeRequest = webRequest.getNativeRequest(parameterType); if (nativeRequest == null) { throw new IllegalStateException( "Current request is not of type [" + parameterType.getName() + "]: " + request); } return nativeRequest; } else if (ServletResponse.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; Object nativeResponse = webRequest.getNativeResponse(parameterType); if (nativeResponse == null) { throw new IllegalStateException( "Current response is not of type [" + parameterType.getName() + "]: " + response); } return nativeResponse; } else if (HttpSession.class.isAssignableFrom(parameterType)) { return request.getSession(); } else if (Principal.class.isAssignableFrom(parameterType)) { return request.getUserPrincipal(); } else if (Locale.class.equals(parameterType)) { return RequestContextUtils.getLocale(request); } else if (InputStream.class.isAssignableFrom(parameterType)) { return request.getInputStream(); } else if (Reader.class.isAssignableFrom(parameterType)) { return request.getReader(); } else if (OutputStream.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getOutputStream(); } else if (Writer.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getWriter(); } return super.resolveStandardArgument(parameterType, webRequest); }