这个标志可能大家不常用,不过本人认为它还是挺有用的。在使用Struts 1.x时,因为跳转通常是用Forward(而不是Redirect)实现的,所以当用户完成请求后,按“F5”刷新页面时,就会重新提交上次的请求,这样经常会出错。要解决这个问题,可以帮你忙。
实现原理
在页面加载时,产生一个GUID(Globally Unique Identifier,全局唯一标识符)值的隐藏输入框如:
<
input
type
="hidden"
name
="struts.token.name"
value
="struts.token"
/>
<
input
type
="hidden"
name
="struts.token"
value
="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"
/>
清单6 的HTML输出
同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个token就会不同。
具体实现:
1.当需要用标签的action不多时,可以用以下的方法实现:
首先看一下Action的代码:
package
com.bhr.ssh.json.action;
![](http://img.e-com-net.com/image/info8/03cce58157ec4e298ef2df7e7627d2b5.gif)
import
com.opensymphony.xwork2.ActionSupport;
![](http://img.e-com-net.com/image/info8/03cce58157ec4e298ef2df7e7627d2b5.gif)
![](http://img.e-com-net.com/image/info8/a84edfb418894590939dbb40ae12ae74.gif)
public
class
TokenAction
extends
ActionSupport
{
private static final long serialVersionUID = 6820659617470261780L;
private String message;
![](http://img.e-com-net.com/image/info8/76d93eee1109450d8b362bfd2f329ccc.gif)
public String getMessage()
{
return message;
}
![](http://img.e-com-net.com/image/info8/6fddf2ef3e1a4230afdb864ffde31a98.gif)
![](http://img.e-com-net.com/image/info8/76d93eee1109450d8b362bfd2f329ccc.gif)
public void setMessage(String message)
{
this.message = message;
}
@Override
![](http://img.e-com-net.com/image/info8/76d93eee1109450d8b362bfd2f329ccc.gif)
public String execute()
{
System.out.println("Executing action, your message is " + message);
return SUCCESS;
}
}
清单7 src/../TokenAction.java
以上代码一目了然,再看看JSP的写法:
%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%
@ taglib prefix
=
"
s
"
uri
=
"
/struts-tags
"
%>
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
>
<
title
>
Struts 2 Cool Tags -
<
s:token/
>
title
>
<
s:head
/>
head
>
<
body
>
<
h2
>
<
s:token/
>
h2
>
<
s:actionerror
/>
<
s:form
action
="Token"
>
<
s:textfield
name
="message"
label
="Message"
/>
<
s:token
/>
<
s:submit
/>
s:form
>
body
>
html
>
清单8 WebContent/token.jsp
JSP也很简单,就是加入标志。接下来是Actoin配置的XML片段:
xml version="1.0" encoding="UTF-8"
?>
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"
>
<
struts
>
<
package
name
="token"
extends
="struts-default"
>
<
action
name
="token"
class
="com.bhr.ssh.json.action.TokenAction"
>
<
interceptor-ref
name
="defaultStack"
/>
<
interceptor-ref
name
="token"
/>
<
result
name
="invalid.token"
>
/token.jsp
result
>
<
result
>
/token.jsp
result
>
action
>
<
action
name
="*"
>
<
result
>
/{1}.jsp
result
>
action
>
package
>
struts
>
清单9 src/struts.xml
以上XML片段值注意的是加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话token与请求token不一致时,将会直接返回“invalid.token”结果。
发布运行应用程序,在浏览器中键入:http://localhost:8080/ssh_leave/token.jsp,出现如下图所示页面:
![Struts2的标签及其自定义token拦截器的定义及配置_第1张图片](http://img.e-com-net.com/image/info8/ff76f33ed1734e308447c7563e60b676.gif)
清单10 正常显示的token.jsp页面
随便填点东西并提交页面,一切正常返回以上页面,然后按“F5”刷新页面,在弹出的对话框中点击“Retry”,出现如下图所示页面:
2.当需要用标签的action很多时
配置较多无疑非常麻烦,于是就写了个基于Annotation的TokenInterceptor,只要在需要避免重复提交的action方法前使用@Token注解,拦截器能自动拦截方法并做Token的检验。使用时除了把在action配置中重定义拦截器,改为注解,其他与原来的拦截器完全一致,包括注意你必须在调用action的token方法前使用获得自己的令牌。
首先看一下Action的代码:
package com.bhr.ssh.json.action; import com.bhr.ssh.json.token.annotations.Token; import com.opensymphony.xwork2.ActionSupport; /** * @author wangxijuan * */ public class TokenAction extends ActionSupport { /** * */ private static final long serialVersionUID = -6788146310542020372L; private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Token public String execute() { System.out.println("Executing action, your message is " + message); return SUCCESS; } }
JSP也很简单,跟上面一样,就是加入标志。接下来是Actoin配置的XML片段:
清单 src/leave-struts/token-default.xml
/jsonAjax/token.jsp /jsonAjax/token.jsp
清单 src/leave-struts/tokentest.xml
或者直接这样配置:
/jsonAjax/token.jsp /jsonAjax/token.jsp
清单 src/leave-struts/tokentest2.xml
清单 src/struts.xml
以上XML片段值注意的是加入了自定义的“token”拦截器的配置
发布运行应用程序,在浏览器中键入:http://localhost:8080/ssh_leave/token.jsp,出现如下图所示页面:
![Struts2的标签及其自定义token拦截器的定义及配置_第3张图片](http://img.e-com-net.com/image/info8/ff76f33ed1734e308447c7563e60b676.gif)
清单10 正常显示的token.jsp页面
随便填点东西并提交页面,一切正常返回以上页面,然后按“F5”刷新页面,在弹出的对话框中点击“Retry”,出现如下图所示页面:
![Struts2的标签及其自定义token拦截器的定义及配置_第4张图片](http://img.e-com-net.com/image/info8/5f3560e6ff644716a7bf5d1b8bcc8373.gif)