原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过。
1.新建注解:
04 | * 在新建页面方法上,设置needSaveToken()为true,此时拦截器会在Session中保存一个token, |
06 | * <input type="hidden" name="token" value="${token}"> |
08 | * 保存方法需要验证重复提交的,设置needRemoveToken为true |
12 | * @date: 2013-6-27上午11:14:02 |
15 | @Target (ElementType.METHOD) |
16 | @Retention (RetentionPolicy.RUNTIME) |
17 | public @interface AvoidDuplicateSubmission { |
18 | boolean needSaveToken() default false ; |
19 | boolean needRemoveToken() default false ; |
2. 新建拦截器
07 | * @date: 2013-6-27上午11:19:05 |
09 | public class AvoidDuplicateSubmissionInterceptor extends HandlerInterceptorAdapter { |
10 | private static final Logger LOG = Logger.getLogger(AvoidDuplicateSubmissionInterceptor. class ); |
13 | public boolean preHandle(HttpServletRequest request, |
14 | HttpServletResponse response, Object handler) throws Exception { |
16 | User user = UserUtil.getUser(); |
18 | HandlerMethod handlerMethod = (HandlerMethod) handler; |
19 | Method method = handlerMethod.getMethod(); |
21 | AvoidDuplicateSubmission annotation = method.getAnnotation(AvoidDuplicateSubmission. class ); |
22 | if (annotation != null ) { |
23 | boolean needSaveSession = annotation.needSaveToken(); |
24 | if (needSaveSession) { |
25 | request.getSession( false ).setAttribute( "token" , TokenProcessor.getInstance().generateToken()); |
28 | boolean needRemoveSession = annotation.needRemoveToken(); |
29 | if (needRemoveSession) { |
30 | if (isRepeatSubmit(request)) { |
31 | LOG.warn( "please don't repeat submit,[user:" + user.getUsername() + ",url:" |
32 | + request.getServletPath() + "]" ); |
35 | request.getSession( false ).removeAttribute( "token" ); |
42 | private boolean isRepeatSubmit(HttpServletRequest request) { |
43 | String serverToken = (String) request.getSession( false ).getAttribute( "token" ); |
44 | if (serverToken == null ) { |
47 | String clinetToken = request.getParameter( "token" ); |
48 | if (clinetToken == null ) { |
51 | if (!serverToken.equals(clinetToken)) { |
3. 在Spring中配置
1 | < bean class = "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" > |
2 | < property name = "interceptors" > |
4 | < bean class = "com.sohu.tv.crm.aop.UserLogInterceptor" /> |
5 | < bean class = "com.sohu.tv.crm.aop.AvoidDuplicateSubmissionInterceptor" /> |
4. 在相关方法中加入注解:
1 | @RequestMapping ( "/save" ) |
2 | @AvoidDuplicateSubmission (needRemoveToken = true ) |
3 | public synchronized ModelAndView save(ExecutionUnit unit, HttpServletRequest request, HttpServletResponse response) |
6 | @RequestMapping ( "/edit" ) |
7 | @AvoidDuplicateSubmission (needSaveToken = true ) |
8 | public ModelAndView edit(Integer id, HttpServletRequest request) throws Exception { |
5.在新建页面中加入
<input type="hidden" name="token" value="${token}">