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 구현 인터페이스 자동 멱 등 입 니 다.도움 이 되 시 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.