springmvc 用拦截器+token防止重复提交

一,原理:

1,在进入到提交页面时,使用拦截器拦截在进入此方法前,生成一个token,放到session中,

    @RequestMapping(value = "/{id}/details")
    @FormToken(produce = true)
    public Object details(@PathVariable String id, HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        GameInfo gameInfo;
        int count;
        try {
            gameInfo = gameInfoService.get(id, -1);
            // 使用此游戏的活动数
            count = activityService.getCountByGid(id);
            gameInfo.setCount(count);
        } catch (TException e) {
            LOGGER.debug("获取指定游戏详情失败!!", e);
            return new MessageEntity.Builder(request).msg("跳转预览页面失败").code(201).success(false)
                    .create();
        }
        map.put("gameInfo",gameInfo);
        return new MessageEntity.Builder(request).msg("success").code(201).content(map).success(true)
                .create();
    }

@FormToken此标签:

package com.caobug.client.annotation;

import java.lang.annotation.*;

/**
 * TOKEN生成与删除
 * Created by caobug on 14-8-15.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FormToken {

    /**
     * 是否在页面生成TOKEN
     *
     * @return
     */
    boolean produce() default false;

    /**
     * 是否删除旧 TOKEN
     *
     * @return
     */
    boolean remove() default false;
}

实现一个拦截器接口

package com.caobug.client.support.interceptor;

import com.caobug.client.annotation.FormToken;
import com.caobug.client.support.MessageCode;
import com.caobug.client.support.MessageEntity;
import com.caobug.client.support.utils.TokenUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 * Token 拦截器
 * <p/>
 * Created by caobug on 14-8-15.
 */
public class FormTokenInterceptor extends HandlerInterceptorAdapter {

    public final static String TOKEN_NAME = "resubmitToken";

