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

时间:2023-03-09 03:46:52
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