当前位置:   article > 正文

开发中常遇到的接口幂等性问题及实现【token使用】_开发中token如何使用

开发中token如何使用

转载:https://juejin.cn/post/7198905912685166651

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 通过传入的key获取到的value与参数avg进行对比,一致说明数据存在reids中,删除key的数据,
// 不一致说明是重复提交,返回0后续业务处理。
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
  • 1
  • 2
  • 3

在这里插入图片描述

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

/**
 * Redis配置类
 * @author 单程车票
 */
@Configuration
public class RedisConfig {

    /**
    *  配置Redis的序列化器
    */
     public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

         RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
         redisTemplate.setConnectionFactory(redisConnectionFactory);
         // 使用jackson序列化方式序列化json
         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
         ObjectMapper objectMapper = new ObjectMapper();
         objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
         objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
         jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

         redisTemplate.setKeySerializer(new StringRedisSerializer());
         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

         redisTemplate.afterPropertiesSet();
         return redisTemplate;
     }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在这里插入图片描述

# 端口号
server:
  port: 8888
# 配置Redis
spring:
  redis:
    host: localhost
    port: 6379
    database: 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

/**
 * 业务接口类
 * @author 单程车票
 */
public interface TokenService {
    // 创建token
    String getToken();
    // 校验token并执行业务代码
    boolean checkToken(HttpServletRequest request);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

/**
 * 主要业务
 * @author 单程车票
 */
@Service
public class TokenServiceImpl implements TokenService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String getToken() {
        // 通过UUID生成token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 将生成的token存入redis中,这里为了方便观察,把key写死为testToken,因为只测试一个接口,实际开发中,key是需要动态的(可以找一个唯一值替代,比如订单号等)
        stringRedisTemplate.opsForValue().set("testToken", token);
        // 返回token
        return token;
    }

    @Override
    public boolean checkToken(HttpServletRequest request) {
        // 从请求头中获取token
        String token = request.getHeader("token");
        // 判断是否为空
        if (StringUtils.isEmpty(token)) {
            // token为空则抛出异常
            throw new CustomException("请求头未携带token!");
        }
        
        // LUA脚本保证获取token,校验token,删除token是原子性的
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        // 调用execute执行,第一个参数传入脚本,第二个参数传入key(这里是之前写死的testToken),第三个参数传入AVG(这里是请求头携带的token)
        // 该lua脚本会对比 传入的key获取到的value是否与请求头获取的token一致,一致说明存在,删除key的数据,不一致返回0
        Long res = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), List.of("testToken"),  token);

        // 不一致,说明不存在,抛出重复异常
        if (res == 0) {
            throw new CustomException("请求重复提交!");
        }

        // 执行业务代码
        System.out.println("执行业务代码");

        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

在这里插入图片描述

/**
 * 测试
 * @author 单程车票
 */
@RestController
public class OrderController {

    @Autowired
    private TokenService tokenService;

    @GetMapping("/getToken")
    public R<String> getToken() {
        String token = tokenService.getToken();
        return R.success(token);
    }

    @PostMapping("/order")
    public R<String> order(HttpServletRequest request) {
        // 校验并执行业务代码
        boolean res = tokenService.checkToken(request);
        if (res) return R.success("执行成功!");
        else return R.fail("执行失败");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转载:https://juejin.cn/post/7198905912685166651

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号