文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

这篇写的太好了!Spring Boot + Redis 实现接口幂等性

2024-12-03 17:04

关注

本文转载自微信公众号「小明菜市场」,可以通过以下二维码关注。转载本文请联系小明菜市场公众号。

介绍

幂等性的概念是,任意多次执行所产生的影响都与一次执行产生的影响相同,按照这个含义,最终的解释是对数据库的影响只能是一次性的,不能重复处理。手段如下

小小主要带你们介绍Redis实现自动幂等性。其原理如下图所示。

实现过程

引入 maven 依赖

  1.  
  2.            org.springframework.boot 
  3.            spring-boot-starter-data-redis 
  4.         

spring 配置文件写入

  1. server.port=8080 
  2. core.datasource.druid.enabled=true 
  3. core.datasource.druid.url=jdbc:mysql://192.168.1.225:3306/?useUnicode=true&characterEncoding=UTF-8 
  4. core.datasource.druid.username=root 
  5. core.datasource.druid.password
  6. core.redis.enabled=true 
  7. spring.redis.host=192.168.1.225 #本机的redis地址 
  8. spring.redis.port=16379 
  9. spring.redis.database=3 
  10. spring.redis.jedis.pool.max-active=10 
  11. spring.redis.jedis.pool.max-idle=10 
  12. spring.redis.jedis.pool.max-wait=5s 
  13. spring.redis.jedis.pool.min-idle=10 

引入 Redis

引入 Spring boot 中的redis相关的stater,后面需要用到 Spring Boot 封装好的 RedisTemplate

  1. package cn.smallmartial.demo.utils; 
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired; 
  4. import org.springframework.data.redis.core.RedisTemplate; 
  5. import org.springframework.data.redis.core.ValueOperations; 
  6. import org.springframework.stereotype.Component; 
  7.  
  8. import java.io.Serializable
  9. import java.util.Objects; 
  10. import java.util.concurrent.TimeUnit; 
  11.  
  12.  
  13. @Component 
  14. public class RedisUtil { 
  15.  
  16.     @Autowired 
  17.     private RedisTemplate redisTemplate; 
  18.  
  19.      
  20.     public boolean set(final String key, Object value) { 
  21.         boolean result = false
  22.         try { 
  23.             ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); 
  24.             operations.set(key, value); 
  25.             result = true
  26.         } catch (Exception e) { 
  27.             e.printStackTrace(); 
  28.         } 
  29.         return result; 
  30.     } 
  31.  
  32.      
  33.     public boolean setEx(final String key, Object value, long expireTime) { 
  34.         boolean result = false
  35.         try { 
  36.             ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); 
  37.             operations.set(key, value); 
  38.             redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); 
  39.             result = true
  40.         } catch (Exception e) { 
  41.             e.printStackTrace(); 
  42.         } 
  43.         return result; 
  44.     } 
  45.  
  46.      
  47.     public Object get(final String key) { 
  48.         Object result = null
  49.         ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); 
  50.         result = operations.get(key); 
  51.         return result; 
  52.     } 
  53.  
  54.      
  55.     public boolean remove(final String key) { 
  56.         if (exists(key)) { 
  57.             Boolean delete = redisTemplate.delete(key); 
  58.             return delete
  59.         } 
  60.         return false
  61.  
  62.     } 
  63.  
  64.      
  65.     public boolean exists(final String key) { 
  66.         boolean result = false
  67.         ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); 
  68.         if (Objects.nonNull(operations.get(key))) { 
  69.             result = true
  70.         } 
  71.         return result; 
  72.     } 
  73.  
  74.  

自定义注解

