Struts的Token(令牌)机制能够很好的解决表单重复提交的问题,基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
具体使用方法如下:
1.先在一个Action中,调用saveToken(HttpServletRequest request)方法。然后转向带有表单的JSP页面。
2.在JSP页面提交表单给一个Action,再这个Action中进行是否为重复提交的判断。
1 if (isTokenValid(request, true)) { 2 3 // 未重复提交时,正确的时候应该做的事情 4 5 return mapping.findForward("success"); 6 7 } else { 8 9 // 重复提交时,需要做的事情 10 11 saveToken(request); 12 13 return mapping.findForward("error"); 14 15 }
Struts Token 机制原理:
1, 由第一个Action调用saveToken(HttpServletRequest request),这个方法内部实现如下:
protected void saveToken(HttpServletRequest request) { token.saveToken(request); } public synchronized void saveToken(HttpServletRequest request) { HttpSession session = request.getSession(); String token = generateToken(request); if (token != null) { session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token); } }
这个方法调用generateToken方法实现如下:
public synchronized void saveToken(HttpServletRequest request) { HttpSession session = request.getSession(); String token = generateToken(request); if (token != null) { session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token); } }
generateToken完毕后,将得到的唯一值setAttribute到session中。
session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);
Globals.TRANSACTION_TOKEN_KEY的值是:” org.apache.struts.action.TOKEN”
然后跳转到JSP页面。
2, JSP页面的Struts自定义标签 <html:form>的标签类:org.apache.struts.taglib.html. FormTag
这个类的doStartTag()方法会调用本类的renderToken()方法。
protected String renderToken() { StringBuffer results = new StringBuffer(); HttpSession session = pageContext.getSession(); if (session != null) { String token = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY); if (token != null) { results.append("<input type="hidden" name=""); results.append(Constants.TOKEN_KEY); results.append("" value=""); results.append(token); if (this.isXhtml()) { results.append("" />"); } else { results.append("">"); } } } return results.toString(); }
这样子会生成类似于
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"
value="6aa35341f25184fd996c4c918255c3ae">
的隐藏标签。
然后提交到一个Action中,在Action中用isTokenValid()方法进行比较session中” org.apache.struts.action.TOKEN”的这个key所对应的值和提交来的request中的” org.apache.struts.action.TOKEN”的这个value是否一致。
如果为true,那么证明可以提交。如果为false,证明已经重复,不允许提交。