아이디어의 실현
봄 부팅 2.x를 기반으로
API를 표시하는 데 사용됩니다 사용자 정의 주석, 반복 요청 여부를 모니터링 할 필요가있다
스프링 AOP는 모니터링, 컨트롤러 계층에 의해 절단하는
토큰 + ServletPath + SHA1RequestParas : 검사를 반복 키를 요청
- 토큰 : 사용자가 로그인이 생성 토큰
- ServletPath : 경로 요청
- SHA1RequestParas : 요청 파라미터 사용되는 암호화 알고리즘을 SHA-1 해시
위의 세 가지 매개 변수를 사용하여 반복 요청 여부를 판사로 키 접합
사용 레디 스 저장 키, 그리고 레디 스의 특성, 키는 자동으로 지정된 시간 내에 삭제하도록 설정할 수 있습니다. 여기서 지정된 시간을 반복 할 수없는 API는 규정 된 시간 내에 제출된다.
사용자 정의 주석 ( 컨트롤러 API 층에 주석 연기 )
@Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) 공공 @의 인터페이스 NoRepeatSubmission { }
논리 섹션
SLF4J @ @Aspect @Component 공공 클래스 NoRepeatSubmissionAspect { @Autowired RedisTemplate <문자열, 문자열> redisTemplate; / ** *环绕通知 * @param PJP * @param ARS * @return * / @Around ( "실행 (공개 com.example.apirepeatrequest.controller * .. *. * (...)) && @annotation (ARS) " ) 공공 객체 doAround (ProceedingJoinPoint의 PJP, NoRepeatSubmission의 ARS) { ValueOperations <문자열, 문자열> opsForValue = redisTemplate.opsForValue (); 시도 { 경우 (ARS == null이 ) { 반환 ) (pjp.proceed을; } HttpServletRequest의 요청 = ((ServletRequestAttributes) Objects.requireNonNull (RequestContextHolder.getRequestAttributes ())) 대해 GetRequest ().; 문자열 토큰 = request.getHeader ( "토큰" ); 만약 (! checkToken) (토큰) { 반환 Result.failure를 ( "토큰无效" ); } 문자열은 servletPath = )를 request.getServletPath (; 문자열 jsonString는 = 이.getRequestParasJSONString (PJP); 문자열 SHA1 = 이 .generateSHA1 (jsonString); // 키 = 토큰 + 서블릿 경로 문자열 키 = 토큰 + "-"+ servletPath + "-"+ SHA1; log.info ( "\ n {\ n \ tServlet 경로 : {} \ n \ tToken : {} \ n \ tJson 문자열 : {} \ n \ tSHA-1 : {} \ n \ tResult 키 : {} \ n } " , servletPath, 토큰, jsonString, SHA1, 키); // 如果레디 스中有这个키则URL视为重复请求 경우 (opsForValue.get (키) == 널 ) { O 개체 = pjp.proceed (); opsForValue.set (키 한 String.valueOf ( 0), 3 , TimeUnit.SECONDS); 반환 O; } 다른 { 반환 Result.failure ( "마 반복하지 요청" ); } } 캐치 (Throwable의 E) { e.printStackTrace (); 반환 ( "알 수없는 인증 이상 반복 요청"Result.failure ); } } / ** * 취득 요구 파라미터 * @param PJP * @return * / 개인 문자열 getRequestParasJSONString (ProceedingJoinPoint PJP) { 문자열 [] parameterNames = ((MethodSignature) pjp.getSignature ())에 대해 getParameterNames을 (); ConcurrentHashMap의 <문자열, 문자열> 인수 = 널 ; 경우 (Objects.nonNull (parameterNames)) { 인수 = 새로운 ConcurrentHashMap의 <> (parameterNames.length); 위한 ( INT I ++; I <parameterNames.length I 0 = {) 문자열 값 = pjp.getArgs ()를 [I]! = null이 ? pjp.getArgs () [I]로 .toString () "널 (null)" ; args.put (parameterNames [I]의 값); } } 리턴 JacksonSerializer.toJSONString (인수)를; } }
코드 부분의 메인 로직은 요청에 관련된 정보를 획득하는 것, 그리고 키에 접합, 레디 스이, 존재하지 않는이고, 소정 시간은 자동 삭제 설정되면 추가 반복 요청의 존재 여부를 판정한다.