springboot整合redis解决订单重复请求的问题

实现思路:将请求的json数据,去除一些可变字段,将key升序排序,拼接成字符串并进行md5加密,再拼接一些用户信息,这样相同的请求参数得到的加密串必然一致,将此字符串作为key,存入redis,设置过期时间为1秒,一般重复提交都是在1000ms以内;

代码部分
package com.wang.learn.cloudredis.controller;

import com.alibaba.fastjson.JSONObject;
import com.wang.learn.cloudredis.entity.Book;
import com.wang.learn.cloudredis.utils.ReqDedupHelper;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;

/**
 * ClassName RedisController
 * Description
 *
 * @author wang
 * Date 2021/6/19 10:48
 */
@RestController
@RequestMapping("/redis")
public class RedisController {


    @Resource
    private RedisTemplate<String, Object> stringRedisTemplate;

    @RequestMapping("/repeat")
    public Object repeat(@RequestBody @Valid Book book){
        //用户
        String userId= "12345678";
        //接口名
        String method = "pay";
        //计算请求参数摘要,其中剔除里面请求时间的干扰
        String dedupMD5 = ReqDedupHelper.dedupParamMD5(JSONObject.toJSONString(book),"time");
        String KEY = "dedup:U=" + userId + "M=" + method + "P=" + dedupMD5;
        // 1000毫秒过期,1000ms内的重复请求会认为重复
        long expireTime =  1000;
        long expireAt = System.currentTimeMillis() + expireTime;

        String val = "expireAt@" + expireAt;
        // 如果key不存在,set并返回true;如果key存在,不做操作返回false
        Boolean firstSet = stringRedisTemplate.opsForValue().setIfAbsent(key, val, expireTime, TimeUnit.MILLISECONDS);

        final boolean isConsiderDup;
        if (firstSet != null && firstSet) {
            return book;
        } else {
            return "订单重复!";
        }
    }

}

package com.wang.learn.cloudredis.utils;

import com.alibaba.fastjson.JSON;
import com.wang.learn.cloudredis.entity.Book;
import lombok.extern.slf4j.Slf4j;

import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;

/**
 * ClassName Req
 * Description
 *
 * @author wang
 * Date 2021/6/19 10:29
 */
@Slf4j
public class ReqDedupHelper {

    /**
     *
     * @param reqJSON 请求的参数,这里通常是JSON
     * @param excludeKeys 请求参数里面要去除哪些字段再求摘要(如时间戳字段)
     * @return 去除参数的MD5摘要
     */
    public static String dedupParamMD5(final String reqJSON, String... excludeKeys) {
        String decreptParam = reqJSON;

        TreeMap paramTreeMap = JSON.parseObject(decreptParam, TreeMap.class);
        if (excludeKeys!=null) {
            List<String> dedupExcludeKeys = Arrays.asList(excludeKeys);
            if (!dedupExcludeKeys.isEmpty()) {
                for (String dedupExcludeKey : dedupExcludeKeys) {
                    if(paramTreeMap.containsKey(dedupExcludeKey)){
                        paramTreeMap.remove(dedupExcludeKey);
                    }
                }
            }
        }

        String paramTreeMapJSON = JSON.toJSONString(paramTreeMap);
        String md5deDupParam = jdkMD5(paramTreeMapJSON);
        log.debug("md5deDupParam = {}, excludeKeys = {} {}", md5deDupParam, Arrays.deepToString(excludeKeys), paramTreeMapJSON);
        return md5deDupParam;
    }

    private static String jdkMD5(String src) {
        String res = null;
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            byte[] mdBytes = messageDigest.digest(src.getBytes());
            res = DatatypeConverter.printHexBinary(mdBytes);
        } catch (Exception e) {
            log.error("",e);
        }
        return res;
    }

    public static void main(String[] args) {
        Book book = new Book();
        book.setId(1);
        book.setCount(2);
        book.setName("java编程思想");
        book.setTime(System.currentTimeMillis());

        String key = dedupParamMD5(JSON.toJSONString(book), "time", "456");
        System.out.println(key);


    }

}

源码参考 https://gitee.com/wangLi1997/spring-cloud-learn cloud-redis模块

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宁漂打工仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值