在任何地方访问HttpServletRequest

时间:2012-12-19 15:35:04

标签: java spring hibernate open-session-in-view

我以前在基于Cookie的JSF 2应用程序的对话过滤器中有一个Open Session。现在我想建立相同的机制,但技术无关。重用一些代码,我在一个扩展OncePerRequestFilter的类中写了这个:

@Override
protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    UUID conversationId = lookupConversationOrCreateIfNecessary(request,
            response);

    log.debug("Binding conversation '{}' to request '{}'", conversationId,
            request);
    bindConversation(conversationId, request);

    try {
        filterChain.doFilter(request, response);
    } finally {
        log.debug("Unbinding conversation '{}' from request '{}'",
                conversationId, request);
        unbindConversation(conversationId, request);
    }

}

现在,当我到达bindConversation(conversationId, request)时,我只需添加一个请求属性,该属性指向映射到Hibernate Session的conversationId。

无论如何,在JSF中,我可以使用FacesContext.getCurrentInstance().getExternalContext().getRequest()访问当前请求,并使用此实现CurrentSessionContext。但是在普通的servlet中,如何以编程方式访问当前请求?

注意:我一直在阅读OncePerRequestFilter javadocs,我发现了这个:

  

从Servlet 3.0开始,可以调用过滤器作为REQUEST或的一部分   ASYNC调度发生在单独的线程中。过滤器可以   在web.xml中配置是否应该参与异步   调度。但是,在某些情况下,servlet容器会有所不同   默认配置。因此子类可以覆盖该方法   如果他们[sic] shouuld,则shouldNotFilterAsyncDispatch()静态声明   确实可以在两种类型的调度期间调用一次   提供线程初始化,日志记录,安全性等。这个   机制补充并不代替配置的需要   在带有调度程序类型的web.xml中进行过滤。

那么,使用ThreadLocal来实现我想要的东西会是危险的吗?

1 个答案:

答案 0 :(得分:1)

正如您在问题中提到的:使用ThreadLocal似乎是一个不错的选择。一旦您将过滤器用于REQUEST和ASYNC,我就不明白为什么它会不安全。

修改

@Override
protected void doFilterInternal(HttpServletRequest request,
                                HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {


    UUID conversationId = lookupConversationOrCreateIfNecessary(request,
            response);

    log.debug("Binding conversation '{}' to request '{}'", conversationId,
            request);

    ConversationHolder.setId(conversationId);

    bindConversation(conversationId, request);

    try {
        filterChain.doFilter(request, response);
    } finally {
        log.debug("Unbinding conversation '{}' from request '{}'",
                conversationId, request);
        ConversationHolder.clear();
        unbindConversation(conversationId, request);
    }

}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    return false; //to be sure both REQUEST and ASYNC are filtered
}

和ConversationHolder

public class ConversationHolder extends ThreadLocal<UUID>{

    private static ConversationHolder INSTANCE = new ConversationHolder();

    public static void setId(UUID conversationId){
          INSTANCE.set(conversationId);
    }

    public static UUID getId(){
        return INSTANCE.get();
    }

    public static void clear(){
        INSTANCE.remove();
    }

}

由于conversationId是一个局部变量,因此不会在请求之间共享。

由于ConversationHolder是ThreadLocal,因此在doFilter(...)期间从中获取的值将是正确的。 (除非您在请求处理期间手动创建新线程,但它不是推荐的设计)