原理:在新建页面中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}">