过滤器中的会话属性为空

Session attributes coming as null in filter

背景:我需要创建一个过滤器,旨在在第一次点击时捕获 servlet 的 http 响应。 Post 在随后的 servlet 命中时,我需要发回我之前捕获的相同的 http 响应。为此,我将 servlet 响应保存在文本文件中,并在第二次访问 servlet 时将其作为响应的一部分发送。

现在,在我的应用程序中,每个屏幕都由 2 个 servlet 绘制。第一个 servlet(我正在为其保存 http 响应)发回基本模板以及一些动态 xml 数据和 xsl 名称。在加载第一个 servlet 的 DHTML 响应期间,调用第二个 servlet 来获取 XSL。作为安全的一部分,在第一次 servlet 命中期间,xsl 名称被添加为会话属性的一部分,当调用第二个 servlet 以获取 xsl 时验证该属性。

现在,问题是当我在过滤器中捕获第一个 servlet 的 http 响应并将其作为后续命中的一部分重新发送时,会话属性在第二个 servlet 中变为 null。 (问题 1:为什么?)

现在,考虑解决方法,当我在文本文件中保存 http 响应时,我在并发哈希图中添加了会话属性。当第二次调用 servlet 时,我明确设置会话属性并从文本文件发送响应。现在,在第二次 servlet 命中期间,这些属性再次变为空。为了检查更多,我尝试在 dofilter 方法中打印 concurrenthashmap。我观察到会话属性的值在随后的 servlet 命中时变为空。 (问题 2:为什么?)

public class ServletResponseMocker implements Filter {

    private ServletContext context;
    private ConcurrentHashMap<String,String> hmURI_FileNameMap=new ConcurrentHashMap<String, String>();
    private ConcurrentHashMap<String,List<String>> hmURI_SessionAttrLMap=new ConcurrentHashMap<String, List<String>>();

    private String rootPath;

    public void init(FilterConfig fConfig) throws ServletException {
        this.context = fConfig.getServletContext();         
        rootPath=System.getProperty("WAR_ROOT_PATH");
    }

    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    String uri = req.getRequestURI();
    boolean bToBeProcessed = false;

    if (uri.startsWith("some/pattern"))
        bToBeProcessed = true;

    if (bToBeProcessed) {

        res.setCharacterEncoding(System.getProperty("CHARSETTYPE"));
        OutputStream out = res.getOutputStream();
        byte responseContent[] = null;
        String filename = null;
        if (hmURI_FileNameMap.containsKey(uri)) {
            filename = hmURI_FileNameMap.get(uri);

            responseContent = Utils.readBytesFromFile(rootPath + "\somefolder\"
                    + filename);
            res.setContentType("text/html;charset=UTF-8");
            res.setContentLength(responseContent.length);
            HttpSession session = req.getSession(false);
            if (session != null) {

                if (hmURI_SessionAttrLMap.get(uri) != null)
                    session.setAttribute("ClientXSL",
                            hmURI_SessionAttrLMap.get(uri));

            }

            res.setHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
        } else {

            filename = uri.substring(uri.lastIndexOf("/") + 1) + ".vdb";
            hmURI_FileNameMap.put(uri, filename);

            ResponseWrapper wrapper = new ResponseWrapper(res);

            chain.doFilter(request, wrapper);
            HttpSession session = req.getSession(false);
            // This session attribute is set by some filter in chain and is
            // always not null here.
            List<String> clientXSLList = (List) session
                    .getAttribute("ClientXSL");
            if (clientXSLList != null) {

                hmURI_SessionAttrLMap.put(uri, clientXSLList);
            }

            responseContent = wrapper.getData();
            /*Writing data to text file*/

        }
        out.write(responseContent);
        out.flush();
        out.close();
    } else {

        // To identify the 2nd servlet of the screen which is same for all
        // screens
        if(uri.startsWith("/someother/pattern/com.second.servlet.fetchXSL")){

        HttpSession session = req.getSession(false);
        if (session != null) {
            // Below session attributes always comes as not null during
            // fisrst time screen loading. However, comes as null when
            // static response is sent for subsequent servlet hit.
            List<String> clientXSLList = (List) session
                    .getAttribute("ClientXSL");
            if (clientXSLList != null)
                this.context.log("Getting clientXSL list from session:"
                        + Arrays.toString(clientXSLList.toArray()));
        }
    }
    chain.doFilter(request, response);
}

    public void destroy() {
    }


}

好的,找到问题了。

对于问题 1:我忽略了第二个 servlet 中的代码。每当它被击中时,它都会清除会话属性。因此,当我第二次捕获第一个 servlet 的 http 响应时,会话属性已经为空。因此,它们在第二个 servlet 中为 null。

对于问题 2:问题出在我的过滤器代码中。

List<String> clientXSLList = (List) session
                    .getAttribute("ClientXSL");
            if (clientXSLList != null) {

                hmURI_SessionAttrLMap.put(uri, clientXSLList);
            }

会话属性已添加到作为会话的一部分添加的列表中。然后当我复制会话属性时,我没有克隆它。因此,同样得到清除。为了解决这个问题,现在我正在创建克隆,然后将其添加到我的 concurrenthashmap 中,如下所示。

ArrayList<String> clientXSLList = (ArrayList<String>) session
                    .getAttribute("ClientXSL");
            if (clientXSLList != null) {

                hmURI_SessionAttrLMap.put(uri, clientXSLList.clone());
            }