SpringBootは重複要求を防止し、重複フォームは超簡単な注釈実装の4(究極版)を提出する.
2018.11.30更新
前言:前の文章にはだめだと言っている子供靴がありますが、どうして繰り返し提出を防ぐことができませんか.
まず説明したいのは、以前の重複コミット防止とは、1回のリクエストが完了する前に重複コミットを防止することです.もちろん、拡張ではセッション間で重複コミットを防止することができます.また、ある期間に拡張したり、重複コミットを永久に防止したりすることができます(これは実現しません).次に、同じセッションを拡張して重複コミットを防止するのは簡単です
前編の上でDuplicateAspectはSESSIONと表記されたtokenを外さずに済む!
1.DuplicateSubmitToken.java属性typeを追加し、デフォルトでは1回の要求が完了するまで繰り返しコミットを防止する
2.DuplicateSubmitAspect.javaメソッドdoAfterReturingは、セッション終了時または失効時にSESSIONタグが自動的に削除されるため、REQUESTが削除された場合に重複コミットを防止すると判断します.
3.セッションとしてマークされた重複コミットの防止
4.これを行うと、データの重複挿入の問題が発生する可能性があります.
フィールドに一意のインデックスを作成することによって、データが重複して挿入されないようにしたり、メソッドにロック(同期)をかけたりすることができます.
5.データ挿入時チェック
たとえば、idフィールドを繰り返さないsqlを挿入します.
6.クリックダウンロード:ソースダウンロードアドレス
前言:前の文章にはだめだと言っている子供靴がありますが、どうして繰り返し提出を防ぐことができませんか.
まず説明したいのは、以前の重複コミット防止とは、1回のリクエストが完了する前に重複コミットを防止することです.もちろん、拡張ではセッション間で重複コミットを防止することができます.また、ある期間に拡張したり、重複コミットを永久に防止したりすることができます(これは実現しません).次に、同じセッションを拡張して重複コミットを防止するのは簡単です
前編の上でDuplicateAspectはSESSIONと表記されたtokenを外さずに済む!
1.DuplicateSubmitToken.java属性typeを追加し、デフォルトでは1回の要求が完了するまで繰り返しコミットを防止する
/**
* @description
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DuplicateSubmitToken {
/** */
public static final int REQUEST=1;
/** */
public static final int SESSION=2;
/** */
boolean save() default true;
/** , : */
int type() default REQUEST;
}
2.DuplicateSubmitAspect.javaメソッドdoAfterReturingは、セッション終了時または失効時にSESSIONタグが自動的に削除されるため、REQUESTが削除された場合に重複コミットを防止すると判断します.
/**
* @description
*/
@Aspect
@Component
@Slf4j
public class DuplicateSubmitAspect {
public static final String DUPLICATE_TOKEN_KEY="duplicate_token_key";
@Pointcut("execution(public * cn.test.controller..*(..))")
public void webLog() {
}
@Before("webLog() && @annotation(token)")
public void before(final JoinPoint joinPoint, DuplicateSubmitToken token){
if (token!=null){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession=token.save();
if (isSaveSession){
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null==t){
String uuid= UUID.randomUUID().toString();
request.getSession().setAttribute(key.toString(),uuid);
log.info("token-key="+key);
log.info("token-value="+uuid.toString());
}else {
throw new DuplicateSubmitException(TextConstants.REQUEST_REPEAT);
}
}
}
}
/**
* key
* @param joinPoint
* @return
*/
public String getDuplicateTokenKey(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
StringBuilder key=new StringBuilder(DUPLICATE_TOKEN_KEY);
key.append(",").append(methodName);
return key.toString();
}
@AfterReturning("webLog() && @annotation(token)")
public void doAfterReturning(JoinPoint joinPoint,DuplicateSubmitToken token) {
// ,
log.info(" :");
if (token!=null){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession=token.save();
if (isSaveSession){
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null!=t&&token.type()==DuplicateSubmitToken.REQUEST){
request.getSession(false).removeAttribute(key);
}
}
}
}
/**
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "webLog()&& @annotation(token)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e, DuplicateSubmitToken token) {
if (null!=token
&& e instanceof DuplicateSubmitException==false){
//
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession=token.save();
//
if (isSaveSession){
String key=getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null!=t){
//
request.getSession(false).removeAttribute(key);
log.info(" -- !");
}
}
}
}
}
3.セッションとしてマークされた重複コミットの防止
/**
* @description
*/
@RestController
public class TestController {
@DuplicateSubmitToken(type = DuplicateSubmitToken.SESSION)
@RequestMapping(value = "/test/d", method = RequestMethod.GET)
public Map test (HttpServletRequest request){
Random r=new Random();
int i = r.nextInt(3);
if (i==2){
throw new CustomException(" ");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map map = new HashMap<>();
request.getSession().setAttribute("request Url", request.getRequestURL());
map.put("request Url", request.getRequestURL());
return map;
}
}
4.これを行うと、データの重複挿入の問題が発生する可能性があります.
フィールドに一意のインデックスを作成することによって、データが重複して挿入されないようにしたり、メソッドにロック(同期)をかけたりすることができます.
5.データ挿入時チェック
たとえば、idフィールドを繰り返さないsqlを挿入します.
insert into tbl(id,name,ctime)
select 1000," ",now() FROM DUAL WHERE NOT EXISTS(SELECT 1 FROM tbl WHERE id=1000)
6.クリックダウンロード:ソースダウンロードアドレス
:
, :)