在自定义类文件中访问Java Web的HttpServletRequest / Response对象

时间:2012-02-19 13:19:53

标签: java java-ee servlets

我真的厌倦了这个问题,找不到最好的做法。让我用一个例子来解决这个问题:

我有一个静态方法,如:

public class AppError {
   public static void systemError(string errorMsg) { //Like "Can't connect to DB"
      HttpServletRequest request = ?????????? "HOW TO ACCESS?";
      request.setAttribute("Error", errorMsg);
      request.getRequestDispatcher("/error.jsp").forward(request, response(????????));
   }
}

正如你所看到的,我需要访问请求和响应对象,我不想通过参数传递HttpServletRequest / Response,因为这意味着将它传递给AppError.systemError调用的地方,那就是这么多地方:读/写文件,cookie和用户操作,数据库操作等......

我以为我找到了一个解决方案,ThreadLocal,我在Filter中使用它并保存了请求和响应对象,但是当我测试时,我通过ThreadLocal.remove()方法释放ThreadLocal变量的Filter.Destroy()方法不被调用它在调试模式下。这意味着该线程可能永远不会被释放。

ServletContextListerner也不是解决方案,因为我找不到访问ServletContext对象中的请求和响应对象的方法。我期待像ServletContext.getRequest()这样的方法,但没有。

我也使用JSF,但JSF的问题是在自定义classess中也无法访问FacesContext。此外,JSF的加载时间晚于侦听器,因此如果我使用FacesContext获取请求和响应对象,则无法在侦听器中使用我的错误系统。

那么这里的最佳做法是什么?我的意思是这是一个明显的问题,如果不解决这个问题我就无法继续前进。

顺便说一句,错误方法就是一个例子,我需要访问其他地方来访问请求和响应对象。

1 个答案:

答案 0 :(得分:4)

原则上,正确设置过滤器无法与线程本地存储(TLS)结合使用。

关键的见解不是清除Filter#Destroy()方法中的TLS,而是清除主过滤链之后的finally子句:

@WebFilter(filterName="requestTLSFilter")
public class RequestTLSFilter extends Filter {

    private static final ThreadLocal<ServletRequest> THREAD_LOCAL = new ThreadLocal<ServletRequest>();

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        try {
            THREAD_LOCAL.put(request);
            chain.doFilter(request, response);
        } finally {
            THREAD_LOCAL.remove();
        }
    }

    // Other methods    
}

关于JSF,FacesContext.getCurrentInstance()随处可见。 JSF没有隐含的知道谁调用它,但它只能在调用Facelets servlet后调用链中的代码。

还有另外一种选择。如果您的容器具有Java容器Java授权合同(JACC)支持,那么以下内容也会为您提供当前请求:

HttpServletRequest request = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest");