I.はじめに
間違い(連続2回のクリックが送信ボタン)接続速度のユーザー、ページカトンやその他の理由にはいくつかのケースでは、データの送信フォームデータベースの重複があるかもしれないより多くの重複データの原因よりも保持しています。
上記の問題は、フロントエンドに解決することができるためには、認証バックエンドがインターセプト処理に行くべきバイパスへのインテリジェントなフロントエンドユーザーがある場合はもちろん、以下の小さなシリーズは、に基づいて行われますどのくらい、判断できないもう一度[保存]ボタンをクリックSpringBoot 2.1.8.RELEASE
して、環境AOP切面
+ 自定义校验注解
+ Redis缓存
この問題を解決します。
二、春ブートチェックフォームの動作を繰り返します
1、pom.xml
必要な依存関係の導入
<!-- ================== 校验表单重复提交所需依赖 ===================== -->
<!-- AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
図2に示すように、application.yml
構成がRedisの導入され
spring:
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
timeout: 6000
# Redis服务器连接密码(默认为空)
# password:
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
3、カスタム注釈 @NoRepeatSubmit
// 作用到方法上
@Target(ElementType.METHOD)
// 运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
/**
* 默认时间3秒
*/
int time() default 3 * 1000;
}
4、AOPインターセプト処理
注:ここで記憶されているRedisのkey
個々のフレキシブルプレイによって値の特定のサービスを、ここでの例であり、
例:単一のユーザは、組み合わせた場合にログインできるtoken + url请求路径
ログイン複数のユーザが同時に、それと結合することができることができますip地址
@Slf4j
@Aspect
@Component
public class NoRepeatSubmitAop {
@Autowired
RedisUtil redisUtil;
/**
* <p> 【环绕通知】 用于拦截指定方法,判断用户表单保存操作是否属于重复提交 <p>
*
* 定义切入点表达式: execution(public * (…))
* 表达式解释: execution:主体 public:可省略 *:标识方法的任意返回值 任意包+类+方法(…) 任意参数
*
* com.zhengqing.demo.modules.*.api : 标识AOP所切服务的包名,即需要进行横切的业务类
* .*Controller : 标识类名,*即所有类
* .*(..) : 标识任何方法名,括号表示参数,两个点表示任何参数类型
*
* @param pjp:切入点对象
* @param noRepeatSubmit:自定义的注解对象
* @return: java.lang.Object
*/
@Around("execution(* com.zhengqing.demo.modules.*.api.*Controller.*(..)) && @annotation(noRepeatSubmit)")
public Object doAround(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) {
try {
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
// 拿到ip地址、请求路径、token
String ip = IpUtils.getIpAdrress(request);
String url = request.getRequestURL().toString();
String token = request.getHeader(Constants.REQUEST_HEADERS_TOKEN);
// 现在时间
long now = System.currentTimeMillis();
// 自定义key值方式
String key = "REQUEST_FORM_" + ip;
if (redisUtil.hasKey(key)) {
// 上次表单提交时间
long lastTime = Long.parseLong(redisUtil.get(key));
// 如果现在距离上次提交时间小于设置的默认时间 则 判断为重复提交 否则 正常提交 -> 进入业务处理
if ((now - lastTime) > noRepeatSubmit.time()) {
// 非重复提交操作 - 重新记录操作时间
redisUtil.set(key, String.valueOf(now));
// 进入处理业务
ApiResult result = (ApiResult) pjp.proceed();
return result;
} else {
return ApiResult.fail("请勿重复提交!");
}
} else {
// 这里是第一次操作
redisUtil.set(key, String.valueOf(now));
ApiResult result = (ApiResult) pjp.proceed();
return result;
}
} catch (Throwable e) {
log.error("校验表单重复提交时异常: {}", e.getMessage());
return ApiResult.fail("校验表单重复提交时异常!");
}
}
}
Redisのツールを使用しています5、
ソースコードのデモ与えられるようにあまりにも多くあるので、ここではそれに直接接続されていない、とケースの端を参照してください。
第三に、テスト
プラス法上のパリティカスタム注釈を検証する@NoRepeatSubmit
には
@RestController
public class IndexController extends BaseController {
@NoRepeatSubmit
@GetMapping(value = "/index", produces = "application/json;charset=utf-8")
public ApiResult index() {
return ApiResult.ok("Hello World ~ ");
}
}
ここでは繰り返しの訪問は、このindex
API要求は、シミュレートテストにフォームを提出します
最初の訪問http://127.0.0.1:8080/indexは
繰り返し、プロンプトをこの要求をリフレッシュ请勿重复提交!
IVの概要
アイデアの実現
- まず、
AOP切面
メソッドに入る前に拦截
、繰り返しに論理的な処理のフォームをチェックするために - 論理判定データ記憶ニーズ[例:キー格納ユーザ提出要求パスAPIの形態を、記憶された値は、コミット時]
Redis
key-value键值对
逻辑处理
:
適切ながに提出Redisのに最初のデータ
の最後の抽出時間は、現在、保存されたが、再び、判断を下すために作業時間に提出キャッシュからRedisのコミット
「決意の我々のセットの最後の作業時間から現在の動作時間あれば時間(3秒)を繰り返す提出「、直接注意書き、または他の処理を提出繰り返し返さ提出繰り返した
そう通常の提出、処理方法に入るトラフィックを...
サプリメント
厳密に準拠する場合、API Restful风格
、すなわち、@PostMapping
フォームの送信、注釈を提出し、繰り返しチェックするパスの必要性を判断する方法をカスタマイズすることはできません、注釈を取得する方法に反映させることにより、AOPセクションの後に直接リクエストパスをインターセプトそこにあれば@PostMapping
ある送信フォームのAPI、つまり検証プロセスは、存在する場合、他がない場合は@GetMapping
、@PutMapping
、@DeleteMapping
操作...