非Controller层通过RequestContextHolder.getRequestAttributes()获取HttpServletRequest,HttpServletRespon空指针问题

       有时我们需要在非Controller层如service层而不通过Controller层传参方式而获得HttpServletRequest,HttpServletResponse,通过查找到RequestContextHolder是Spring提供的可以获取HttpServletRequest的一个工具,于是我在工作中就自己封装了一个工具类如下:

public class ServletUtils {
    /**
     * 获取String参数
     */
    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    /**
     * 获取request
     */
    public static HttpServletRequest getRequest() {
        return getRequestAttributes().getRequest();
    }

    /**
     * 获取response
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }

    /**
     * 获取session
     */
    public static HttpSession getSession() {
        return getRequest().getSession();
    }

    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

}
编码时没问题,但是实际调用时RequestContextHolder.getRequestAttributes()空指针异常。
对RequestContextHolder源码分析,可参考博客 https://blog.csdn.net/u012706811/article/details/53432032

解决办法:

在web.xml配置RequestContextListener监听器:

<listener>
      <listener-class>
          org.springframework.web.context.request.RequestContextListener
      </listener-class>
</listener>

或者WebConfig.class中添加

/**
 * RequestContextListener监听器
 * @return
 */
@Bean
public RequestContextListener requestContextListenerBean() {
   return new RequestContextListener();
}

原理分析

RequestContextListener实现了ServletRequestListener ,在其覆盖的requestInitialized(ServletRequestEvent requestEvent)方法中,将request最终设置到了RequestContextHolder中.

public class RequestContextListener implements ServletRequestListener {
    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE = RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";

    public RequestContextListener() {
    }

    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException("Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        } else {
            HttpServletRequest request = (HttpServletRequest)requestEvent.getServletRequest();
            ServletRequestAttributes attributes = new ServletRequestAttributes(request);
            request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
            LocaleContextHolder.setLocale(request.getLocale());
            RequestContextHolder.setRequestAttributes(attributes);
        }
    }

配置RequestContextListener时大家可能会想到ContextLoaderListener

RequestContextListener与ContextLoaderListener区别:

ContextLoaderListener
ContextLoaderListener extends ContextLoader implements ServletContextListener。

ServletContextListener extends EventListener。 
ServletContextListener只负责监听Web容器的启动和关闭的事件。

ContextLoaderListener(或ContextLoaderServlet)将Web容器与spring容器进行整合。

这是使用Spring 必须配置 的:

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener> 

Spring配置文件的声明:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
</context-param>

如果没有显式声明,则 系统默认 在WEB-INF/applicationContext.xml。

在一个团队使用Spring的实际项目中,应该需要多个Spring的配置文件,如何使用和交叉引用的问题: 
如果想装入多个配置文件,可以用逗号作分隔符,如:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>applicationContext-database.xml,applicationContext.xml</param-value>
</context-param>

多个配置文件里的交叉引用可以用ref的external或bean解决,例如:

applicationContext.xml

<bean id="userService" class="domain.user.service.impl.UserServiceImpl"> 
    <property name="dbbean">
         <ref bean="dbBean"/>
    </property> 
</bean>
dbBean在applicationContext-database.xml中。

RequestContextListener
RequestContextListener implements ServletRequestListener

ServletRequestListener extends EventListener 
ServletRequestListener监听HTTP请求事件,Web服务器接收的每次请求都会通知该监听器。

RequestContextListener将Spring容器与Web容器结合的更加密切。这是可选配置,并且后者与scope=”request”搭配使用:

<listener>
  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
两者区别
ContextLoaderListener(或ContextLoaderServlet)将Web容器与spring容器整合。RequestContextListener将Spring容器与Web容器结合的更加密切。 
前者为必选配置,后者为可选配置,并且后者与scope=”request”搭配使用。

  • 9
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值