采用Annotation和Interceptor方式提供切面拦截,这个技术一直在用,仅是记录一下。注意此种方法只适用于页面支持刷新提交的流程,如果是打开静态页添加数据进行多次提交的,需要扩展处理token问题。
首先提供一个自定义的注释 AvoidDuplicateSubmission。注释提供两个方法:needSaveToken() 和 needRemoveToken()。 从字面就可以知道,在进入时增加token,提交后删除token
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 避免重复提交Annotation
* 提交页面或者表单进入时增加 needSaveToken=true,表单提交后增加 needRemoveToken=true
* @author Paris
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidDuplicateSubmission {
boolean needSaveToken() default false;
boolean needRemoveToken() default false;
}
第二步增加拦截器AvoidDuplicateSubmissionInterceptor
类成员tokenKey有个默认值token,可以通过spring bean属性注入的方式根据实际情况改动。
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.chinesedreamer.stocks.common.annotation.AvoidDuplicateSubmission;
import com.chinesedreamer.stocks.common.generator.TokenProcessor;
/**
* 避免重复提交拦截器
*
* @author Paris
*
*/
public class AvoidDuplicateSubmissionInterceptor extends HandlerInterceptorAdapter {
private String tokenKey = "token";
public String getTokenKey() {
return tokenKey;
}
public void setTokenKey(String tokenKey) {
this.tokenKey = tokenKey;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
AvoidDuplicateSubmission annotation = method.getAnnotation(AvoidDuplicateSubmission.class);
if (null != annotation) {
boolean needSaveToken = annotation.needSaveToken();
if (needSaveToken) {
request.getSession(false).setAttribute(this.tokenKey,
TokenProcessor.getInstance().generateToken(request));
}
boolean needRemoveToken = annotation.needRemoveToken();
if (needRemoveToken) {
if (needRemoveToken) {
if (isRepeatSubmit(request)) {
return false;
}
request.getSession(false).removeAttribute(this.tokenKey);
}
}
}
return true;
}
private boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession(false).getAttribute(this.tokenKey);
if (null == serverToken) {
return true;
}
String clientToken = request.getParameter(this.tokenKey);
if (null == clientToken) {
return true;
}
if (!serverToken.equals(clientToken)) {
return true;
}
return false;
}
}
这里用到里一个token的生成器
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* token生成器
* @author Paris
*
*/
public class TokenProcessor {
private static TokenProcessor instance = new TokenProcessor();
public static TokenProcessor getInstance() {
return instance;
}
protected TokenProcessor() {
super();
}
public String generateToken(HttpServletRequest request) {
HttpSession session = request.getSession();
try {
byte id[] = session.getId().getBytes();
byte now[] = new Long(System.currentTimeMillis()).toString().getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(id);
md.update(now);
return this.toHex(md.digest());
} catch (IllegalStateException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
}
}
public String toHex(byte buffer[]) {
StringBuffer sb = new StringBuffer();
String s = null;
for (int i = 0; i < buffer.length; i++) {
s = Integer.toHexString((int) buffer[i] & 0xff);
if (s.length() < 2) {
sb.append('0');
}
sb.append(s);
}
return sb.toString();
}
}
根据tokenKey保持前后台一致即可以完成拦截操作