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

网友投稿 262 2022-09-01

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

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

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 * */@RestController@RequestMapping("/redis")public class RedisController { @Resource private RedisTemplate 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; // NOTE:直接SETNX不支持带过期时间,所以设置+过期不是原子操作,极端情况下可能设置了就不过期了,后面相同请求可能会误以为需要去重,所以这里使用底层API,保证SETNX+过期时间是原子操作 Boolean firstSet = stringRedisTemplate.execute( (RedisCallback) connection -> connection.set(KEY.getBytes(), val.getBytes(), Expiration.milliseconds(expireTime), RedisStringCommands.SetOption.SET_IF_ABSENT)); final boolean isConsiderDup; if (firstSet != null && firstSet) { return book; } else { return "订单重复!"; } }}

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; @Slf4jpublic 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 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); }}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Redis 如何实现库存扣减操作?如何防止商品被超卖?
下一篇:推荐一个超级简单 Java 图形验证码模块
相关文章

 发表评论

暂时没有评论,来抢沙发吧~