From 51bb8b2c9be1393f2ff2918531a4ab53c22f00ed Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Wed, 10 Jun 2026 18:15:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 38 ++ .idea/.gitignore | 3 + .idea/dbnavigator.xml | 439 ++++++++++++++++++ .idea/encodings.xml | 7 + .idea/misc.xml | 14 + .idea/vcs.xml | 6 + pom.xml | 60 +++ .../java/org/example/SecKillApplication.java | 11 + .../example/controller/SeckillController.java | 62 +++ .../org/example/service/OrderConsumer.java | 18 + src/main/resources/application.yml | 14 + 11 files changed, 672 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/dbnavigator.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/org/example/SecKillApplication.java create mode 100644 src/main/java/org/example/controller/SeckillController.java create mode 100644 src/main/java/org/example/service/OrderConsumer.java create mode 100644 src/main/resources/application.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml new file mode 100644 index 0000000..8bb45cc --- /dev/null +++ b/.idea/dbnavigator.xml @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..82dbec8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5a734cd --- /dev/null +++ b/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.1 + + + + org.example + seckill + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.apache.rocketmq + rocketmq-spring-boot-starter + 2.3.6 + + + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/src/main/java/org/example/SecKillApplication.java b/src/main/java/org/example/SecKillApplication.java new file mode 100644 index 0000000..3af383f --- /dev/null +++ b/src/main/java/org/example/SecKillApplication.java @@ -0,0 +1,11 @@ +package org.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SecKillApplication { + public static void main(String[] args) { + SpringApplication.run(SecKillApplication.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/controller/SeckillController.java b/src/main/java/org/example/controller/SeckillController.java new file mode 100644 index 0000000..c7d8a03 --- /dev/null +++ b/src/main/java/org/example/controller/SeckillController.java @@ -0,0 +1,62 @@ +package org.example.controller; + +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +@RestController +@RequestMapping("/seckill") +public class SeckillController { + + @Autowired + private StringRedisTemplate redis; + + @Autowired + private RocketMQTemplate rocketMQTemplate; + + private final Semaphore semaphore = new Semaphore(100); + + @PostMapping("/{userId}") + public ResponseEntity seckill(@PathVariable Integer userId) throws InterruptedException { + + // 1. 限流 + if (!semaphore.tryAcquire()) { + System.out.println("用户:" + userId + " 秒杀结果:系统繁忙"); + return ResponseEntity.status(200).body("系统繁忙"); + } + + try { + // 2. 防刷 + String userKey = "seckill:user:" + userId; + Boolean first = redis.opsForValue().setIfAbsent(userKey, "1", 60, TimeUnit.SECONDS); + if (Boolean.FALSE.equals(first)) { + // System.out.println("用户:" + userId + " 秒杀结果:请勿重复尝试"); + return ResponseEntity.status(200).body("请勿重复尝试"); + } + + // 3. 扣库存 + String stockKey = "seckill:stock:1"; + Long remain = redis.opsForValue().decrement(stockKey); + if (remain == null || remain < 0) { + redis.opsForValue().increment(stockKey); + System.out.println("用户:" + userId + " 秒杀结果:已售罄"); + return ResponseEntity.status(200).body("已售罄"); + } + + // 4. 发消息 + rocketMQTemplate.convertAndSend("seckill-order", Map.of("userId", userId, "goodsId", 1)); + + System.out.println("用户:" + userId + " 秒杀结果:秒杀成功"); + return ResponseEntity.status(200).body("秒杀成功"); + + } finally { + semaphore.release(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/service/OrderConsumer.java b/src/main/java/org/example/service/OrderConsumer.java new file mode 100644 index 0000000..87e48c8 --- /dev/null +++ b/src/main/java/org/example/service/OrderConsumer.java @@ -0,0 +1,18 @@ +package org.example.service; + +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RocketMQMessageListener(topic = "seckill-order", consumerGroup = "seckill-consumer") +public class OrderConsumer implements RocketMQListener { + + @Override + public void onMessage(Map msg) { + System.out.println("收到订单:" + msg); + // 后期写 DB + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..a40f1ed --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,14 @@ +server: + port: 8080 + +spring: + data: + redis: + host: 192.168.1.100 + port: 6379 + password: medical@2019 + +rocketmq: + name-server: 192.168.1.100:9876 + producer: + group: seckill-producer-group \ No newline at end of file