精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringBoot+Redis:輕松解決海量重復提交問題

數據庫 Redis
我們新建一個接口,創建token服務,里面主要是兩個方法,一個用來創建token,一個用來驗證token。創建token主要產生的是一個字符串,檢驗token的話主要是傳達request對象,為什么要傳request對象呢?

前言

在實際的開發項目中,一個對外暴露的接口往往會面臨很多次請求,這時候需要保證任意多次執行所產生的影響均與一次執行的影響相同 。按照這個含義就是對數據庫的影響只能是一次性的,不能重復處理。如何保證其冪等性,通常有以下手段:

  1. 數據庫建立唯一性索引,可以保證最終插入數據庫的只有一條數據
  2. token機制,每次接口請求前先獲取一個token,然后再下次請求的時候在請求的header體中加上這個token,后臺進行驗證,如果驗證通過刪除token,下次請求再次判斷token
  3. 悲觀鎖或者樂觀鎖,悲觀鎖可以保證每次for update的時候其他sql無法update數據(在數據庫引擎是innodb的時候,select的條件必須是唯一索引,防止鎖全表)
  4. 先查詢后判斷,首先通過查詢數據庫是否存在數據,如果存在證明已經請求過了,直接拒絕該請求,如果沒有存在,就證明是第一次進來,直接放行。

Redis實現自動冪等的原理圖:

圖片圖片

一、搭建服務

1、首先是搭建Redis服務器。可參考《如何快速搭建一套生產級MYSQL》利用docker搭建一套測試環境。

2、引入springboot中到的Redis,或者Spring封裝的Jedis也可以,后面主要用到的api就是它的set方法和exists方法,這里我們使用springboot的封裝好的redisTemplate

/**
 * redis工具類
 */
@Component
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 寫入緩存
     * @param key
     * @param value
     * @return
     */
    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;
    }


    /**
     * 寫入緩存設置時效時間
     * @param key
     * @param value
     * @return
     */
    public boolean setEx(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 判斷緩存中是否有對應的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 讀取緩存
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 刪除對應的value
     * @param key
     */
    public boolean remove(final String key) {
        if (exists(key)) {
            Boolean delete = redisTemplate.delete(key);
            return delete;
        }
        return false;

    }

}

二、自定義注解AutoIdempotent

自定義一個注解,定義此注解的主要目的是把它添加在需要實現冪等的方法上,凡是某個方法注解了它,都會實現自動冪等。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoIdempotent {

}

三、token創建和檢驗

1、token服務接口

我們新建一個接口,創建token服務,里面主要是兩個方法,一個用來創建token,一個用來驗證token。創建token主要產生的是一個字符串,檢驗token的話主要是傳達request對象,為什么要傳request對象呢?主要作用就是獲取header里面的token,然后檢驗,通過拋出的Exception來獲取具體的報錯信息返回給前端

public interface TokenService {

    /**
     * 創建token
     * @return
     */
    public  String createToken();

    /**
     * 檢驗token
     * @param request
     * @return
     */
    public boolean checkToken(HttpServletRequest request) throws Exception;

}

2、token的服務實現類

token引用了Redis服務,創建token采用隨機算法工具類生成隨機uuid字符串,然后放入到redis中(為了防止數據的冗余保留,這里設置過期時間為10000秒,具體可視業務而定),如果放入成功,最后返回這個token值。checkToken方法就是從header中獲取token到值(如果header中拿不到,就從paramter中獲取),如若不存在,直接拋出異常。這個異常信息可以被攔截器捕捉到,然后返回給前端。

@Service
public class TokenServiceImpl implements TokenService {

    @Autowired
    private RedisService redisService;


    /**
     * 創建token
     *
     * @return
     */
    @Override
    public String createToken() {
        String str = RandomUtil.randomUUID();
        StrBuilder token = new StrBuilder();
        try {
            token.append(Constant.Redis.TOKEN_PREFIX).append(str);
            redisService.setEx(token.toString(), token.toString(),10000L);
            boolean notEmpty = StrUtil.isNotEmpty(token.toString());
            if (notEmpty) {
                return token.toString();
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }


    /**
     * 檢驗token
     *
     * @param request
     * @return
     */
    @Override
    public boolean checkToken(HttpServletRequest request) throws Exception {

        String token = request.getHeader(Constant.TOKEN_NAME);
        if (StrUtil.isBlank(token)) {// header中不存在token
            token = request.getParameter(Constant.TOKEN_NAME);
            if (StrUtil.isBlank(token)) {// parameter中也不存在token
                throw new ServiceException(Constant.ResponseCode.ILLEGAL_ARGUMENT, 100);
            }
        }

        if (!redisService.exists(token)) {
            throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);
        }

        boolean remove = redisService.remove(token);
        if (!remove) {
            throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);
        }
        return true;
    }
}

