(六)struts之解决重复登录

平时网上注册大家都经历过,比如用户在注册成功之后,再打击后退按钮,退回到表单页再次提交表单,如果未处理重复提交这一细节上的要求,将会再次成功提交,数据库中有重复数据,在一个良好的程序中式不允许这么出现的。

 Struts的Token(令牌)机制能够很好的解决表单重复提交的问题。

 基本原理是:服务器在处理到达的请求之前,会将请求中包含令牌值与保存在当前会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在相应发送给客户端之前,将会产生一个新的令牌值,该令牌值除传给客户端以外,也会将用户会话中的令牌值进行替换,这样如果用户后退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效的防止了重复提交的发生

用户在使用时要注意一下两点:

第一、用户需要在请求中包含这个令牌值,请求中的令牌值如何保存,其实就和平时在页面中保存一些信息是一样的,通过隐藏域来保存,保存的形式如:<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae" >,这个value是TokenProcessor类中的generateToken()获得的,是根据当前用户的session id 和当前时间的long值计算的

第二、在客户端提交后,要判断在请求中包含的值是否和服务器的令牌一直,因为服务器每次提交都会生成新的Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致


示例

index.jsp


Java代码   收藏代码
  1. <span style="font-size: large;"><%@ page pageEncoding="UTF-8"%>  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  3. <html>  
  4.   <head>  
  5.     <title>Struts应用:利用Token防止重复提交</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     <h3>利用Token防止重复提交</h3><hr/>  
  10.     <a href="user.do?method=toAdd">添加用户</a>  
  11.   </body>  
  12. </html></span>  

 addUser.jsp


Java代码   收藏代码
  1. <span style="font-size: large;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5.   <head>  
  6.     <title>添加用户</title>  
  7.       
  8.     <meta http-equiv="pragma" content="no-cache">  
  9.     <meta http-equiv="cache-control" content="no-cache">  
  10.     <meta http-equiv="expires" content="0">      
  11.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  12.     <meta http-equiv="description" content="This is my page">  
  13.     <!--  
  14.     <link rel="stylesheet" type="text/css" href="styles.css">  
  15.     -->  
  16.   
  17.   </head>  
  18.     
  19.   <body>  
  20.     <h3>添加用户</h3>  
  21.     <html:form action="user.do?method=add" method="post">  
  22.         <table border="1" width="600px">  
  23.             <tr>  
  24.                 <td>登录名</td>  
  25.                 <td><input type="text" name="loginname"/></td>  
  26.             </tr>  
  27.             <tr>  
  28.                 <td>密码</td>  
  29.                 <td><input type="password" name="pwd"/></td>  
  30.             </tr>  
  31.             <tr>  
  32.                 <td colspan="2" align="center">  
  33.                     <input type="submit" value="提交"/>&nbsp;  
  34.                     <input type="reset" value="重置"/>  
  35.                 </td>  
  36.             </tr>  
  37.         </table>  
  38.     </html:form>  
  39.   </body>  
  40. </html>  
  41. </span>  

 login_success.jsp


Java代码   收藏代码
  1. <span style="font-size: large;"><%@ page pageEncoding="UTF-8"%>  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  3. <html>  
  4.   <head>  
  5.     <title>登录成功</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     <h3>登录成功</h3><hr/>  
  10.     <h2>欢迎:${param.loginname}登录!</h2>   
  11.   </body>  
  12. </html></span>  

 login_failure.jsp


Java代码   收藏代码
  1. <span style="font-size: large;"><%@ page pageEncoding="UTF-8"%>  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  3. <html>  
  4.   <head>  
  5.     <title>登录失败</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     <h3>登录失败</h3><hr/>  
  10.     <h2 style="color:red">可能的原因是:${errorMsg}</h2>   
  11.   </body>  
  12. </html></span>  

 LoginForm.java


