zoukankan      html  css  js  c++  java
  • 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,完成了。

    言之有物
  • 相关阅读:
    python使用openpyxl操作execl
    python 修改、读取图片元数据
    python 利用pyttsx3文字转语音(转)
    SQL学习——SELECT INTO和INSERT INTO SELECT
    iOS开发环境搭建 及 编写1个hello world
    xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
    头疼3-4次的问题,数据从DB导出到EXCEL,再从EXCEL导入到DB,数据格式发生错误 ,导致 程序出错。
    安卓自动打包持续集成
    jenkins实现master变化时,才触发构建(过滤分支)
    配置github的pull request触发jenkins自动构建
  • 原文地址:https://www.cnblogs.com/Pikzas/p/6008047.html
Copyright © 2011-2022 走看看