最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用攔截器+Redis實現(xiàn)接口冪思路詳解

 更新時間:2023年08月19日 14:57:38   作者:逛窯子的李靖  
這篇文章主要介紹了使用攔截器+Redis實現(xiàn)接口冪等,接口冪等有很多種實現(xiàn)方式,攔截器/AOP+Redis,攔截器/AOP+本地緩存等等,本文講解一下通過攔截器+Redis實現(xiàn)冪等的方式,需要的朋友可以參考下

使用攔截器+Redis實現(xiàn)接口冪等

1.思路分析

接口冪等有很多種實現(xiàn)方式,攔截器/AOP+Redis,攔截器/AOP+本地緩存等等,本文講解一下通過攔截器+Redis實現(xiàn)冪等的方式。

其原理就是在攔截器中攔截請求,然后根據(jù)一個標識符去redis中查詢是否已經(jīng)存在,如果存在,則說明當前請求正在處理,拋出異常告訴前端請勿重復(fù)請求。

標識符:一般可以使用token+methodType+uri作為標識符,具體業(yè)務(wù)具體分析。

2.具體實現(xiàn)

2.1 創(chuàng)建redis工具類

import com.yunling.sys.config.exception.ParamValidateException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
 * Redis工具類
 *
 * @author 譚永強
 * @date 2023-08-15
 */
