In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-21 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
In this issue, the editor will bring you about how to achieve the concurrent red packet function of springboot+websocket. The article is rich in content and analyzes and describes for you from a professional point of view. I hope you can get something after reading this article.
Overview
The red packet grabbing function is typical in several high concurrency scenarios, how should it be implemented?
Analysis.
With reference to Wechat's red packet grabbing function, the red packet grab is divided into the following steps:
Send red packets; mainly fill in the red packet information to generate red packet records
Callback of red packet payment; after the user successfully sends out the red packet payment, the user receives the callback of WeChat Pay payment successfully and generates the specified number of red packets.
Grab the red packet; the user simultaneously grab the red packet.
Open red packets; record the amount of red packets grabbed by users and transferred.
Effect display
The project uses sessionId to simulate users, and the example opens two browser windows to simulate two users.
Design, publication, structural design
The red packet is recorded in the redpacket table and the details of the red packet received by the user are recorded in the redpacket_detail table.
CREATE DATABASE `redpacket`; use `redpacket` CREATE TABLE `redpacket`.`redpacket` (`id`packet_ (20) NOT NULL AUTO_INCREMENT COMMENT 'primary key ID', `packet_ no`varchar (32) NOT NULL COMMENT' order number', `amount `decimal (5penny 2) NOT NULL COMMENT'up to 10000.00 yuan in red packet amount', `num`int (11) NOT NULL COMMENT 'red packet quantity', `order_ status`int (4) NOT NULL DEFAULT'0' COMMENT 'order status: 0 initial, 1 pending payment, 2 payment successful, 3 cancellation' `pay_ seq` varchar (32) DEFAULT NULL COMMENT 'payment serial number', `create_ datetime NOT NULL COMMENT 'creation time', `user_ id` NOT NULL COMMENT 'user ID', `update_ time`datetime NOT NULL COMMENT' update time', `pay_ time` datetime DEFAULT NULL COMMENT 'payment time', PRIMARY KEY (`id`) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' red packet order table' CREATE TABLE `redpacket`.`redpacket _ detail` (`id`packet_ (20) NOT NULL AUTO_INCREMENT COMMENT 'key ID', `packet_ id`bigint (20) NOT NULL COMMENT' red packet ID', `amount decimal (5Power2) NOT NULL COMMENT 'red packet amount', `received`int (1) NOT NULL DEFAULT'0' COMMENT 'whether 0 is not received, 1 has been received', `create_ time`datetime NOT NULL COMMENT 'creation time', `update_ time`datetime NOT NULL COMMENT 'update time `user_ id` varchar (32) DEFAULT NULL COMMENT 'pick up user', `packet_ no` varchar (32) NOT NULL, PRIMARY KEY (`id`) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' red packet details table' Design of sending red packets
Users need to fill in the amount of red packets, the number of red packets, remarks, etc., generate red packet records, Wechat cashier to issue an order, return to the user to pay.
Public RedPacket generateRedPacket (ReqSendRedPacketsVO data,String userId) {final BigDecimal amount = data.getAmount (); / / number of red packets final Integer num = data.getNum (); / / initial order final RedPacket redPacket = new RedPacket (); redPacket.setPacketNo (UUID.randomUUID (). ToString (). Replace ("-", ")); redPacket.setAmount (amount); redPacket.setNum (num); redPacket.setUserId (userId); Date now = new Date () RedPacket.setCreateTime (now); redPacket.setUpdateTime (now); int I = redPacketMapper.insertSelective (redPacket); if (I! = 1) {throw new ServiceException ("error generating red packet", ExceptionType.SYS_ERR);} / / simulated cashier to issue an order String paySeq = UUID.randomUUID () .toString () .replace ("-", "") / get the result of issuing the order at the cashier and update the order to be paid redPacket.setOrderStatus (1); / / redPacket.setPaySeq (paySeq) to be paid; I = redPacketMapper.updateByPrimaryKeySelective (redPacket); if (I! = 1) {throw new ServiceException ("error generating red packet", ExceptionType.SYS_ERR);} return redPacket;}
Successful callback design of red packet payment
After the user pays successfully, the system receives the Wechat callback interface.
Update red packet payment status
The specified number of red packets are generated by the double mean method and stored in batches. Red packet algorithm reference: Java implements four red packet snatching algorithms for Wechat
The total number of red packets is added to redis, and the expiration time of red packets is set to 24 hours.
Websocket notifies online users to receive new red packets
@ Transactional (rollbackFor = Exception.class) public void dealAfterOrderPayCallback (String userId,ReqOrderPayCallbackVO data) {RedPacketExample example = new RedPacketExample (); final String packetNo = data.getPacketNo (); final String paySeq = data.getPaySeq (); final Integer payStatus = data.getPayStatus (); example.createCriteria (). AndPacketNoEqualTo (packetNo) .andPaySeqEqualTo (paySeq) .andOrderStatusEqualTo (1); / / pending payment status / / updating order payment status Date now = new Date () RedPacket updateRedPacket = new RedPacket (); updateRedPacket.setOrderStatus (payStatus); updateRedPacket.setUpdateTime (now); updateRedPacket.setPayTime (now); int I = redPacketMapper.updateByExampleSelective (updateRedPacket, example); if (I! = 1) {throw new ServiceException ("order status update failed", ExceptionType.SYS_ERR);} if (payStatus = = 2) {RedPacketExample query = new RedPacketExample () Query.createCriteria (). AndPacketNoEqualTo (packetNo) .andPaySeqEqualTo (paySeq) .andOrderStatusEqualTo (2); final RedPacket redPacket = redPacketMapper.selectByExample (query) .get (0); final List detailList = getRedPacketDetail (redPacket.getAmount (), redPacket.getNum ()); final int size = detailList.size (); if (size size-1) {toIndex = size-1 } final List subList = detailList.subList (fromIndex, toIndex); I = detailMapper.batchInsert (subList, redPacket); if (subList.size ()! = I) {throw new ServiceException ("failed to generate red packets", ExceptionType.SYS_ERR) } final String redisKey = REDPACKET_NUM_PREFIX + redPacket.getPacketNo () String lua = "local I = redis.call ('setnx',KEYS [1], ARGV [1])\ r\ n" + "if I = = 1 then\ r\ n" + "local j = redis.call (' expire',KEYS [1], ARGV [2])\ r\ n" + "end\ r\ n" + "return I" / / optimized into lua script final Long execute = redisTemplate.execute (new DefaultRedisScript (lua, Long.class), Arrays.asList (redisKey), size, 3600 * 24); if (execute! = 1L) {throw new ServiceException ("failed to generate red packets", ExceptionType.SYS_ERR);} / / websocket notifies online users of new red packets Websocket.sendMessageToUser (userId, JSONObject.toJSONString (redPacket)) }} / * Red packet Random algorithm * * @ param amount Red packet amount * @ param num Red packet amount * @ return Random Red packet set * / private List getRedPacketDetail (BigDecimal amount, Integer num) {List redPacketsList = new ArrayList (num); / / minimum red packet amount final BigDecimal min = new BigDecimal; / / minimum red packet amount final BigDecimal bigNum = new BigDecimal (num) Final BigDecimal atLastAmount = min.multiply (bigNum); / / the remaining amount after the minimum red packet amount BigDecimal remain = amount.subtract (atLastAmount); if (remain.compareTo (BigDecimal.ZERO) = = 0) {for (int I = 0; I)
< num; i++) { redPacketsList.add(min); } return redPacketsList; } final Random random = new Random(); final BigDecimal hundred = new BigDecimal("100"); final BigDecimal two = new BigDecimal("2"); BigDecimal redPacket; for (int i = 0; i < num; i++) { if (i == num - 1) { redPacket = remain; } else { //100内随机获得的整数 final int rand = random.nextInt(100); redPacket = new BigDecimal(rand).multiply(remain.multiply(two).divide(bigNum.subtract(new BigDecimal(i)), 2, RoundingMode.CEILING)).divide(hundred, 2, RoundingMode.FLOOR); } if (remain.compareTo(redPacket) >0) {remain = remain.subtract (redPacket);} else {remain = BigDecimal.ZERO;} redPacketsList.add (min.add (redPacket));} return redPacketsList;}
Initialize the websocket after the page is loaded successfully, monitor the new red packet generated at the backend, and dynamically add the red packet to the chat window.
$(function () {var websocket; if ('WebSocket' in window) {console.log ("this browser supports websocket"); websocket = new WebSocket ("ws://127.0.0.1:8082/websocket/$ {session.id}");} else if (' MozWebSocket' in window) {alert ("this browser only supports MozWebSocket");} else {alert ("this browser only supports SockJS") } websocket.onopen = function (evnt) {console.log ("Link server succeeded!")}; websocket.onmessage = function (evnt) {console.log (evnt.data); var json = eval ('('+ evnt.data+')'); obj.addPacket (json.id,json.packetNo,json.userId)}; websocket.onerror = function (evnt) {} Websocket.onclose = function (evnt) {console.log ("disconnected from the server!")}); red packet design
Grab red packet design high concurrency, local stand-alone project, through atomic Integer control to grab red packet interface concurrency limit to 20
Private AtomicInteger receiveCount = new AtomicInteger (0); @ PostMapping ("/ receive") public CommonJsonResponse receiveOne (@ Validated @ RequestBody CommonJsonRequest vo) {Integer num = null; try {/ / Control concurrency no more than 20 if (receiveCount.get () > 20) {return new CommonJsonResponse ("9999", "too fast");} num = receiveCount.incrementAndGet (); final String s = orderService.receiveOne (vo.getData ()) Return StringUtils.isEmpty (s)? CommonJsonResponse.ok (): new CommonJsonResponse ("9999", s);} finally {if (num! = null) {receiveCount.decrementAndGet ();}
For users who have not received the red packet, if the red packet does not expire and there are any remaining red packets, if the red packet is successfully snatched, the record is successfully marked into redis, and the expiration time of the logo is set to 5 seconds.
Public String receiveOne (ReqReceiveRedPacketVO data) {final Long redPacketId = data.getPacketId (); final String redPacketNo = data.getPacketNo (); final String redisKey = REDPACKET_NUM_PREFIX + redPacketNo; if (! redisTemplate.hasKey (redisKey)) {return "red packet expired";} final Integer num = (Integer) redisTemplate.opsForValue (). Get (redisKey); if (num {final JSONObject packetDetail = (JSONObject) item Return ReceiveRecordVO.builder () .amount (packetDetail.getBigDecimal ("amount")) .receiveTime (packetDetail.getDate ("updateTime")) .UserID (packetDetail.getString ("userId")) .packetId (packetDetail.getLong ("redpacketId")) .packetNo (packetDetail.getString ("redpacketNo")) .build () Collectors.toList (); return RespReceiveListVO.builder (). List ((List) collect). Build ();} jmeter concurrent testing grabs red packets and looks up red packet interfaces
Set the jmeter parameter for 50 concurrent requests to grab 11 red packets in 1 second. You can see that all the previous requests were successful, and some of them reached the concurrency limit after the concurrency came up, and all the requests failed after the red packets were grabbed.
The above is the springboot+websocket shared by the editor how to achieve the concurrent red packet function. If you happen to have similar doubts, you might as well refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.