springboot 实现接口幂等

简介: 幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。接口就是用户对同一操作发起了一次或多次请求的对数据的影响是一致不变的。简单理解:就是针对一个操作,不管做多少次,产生的效果都是一样的,常见于表单的重复提交

1、什么是接口幂等性?


幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。


接口就是用户对同一操作发起了一次或多次请求的对数据的影响是一致不变的。


简单理解:就是针对一个操作,不管做多少次,产生的效果都是一样的,常见于表单的重复提交



2、怎么解决这个问题?


使用token机制,在用户提交表单的时候,顺带提交一个从后台获取的token值,当后台第一次处理结束后,删除该token值,那么下次再过来请求的时候,会提示该token失效,继而避免重复操作。



3、具体实现


1、 首先定义一个注解


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

2、然后定义一个拦截器,用于拦截校验


package cn.couldme.study.web.security.interceptor;
import cn.couldme.study.web.common.exception.BizException;
import cn.couldme.study.web.security.annotation.ApiIdempotent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
 * 接口幂等性拦截器
 * @Author: szwei
 * @Date: 2020-03-31 15:12
 **/
public class ApiIdempotentInterceptor implements HandlerInterceptor {
    @Autowired
    private TokenService tokenService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws BizException {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class);
        if (methodAnnotation != null) {
            check(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
        }
        return true;
    }
    private void check(HttpServletRequest request) throws BizException {
        tokenService.checkToken(request);
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

这里调用了 TokenService类的方法,具体实现如下:


public void checkToken(HttpServletRequest request) throws BizException {
        String token = request.getHeader(TOKEN_NAME);
        if (StrUtil.isBlank(token)) {// header中不存在token
            token = request.getParameter(TOKEN_NAME);
            if (StrUtil.isBlank(token)) {// parameter中也不存在token
                throw new BizException("非法请求");
            }
        }
        if (Objects.isNull(redisTemplate.opsForValue().get(token))) {
            throw new BizException("不可以多次提交");
        }
        Boolean del = redisTemplate.delete(token);
        if (!del) {
            throw new BizException("不可以多次提交");
        }
    }

从请求头中获取token,如果请求头中没有,从请求参数中获取,如果都获取不到,返回错误。如果获取到了,从Redis中判断是否有这个token,没有说明之前请求过了,返回错误,如果有,执行删除,如果删除失败,返回错误。


3、将拦截器注入


package cn.couldme.study.web.security.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * 拦截器配置类
 * @Author: szwei
 * @Date: 2020-03-31 16:02
 **/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(apiIdempotentInterceptor());
    }
    @Bean
    public ApiIdempotentInterceptor apiIdempotentInterceptor() {
        return new ApiIdempotentInterceptor();
    }
}

4、获取token


用户每次打开表单时,先从后台获取token,后台UUID生成token,存到Redis中,等用户提交表单时,校验其token,如果校验成功,执行操作,删除掉token。

目录
相关文章
|
6月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
900 3
|
9月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
836 56
Spring Boot 的接口限流算法
|
9月前
|
Java API 网络架构
基于 Spring Boot 框架开发 REST API 接口实践指南
本文详解基于Spring Boot 3.x构建REST API的完整开发流程,涵盖环境搭建、领域建模、响应式编程、安全控制、容器化部署及性能优化等关键环节,助力开发者打造高效稳定的后端服务。
1235 1
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
510 16
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
SQL JSON Java
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
本文为Spring Boot增删改查接口的小白入门教程,介绍了项目的构建、配置YML文件、代码编写(包括实体类、Mapper接口、Mapper.xml、Service和Controller)以及使用Postman进行接口测试的方法。同时提供了SQL代码和完整代码的下载链接。
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
466 1
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
676 1
|
监控 Java 开发者
掌握SpringBoot扩展接口:提升代码优雅度的16个技巧
【10月更文挑战第20天】 SpringBoot以其简化配置和快速开发而受到开发者的青睐。除了基本的CRUD操作外,SpringBoot还提供了丰富的扩展接口,让我们能够更灵活地定制和扩展应用。以下是16个常用的SpringBoot扩展接口,掌握它们将帮助你写出更加优雅的代码。
549 0