@Component
public class RedisUtils {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 寫入緩存
     *
     * @param key   建
     * @param value 值
     * @return 成功/失敗
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 寫入緩存設(shè)置時效時間
     *
     * @param key   鍵
     * @param value 值
     * @return 成功/失敗
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 判斷緩存中是否有對應(yīng)的value
     *
     * @param key 鍵
     * @return 成功/失敗
     */
    public boolean exists(final String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
    /**
     * 讀取緩存
     *
     * @param key 鍵
     * @return 成功/失敗
     */
    public Object get(final String key) {
        return redisTemplate.opsForValue().get(key);
    }
    /**
     * 刪除對應(yīng)的value
     *
     * @param key 鍵
     * @return 成功/失敗
     */
    public boolean remove(final String key) {
        if (exists(key)) {
            return Boolean.TRUE.equals(redisTemplate.delete(key));
        }
        return false;
    }
    /**
     * 遞增
     *
     * @param key   鍵
     * @param delta 要增加幾(大于0)
     * @return 結(jié)果
     */
    public Long incr(String key, long delta) {
        if (ObjectUtils.isEmpty(key)) {
            throw new ParamValidateException("key值不能為空");
        }
        if (delta < 0) {
            throw new ParamValidateException("遞增因子必須大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }
    /**
     * 遞減
     *
     * @param key   鍵
     * @param delta 要減少幾(小于0)
     * @return 結(jié)果
     */
    public Long decr(String key, long delta) {
        if (ObjectUtils.isEmpty(key)) {
            throw new ParamValidateException("key值不能為空");
        }
        if (delta < 0) {
            throw new ParamValidateException("遞減因子必須大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }
}

2.2 自定義冪等注解

自定義冪等注解,將seconds設(shè)置為該注解的屬性,在攔截器中判斷方法上是否有該注解,如果有該注解,則說明當前方法需要做冪等校驗。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 自動冪等
 * 該注解加在需要冪等的方法上,即可自動上線方法的冪等。
 *
 * @author 譚永強
 * @date 2023-08-15
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoIdempotent {
    /**
     * 限定時間(秒)
     * 限制多少秒內(nèi),每個用戶只能請求一次該接口。
     */
    long seconds() default 1;
}

2.3 自定義冪等攔截器

定義冪等接口用于攔截處理請求。

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.yunling.sys.annotate.AutoIdempotent;
import com.yunling.sys.common.RedisUtils;
import com.yunling.sys.common.ResultData;
import com.yunling.sys.common.ReturnCode;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
 * 自動冪等攔截器
 *
 * @author 譚永強
 * @date 2023-08-15
 */
@Component
public class AutoIdempotentInterceptor extends HandlerInterceptorAdapter {
    @Resource
    private RedisUtils redisUtils;
    /**
     * @param request  請求
     * @param response 響應(yīng)
     * @param handler  處理
     * @return 結(jié)果
     * @throws Exception 異常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判斷請求是否為方法的請求
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod method = (HandlerMethod) handler;
        //獲取方法中是否有冪等性注解
        AutoIdempotent anno = method.getMethodAnnotation(AutoIdempotent.class);
        //若注解為空則直接返回
        if (Objects.isNull(anno)) {
            return true;
        }
        //限定時間
        long seconds = anno.seconds();
        //token
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (Objects.isNull(token)) {
            ResultData<String> resultData = ResultData.fail(ReturnCode.ACCESS_DENIED.getCode(), "token不能為空");
            write(response, JSON.toJSONString(resultData));
            return false;
        }
        //此處轉(zhuǎn)MD5的原因就是token長度太長了,轉(zhuǎn)成md5短一些,此操作并不是必須的
        String md5 = MD5Utils.md5Hex(token, StandardCharsets.UTF_8.toString());
        //使用token+method+uri作為key值,此處需要通過key值確定請求的唯一性,也可以使用其他的組合,只要保證唯一性即可
        String key = md5 + ":" + request.getMethod() + ":" + request.getRequestURI();
        Object requestCountObj = redisUtils.get(key);
        if (!ObjectUtils.isEmpty(requestCountObj)) {
            //不為空,說明不是第一次請求,直接報錯
            ResultData<String> resultData = ResultData.fail(ReturnCode.RC206.getCode(), "請求已提交,請勿重復(fù)請求");
            write(response, JSON.toJSONString(resultData));
            return false;
        }
        //若為空則為第一次請求
        return redisUtils.set(key, 1, seconds);
    }
    /**
     * 返回結(jié)果到前端
     *
     * @param response 響應(yīng)
     * @param body     結(jié)果
     * @throws IOException 異常
     */
    private void write(HttpServletResponse response, String body) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        ServletOutputStream os = response.getOutputStream();
        os.write(body.getBytes());
        os.flush();
        os.close();
    }
}

2.4 注入攔截器到容器

將攔截器注冊到容器中。

package com.yunling.sys.config;
import com.yunling.sys.config.interceptor.AutoIdempotentInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
 * 將攔截器注入到容器中
 *
 * @author 譚永強
 * @date 2023-08-15
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Resource
    private AutoIdempotentInterceptor autoIdempotentInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(autoIdempotentInterceptor);
    }
}

3.測試

@RestController
@RequestMapping("user")
public class SysUserController {
    /**
     * 用戶新增
     *
     * @param user 用戶信息
     */
    @AutoIdempotent(seconds = 60)
    @PostMapping("add")
    public void add(@RequestBody SysUser user) {
       //業(yè)務(wù)代碼.....
    }
}

請求該接口,如果在60s內(nèi)再次請求,就會返回重復(fù)請求的結(jié)果。seconds具體值設(shè)置多少由該接口的實際響應(yīng)時間為標準,默認值為1秒。

在這里插入圖片描述

到此這篇關(guān)于使用攔截器+Redis實現(xiàn)接口冪思路詳解的文章就介紹到這了,更多相關(guān)Redis接口冪內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Redis實現(xiàn)訂閱發(fā)布功能

    基于Redis實現(xiàn)訂閱發(fā)布功能

    本文介紹了在SpringBoot項目中使用Redis實現(xiàn)異步解耦的方法,無需引入MQ中間件,首先引入Redis依賴并配置Redis,隨后創(chuàng)建Redis配置類來配置Redis連接工廠和監(jiān)聽器,接著創(chuàng)建消息訂閱者和發(fā)布者,通過RedisTemplate發(fā)送消息,最后強調(diào)了可以設(shè)置多個消息適配器來監(jiān)聽多個channel
    2026-05-05
  • redis主從復(fù)制的原理及實現(xiàn)

    redis主從復(fù)制的原理及實現(xiàn)

    Redis主從復(fù)制是一種數(shù)據(jù)同步機制,它通過將一個Redis實例的數(shù)據(jù)復(fù)制到其他Redis,本文主要介紹了redis主從復(fù)制的原理及實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • redis過期回調(diào)坑的解決

    redis過期回調(diào)坑的解決

    Redis提供了一種過期回調(diào)的機制,可以在某個鍵過期時觸發(fā)一個回調(diào)函數(shù),然而,在實際使用中,我們往往會遇到一些災(zāi)難性的問題,其中一個就是在使用過期回調(diào)的時候,我們可能會遭遇到無法預(yù)料的錯誤,本文就詳細的介紹一下
    2023-09-09
  • Redis的Sentinel解決方案介紹與運行機制

    Redis的Sentinel解決方案介紹與運行機制

    這篇文章主要介紹了Redis的Sentinel解決方案介紹與運行機制, Sentinel 是一款面向分布式服務(wù)架構(gòu)的輕量級流量控制組件,主要以流量為切入點,從流量控制、熔斷降級、系統(tǒng)自適應(yīng)保護等多個維度來保障服務(wù)的穩(wěn)定性,需要的朋友可以參考下
    2023-07-07
  • 使用Redis實現(xiàn)會話管理的示例代碼

    使用Redis實現(xiàn)會話管理的示例代碼

    文章介紹了如何使用Redis實現(xiàn)會話管理,包括會話的創(chuàng)建、讀取、更新和刪除操作,通過設(shè)置會話超時時間并重置,可以確保會話在用戶持續(xù)活動期間不會過期,此外,展示了使用Redis的Hashes存儲更多信息,并使用Redis集群提高系統(tǒng)的可用性和擴展性,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • redis使用skiplist跳表的原因解析

    redis使用skiplist跳表的原因解析

    經(jīng)常會有人問這個問題,redis中為什么要使用跳表?這個問題,redis作者已經(jīng)給出過明確答案,今天通過本文再給大家講解下這個問題,對redis?skiplist跳表知識感興趣的朋友一起看看吧
    2022-10-10
  • 深入剖析 Redis 的三種集群方式以及實戰(zhàn)配置

    深入剖析 Redis 的三種集群方式以及實戰(zhàn)配置

    本文深入解析Redis三種集群部署方式,文章包含完整的配置示例和操作指南,為Redis集群部署提供實用參考,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Redis實現(xiàn)集群搭建+集群讀寫的示例

    Redis實現(xiàn)集群搭建+集群讀寫的示例

    本文介紹了Redis集群的搭建和讀寫操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-02-02
  • Redis批量查詢的四種方式詳解

    Redis批量查詢的四種方式詳解

    在高并發(fā)場景下,巧妙地利用緩存批量查詢技巧能夠顯著提高系統(tǒng)性能,熟練掌握細粒度的緩存使用是每位架構(gòu)師必備的技能,因此,在本文中,我們將深入探討 Redis 中批量查詢的一些技巧,希望能夠給你帶來一些啟發(fā),需要的朋友可以參考下
    2025-10-10
  • Redis有序集合類型的操作_動力節(jié)點Java學院整理

    Redis有序集合類型的操作_動力節(jié)點Java學院整理

    今天通過本文給大家說一下Redis中最后一個數(shù)據(jù)類型 “有序集合類型”,需要的的朋友參考下吧
    2017-08-08

最新評論

宜兴市| 湄潭县| 高尔夫| 台湾省| 鄱阳县| 兰坪| 秦安县| 鲁山县| 丰镇市| 嘉峪关市| 兴业县| 惠州市| 晋城| 冕宁县| 启东市| 上蔡县| 景洪市| 容城县| 奈曼旗| 黄石市| 武鸣县| 盐池县| 诸城市| 射阳县| 临泉县| 瑞昌市| 汾阳市| 咸丰县| 泰宁县| 通榆县| 张家界市| 道孚县| 登封市| 神农架林区| 天峻县| 独山县| 梓潼县| 南康市| 山阴县| 双柏县| 吉安县|