首页 > 代码库 > springmvc 用拦截器+token防止重复提交

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

一,原理:

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

    @RequestMapping(value = "http://www.mamicode.com/{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="http://www.mamicode.com/${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

 

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