背景:我需要创建一个过滤器,旨在捕获servlet第一次被击中时的http响应。发布后续的servlet命中,我需要发回我之前捕获的相同的http响应。为此,我将servlet响应保存在文本文件中,并在第二次访问servlet时将其作为响应的一部分发送。
现在,在我的应用程序中,每个屏幕都由2个servlet绘制。第一个servlet(我正在保存http响应)发送回基本模板以及一些动态xml数据和xsl名称。在加载第一个servlet的DHTML响应期间,调用第二个servlet来获取XSL。作为安全性的一部分,在第一次servlet命中时,xsl名称作为session属性的一部分添加,在调用第二个servlet来获取xsl时进行验证。
现在,问题是当我在过滤器中捕获第一个servlet的http响应并在后续命中的一部分重新发送时,会话属性在第二个servlet中变为null。 (问题1:为什么?)
现在,考虑到解决方法,当我在文本文件中保存http响应时,我在concurrenthashmap中添加会话属性。当第二次触发servlet时,我明确设置会话属性并从文本文件发送响应。现在,再次,在第二次servlet命中期间,这些属性将变为null。为了检查更多,我尝试在dofilter方法中打印concurrenthashmap。我观察到的是会话属性的值在后续的servlet命中时变为null。 (问题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() {
}
}
答案 0 :(得分:1)
确定找到了问题。
对于问题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());
}