Struts的Token(令牌)机制能够很好的解决表单重复提交的问题,基本原理是:
服务器端
在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会
产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的
令牌就和
服务器端的令牌不一致,从而有效地防止了重复提交的发生。
这时其实也就是两点,第一:你需要在请求中有这个令牌值,请求中的令牌值如何保存,其实就和我们平时在页面中保存一些信息是一样的,通过隐藏字段来保
存,保存的形式如: 〈input type="hidden"
name="org.apache.struts.taglib.html.TOKEN"
value="6aa35341f25184fd996c4c918255c3ae"〉,这个value是TokenProcessor类中的
generateToken()获得的,是根据当前用户的session
id和当前时间的long值来计算的。第二:在客户端提交后,我们要根据判断在请求中包含的值是否和服务器的令牌一致,因为服务器每次提交都会生成新的
Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致。下面就以在数据库中插入一条数据来说明如何防止重复提交。
首先:要在表单页的上一个控制页面,也就是说,如果想用表单提交时,要先利用sturts的转发机制,从一个action转到表单页,在这个转发
action中,要定义一个“令牌” 很简单,
saveToken(request);然后再由此ACTION转向到实际录入拥有FORM的页面,由此FORM页面再向下一个ACTION提交。(这时
会在表单页自动生成一个hidden 保存了一个和时间相关的计算值)
其次 : 在表单提交后的action中,进行一个判断 if(isTokenValid(reqeust)) 如果表单提交的串值与session中的相符那就完成动作,同时session清空此串值(restToken(request);)。此时如果后退再提交,就出错,同时再次改写saveToken返回目的页,如录入或者主页面。
1 . <html:link page="/tokenaction.do?token=insertUser">用户注册</html:link>
2.<action path="/tokenaction" type="com.token.action.PreInsert" parameter="token">
<forward name="regUser" path="/reguser.jsp"></forward>
</action>
3. public class PreInsert extends DispatchAction {
public ActionForward insertUser(ActionMapping mapping, ActionForm
form, HttpServletRequest request, HttpServletResponse response) throws
Exception {
this.saveToken(request);
return mapping.findForward("regUser");
}
}
4.<html:form action="/reguser">
5. <action attribute="regForm" input="/reguser.jsp" name="regForm"
path="/reguser" scope="request"
type="com.token.struts.action.RegAction" validate="false" >
<forward name="mutiSubmit" path="/reguser.jsp"></forward>
</action>
6. RegAction类excute方法内
ApplicationResources.properties :error.mutiSubmit=<script>alert("you shouldn't submit form twice !");</script>
ActionMessages errors=new ActionMessages();
if(!this.isTokenValid(request)){
errors.add("mutiSubmit",new ActionMessage("error.mutiSubmit"));
this.saveErrors(request, errors);
return mapping.findForward("mutiSubmit");
}else{
this.resetToken(request);
……..
}
验证 (application.properties)
命令 native2ascii –encoding gbk f:"1.txt f:"2.txt
username="u7528"u6237"u540d :
password="u5bc6"u7801 :
name.error=<script>alert(""u7528"u6237"u540d"u4e0d"u80fd"u4e3a"u7a7a!");</script>
name.length=<script>alert(""u7528"u6237"u540d"u957f"u5ea6"u5fc5"u987b"u662f6-12"u4f4d!");</script>
pwd.error=<script>alert(""u5bc6"u7801"u4e0d"u80fd"u4e3a"u7a7a!");</script>
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if(username==null||username.equals("")){
errors.add("user",new ActionMessage("name.error"));
return errors;
}
if(username.length()<6||username.length()>12){
errors.add("userlength", new ActionMessage("name.length"));
request.setAttribute("usercheck",username);
return errors;
}
if(password==null||password.equals("")){
errors.add("pass",new ActionMessage("pwd.error"));
return errors;
}
return errors;
}