四、攔截器的配置

1、實現WebMvcConfigurerAdapter,主要作用就是添加autoIdempotentInterceptor到配置類中,這樣我們到攔截器才能生效,注意使用@Configuration注解,這樣在容器啟動是時候就可以添加進入context中
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Resource
   private AutoIdempotentInterceptor autoIdempotentInterceptor;

    /**
     * 添加攔截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(autoIdempotentInterceptor);
        super.addInterceptors(registry);
    }
}

2、攔截處理器:主要的功能是攔截掃描到AutoIdempotent到注解到方法,然后調用tokenService的checkToken()方法校驗token是否正確,如果捕捉到異常就將異常信息渲染成json返回給前端

/**
 * 攔截器
 */
@Component
public class AutoIdempotentInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    /**
     * 預處理
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //被ApiIdempotment標記的掃描
        AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class);
        if (methodAnnotation != null) {
            try {
                return tokenService.checkToken(request);// 冪等性校驗, 校驗通過則放行, 校驗失敗則拋出異常, 并通過統一異常處理返回友好提示
            }catch (Exception ex){
                ResultVo failedResult = ResultVo.getFailedResult(101, ex.getMessage());
                writeReturnJson(response, JSONUtil.toJsonStr(failedResult));
                throw ex;
            }
        }
        //必須返回true,否則會被攔截一切請求
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    /**
     * 返回的json值
     * @param response
     * @param json
     * @throws Exception
     */
    private void writeReturnJson(HttpServletResponse response, String json) throws Exception{
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);

        } catch (IOException e) {
        } finally {
            if (writer != null)
                writer.close();
        }
    }

}

五、測試用例

1、模擬業務請求類

首先我們需要通過/get/token路徑通過getToken()方法去獲取具體的token,然后我們調用testIdempotence方法,這個方法上面注解了@AutoIdempotent,攔截器會攔截所有的請求,當判斷到處理的方法上面有該注解的時候,就會調用TokenService中的checkToken()方法,如果捕獲到異常會將異常拋出調用者,下面我們來模擬請求一下:

@RestController
public class BusinessController {


    @Resource
    private TokenService tokenService;

    @Resource
    private TestService testService;


    @PostMapping("/get/token")
    public String  getToken(){
        String token = tokenService.createToken();
        if (StrUtil.isNotEmpty(token)) {
            ResultVo resultVo = new ResultVo();
            resultVo.setCode(Constant.code_success);
            resultVo.setMessage(Constant.SUCCESS);
            resultVo.setData(token);
            return JSONUtil.toJsonStr(resultVo);
        }
        return StrUtil.EMPTY;
    }


    @AutoIdempotent
    @PostMapping("/test/Idempotence")
    public String testIdempotence() {
        String businessResult = testService.testIdempotence();
        if (StrUtil.isNotEmpty(businessResult)) {
            ResultVo successResult = ResultVo.getSuccessResult(businessResult);
            return JSONUtil.toJsonStr(successResult);
        }
        return StrUtil.EMPTY;
    }
}

2、使用postman請求

首先訪問get/token路徑獲取到具體的token:

圖片圖片

利用獲取到的token,然后放到具體請求到header中,可以看到第一次請求成功,接著我們請求第二次:

圖片圖片

第二次請求,返回的是重復性操作,可見重復性驗證通過,再多次請求到時候我們只讓其第一次成功,第二次就是失敗:

圖片 圖片

責任編輯:武曉燕 來源: 一安未來
相關推薦

2020-04-23 14:35:30

SpringBootRedis數據庫

2024-11-15 10:39:11

2024-07-02 11:42:53

SpringRedis自定義

2020-02-11 16:10:44

Redis分布式鎖Java

2024-03-07 12:51:44

代碼CRUD數據

2009-11-26 16:30:52

Suse中文亂碼問題

2009-01-11 10:23:00

網絡掉線頻繁掉線

