原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过
好的,下面来讲一下如何在Spring MVC里面解决此问题(其它框架也一样,逻辑一样,思想一样,和具体框架没什么关系)。要解决重复提交,有很多办法,比如说在提交完成后redirect一下,也可以用本文提到的使用token的方法(我不使用redirect是因为那样解决不了ajax提交数据或者移动应用提交数据,另一个原因是现在比较通行的方法是使用token,像python里的django框架也是使用token来解决)。
使用token的逻辑是,给所有的url加一个拦截器,在拦截器里面用java的UUID生成一个随机的UUID并把这个UUID放到session里面,然后在浏览器做数据提交的时候将此UUID提交到服务器。服务器在接收到此UUID后,检查一下该UUID是否已经被提交,如果已经被提交,则不让逻辑继续执行下去…
1.新建注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
boolean save() default false;
boolean remove() default false;
}
2. 新建拦截器
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
if(handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Token annotation = method.getAnnotation(Token.class);
if(annotation != null) {
boolean needSaveSession = annotation.save();
if(needSaveSession) {
request.getSession(false).setAttribute("token", UUID.randomUUID().toString());
}
boolean needRemoveSession = annotation.remove();
if(needRemoveSession) {
if(isRepeatSubmit(request)) {
return false;
}
request.getSession(false).removeAttribute("token");
}
}
return true;
}else{
return super.preHandle(request, response, handler);
}
}
private boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession(false).getAttribute("token");
if(serverToken == null) {
return true;
}
String clinetToken = request.getParameter("token");
if(clinetToken == null) {
return true;
}
if(!serverToken.equals(clinetToken)) {
return true;
}
return false;
}
}
3.在Spring MVC的配置文件里加入
<!-- **************repeat submit token************** -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path = "/**"/>
<bean class = "com.lei.demo.common.TokenInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- ************************************************ -->
4. 在相关方法中加入注解:
@Token(save=true)
@RequestMapping(value="/add",method=RequestMethod.GET)
public ModelAndView getAdd(){
ModelAndView mv = new ModelAndView();
mv.setViewName("user/add");
return mv;
}
@Token(remove=true)
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(@ModelAttribute("user") User user){
userService.create(user);
return "redirect:/user/list";
}
5.在新建页面中加入
<input type="hidden" name="token" value="${token}">