Springboot+redis+Interceptor+사용자 정의 annotation 인터페이스 자동 멱 등 실현

선언:
 실제 개발 프로젝트 에서 대외 적 으로 노출 된 인 터 페 이 스 는 여러 번 의 요구 에 직면 하 게 된다.우 리 는 멱 등의 개념 을 설명 한다.임 의적 으로 여러 번 집행 하면 발생 하 는 영향 은 모두 한 번 의 집행 의 영향 과 같다.이 의미 에 따 르 면 최종 의 미 는 데이터 베이스 에 미 치 는 영향 은 일회 성 일 뿐 중복 처리 할 수 없다 는 것 이다.어떻게 그 멱 등 성 을 보증 합 니까?보통 다음 과 같은 수단 이 있 습 니 다.
1:데이터 베 이 스 는 유일한 색인 을 만 들 고 최종 적 으로 데이터 베 이 스 를 삽입 하 는 데 한 가지 데이터 만 있 음 을 보증 할 수 있 습 니 다.
2:token 메커니즘,인터페이스 요청 전에 token 을 가 져 온 다음 요청 할 때 요청 한 header 에 이 token 을 추가 하여 배경 에서 검증 합 니 다.만약 검증 이 token 을 삭제 하면 다음 요청 은 token 을 다시 판단 합 니 다.
3:비관 적 잠 금 또는 낙관적 잠 금,비관 적 잠 금 은 매번 for update 일 때 다른 sql 에서 데 이 터 를 업데이트 할 수 없 음 을 보증 합 니 다(데이터베이스 엔진 이 innodb 일 때 select 의 조건 은 유일한 색인 이 어야 합 니 다.전체 표 잠 금 을 방지 합 니 다)
4:먼저 조회 한 후에 데이터 베 이 스 를 통 해 데이터 가 존재 하 는 지 여 부 를 판단 합 니 다.만약 에 증명 이 요청 되 었 다 면 이 요 구 를 직접 거절 하고 존재 하지 않 으 면 처음으로 들 어 왔 다 는 것 을 증명 하고 바로 통과 시 킵 니 다.
redis 자동 멱 등 을 실현 하 는 원리 도:

목차
하나:redis 서비스 구축 Api
1:우선 redis 서버 를 구축 하 는 것 입 니 다.이것 은 전에 설치 한 것 이 니 긴 말 하지 않 겠 습 니 다.상세 한 상황 은 참고 할 수 있다.
2:springboot 에 있 는 redis 의 stater 를 도입 하거나 Spring 에 포 장 된 jedis 를 도입 하 셔 도 됩 니 다.그 다음 에 주로 사용 하 는 api 는 set 방법 과 exists 방법 입 니 다.여 기 는 springboot 의 포 장 된 redis Template 를 사용 합 니 다.

/**
 * redis   
 */
