1.引入依賴guava
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
2.自定義註解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 作用到方法上
@Retention(RetentionPolicy.RUNTIME) // 運行時有效
public @interface NoRepeatSubmit {
}
3.緩存
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
@Configuration
public class UrlCache {
@Bean
public Cache<String, Integer> getCache() {
// 緩存有效期爲6秒
return CacheBuilder.newBuilder().expireAfterWrite(6L, TimeUnit.SECONDS).build();
}
}
4.定義AOP
注意:@Around非線程安全,需要synchronized 關鍵字
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import com.google.common.cache.Cache;
import com.xxx.xxx.util.Jackson2Util;
@Aspect
@Component
public class NoRepeatSubmitAop {
private static final Logger logger= LogManager.getLogger(NoRepeatSubmitAop.class);
@Autowired
private Cache<String, Integer> cache;
@Around("execution(* com.xxx.xxx..*Controller.*(..)) && @annotation(nrs)")
public synchronized Object around(ProceedingJoinPoint pjp, NoRepeatSubmit nrs) {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
String sessionId = RequestContextHolder.getRequestAttributes().getSessionId();
HttpServletRequest request = attributes.getRequest();
String key = sessionId + "-" + request.getServletPath();
// 如果緩存中有這個url視爲重複提交
if (cache.getIfPresent(key) == null) {
Object o = pjp.proceed();
cache.put(key, 1);
return o;
} else {
logger.info("重複提交");
ModelAndView mv = new ModelAndView();
mv.setView(Jackson2Util.jsonView());
mv.addObject("code", 1);
mv.addObject("msg", "請不要重複提交!");
return mv;
}
} catch (Throwable e) {
e.printStackTrace();
logger.error("驗證重複提交時出現未知異常!");
ModelAndView mv = new ModelAndView();
mv.setView(Jackson2Util.jsonView());
mv.addObject("code", 2);
mv.addObject("msg", "驗證重複提交內部錯誤!");
return mv;
}
}
}
4.Controller方法使用
@NoRepeatSubmit
@RequestMapping("uploadData")
public ModelAndView uploadData(UploadData data) throws Exception {
ModelAndView mv = new ModelAndView();
mv.setView(Jackson2Util.jsonView());
mv.addObject("code","0");
mv.addObject("msg","上傳成功");
return mv;
}