Struts的Token(令牌)机制能够很好的解决表单重复提交的问题.
基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
这时其实也就是两点,第一:你需要在请求中有这个令牌值,请求中的令牌值如何保存,其实就和我们平时在页面中保存一些信息是一样的,通过隐藏字段来保存,保存的形式如:
〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,
这个value是TokenProcessor类中的generateToken()获得的,是根据当前用户的session id和当前时间的long值来计算的。第二:在客户端提交后,我们要根据判断在请求中包含的值是否和服务器的令牌一致,因为服务器每次提交都会生成新的 Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致。
一、使用方法
1、 假如你要提交的页面为toSubmit.jsp;
2、 在打开toSubmit.jsp的Action1 中加入:saveToken(request),例如
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//生成同步令牌
saveToken(request);
return mapping.findForward("toSubmit");
}
3、 在提交toSubmit.jsp的Action2 中加入:isTokenValid(request, true),例如:
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// 验证同步令牌
if (isTokenValid(request, true)) {
//执行提交操作
}else {
// 重复提交
return mapping.findForward("Error");
}
}
4、 使用注意:toSubmit.jsp中的form必须使用 struts的标签<html:form>。
二、基本原理
第一步、在session中放入同步令牌
在Action1中加入了saveToken(request)的方法后,调用TokenProcessor 类的saveToken方法如下:
public synchronized void saveToken(HttpServletRequest request) {
HttpSession session = request.getSession();
String token = generateToken(request);
if (token != null) {
session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);
}
}
很明显在session中放入了同步令牌,名称为Globals.TRANSACTION_TOKEN_KEY。
第二步、在页面创建hidden元素
当应用服务器初始化toSubmit.jsp页面遇到标签<html:form>时,便会调用struts 的FormTag类,其中有一个方法:
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();
}
其意为:当检测到session中的Globals.TRANSACTION_TOKEN_KEY不为空时,在 toSubmit.jsp页面创建元素:
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="">
名称为:org.apache.struts.taglib.html.TOKEN就是 Constants.TOKEN_KEY;
值为:session中的Globals.TRANSACTION_TOKEN_KEY的值,即为同步令牌值。
第三步、验证同步令牌
在Action2中加入isTokenValid方法,实际上是调用TokenProcessor类的 isTokenValid方法如下:
public synchronized boolean isTokenValid(
HttpServletRequest request,
boolean reset) {
// Retrieve the current session for this request
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
// Retrieve the transaction token from this session, and
// reset it if requested
String saved = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
if (saved == null) {
return false;
}
if (reset) {
this.resetToken(request);
}
// Retrieve the transaction token included in this request
String token = request.getParameter(Constants.TOKEN_KEY);
if (token == null) {
return false;
}
return saved.equals(token);
}
它首先取得session中的令牌值,然后resetToken,再从页面hidden元素取来令牌值,进行比较,如果相等则为第一次,不等则为重复提交。
其中resetToken方法如下:
public synchronized void resetToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY);
}
Struts中防止刷新重复提交令牌的用法(防止刷新或防止重复提交数据库)
最新推荐文章于 2018-01-11 17:03:33 发布