@Component
public class RedisService {
  @Autowired
  private RedisTemplate redisTemplate;
  /**
   *     
   * @param key
   * @param value
   * @return
   */
  public boolean set(final String key, Object value) {
    boolean result = false;
    try {
      ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
      operations.set(key, value);
      result = true;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return result;
  }
  /**
   *           
   * @param key
   * @param value
   * @return
   */
  public boolean setEx(final String key, Object value, Long expireTime) {
    boolean result = false;
    try {
      ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
      operations.set(key, value);
      redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
      result = true;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return result;
  }
  /**
   *            value
   * @param key
   * @return
   */
  public boolean exists(final String key) {
    return redisTemplate.hasKey(key);
  }
  /**
   *     
   * @param key
   * @return
   */
  public Object get(final String key) {
    Object result = null;
    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
    result = operations.get(key);
    return result;
  }
  /**
   *      value
   * @param key
   */
  public boolean remove(final String key) {
    if (exists(key)) {
      Boolean delete = redisTemplate.delete(key);
      return delete;
    }
    return false;
  }
}
2.사용자 정의 주석 AutoIdempotent
주 해 를 사용자 정의 합 니 다.이 주 해 를 정의 하 는 주요 목적 은 멱 등 을 실현 해 야 하 는 방법 에 추가 하 는 것 입 니 다.어떤 방법 으로 주 해 를 하면 자동 멱 등 을 실현 합 니 다.배경 에서 반 사 를 이용 하여 이 주 해 를 스 캔 하면 이 방법 을 처리 하여 자동 멱 등 을 실현 합 니 다.원 주해 Element Type.METHOD 를 사용 하여 방법 에 만 놓 을 수 있 음 을 표시 합 니 다.etentionPolicy.RUNTIME 은 실행 중 임 을 표시 합 니 다.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoIdempotent {
 
}
3.token 생 성 및 검사
1:token 서비스 인터페이스
우 리 는 새로운 인 터 페 이 스 를 만 들 고 token 서 비 스 를 만 듭 니 다.그 안 에는 주로 두 가지 방법 이 있 습 니 다.하 나 는 token 을 만 들 고 하 나 는 token 을 검증 하 는 데 사 용 됩 니 다.token 을 만 드 는 것 은 주로 문자열 입 니 다.token 을 검사 하면 주로 request 대상 을 전달 합 니 다.왜 request 대상 을 전달 합 니까?주요 역할 은 header 에 있 는 token 을 가 져 온 다음 에 검 사 를 한 다음 에 던 진 Exception 을 통 해 구체 적 인 오류 정 보 를 얻 고 전단 으로 돌아 가 는 것 입 니 다.

public interface TokenService {

  /**
   *   token
   * @return
   */
  public String createToken();

  /**
   *   token
   * @param request
   * @return
   */
  public boolean checkToken(HttpServletRequest request) throws Exception;

}
2:token 의 서비스 실현 클래스
token 은 redis 서 비 스 를 참조 하여 token 을 만 들 고 랜 덤 알고리즘 도구 류 로 랜 덤 uid 문자열 을 만 든 다음 redis 에 넣 습 니 다.성공 하면 이 token 값 을 되 돌려 줍 니 다.checkToken 방법 은 header 에서 token 을 값 으로 가 져 오 는 것 입 니 다.(header 에서 가 져 오지 못 하면 paramter 에서 가 져 옵 니 다)존재 하지 않 으 면 이상 을 던 집 니 다.이 이상 정 보 는 차단기 에 포착 되 어 전단 으로 되 돌아 갈 수 있다.

@Service
public class TokenServiceImpl implements TokenService {

  @Autowired
  private RedisService redisService;


  /**
   *   token
   *
   * @return
   */
  @Override
  public String createToken() {
    String str = RandomUtil.randomUUID();
    StrBuilder token = new StrBuilder();
    try {
      token.append(Constant.Redis.TOKEN_PREFIX).append(str);
      redisService.setEx(token.toString(), token.toString(),1000L);
      boolean notEmpty = StrUtil.isNotEmpty(token.toString());
      if (notEmpty) {
        return token.toString();
      }
    }catch (Exception ex){
      ex.printStackTrace();
    }
    return null;
  }


  /**
   *   token
   *
   * @param request
   * @return
   */
  @Override
  public boolean checkToken(HttpServletRequest request) throws Exception {

    String token = request.getHeader(Constant.TOKEN_NAME);
    if (StrUtil.isBlank(token)) {// header    token
      token = request.getParameter(Constant.TOKEN_NAME);
      if (StrUtil.isBlank(token)) {// parameter     token
        throw new ServiceException(Constant.ResponseCode.ILLEGAL_ARGUMENT, 100);
      }
    }

    if (!redisService.exists(token)) {
      throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);
    }

    boolean remove = redisService.remove(token);
    if (!remove) {
      throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);
    }
    return true;
  }
}
4:차단기 설정
1:웹 설정 클래스,WebMvcConfigurerAdapter 를 실현 합 니 다.주요 역할 은 autoIdempotent Interceptor 를 설정 클래스 에 추가 하 는 것 입 니 다.그러면 차단 기 에 가 야 효력 이 발생 합 니 다.@Configuration 주 해 를 사용 하 십시오.용기 가 시 작 될 때 context 에 추가 할 수 있 습 니 다.

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

  @Resource
  private AutoIdempotentInterceptor autoIdempotentInterceptor;

  /**
   *      
   * @param registry
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(autoIdempotentInterceptor);
    super.addInterceptors(registry);
  }
}
2:차단 프로세서:주 된 기능 은 AutoIdempotent 를 주 해 된 방법 으로 스 캔 한 다음 tokenService 의 checkToken()방법 으로 token 이 정확 한 지 확인 하 는 것 입 니 다.이상 이 포착 되면 이상 정 보 를 json 으로 렌 더 링 하여 전단 으로 되 돌려 줍 니 다.

/**
 *    
 */
@Component
public class AutoIdempotentInterceptor implements HandlerInterceptor {

  @Autowired
  private TokenService tokenService;

