struts2 防止重复提交 与 进入等待画面
演示重復提交的錯誤:
相關文件:
struts.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="strutsqs" extends="struts-default"><action name="Login" class="com.gq.LoginAction"><result name="error">/error.jsp</result><result name="success">/success.jsp</result></action></package> </struts>login.jsp <%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><base href="<%=basePath%>"><title>My JSP 'login.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--></head><body><form action="Login.action" method="post"><table width="207" border="1" height="82"> <tbody><tr> <td>?UserName:</td> <td>?<input type="text" name="username"></td></tr> <tr> <td>?Password:</td> <td>?<input type="password" name="password"></td></tr> <tr> <td>?<input type="submit" value="Login"></td> <td>?<input type="reset" value="Reset" name="reset"></td></tr> </tbody></table></form></body> </html>LoginAction.java public class LoginAction {private String username;private String password;public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@SuppressWarnings("unchecked")public String execute() throws Exception{// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){ActionContext.getContext().getSession().put(key, value);}//消耗時間,提供重復提交的機會void consumeTimeForToken(){int result = 0;for( int i = 0 ; i<30000000 ; i++ ){result += (int)i/551.22;result /= 3.1458;}System.out.println("result=" + result);}// Just used for unit test!String findCompanyByName( ){Map<String, String> records = new HashMap<String, String>();records.put("gqltt", "SNJP");records.put("Liyanhong", "baidu");records.put("Bill", "Microsoft");return records.get( getUsername() );} }提交頁面:輸出結果:
解決辦法:
1、在提交頁面的 form 中添加 <s:token/>
2、在Struts2 的配置文件中啟用 TokenInterceptor攔截器或 TokenSessionStoreInterceptor攔截器
注意:
1、必須配置默認的攔截器(basicStack),否則取不到數據,拋出 NullPointerException
2、必須指定重復提交后的錯誤頁面(invalid.token)
優點:可以防止客戶重復提交,大大地降低了服務器的負荷。
缺點:對用戶來說,可能會很不方便,一不小心點擊了提交按鈕,進入到了invalid.token頁面,就再也回不去了,上述的操作就再也看不見了。(的確很惡心,即使倒退回登錄頁面,再次正常登錄,還是會進入 invalid.token 頁面!除非關掉網頁再打開。)
參考:http://chengyue2007.iteye.com/category/73492?show_full=true
等待畫面:
struts.xml 添加配置:
<action name="LongLived" class="com.gq.LongLivedAction"><interceptor-ref name="completeStack"/> <interceptor-ref name="execAndWait"/> <result name="wait">/wait.jsp</result> <result name="error">/error.jsp</result><result name="success">/success.jsp</result> </action>LongLiveAction.java public class LongLivedAction {private String username;private String password;public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@SuppressWarnings("unchecked")public String execute() throws Exception{addToSessionScope("user", getUsername());// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){//addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){Map session = ActionContext.getContext().getSession();if( session == null ){System.out.println("Error: session is null...");return ;}session.put(key, value);//ActionContext.getContext().getSession().put(key, value);}//消耗時間void consumeTimeForToken(){try {Thread.sleep( 4*1000 );} catch (InterruptedException e) {// do nothing...}System.out.println("After 4 seconds...");} }wait.jsp注意:不要忘了加入?<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ page language="java" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><base href="<%=basePath%>"><title>Please Wait</title><meta http-equiv="refresh" content="3;url=<s:url includeParams='all'/> "/> </head><body>Please Wait...</body> </html>缺點:將參數寫在 URL 中,明文化了(密碼都看得到了!!!)
問題:取不到 session,Map session = ActionContext.getContext().getSession(); 操作一直返回 Null。為什么?
參考:http://webservices.ctocio.com.cn/java/470/9189470.shtml
下面是另一種,等待畫面的配置,可以解決 session 為 Null 的問題:
struts.xml 添加配置:
<action name="Wait" class="com.gq.WaitAction"> <interceptor-ref name="defaultStack"/><interceptor-ref name="execAndWait"> <param name="excludeMethods">input</param> <!-- 等待時間,執行時間沒有超過此值,將不顯示等待畫面 (毫秒) <param name="delay">1000</param>--> <!-- 間隔檢查時間,檢查后臺進程有沒有執行完畢,如果完成了它就立刻返回,不用等到等待,用戶不會看到等待畫面 <param name="delaySleepInterval">50</param>--> </interceptor-ref> <result name="wait">/wait.jsp</result> <result name="error">/error.jsp</result><result name="success">/success.jsp</result></action>WaitAction.java
public class WaitAction extends ActionSupport implements SessionAware {private static final long serialVersionUID = -5724238080200557097L;private Map session;public void setSession(Map session) {this.session = session;}public Map getSession(){return session;}private String username;private String password;public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@SuppressWarnings("unchecked")public String execute() throws Exception{System.out.println("In Wait.action");addToSessionScope("user", getUsername());// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){//addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){getSession().put(key, value);}//消耗時間void consumeTimeForToken(){try {Thread.sleep( 4*1000 );} catch (InterruptedException e) {// do nothing...}System.out.println("After 4 seconds...");} } 注意:Action 要實現 SessionAware接口(驗證過——這樣的添加屬性到 session 是OK 的!)因為這個action將會以單獨的線程執行,所以你不能用ActionContext,因為它是ThreadLocal.這也就是說如果你要訪問session數據,你必須實現 SessionAware結構而不是調用ActionContext.getSesion() 。
wait.jsp(帶刷新失敗時候的超鏈接)
<%@page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="s"uri="/struts-tags"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta http-equiv="refresh" content="1;url=<s:url includeParams="none" />"/> <title> </title> </head> <body> <h1>數據處理中,請稍等......</h1> 如果沒有自動跳轉請<a href="<s:url includeParams="all" />">點這里</a>. </body> </html>其中的includeParams參數取值為:none,不把參數加入到url參數中?
all,是把get和post中的參數加入到url參數中
get,是只把get中的參數加入到url參數中?
總結
以上是生活随笔為你收集整理的struts2 防止重复提交 与 进入等待画面的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java并发编程实战~Balking模式
- 下一篇: Java消息服务~JMSReplyTo示