    /**
     * 方法处理前处理
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        FormToken formToken = method.getAnnotation(FormToken.class);
        if (null != formToken) {
            if ((formToken.produce() && formToken.remove()) || (!formToken.produce() && !formToken.remove())) {
                throw new RuntimeException("请不要在同一个方法上同时注解:@FormToken(remove = true/false, produce = true/false)");
            } else if (formToken.produce()) {
                request.getSession().setAttribute(TOKEN_NAME, TokenUtils.getToken());
            } else if (formToken.remove()) {
                String serverToken = (String) request.getSession().getAttribute(TOKEN_NAME);
                String clientToken = request.getParameter(TOKEN_NAME);
                request.getSession().removeAttribute(TOKEN_NAME); // remove token
                if (!StringUtils.equals(serverToken, clientToken)) {
                    if (null != method.getAnnotation(ResponseBody.class)) { // JSON
                        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                        PrintWriter out = response.getWriter();
                        out.print(new ObjectMapper().writeValueAsString(new MessageEntity.Builder(null).
                                code(MessageCode.SEND_MULTIPLE).msg("无效请求,请刷新页面后重试").create()));
                        out.flush();
                        out.close();
                    } else { // 普通页面
                        request.getRequestDispatcher("/error/invalidRequest").forward(request, response);
                    }
                    return false;
                }
            }
        }
        return super.preHandle(request, response, handler);
    }
}

xml配置:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="interceptors">
            <list>
                <bean class="com.caobug.client.support.interceptor.FormTokenInterceptor"/>
            </list>
        </property>
    </bean>

2,在提交页面中接收到这个值:

<input type="hidden" name="token" value="${token}" />

3,提交处理;

@RequestMapping("/SaveDataController/saveData")
    @ResponseBody
    @FormToken(remove=true)
    public void saveData(HttpServletRequest request,HttpServletResponse response,
                         String tablename,String trowkey,String columns,
                         String indextablename,String irowkey,String icolumns,
                         String task_id,String savetype,String memoryCodes){
        System.out.println(task_id);
        saveDataService.saveData(task_id,savetype,memoryCodes,tablename, trowkey, columns, indextablename, irowkey, icolumns);
    }

4,第一次提交时,在还没进入到提交页面时,就在服务器端生成一个token(拦截器做出此动作),把此token传递给提交页面,点击“提交”按钮,进入到处理的method方法,拦截此方法,在拦截器中把session的值清空,对比两个token,

http://www.cnblogs.com/hdwpdx/archive/2016/03/29/5333943.html

时间: 2024-10-12 10:48:15

springmvc 用拦截器+token防止重复提交的相关文章

spring MVC 后台token防重复提交解决方案

看到公司有个部门提出了这个问题,补个粗略的解决方案... 1.编写拦截器 /** * Description: 防止重复提交 * * @Author liam * @Create Date: 2018/3/9 9:22 */ public class AvoidReSubmitIntercepter extends HandlerInterceptorAdapter { private static final String SPLIT_FLAG = "_"; private stat

springmvc的token防重复提交

一:首要创立一个号码大全token处置类  ,这儿的类名叫关键词挖掘工具  TokenHandler private static Logger logger = Logger.getLogger(TokenHandler.class); static Map springmvc_token http://www.3h5.cn = null; //生成一个仅有值的token @SuppressWarnings("unchecked") public synchronized stati

struts2中token防止重复提交表单

struts2中token防止重复提交表单 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 2015年7月12日 11:52:32 星期日 http://fanshuyao.iteye.com/ 第一步:在表单中加上<s:token></s:token>

SpringMVC:拦截器

SpringMVC:拦截器 2019-10-19 / Java / 狂神说位置: Home » Java » 本页 概述 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.开发者可以自己定义一些拦截器来实现特定的功能. 过滤器与拦截器的区别:拦截器是AOP思想的具体应用. 过滤器 servlet规范中的一部分,任何java web工程都可以使用 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截 拦截器 拦截器是

SpringMVC使用拦截器

拦截器也算得上是spring中的一大特色,即使没用过spring的拦截器至少也用过struts2的拦截器,拦截器大多数情况都是用来做权限的控制的,极少情况下用来初始化资源或释放资源.springmvc当然也可以直接使用拦截器,而且使用起来也特别简单. 一  springmvc的拦截器实现方式 springmvc实现拦截器主要有以下2种方式: 1 实现HandlerInterceptor接口 package com.sxt.interceptor; import javax.servlet.htt

springmvc中拦截器与springmvc全局异常处理器的问题

最近在做一个练手的小项目, 系统架构中用了springmvc的全局异常处理器, 做了系统的统一异常处理. 后来加入了springmvc的拦截器, 为了一些需求, 在拦截器中的 preHandle 方法 中抛出了系统自定义异常, 当时有有个疑惑, 就是抛出的这个异常全局异常处理器怎么处理的. 这里的全局异常处理器时通过实现HandlerExceptionResolver这个借口实现的 要指出的是 resolveException方法 中 handler中代表的是什么,我没遇到这个问题之前我认为这玩

springMVC之拦截器

有两种方法配置spring的拦截器 1. 实现接口: HandleInterceptor public class MyInterceptor1 implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj, Exception e) throws Exception { Syste

SpringMVC经典系列-14自定义SpringMVC的拦截器---【LinusZhu】

注意:此文章是个人原创,希望有转载需要的朋友们标明文章出处,如果各位朋友们觉得写的还好,就给个赞哈,你的鼓励是我创作的最大动力,LinusZhu在此表示十分感谢,当然文章中如有纰漏,请联系[email protected],敬请朋友们斧正,谢谢. 这部分主要讲解SpringMVC的拦截器的部分,会带着大家完成定义拦截器的两种方式的实例,不多说了,开始-- SpringMVC的拦截器主要是用于拦截用户的请求,并且进行相应的处理,如:权限验证.判断登录等. 定义拦截器的两种方式,如下: 1. 实现接

springMVC的拦截器工作流程

首先,springmvc的拦截器配置在这就不多说了.主要讲一下拦截器的三个方法的执行顺序. preHandle方法一定是最先执行的方法,如果它返回为false下面的方法均不执行. postHandle是在返回再次调用拦截器的方法. afterCompletion方法是最终执行的方法,可以看做finally,用于关闭一些一定要close的东西. 下面附上流程图