  /**
   *    
   *
   * @param request
   * @param response
   * @param handler
   * @return
   * @throws Exception
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    if (!(handler instanceof HandlerMethod)) {
      return true;
    }
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    // ApiIdempotment     
    AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class);
    if (methodAnnotation != null) {
      try {
        return tokenService.checkToken(request);//      ,        ,          ,                
      }catch (Exception ex){
        ResultVo failedResult = ResultVo.getFailedResult(101, ex.getMessage());
        writeReturnJson(response, JSONUtil.toJsonStr(failedResult));
        throw ex;
      }
    }    //    true,          
    return true;
  }


  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

  }

  /**
   *    json 
   * @param response
   * @param json
   * @throws Exception
   */
  private void writeReturnJson(HttpServletResponse response, String json) throws Exception{
    PrintWriter writer = null;
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html; charset=utf-8");
    try {
      writer = response.getWriter();
      writer.print(json);

    } catch (IOException e) {
    } finally {
      if (writer != null)
        writer.close();
    }
  }

}
테스트 용례
1:아 날로 그 업무 요청 클래스
우선,우 리 는/get/token 경 로 를 통 해 getToken()방법 을 통 해 구체 적 인 token 을 얻 은 다음 에 testIdempotence 방법 을 호출 해 야 합 니 다.이 방법 에@AutoIdempotent 를 주 해 했 습 니 다.차단 기 는 모든 요청 을 차단 합 니 다.처리 방법 에 주석 이 있 는 것 으로 판단 되면 TokenService 의 checkToken()방법 을 호출 합 니 다.이상 이 잡 히 면 호출 자 를 던 집 니 다.다음은 요청 을 모 의 해 보 겠 습 니 다.

@RestController
public class BusinessController {


  @Resource
  private TokenService tokenService;

  @Resource
  private TestService testService;


  @PostMapping("/get/token")
  public String getToken(){
    String token = tokenService.createToken();
    if (StrUtil.isNotEmpty(token)) {
      ResultVo resultVo = new ResultVo();
      resultVo.setCode(Constant.code_success);
      resultVo.setMessage(Constant.SUCCESS);
      resultVo.setData(token);
      return JSONUtil.toJsonStr(resultVo);
    }
    return StrUtil.EMPTY;
  }


  @AutoIdempotent
  @PostMapping("/test/Idempotence")
  public String testIdempotence() {
    String businessResult = testService.testIdempotence();
    if (StrUtil.isNotEmpty(businessResult)) {
      ResultVo successResult = ResultVo.getSuccessResult(businessResult);
      return JSONUtil.toJsonStr(successResult);
    }
    return StrUtil.EMPTY;
  }
}
2:postman 요청 사용
먼저 get/token 경 로 를 방문 하여 token 으로 가 져 옵 니 다.

token 을 가 져 온 다음 에 구체 적 인 요청 을 header 에 넣 으 면 첫 번 째 요청 이 성공 한 것 을 볼 수 있 습 니 다.이어서 두 번 째 요청 을 할 수 있 습 니 다.

두 번 째 요청 은 반복 적 인 작업 으로 되 돌아 가 는 것 을 볼 수 있 습 니 다.반복 적 인 검증 이 통 과 된 것 을 알 수 있 습 니 다.다시 여러 번 요청 하면 우 리 는 첫 번 째 성공 만 하고 두 번 째 는 실패 입 니 다.

총화
이 블 로 그 는 springboot 과 차단기,redis 를 사용 하여 인터페이스 멱 등 을 우아 하 게 실현 하 는 것 이 실제 개발 과정 에서 매우 중요 하 다 고 소개 했다.하나의 인터페이스 가 수많은 클 라 이언 트 에 의 해 호출 될 수 있 기 때문에 배경 업무 처리 에 영향 을 주지 않 고 데이터 에 한 번 만 영향 을 미 치 는 것 을 어떻게 보장 하 느 냐 가 매우 중요 하 다.그것 은 더러 운 데이터 가 발생 하거나 데이터 가 흐 트 러 지 는 것 을 방지 할 수 있 고,병발 량 을 줄 일 수 있어 서 매우 유익 한 일이 다.전통 적 인 방법 은 매번 데 이 터 를 판단 하 는데 이런 방법 은 지능 화 와 자동화 가 부족 하고 비교적 번거롭다.오늘날 의 이런 자동화 처리 도 프로그램의 신축성 을 높 일 수 있다.
위 에서 말 한 것 은 소 편 이 소개 한 Springboot+redis+Interceptor+사용자 정의 annotation 구현 인터페이스 자동 멱 등 입 니 다.도움 이 되 시 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기