自定义一个注解,定义此注解的目的是把它添加到需要实现幂等的方法上,只要某个方法注解了其,都会自动实现幂等操作。其代码如下

  1. @Target({ElementType.METHOD}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. public @interface AutoIdempotent { 
  4.    

token 的创建和实现

token 服务接口,我们新建一个接口,创建token服务,里面主要是有两个方法,一个用来创建 token,一个用来验证token

  1. public interface TokenService { 
  2.  
  3.      
  4.     public  String createToken(); 
  5.  
  6.      
  7.     public boolean checkToken(HttpServletRequest request) throws Exception; 
  8.  

token 的实现类,token中引用了服务的实现类,token引用了 redis 服务,创建token采用随机算法工具类生成随机 uuid 字符串,然后放入 redis 中,如果放入成功,返回token,校验方法就是从 header 中获取 token 的值,如果不存在,直接跑出异常,这个异常信息可以被直接拦截到,返回给前端。

  1. package cn.smallmartial.demo.service.impl; 
  2.  
  3. import cn.smallmartial.demo.bean.RedisKeyPrefix; 
  4. import cn.smallmartial.demo.bean.ResponseCode; 
  5. import cn.smallmartial.demo.exception.ApiResult; 
  6. import cn.smallmartial.demo.exception.BusinessException; 
  7. import cn.smallmartial.demo.service.TokenService; 
  8. import cn.smallmartial.demo.utils.RedisUtil; 
  9. import io.netty.util.internal.StringUtil; 
  10. import org.springframework.beans.factory.annotation.Autowired; 
  11. import org.springframework.stereotype.Service; 
  12. import org.springframework.util.StringUtils; 
  13.  
  14. import javax.servlet.http.HttpServletRequest; 
  15. import java.util.Random; 
  16. import java.util.UUID; 
  17.  
  18.  
  19. @Service 
  20. public class TokenServiceImpl implements TokenService { 
  21.     @Autowired 
  22.     private RedisUtil redisService; 
  23.  
  24.      
  25.     @Override 
  26.     public String createToken() { 
  27.         String str = UUID.randomUUID().toString().replace("-"""); 
  28.         StringBuilder token = new StringBuilder(); 
  29.         try { 
  30.             token.append(RedisKeyPrefix.TOKEN_PREFIX).append(str); 
  31.             redisService.setEx(token.toString(), token.toString(), 10000L); 
  32.             boolean empty = StringUtils.isEmpty(token.toString()); 
  33.             if (!empty) { 
  34.                 return token.toString(); 
  35.             } 
  36.         } catch (Exception ex) { 
  37.             ex.printStackTrace(); 
  38.         } 
  39.         return null
  40.     } 
  41.  
  42.      
  43.     @Override 
  44.     public boolean checkToken(HttpServletRequest request) throws Exception { 
  45.  
  46.         String token = request.getHeader(RedisKeyPrefix.TOKEN_NAME); 
  47.         if (StringUtils.isEmpty(token)) {// header中不存在token 
  48.             token = request.getParameter(RedisKeyPrefix.TOKEN_NAME); 
  49.             if (StringUtils.isEmpty(token)) {// parameter中也不存在token 
  50.                 throw new BusinessException(ApiResult.BADARGUMENT); 
  51.             } 
  52.         } 
  53.  
  54.         if (!redisService.exists(token)) { 
  55.             throw new BusinessException(ApiResult.REPETITIVE_OPERATION); 
  56.         } 
  57.  
  58.         boolean remove = redisService.remove(token); 
  59.         if (!remove) { 
  60.             throw new BusinessException(ApiResult.REPETITIVE_OPERATION); 
  61.         } 
  62.         return true
  63.     } 

拦截器的配置

用于拦截前端的 token,判断前端的 token 是否有效

  1. @Configuration 
  2. public class WebMvcConfiguration extends WebMvcConfigurationSupport { 
  3.  
  4.     @Bean 
  5.     public AuthInterceptor authInterceptor() { 
  6.         return new AuthInterceptor(); 
  7.     } 
  8.  
  9.      
  10.     @Override 
  11.     public void addInterceptors(InterceptorRegistry registry) { 
  12.         registry.addInterceptor(authInterceptor()); 
  13. //                .addPathPatterns("/ksb 
  14. @RestController 
  15. public class BusinessController { 
  16.  
  17.  
  18.     @Autowired 
  19.     private TokenService tokenService; 
  20.  
  21.     @GetMapping("/get/token"
  22.     public Object  getToken(){ 
  23.         String token = tokenService.createToken(); 
  24.         return ResponseUtil.ok(token) ; 
  25.     } 
  26.  
  27.  
  28.     @AutoIdempotent 
  29.     @GetMapping("/test/Idempotence"
  30.     public Object testIdempotence() { 
  31.         String token = "接口幂等性测试"
  32.         return ResponseUtil.ok(token) ; 
  33.     } 

用浏览器进行访问

用获取到的token第一次访问

用获取到的token再次访问可以看到,第二次访问失败,即,幂等性验证通过。

关于作者

我是小小,双鱼座的程序猿,活在一线城市,我们下期再见。

 

来源: 小明菜市场 内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