Java代码   收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.web.formbean;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4.   
  5. import org.apache.struts.action.ActionErrors;  
  6. import org.apache.struts.action.ActionForm;  
  7. import org.apache.struts.action.ActionMapping;  
  8.   
  9. /** 
  10.  * 用来收集客户端提交数据. 
  11.  * 要收集数据的属性的名一定要跟请求参数名相同 
  12.  */  
  13. public class LoginForm extends ActionForm {  
  14.       
  15.     public ActionErrors validate(ActionMapping mapping,  
  16.             HttpServletRequest request) {  
  17.         return null;  
  18.     }  
  19.   
  20.     private static final long serialVersionUID = 6619272689058619128L;  
  21.   
  22.     private String loginname;  
  23.       
  24.     private String pwd;  
  25.   
  26.     public String getLoginname() {  
  27.         return loginname;  
  28.     }  
  29.   
  30.     public void setLoginname(String loginname) {  
  31.         this.loginname = loginname;  
  32.     }  
  33.   
  34.     public String getPwd() {  
  35.         return pwd;  
  36.     }  
  37.   
  38.     public void setPwd(String pwd) {  
  39.         this.pwd = pwd;  
  40.     }  
  41. }</span>  

 LoginAction.java


Java代码   收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.web.action;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import org.apache.struts.action.ActionForm;  
  7. import org.apache.struts.action.ActionForward;  
  8. import org.apache.struts.action.ActionMapping;  
  9. import org.apache.struts.actions.DispatchAction;  
  10.   
  11. /** 
  12.  * 业务控制器:控制业务处理的流程 
  13.  * 
  14.  */  
  15. public class LoginAction extends DispatchAction {  
  16.   
  17.     //具体业务流程处理方法,由Struts框架回调  
  18.     public ActionForward toAdd(ActionMapping mapping, ActionForm form,  
  19.             HttpServletRequest request, HttpServletResponse response)  
  20.             throws Exception {  
  21.         //产生Token值并存储到session中  
  22.         this.saveToken(request);  
  23.           
  24.         return mapping.findForward("toadd");  
  25.     }  
  26.       
  27.     public ActionForward add(ActionMapping mapping, ActionForm form,  
  28.             HttpServletRequest request, HttpServletResponse response)  
  29.             throws Exception {  
  30.           
  31.         if(this.isTokenValid(request)){  
  32.             this.saveToken(request);  
  33.             System.out.println("往数据库添加数据...");  
  34.               
  35.             return mapping.findForward("succ");  
  36.         }else{  
  37.               
  38.             System.out.println("请不要重复提交数据.....");  
  39.             return mapping.findForward("failure");  
  40.         }  
  41.           
  42.     }  
  43.       
  44. }</span>  

 WEB-INF/struts-config.xml


Java代码   收藏代码
  1. <span style="font-size: large;"><?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3. <!DOCTYPE struts-config PUBLIC  
  4.           "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"  
  5.           "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">  
  6.   
  7. <struts-config>  
  8.   
  9. <!-- ================================================ Form Bean Definitions  
  10. -->  
  11.     <form-beans>  
  12.         <form-bean name="loginForm" type="com.javacrazyer.web.formbean.LoginForm"/>  
  13.     </form-beans>  
  14.   
  15. <!-- =========================================== Action Mapping Definitions  
  16. -->  
  17.     <action-mappings>  
  18.         <action path="/user" name="loginForm" type="com.javacrazyer.web.action.LoginAction"  
  19.             parameter="method">  
  20.             <forward name="toadd" path="/adduser.jsp"/>  
  21.             <forward name="succ" path="/login_success.jsp"/>  
  22.             <forward name="failure" path="/login_failure.jsp"/>  
  23.         </action>  
  24.     </action-mappings>  
  25. </struts-config></span>  

 具体页面的流程为



 

 这时如果点击后退那个箭头,再提交的话那么就是重复提交了,控制台多出现一条‘请不要重复提交数据’的输出信息


解释下这个流程:

首先是点击添加用户,跳到登录页面,这个过程调用了LoginAction.java中的toadd方法,这个方法中正好有个

saveToken(request)方法,那么这就说明了要将这步请求的TOKEN值保存在会话中,这样跳到登陆页面的话,登录页面会多出一个隐藏表单类似于上面说的<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae" >,点击登录后那么就会出现将登录页面请求中包含的TOKEN值跟会话中的TOKEN值对比的情况,如果通过就提交成功。这样处理过后那么就会产生新的令牌值,会话中的令牌值也将改变,因此当点击最后页面的后退在提交时,页面的TOKEN值与会话中的已经不一样了,所以就避免了重复提交

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值