文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

Springboot怎么利用Redis实现接口幂等性拦截

2023-07-02 12:00

关注

今天小编给大家分享一下Springboot怎么利用Redis实现接口幂等性拦截的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

正文

Springboot怎么利用Redis实现接口幂等性拦截

自定义注解 怎么玩的 :      

①标记哪个接口需要进行幂等性拦截        

②每个接口可以要求幂等性范围时间不一样,举例:可以2秒内,可以3秒内,时间自己传        

③ 一旦触发了,提示语可以不同 ,举例:VIP的接口,普通用户的接口,提示语不一样(开玩笑)

效果:

Springboot怎么利用Redis实现接口幂等性拦截

Springboot怎么利用Redis实现接口幂等性拦截

实战开始

核心三件套

注解、拦截器、拦截器配置

① RepeatDaMie.java

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; @Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RepeatDaMie {         public int second() default 1;         public String describe() default "重复提交了,兄弟";    }

②ApiRepeatInterceptor.java

import com.example.repeatdemo.annotation.RepeatDaMie;import com.example.repeatdemo.util.ContextUtil;import com.example.repeatdemo.util.Md5Encrypt;import com.example.repeatdemo.util.RedisUtils;import com.example.repeatdemo.wrapper.CustomHttpServletRequestWrapper;import com.fasterxml.jackson.databind.ObjectMapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Objects; @Componentpublic class ApiRepeatInterceptor implements HandlerInterceptor {     private final Logger log = LoggerFactory.getLogger(this.getClass());     private static final String POST="POST";    private static final String GET="GET";    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        try {            if (handler instanceof HandlerMethod) {                HandlerMethod handlerMethod = (HandlerMethod) handler;                // 获取RepeatDaMie注解                RepeatDaMie repeatDaMie = handlerMethod.getMethodAnnotation(RepeatDaMie.class);                if (null==repeatDaMie) {                    return true;                }                //限制的时间范围                int seconds = repeatDaMie.second();                //这个用户唯一标识,可以自己细微调整,是userId还是token还是sessionId还是不需要                String userUniqueKey = request.getHeader("userUniqueKey");                String method = request.getMethod();                String apiParams = "";                if (GET.equals(method)){                    log.info("GET请求来了");                    apiParams = new ObjectMapper().writeValueAsString(request.getParameterMap());                }else if (POST.equals(method)){                    log.info("POST请求来了");                    CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;                    apiParams = wrapper.getBody();                }               log.info("当前参数是:{}",apiParams);                // 存储key                String keyRepeatDaMie = Md5Encrypt.md5(userUniqueKey+request.getServletPath()+apiParams) ;                RedisUtils redisUtils = ContextUtil.getBean(RedisUtils.class);                if (Objects.nonNull(redisUtils.get(keyRepeatDaMie))){                   log.info("重复请求了,重复请求了,拦截了");                   returnData(response,repeatDaMie.describe());                   return false;               }else {                    redisUtils.setWithTime(keyRepeatDaMie, true,seconds);               }             }            return true;        } catch (Exception e) {            log.warn("请求过于频繁请稍后再试");            e.printStackTrace();        }        return true;    }     public void returnData(HttpServletResponse response,String msg) throws IOException {        response.setCharacterEncoding("UTF-8");        response.setContentType("application/json; charset=utf-8");        ObjectMapper objectMapper = new ObjectMapper();        //这里传提示语可以改成自己项目的返回数据封装的类        response.getWriter().println(objectMapper.writeValueAsString(msg));        return;    } }

③ WebConfig.java

import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configurationpublic class WebConfig implements WebMvcConfigurer {         @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new ApiRepeatInterceptor()).addPathPatterns("@Componentpublic final class ContextUtil implements ApplicationContextAware {    protected static ApplicationContext applicationContext ;    @Override    public void setApplicationContext(ApplicationContext arg0) throws BeansException {        if (applicationContext == null) {            applicationContext = arg0;        }    }    public static Object getBean(String name) {        //name表示其他要注入的注解name名        return applicationContext.getBean(name);    }        public static <T> T getBean(Class<T> clazz) {        return applicationContext.getBean(clazz);    }}

②Md5Encrypt.java

import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException; public class Md5Encrypt {     private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',            'b', 'c', 'd', 'e', 'f'};         public static String md5(String text) {        MessageDigest msgDigest = null;         try {            msgDigest = MessageDigest.getInstance("MD5");        } catch (NoSuchAlgorithmException e) {            throw new IllegalStateException("System doesn't support MD5 algorithm.");        }         try {            // 注意该接口是按照指定编码形式签名            msgDigest.update(text.getBytes("UTF-8"));         } catch (UnsupportedEncodingException e) {             throw new IllegalStateException("System doesn't support your  EncodingException.");         }         byte[] bytes = msgDigest.digest();         String md5Str = new String(encodeHex(bytes));         return md5Str;    }     private static char[] encodeHex(byte[] data) {         int l = data.length;         char[] out = new char[l << 1];        // two characters form the hex value.        for (int i = 0, j = 0; i < l; i++) {            out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];            out[j++] = DIGITS[0x0F & data[i]];        }         return out;    }}

③RedisUtils.java

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.*;import org.springframework.stereotype.Component;import java.io.Serializable;import java.util.List;import java.util.Set;import java.util.concurrent.TimeUnit;  @Componentpublic class RedisUtils {     @Autowired    private RedisTemplate redisTemplate;          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;     }            public boolean setWithTime(final String key, Object value,int seconds) {        boolean result = false;        try {             ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();            operations.set(key, value,seconds, TimeUnit.SECONDS);            result = true;        } catch (Exception e) {            e.printStackTrace();        }        return result;     }            public void remove(final String... keys) {        for (String key : keys) {            remove(key);        }    }          public void removePattern(final String pattern) {        Set<Serializable> keys = redisTemplate.keys(pattern);        if (keys.size() > 0)            redisTemplate.delete(keys);    }          public void remove(final String key) {        if (exists(key)) {            redisTemplate.delete(key);        }    }           public boolean exists(final String key) {        return redisTemplate.hasKey(key);    }           public Object get(final String key) {        Object result = null;        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();        result = operations.get(key);        return result;    }           public void hmSet(String key, Object hashKey, Object value) {         HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();         hash.put(key, hashKey, value);     }           public Object hmGet(String key, Object hashKey) {        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();        return hash.get(key, hashKey);     }           public void lPush(String k, Object v) {        ListOperations<String, Object> list = redisTemplate.opsForList();        list.rightPush(k, v);    }           public List<Object> lRange(String k, long l, long l1) {        ListOperations<String, Object> list = redisTemplate.opsForList();        return list.range(k, l, l1);    }           public void add(String key, Object value) {        SetOperations<String, Object> set = redisTemplate.opsForSet();        set.add(key, value);    }           public Set<Object> setMembers(String key) {         SetOperations<String, Object> set = redisTemplate.opsForSet();         return set.members(key);     }           public void zAdd(String key, Object value, double scoure) {        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();        zset.add(key, value, scoure);    }           public Set<Object> rangeByScore(String key, double scoure, double scoure1) {         ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();         return zset.rangeByScore(key, scoure, scoure1);     }           public Set<Integer> sGet(String key) {        try {            return redisTemplate.opsForSet().members(key);        } catch (Exception e) {            e.printStackTrace();            return null;        }    }           public boolean sHasKey(String key, Object value) {        try {            return redisTemplate.opsForSet().isMember(key, value);        } catch (Exception e) {            e.printStackTrace();            return false;        }    } }

REDIS配置类

RedisConfig.java

import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializationContext;import org.springframework.data.redis.serializer.StringRedisSerializer;import static org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig; @Configuration@EnableCachingpublic class RedisConfig {    @Bean    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {        RedisCacheConfiguration cacheConfiguration =                defaultCacheConfig()                        .disableCachingNullValues()                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer(Object.class)));        return RedisCacheManager.builder(connectionFactory).cacheDefaults(cacheConfiguration).build();    }      @Bean    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();        redisTemplate.setConnectionFactory(factory);        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);        ObjectMapper om = new ObjectMapper();        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);        jackson2JsonRedisSerializer.setObjectMapper(om);        //序列化设置 ,这样为了存储操作对象时正常显示的数据,也能正常存储和获取        redisTemplate.setKeySerializer(new StringRedisSerializer());        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);        redisTemplate.setHashKeySerializer(new StringRedisSerializer());        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);        return redisTemplate;    }    @Bean    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();        stringRedisTemplate.setConnectionFactory(factory);        return stringRedisTemplate;    } }

最后写测试接口,看看效果(一个POST,一个GET):

故意把时间放大,1000秒内重复调用,符合我们拦截规则的都会被拦截。

TestController.java

import com.example.repeatdemo.dto.PayOrderApply;import com.example.repeatdemo.annotation.RepeatDaMie;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.*; @RestControllerpublic class TestController {    private final Logger log = LoggerFactory.getLogger(this.getClass());     @RepeatDaMie(second = 1000,describe = "尊敬的客户,您慢点")    @PostMapping(value = "/doPost")    @ResponseBody    public void test(@RequestBody PayOrderApply payOrderApply) {        log.info("Controller POST请求:"+payOrderApply.toString());    }     @RepeatDaMie(second = 1000,describe = "大哥,你冷静点")    @GetMapping(value = "/doGet")    @ResponseBody    public void doGet( PayOrderApply payOrderApply) {        log.info("Controller GET请求:"+payOrderApply.toString());    } }

PayOrderApply.java

public class PayOrderApply {     private String sn;    private Long amount;    private String proCode;     public String getSn() {        return sn;    }     public void setSn(String sn) {        this.sn = sn;    }     public Long getAmount() {        return amount;    }     public void setAmount(Long amount) {        this.amount = amount;    }     public String getProCode() {        return proCode;    }     public void setProCode(String proCode) {        this.proCode = proCode;    }     @Override    public String toString() {        return "PayOrderApply{" +                "sn='" + sn + '\'' +                ", amount=" + amount +                ", proCode='" + proCode + '\'' +                '}';    }}

Springboot怎么利用Redis实现接口幂等性拦截

redis生成了值:

Springboot怎么利用Redis实现接口幂等性拦截

Springboot怎么利用Redis实现接口幂等性拦截

以上就是“Springboot怎么利用Redis实现接口幂等性拦截”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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