写在前面
javax.servlet.ServletRequest和javax.servlet.ServletResponse都是Servlet容器中定义的接口,分别用于获取客户端请求信息和将响应消息发送给客户端。
有两种方法在Contoller方法中获取它们:
- 直接在
Controller方法参数中声明 - 通过工具类
org.springframework.web.context.request.RequestContextHolder获取
实际的对象实例类跟具体的Servlet容器有关:
- 如果Servlet容器为Tomcat,
javax.servlet.ServletRequest实现类为org.apache.catalina.connector.RequestFacade,javax.servlet.ServletResponse实现类为org.apache.catalina.connector.ResponseFacade - 如果Servlet容器为Undertow,
javax.servlet.ServletRequest实现类为io.undertow.servlet.spec.HttpServletRequestImpl,javax.servlet.ServletResponse实现类为io.undertow.servlet.spec.HttpServletResponseImpl
在Controller方法参数中声明
可以直接在Controller方法参数中声明javax.servlet.ServletRequest和javax.servlet.ServletResponse对象,如下示例:
@GetMapping("/hello")
public String request(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("req: " + req);
System.out.println("resp: " + resp);
return "Success";
}
之所以能直接在Controller方法参数中声明javax.servlet.ServletRequest和javax.servlet.ServletResponse对象,实际上是在org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues()方法中进行了解析处理,如下:
// org.springframework.web.method.support.InvocableHandlerMethod
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) { // 判断是否为支持解析的参数类型
try {
args[i] = this.argumentResolvers.resolveArgument( // 解析参数对象
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
最终通过org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver.resolveArgument()方法解析获取到具体对象。
通过RequestContextHolder工具类获取
在使用Spring Boot框架时,除了可以直接在Controller方法参数中声明javax.servlet.ServletRequest和javax.servlet.ServletResponse对象,还可以通过工具类org.springframework.web.context.request.RequestContextHolder获取,如下示例:
@GetMapping("/hello")
public String hello() {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes) {
ServletRequestAttributes httpRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest req = httpRequestAttributes.getRequest();
HttpServletResponse resp = httpRequestAttributes.getResponse();
System.out.println("req: " + req);
System.out.println("resp: " + resp);
}
return "Success";
}
之所以可以通过RequestContextHolder工具类获取javax.servlet.ServletRequest和javax.servlet.ServletResponse对象,是因为在org.springframework.web.servlet.FrameworkServlet.processRequest()方法中进行了注入。
// org.springframework.web.servlet.FrameworkServlet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 省略其他代码...
// 在工具类RequestContextHolder中注入ServletRequest和ServletResponse对象
initContextHolders(request, localeContext, requestAttributes);
// 省略其他代码...
}
【参考】
Spring——Web作用域:RequestContextListener
springboot 整合 ServletRequestListener监听器
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,在下面评论区告诉我^_^^_^