2023-04-26 01:07:03

2009-11-17 11:30:31

PHP表單

2023-08-24 08:02:19

冪等性API請求

2025-09-10 07:57:44

SpringBootMinio存儲

2015-06-05 15:29:16

網絡優化

2024-11-14 10:38:43

2011-04-07 10:47:35

2009-02-03 09:30:00

2024-02-27 08:14:51

Nginx跨域服務

2025-10-31 07:37:48

2010-09-30 15:10:12

Javascriptimg

2010-10-08 15:35:32

Javascriptimg

2022-06-09 09:20:41

ahooksaxios
點贊
收藏

51CTO技術棧公眾號

免费黄在线观看| 国产亚洲综合视频| a天堂中文在线观看| 91精品一区国产高清在线gif | 亚洲第一天堂av| 日韩欧美国产综合在线| 亚洲 国产 欧美 日韩| 精品白丝av| 精品国产123| 嫩草av久久伊人妇女超级a| а√中文在线8| 99久久精品99国产精品| 国产精品久久久久久网站| 老熟妇高潮一区二区三区| www.豆豆成人网.com| 日韩欧美国产视频| 亚洲视频电影| 人妻精品一区一区三区蜜桃91 | 久久久久久久久久久免费视频| 成年人在线观看视频| 国产精品一二一区| 欧美最猛性xxxxx(亚洲精品)| 国产精品久久波多野结衣| 久久久精品99| 久久综合色占| 欧美一卡二卡在线| 国产成人av影视| 色老头在线观看| 久久久国产午夜精品| 91传媒在线免费观看| youjizz在线视频| 欧美高清不卡| 中文字幕日韩精品在线| 亚州av综合色区无码一区| 男人亚洲天堂| 色哟哟国产精品| 国产精品视频二| yiren22亚洲综合伊人22| 国产一区二区三区在线观看精品| 68精品国产免费久久久久久婷婷| 任我爽在线视频| 杨幂一区二区三区免费看视频| 日韩一区二区在线免费观看| 国内自拍视频一区| a国产在线视频| 亚洲免费av在线| 先锋影音欧美| 欧洲亚洲精品视频| 暴力调教一区二区三区| caoporn国产精品免费公开| 一区二区视频免费| 日本aⅴ免费视频一区二区三区| 欧美激情a在线| 久久免费看少妇高潮v片特黄| 日韩av自拍| 在线观看欧美日韩国产| 亚洲av综合一区二区| 欧美福利在线播放网址导航| 欧美成人bangbros| 毛片毛片毛片毛片毛| 热久久久久久| 欧美视频三区在线播放| 无码人妻精品一区二区三区66| 老色鬼在线视频| 一区二区成人在线| 男女爱爱视频网站| www在线免费观看视频| 中文字幕色av一区二区三区| 正在播放91九色| 91在线网址| 国产精品水嫩水嫩| 午夜精品一区二区三区在线观看 | 激情视频一区二区| 日本xxxxwww| eeuss国产一区二区三区| eeuss一区二区三区| 一级淫片免费看| 精品一区二区三区久久久| 国产中文字幕日韩| www.五月婷婷| 成人久久视频在线观看| 国产二区不卡| 天堂中文资源在线观看| 91在线免费播放| 欧美日韩精品久久| 二区三区在线| 中文字幕一区二区三中文字幕| 正在播放91九色| 三级网站视频在在线播放| 亚洲午夜视频在线观看| 免费成人在线视频网站| 成人免费观看在线观看| 欧美视频中文字幕在线| 男女污污的视频| 婷婷久久免费视频| 日韩欧美高清一区| 国产特黄级aaaaa片免| blacked蜜桃精品一区| 自拍偷拍亚洲区| 欧美日韩成人免费观看| 午夜亚洲激情| 91欧美精品成人综合在线观看| 国产av无码专区亚洲av| 成人激情免费网站| 日本午夜精品一区二区| 国产福利在线看| 亚洲精品乱码久久久久久久久| 五十路熟女丰满大屁股| 成人在线视频观看| 精品国产伦一区二区三区观看体验 | 国产亚洲福利社区| jizz日韩| 午夜视频在线观看一区二区三区| 国产一区二区视频免费在线观看| 91精品网站在线观看| 欧美精品一区二区三| 一级在线观看视频| 欧美体内she精视频在线观看| 日韩69视频在线观看| 国产人妻精品一区二区三| 91麻豆国产福利精品| 黄色高清视频网站| 亚洲精品mv| 日韩一区二区在线看| 69精品无码成人久久久久久| 韩国在线视频一区| 国产精品网址在线| 青青草视频在线免费观看| 欧美激情综合网| 日韩国产一级片| 四虎影视国产精品| 亚洲精品小视频| 一区视频免费观看 | 2022中文字幕| 国产91在线精品| 精品一区二区三区三区| 激情五月婷婷在线| 久久永久免费| 国产精品一区视频网站| a视频在线观看| 欧美图片一区二区三区| 国产精品伦子伦| 亚洲五月综合| 国产欧美婷婷中文| youjizz在线播放| 色婷婷久久久综合中文字幕| 日本少妇一级片| 成人看的视频| 国产成人在线视频| 丝袜视频国产在线播放| 亚洲一级二级在线| 乳色吐息在线观看| 中国精品18videos性欧美| 国产精品香蕉av| 国产一级片在线| 在线视频国产一区| 亚洲人成人无码网www国产 | 91麻豆免费观看| 国产女大学生av| 国内精品国产成人国产三级粉色 | 爱福利在线视频| 日韩一区二区电影| 青草草在线视频| 国产综合久久久久影院| 欧美h视频在线观看| 高清一区二区三区av| 久久久国产精品亚洲一区| 国产情侣激情自拍| 一区二区三区四区五区视频在线观看| 色哟哟免费视频| 欧美精品1区| 俄罗斯精品一区二区三区| 爱情岛亚洲播放路线| 精品区一区二区| 欧美日韩三级在线观看| 99久久精品久久久久久清纯| 春日野结衣av| 国产一区网站| 国产日本欧美一区二区三区| 天堂资源在线中文| 日韩一卡二卡三卡| 精品亚洲永久免费| 91小视频在线观看| 日韩av一二三四| 日本在线电影一区二区三区| 91久久久久久久久| av丝袜在线| 亚洲精品一区在线观看香蕉 | 欧美日韩午夜在线| 国产精品成人在线视频| 国产一区二区精品久久91| 波多野结衣av一区二区全免费观看 | 两根大肉大捧一进一出好爽视频| 色婷婷精品视频| 国产精品久久网| 国产cdts系列另类在线观看| 亚洲国产精品久久精品怡红院| 久热这里只有精品6| 国产婷婷色一区二区三区 | 手机在线理论片| 在线观看免费高清视频97| 国产乱码久久久久| 岛国av在线不卡| 国产精品久久久免费看| 成人深夜在线观看| 丁香啪啪综合成人亚洲| 久久久久久久久丰满| 国产主播一区二区三区四区| 五月激情久久| 欧美国产日韩一区二区三区| 国产污视频在线| 精品久久久久av影院| 日本熟妇乱子伦xxxx| 国产精品视频一二三| 久久国产免费视频| 日韩 欧美一区二区三区| 久久精品在线免费视频| 国产欧美日韩免费观看| 成人9ⅰ免费影视网站| 裤袜国产欧美精品一区| 久久亚洲精品一区二区| 精品久久av| 欧美成人伊人久久综合网| 精品一区二区无码| 亚洲国产精品一区二区久久| 欧美成人久久久免费播放| proumb性欧美在线观看| 97超碰人人爽| 日韩视频在线一区二区三区| 最新不卡av| 精品久久久久久久| 精品高清视频| swag国产精品一区二区| 91色精品视频在线| 成人在线爆射| **欧美日韩vr在线| 欧美一卡二卡| 久久久成人的性感天堂| 色综合久久影院| 国产午夜精品全部视频播放| 天堂在线视频免费观看| 欧美一区二区三区公司| 在线观看免费视频一区| 亚洲成人av电影| 欧美国产在线看| 亚洲日本在线视频观看| 午夜黄色福利视频| 国产视频一区不卡| 欧美色图亚洲激情| 91麻豆精品秘密| 亚洲av无码国产精品久久| 99久久综合国产精品| 日韩不卡的av| 国产最新精品免费| 五月天婷婷亚洲| 久色婷婷小香蕉久久| 日韩一级理论片| 青草av.久久免费一区| 欧美视频在线播放一区| 国产精品久久久免费| 国产美女网站在线观看| 午夜影院日韩| 日韩免费毛片视频| 日本在线播放一区二区三区| 激情网站五月天| 久久婷婷激情| 国产aaaaa毛片| 毛片av中文字幕一区二区| 九九热免费在线观看| 国产精品影视在线观看| 无套内谢丰满少妇中文字幕| 国产精品18久久久| 免费网站在线观看黄| 国产乱码字幕精品高清av| 一区二区三区四区影院| 成人黄色777网| 人妻精品久久久久中文字幕| 中文字幕欧美激情| 黄色裸体一级片| 亚洲精品高清在线观看| 日韩高清精品免费观看| 色综合久久综合中文综合网| 波多野结衣电车| 欧美高清hd18日本| 精品国产av鲁一鲁一区| 欧美一区二区人人喊爽| 男人的天堂a在线| 亚洲欧美精品伊人久久| a天堂中文在线| 欧美精品在线极品| 国产福利电影在线播放| 欧美一区二区.| 麻豆久久久久| av资源一区二区| 国产乱码精品一区二区三区四区| 中文字幕中文字幕在线中一区高清| 亚洲精品一二三区区别| 国产v片免费观看| 美女脱光内衣内裤视频久久网站| 在线观看网站黄| 久久久99精品免费观看| 国产三级国产精品国产国在线观看| 午夜视频一区二区| 自拍偷拍第八页| 精品国产百合女同互慰| 国产高清一级毛片在线不卡| 欧美另类在线播放| 日本免费一区二区三区四区| 亚洲自拍偷拍福利| 久草成人资源| 欧美交换配乱吟粗大25p| 麻豆精品网站| 香蕉视频免费网站| 国产精品视频看| 亚洲婷婷综合网| 日韩一区二区精品葵司在线| 国产中文字幕在线看| 欧美激情亚洲自拍| 97精品国产综合久久久动漫日韩| 国产精品制服诱惑| 天天做天天爱天天综合网| 男人天堂1024| 国产成人免费视频网站| 超碰人人人人人人人| 亚洲精一区二区三区| 五月天av在线播放| 日本一区二区三区四区在线视频 | 91视频国产高清| 欧美综合久久| 宅男噜噜噜66国产免费观看| 久久综合狠狠综合久久综合88 | 成人高清免费在线播放| 热99久久精品| 亚洲精品国产动漫| 又粗又黑又大的吊av| 本田岬高潮一区二区三区| 国产真实的和子乱拍在线观看| 日韩一区二区免费在线观看| www免费视频观看在线| 91成人理论电影| 欧美日韩三级电影在线| 99riav国产精品视频| 亚洲一二三级电影| 欧美性受xxxx狂喷水| 久久久久亚洲精品国产| 北条麻妃在线一区二区免费播放| 黄色三级中文字幕| 成人av免费网站| 国产无人区码熟妇毛片多| 亚洲男女性事视频| 欧美精品高清| 视频一区亚洲| 毛片av一区二区| 久久久久亚洲av片无码| 日韩欧美一区在线| 国产精品探花在线| 久久久久久艹| 日韩制服丝袜av| 男人天堂资源网| 91精品国产欧美一区二区成人| 色女人在线视频| 九九九九九精品| 日韩高清不卡在线| 黄色a级片在线观看| 亚洲福利在线播放| 日本欧美日韩| 中文精品一区二区三区| 懂色av中文字幕一区二区三区| 国产成人在线免费观看视频| 国产亚洲精品91在线| 午夜精品久久久久久毛片| 日本免费成人网| 久久综合久色欧美综合狠狠| 中文字幕日本人妻久久久免费| 久久九九国产精品怡红院| 国产伦乱精品| 亚洲黄色av网址| 亚洲一级不卡视频| 国产污视频在线| www.成人av| 狂野欧美性猛交xxxx巴西| 国产精品视频一区二区三| 日韩精品在线观看视频| jizz亚洲女人高潮大叫| 国产女教师bbwbbwbbw| 久久久久88色偷偷免费| 国产日韩免费视频| 日本成人激情视频| 亚洲精品网址| 深爱五月激情网| 日韩精品一区二区三区中文不卡| av资源亚洲| 国产91沈先生在线播放| 欧美高清在线视频| 天天操天天射天天舔| 91久久久亚洲精品| 麻豆精品网站| 久久精品久久国产| 久久久av网站| 狠狠操综合网|