Token+Redis实现接口幂等性处理

9 篇文章 0 订阅

一、大致流程:
客户端先发送get请求到服务端获取服务端生成的一个token,同时服务端将这个token存入到redis中用于后续做判断。客户端每向服务端发送一个请求都要在请求头或请求地址栏携带这个token,如果是第一次请求,则服务端会从redis中将这个token删除,客户端如果再携带这个token来访问服务端,因为服务端已经将这个token从reids中删除了所以后续的这些请求都为重复请求。
二、具体实现

环境搭建:引入Web和Reids依赖,配置reids参数(host,port,password)
1.自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Idempontent {
}

2.创建控制类和方法,在指定方法上添加自定义注解

@RestController
public class HelloController {

    @Autowired
    TokenService tokenService;

    @PostMapping("/hello")
    @Idempontent
    public String helloPost() {
        return "hello post";
    }

    @GetMapping("/hello")
    public String helloGet() {
        return "hello get";
    }

    @GetMapping("/generate")
    public String generateToken() {
        return tokenService.generateToken();
    }
}

3.定义响应实体类

public class RespBean {
    private String msg;
    private Object data;
    private Integer status;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }
}

4.定义拦截器,获取控制类方法上有自定义注解的方法用于后续操作

@Component
public class IdempontentInterceptor implements HandlerInterceptor {

    @Autowired
    TokenService tokenService;

    /**
     * 在 Controller 中的方法执行之前会触发该方法
     * @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) {
            //这个实际上就是具体的接口方法
            HandlerMethod hm = (HandlerMethod) handler;
            //获取接口方法上的 Idempontent 注解
            Idempontent methodAnnotation = hm.getMethodAnnotation(Idempontent.class);
            if (methodAnnotation != null) {
                //说明这个接口需要进行幂等性处理
                boolean result = tokenService.checkToken(request);
                if (!result) {
                    RespBean respBean = new RespBean();
                    respBean.setStatus(500);
                    respBean.setMsg("请求重复");
                    response.setContentType("application/json;charset=utf-8");
                    response.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                    return false;
                }
            }
        }
        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 {

    }
}

5.配置拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    IdempontentInterceptor idempontentInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(idempontentInterceptor)
                .addPathPatterns("/**");
    }
}

6.在service中获取请求头或请求参数里的token,结合reids判断该token是否存在,如果存在则将其删除

@Service
public class TokenService {

    @Autowired
    RedisService redisService;

    public boolean checkToken(HttpServletRequest request) {
        //先从请求头中获取令牌
        String token = request.getHeader("token");
        //如果请求头中没有令牌,则从请求参数中获取令牌
        if (token == null || "".equals(token)) {
            token = request.getParameter("token");
            if (token == null || "".equals(token)) {
                //说明请求没有携带令牌
                return false;
            }
        }
        boolean exists = redisService.exists(token);
        if (exists) {
            //redis 中令牌存在
            boolean delResult = redisService.deleteToken(token);
            return delResult;
        }
        return false;
    }

    public String generateToken() {
        String s = UUID.randomUUID().toString();
        redisService.saveToken(s);
        return s;
    }
}
@Service
public class RedisService {

    @Autowired
    StringRedisTemplate redisTemplate;

    public boolean exists(String token) {
        return redisTemplate.hasKey(token);
    }

    public boolean deleteToken(String token) {
        if (exists(token)) {
            return redisTemplate.delete(token);
        }
        return false;
    }

    public void saveToken(String token) {
        redisTemplate.opsForValue().set(token, token);
    }
}

三、业务测试

1.get请求获取token

2.post第一次请求 

3.多次请求

以上就是Token+Redis实现接口幂等性处理的具体流程。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值