Token注解实现防止表单重复提交

Token注解防止表单的重复提交
注解的一些基础:

参见http://blog.csdn.net/duo2005duo/article/details/50505884和

http://blog.csdn.net/duo2005duo/article/details/50511476这两篇文章

1,自定义一个注解@Token 用来标记需要防止重复提交的方法

复制代码
 1 package com.bjca.framework.util;
 2 /**
 3  * <p>
 4 *关于这个方法的用法是:
 5 *在需要生成token的controller上增加@Token(save=true),
 6 *而在需要检查重复提交的controller上添加@Token(remove=true)就可以了
 7 *另外,你需要在view里在form里增加下面代码:
 8 *<input type="hidden" name="token" value="${token}">
 9  * 此时会在拦截器中验证是否重复提交
10  * </p>
11  *
12  */
13 import java.lang.annotation.*;
14 
15 @Target(ElementType.METHOD)
16 @Retention (RetentionPolicy.RUNTIME)
17 public @interface Token {
18  
19      boolean save() default false ;
20  
21      boolean remove() default false ;
22 }
复制代码
 

2,自定义一个针对该注解的拦截器 TokenInterceptor 

复制代码
 1 package com.bjca.framework.util;
 2 
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.springframework.web.method.HandlerMethod;
 6 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 7 
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 import java.lang.reflect.Method;
11 import java.util.UUID;
12 
13 public class TokenInterceptor extends HandlerInterceptorAdapter {
14     public static Log log = LogFactory.getLog(TokenInterceptor.class);
15      @Override
16      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
17           System.out.println(handler.getClass());
18          if (handler instanceof HandlerMethod) {
19              HandlerMethod handlerMethod = (HandlerMethod) handler;
20              Method method = handlerMethod.getMethod();
21              Token annotation = method.getAnnotation(Token. class );
22            
23              if (annotation != null ) {
24                  boolean needSaveSession = annotation.save();
25                  if (needSaveSession) {
26                      String uuid=UUID.randomUUID().toString();
27                         log.debug("提交生成除令牌"+uuid);
28                      request.getSession( false ).setAttribute( "token" , uuid);
29                  }
30                  boolean needRemoveSession = annotation.remove();
31                  if (needRemoveSession) {
32                      if (isRepeatSubmit(request)) {
33                          return false ;
34                      }
35                      log.debug("提交移除令牌"+request.getSession().getAttribute("token" ));
36                      request.getSession( false ).removeAttribute( "token" );
37                  }
38              }
39              return true ;
40          } else {
41              return super .preHandle(request, response, handler);
42          }
43      }
44  
45      private boolean isRepeatSubmit(HttpServletRequest request) {
46          String serverToken = (String) request.getSession( false ).getAttribute( "token" );
47          if (serverToken == null ) {
48              return true ;
49          }
50          String clinetToken = request.getParameter( "token" );
51          if (clinetToken == null ) {
52              return true ;
53          }
54          if (!serverToken.equals(clinetToken)) {
55              return true ;
56          }
57          return false ;
58      }
59 }
复制代码
3,在spring MVC的配置文件里注册该拦截器

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:mvc="http://www.springframework.org/schema/mvc" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:p="http://www.springframework.org/schema/p" 
 6     xmlns:context="http://www.springframework.org/schema/context"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
 9         http://www.springframework.org/schema/context 
10         http://www.springframework.org/schema/context/spring-context-4.0.xsd 
11         http://www.springframework.org/schema/mvc 
12         http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
13     >
14     <!-- 对spring org.lxh包下所有注解扫描 -->
15     <context:component-scan base-package="com.xxx">
16         <context:exclude-filter type="annotation"  expression="org.springframework.stereotype.Repository" />
17     </context:component-scan>
20     <!-- 支持spring mvc新的注解类型 详细spring3.0手册 15.12.1 mvc:annotation-driven-->
21     <mvc:annotation-driven />
22     
23     <bean  id="viewResolver"
24             class="org.springframework.web.servlet.view.InternalResourceViewResolver">
25             <!-- 为了使用JSTL Tag修改默认的viewClass属性 -->
26             <property
27                   name="viewClass"
28                   value="org.springframework.web.servlet.view.JstlView" />
29             <property
30                   name="prefix"
31                   value="/WEB-INF/views/" />
32             <property
33                   name="suffix"
34                   value=".jsp"></property>
35             <property
36                   name="order"
37                   value="1"></property>
38         </bean>
39    <!-- 拦截器 -->
40     <mvc:interceptors>
41        <!-- 用户登录拦截 -->
42         <bean class="com.xx.xxx.filter.StageSecurityInterceptor">
43             <property name="patterns" >
44                 <list>
45                     <value>.*/console/.*\.jhtml</value>
46                     <value>.*/center/.*\.jhtml</value>
47                   
48                 </list>
49             </property>
50             <property name="loginView">
51                 <value>/manage.jsp</value>
52             </property>
53         </bean>
54          <!-- 配置Token拦截器,防止用户重复提交数据 -->
55         <mvc:interceptor>
56             <mvc:mapping path="/**"/>
57             <bean class="com.xxx.framework.util.TokenInterceptor"/>
58         </mvc:interceptor>
59     </mvc:interceptors>
60     <!--  
61      <bean id="viewResolver"
62           class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
63         <property name="basenames">
64             <list>
65                 <value>views-stage</value>
66             </list>
67         </property>
68     </bean>
69     -->
70 </beans>
复制代码
 4,演示demo

4.1,在跳转至某个需要加上@Token(save = true)

复制代码
1     @RequestMapping("/personalForm.jhtml")
2   @Token(save = true)
3     public String personalForm(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
4         Account account = Account.sessionAccount();
5         if (account == null) {
6             return "redirect:/login.jsp";
7         }
8       //..........业务..............
9   }    
复制代码
 

 4.2,在上个Controller 跳转的方法上加入${Token} 

复制代码
 1 <div class="main clearfix nav center regist copyright_main5">
 2         <h3 class="registTitle">填写身份信息</h3>
 3         <img alt="" src="<c:url value='/platform/stage/image/regist/wave.png'/>"><br /> <img src="<c:url value='/platform/stage/image/portals/regist-info.png'/>"></img>
 4         <c:if test="${personalInfoForm.checkState eq 2}">
 5         <br/>
 6         <div>
 7         <font color="red" size="2"><span>身份认证意见:${personalInfoForm.checkOpnion}</span></font>
 8         </div>
 9         </c:if>
10         <form autocomplete="off" style="margin: 0;" id="form1" method="post" name="personalInfoForm" action="<c:url value='/center/member/savePersonalInfo.jhtml'/>" enctype="multipart/form-data">
11             <input type="hidden" value="${personalInfoForm.id}" name="id" />
12             <input type="hidden" name="token" value="${token}">             
复制代码
 4.3,在表单提交方法的地方加上注解 @Token(remove = true)

复制代码
 1 @RequestMapping(value = "/savePersonalInfo.jhtml", method = {RequestMethod.POST})
 2     @Token(remove = true)
 3     public String savePersonalInfo(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, PersonalInfo personalInfoForm) throws Exception {
 4         DateFormat fm = new SimpleDateFormat("yyyy-MM-dd");
 5         Date birthday = fm.parse(request.getParameter("birthday2"));
 6         personalInfoForm.setBirthday(birthday);
 7       
 8         Account account = Account.sessionAccount();
 9         if(account==null){
10             return "redirect:/login.jsp";
11         }
12     //.....................业务.........................
13 }    
复制代码
 5,完成了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值