From c4129ae13d130f584137459afb6b3d0c64f3f6a5 Mon Sep 17 00:00:00 2001 From: renfuji Date: Thu, 6 Nov 2025 19:58:42 +0800 Subject: [PATCH] CN.916374046380324:e708029d9995f1858774a2eda60931fa_690b48cca591e01fed51cbe9.690b57daa591e01fed51cc87.690b57daf9d72f3c94b9271d:Trae CN.T(2025/11/5 21:57:46) --- .../secondskill/common/MockConfig.java | 17 + .../common/RedisPreheatRunner.java | 8 +- .../common/StockWithRedis/StockWithRedis.java | 10 +- .../stockWithRedis/RedisKeysConstant.java | 2 +- .../common/utils/MockRedisPoolUtil.java | 111 ++++ .../controller/AdminController.java | 137 +++++ .../secondskill/dao/StockMapper.java | 19 +- .../secondskill/pojo/DeviceFingerprint.java | 29 + .../daydreamdev/secondskill/pojo/Stock.java | 2 + .../secondskill/service/api/StockService.java | 22 + .../service/impl/OrderServiceImpl.java | 11 +- .../service/impl/StockServiceImpl.java | 21 +- .../resources/application-prod.properties | 32 ++ .../resources/application-test.properties | 33 ++ src/main/resources/static/admin.html | 504 ++++++++++++++++++ src/main/resources/static/seckill.html | 213 ++++++++ 16 files changed, 1148 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/daydreamdev/secondskill/common/MockConfig.java create mode 100644 src/main/java/com/daydreamdev/secondskill/common/utils/MockRedisPoolUtil.java create mode 100644 src/main/java/com/daydreamdev/secondskill/controller/AdminController.java create mode 100644 src/main/java/com/daydreamdev/secondskill/pojo/DeviceFingerprint.java create mode 100644 src/main/resources/application-prod.properties create mode 100644 src/main/resources/application-test.properties create mode 100644 src/main/resources/static/admin.html create mode 100644 src/main/resources/static/seckill.html diff --git a/src/main/java/com/daydreamdev/secondskill/common/MockConfig.java b/src/main/java/com/daydreamdev/secondskill/common/MockConfig.java new file mode 100644 index 0000000..bf1a285 --- /dev/null +++ b/src/main/java/com/daydreamdev/secondskill/common/MockConfig.java @@ -0,0 +1,17 @@ +package com.daydreamdev.secondskill.common; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +/** + * Mock配置类 + * 当配置文件中mock.enabled=true时生效 + * @auther G.Fukang + * @date 6/10 14:36 + */ +@Configuration +@ConditionalOnProperty(name = "mock.enabled", havingValue = "true") +public class MockConfig { + // 可以在这里配置mock相关的bean +} \ No newline at end of file diff --git a/src/main/java/com/daydreamdev/secondskill/common/RedisPreheatRunner.java b/src/main/java/com/daydreamdev/secondskill/common/RedisPreheatRunner.java index 676d773..68f6c7d 100644 --- a/src/main/java/com/daydreamdev/secondskill/common/RedisPreheatRunner.java +++ b/src/main/java/com/daydreamdev/secondskill/common/RedisPreheatRunner.java @@ -1,6 +1,6 @@ package com.daydreamdev.secondskill.common; -import com.daydreamdev.secondskill.common.stockWithRedis.RedisKeysConstant; +import com.daydreamdev.secondskill.common.StockWithRedis.RedisKeysConstant; import com.daydreamdev.secondskill.common.utils.RedisPoolUtil; import com.daydreamdev.secondskill.pojo.Stock; import com.daydreamdev.secondskill.service.api.StockService; @@ -26,9 +26,9 @@ public void run(ApplicationArguments args) throws Exception { Stock stock = stockService.getStockById(1); // 删除旧缓存 - RedisPoolUtil.del(RedisKeysConstant.STOCK_COUNT + stock.getCount()); - RedisPoolUtil.del(RedisKeysConstant.STOCK_SALE + stock.getSale()); - RedisPoolUtil.del(RedisKeysConstant.STOCK_VERSION + stock.getVersion()); + RedisPoolUtil.del(RedisKeysConstant.STOCK_COUNT + stock.getId()); + RedisPoolUtil.del(RedisKeysConstant.STOCK_SALE + stock.getId()); + RedisPoolUtil.del(RedisKeysConstant.STOCK_VERSION + stock.getId()); //缓存预热 int sid = stock.getId(); RedisPoolUtil.set(RedisKeysConstant.STOCK_COUNT + sid, String.valueOf(stock.getCount())); diff --git a/src/main/java/com/daydreamdev/secondskill/common/StockWithRedis/StockWithRedis.java b/src/main/java/com/daydreamdev/secondskill/common/StockWithRedis/StockWithRedis.java index d09c326..c93d7b6 100644 --- a/src/main/java/com/daydreamdev/secondskill/common/StockWithRedis/StockWithRedis.java +++ b/src/main/java/com/daydreamdev/secondskill/common/StockWithRedis/StockWithRedis.java @@ -1,4 +1,4 @@ -package com.daydreamdev.secondskill.common.stockWithRedis; +package com.daydreamdev.secondskill.common.StockWithRedis; import com.daydreamdev.secondskill.common.utils.RedisPool; import com.daydreamdev.secondskill.common.utils.RedisPoolUtil; @@ -26,10 +26,10 @@ public static void updateStockWithRedis(Stock stock) { jedis = RedisPool.getJedis(); // 开始事务 Transaction transaction = jedis.multi(); - // 事务操作 - RedisPoolUtil.decr(RedisKeysConstant.STOCK_COUNT + stock.getId()); - RedisPoolUtil.incr(RedisKeysConstant.STOCK_SALE + stock.getId()); - RedisPoolUtil.incr(RedisKeysConstant.STOCK_VERSION + stock.getId()); + // 事务操作:直接使用同一个Jedis实例执行命令 + transaction.decr(RedisKeysConstant.STOCK_COUNT + stock.getId()); + transaction.incr(RedisKeysConstant.STOCK_SALE + stock.getId()); + transaction.incr(RedisKeysConstant.STOCK_VERSION + stock.getId()); // 结束事务 List list = transaction.exec(); } catch (Exception e) { diff --git a/src/main/java/com/daydreamdev/secondskill/common/stockWithRedis/RedisKeysConstant.java b/src/main/java/com/daydreamdev/secondskill/common/stockWithRedis/RedisKeysConstant.java index 92133fa..bfa62ff 100644 --- a/src/main/java/com/daydreamdev/secondskill/common/stockWithRedis/RedisKeysConstant.java +++ b/src/main/java/com/daydreamdev/secondskill/common/stockWithRedis/RedisKeysConstant.java @@ -1,4 +1,4 @@ -package com.daydreamdev.secondskill.common.stockWithRedis; +package com.daydreamdev.secondskill.common.StockWithRedis; /** * @auther G.Fukang diff --git a/src/main/java/com/daydreamdev/secondskill/common/utils/MockRedisPoolUtil.java b/src/main/java/com/daydreamdev/secondskill/common/utils/MockRedisPoolUtil.java new file mode 100644 index 0000000..e40f716 --- /dev/null +++ b/src/main/java/com/daydreamdev/secondskill/common/utils/MockRedisPoolUtil.java @@ -0,0 +1,111 @@ +package com.daydreamdev.secondskill.common.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Redis工具类的Mock实现 + * 用于测试环境,模拟Redis的基本操作 + * @auther G.Fukang + * @date 6/10 15:36 + */ +@Slf4j +public class MockRedisPoolUtil { + + private static Map mockRedis = new HashMap<>(); + + /** + * 设置 key - value 值 + * + * @param key + * @param value + */ + public static String set(String key, String value) { + log.info("Mock Redis set key:{} value:{}", key, value); + mockRedis.put(key, value); + return "OK"; + } + + /** + * 获取 key - value 值 + * + * @param key + */ + public static String get(String key) { + log.info("Mock Redis get key:{}", key); + return mockRedis.get(key); + } + + /** + * 删除 key - value 值 + * + * @param key + */ + public static Long del(String key) { + log.info("Mock Redis del key:{}", key); + if (mockRedis.remove(key) != null) { + return 1L; + } + return 0L; + } + + /** + * key - value 自增 + */ + public static Long incr(String key) { + log.info("Mock Redis incr key:{}", key); + String value = mockRedis.get(key); + long num = 0; + if (value != null) { + num = Long.parseLong(value); + } + num++; + mockRedis.put(key, String.valueOf(num)); + return num; + } + + /** + * key - value 自减 + */ + public static Long decr(String key) { + log.info("Mock Redis decr key:{}", key); + String value = mockRedis.get(key); + long num = 0; + if (value != null) { + num = Long.parseLong(value); + } + num--; + mockRedis.put(key, String.valueOf(num)); + return num; + } + + /** + * List - get 操作 + */ + public static List listGet(String key) { + log.info("Mock Redis listGet key:{}", key); + // 简单模拟list操作 + String value = mockRedis.get(key); + List result = new ArrayList<>(); + if (value != null) { + result.add(value); + } + return result; + } + + /** + * List - put 操作 + */ + public static Long listPut(String key, String count, String sale, String version) { + log.info("Mock Redis listPut key:{}, count:{}, sale:{}, version:{}", key, count, sale, version); + // 简单模拟list操作 + mockRedis.put(key + "_count", count); + mockRedis.put(key + "_sale", sale); + mockRedis.put(key + "_version", version); + return 3L; + } +} \ No newline at end of file diff --git a/src/main/java/com/daydreamdev/secondskill/controller/AdminController.java b/src/main/java/com/daydreamdev/secondskill/controller/AdminController.java new file mode 100644 index 0000000..b116891 --- /dev/null +++ b/src/main/java/com/daydreamdev/secondskill/controller/AdminController.java @@ -0,0 +1,137 @@ +package com.daydreamdev.secondskill.controller; + +import com.daydreamdev.secondskill.pojo.Stock; +import com.daydreamdev.secondskill.service.api.StockService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; + +/** + * 后台管理系统控制器 + * @auther G.Fukang + * @date 6/7 15:36 + */ +@Slf4j +@Controller +@RequestMapping(value = "/admin") +public class AdminController { + + private static final String success = "SUCCESS"; + private static final String error = "ERROR"; + + @Autowired + private StockService stockService; + + /** + * 获取所有商品列表 + * @return List + */ + @RequestMapping(value = "/product", method = RequestMethod.GET) + @ResponseBody + public List getAllProducts() { + try { + return stockService.getAllStocks(); + } catch (Exception e) { + log.error("Exception: ", e); + return null; + } + } + + /** + * 添加商品 + * @param stock + * @return String + */ + @RequestMapping(value = "/product", method = RequestMethod.POST) + @ResponseBody + public String addProduct(@RequestBody Stock stock) { + try { + // 设置默认状态为上架 + if (stock.getStatus() == null) { + stock.setStatus(1); + } + // 设置初始销量为0 + if (stock.getSale() == null) { + stock.setSale(0); + } + // 设置初始版本号为0 + if (stock.getVersion() == null) { + stock.setVersion(0); + } + int res = stockService.addStock(stock); + return res == 1 ? success : error; + } catch (Exception e) { + log.error("Exception: ", e); + return error; + } + } + + /** + * 更新商品状态(上架/下架) + * @param id + * @param status + * @return String + */ + @RequestMapping(value = "/product/status", method = RequestMethod.PUT) + @ResponseBody + public String updateProductStatus(int id, int status) { + try { + Stock stock = stockService.getStockById(id); + if (stock == null) { + return error; + } + stock.setStatus(status); + int res = stockService.updateStockById(stock); + return res == 1 ? success : error; + } catch (Exception e) { + log.error("Exception: ", e); + return error; + } + } + + /** + * 更新商品库存 + * @param id + * @param count + * @return String + */ + @RequestMapping(value = "/stock", method = RequestMethod.PUT) + @ResponseBody + public String updateStock(int id, int count) { + try { + Stock stock = stockService.getStockById(id); + if (stock == null) { + return error; + } + stock.setCount(count); + int res = stockService.updateStockById(stock); + return res == 1 ? success : error; + } catch (Exception e) { + log.error("Exception: ", e); + return error; + } + } + + /** + * 删除商品 + * @param id + * @return String + */ + @RequestMapping(value = "/product", method = RequestMethod.DELETE) + @ResponseBody + public String deleteProduct(int id) { + try { + int res = stockService.deleteStockById(id); + return res == 1 ? success : error; + } catch (Exception e) { + log.error("Exception: ", e); + return error; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/daydreamdev/secondskill/dao/StockMapper.java b/src/main/java/com/daydreamdev/secondskill/dao/StockMapper.java index b330c9c..d66703e 100644 --- a/src/main/java/com/daydreamdev/secondskill/dao/StockMapper.java +++ b/src/main/java/com/daydreamdev/secondskill/dao/StockMapper.java @@ -1,10 +1,9 @@ package com.daydreamdev.secondskill.dao; import com.daydreamdev.secondskill.pojo.Stock; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.annotations.*; + +import java.util.List; /** * @auther G.Fukang @@ -22,11 +21,21 @@ public interface StockMapper { @Select("SELECT * FROM stock WHERE id = #{id, jdbcType = INTEGER}") Stock selectByPrimaryKey(@Param("id") int id); + @Select("SELECT * FROM stock") + List selectAll(); + + @Insert("INSERT INTO stock (name, count, sale, version, status) VALUES " + + "(#{name, jdbcType = VARCHAR}, #{count, jdbcType = INTEGER}, #{sale, jdbcType = INTEGER}, #{version, jdbcType = INTEGER}, #{status, jdbcType = INTEGER})") + int insertSelective(Stock stock); + @Update("UPDATE stock SET count = #{count, jdbcType = INTEGER}, name = #{name, jdbcType = VARCHAR}, " + - "sale = #{sale,jdbcType = INTEGER},version = #{version,jdbcType = INTEGER} " + + "sale = #{sale,jdbcType = INTEGER},version = #{version,jdbcType = INTEGER}, status = #{status, jdbcType = INTEGER} " + "WHERE id = #{id, jdbcType = INTEGER}") int updateByPrimaryKeySelective(Stock stock); + @Delete("DELETE FROM stock WHERE id = #{id, jdbcType = INTEGER}") + int deleteByPrimaryKey(@Param("id") int id); + /** * 乐观锁 version */ diff --git a/src/main/java/com/daydreamdev/secondskill/pojo/DeviceFingerprint.java b/src/main/java/com/daydreamdev/secondskill/pojo/DeviceFingerprint.java new file mode 100644 index 0000000..2613409 --- /dev/null +++ b/src/main/java/com/daydreamdev/secondskill/pojo/DeviceFingerprint.java @@ -0,0 +1,29 @@ +package com.daydreamdev.secondskill.pojo; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * 设备指纹实体类 + * 用于记录用户设备信息 + * @auther G.Fukang + * @date 6/10 16:36 + */ +@Getter +@Setter +public class DeviceFingerprint { + + private Long id; + private String userId; + private String deviceId; + private String deviceType; + private String os; + private String browser; + private String ipAddress; + private String userAgent; + private String networkType; + private Date createTime; + private Date updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/daydreamdev/secondskill/pojo/Stock.java b/src/main/java/com/daydreamdev/secondskill/pojo/Stock.java index d729a72..8f51d8e 100644 --- a/src/main/java/com/daydreamdev/secondskill/pojo/Stock.java +++ b/src/main/java/com/daydreamdev/secondskill/pojo/Stock.java @@ -20,4 +20,6 @@ public class Stock { private Integer sale; private Integer version; + + private Integer status; // 0: 下架, 1: 上架 } diff --git a/src/main/java/com/daydreamdev/secondskill/service/api/StockService.java b/src/main/java/com/daydreamdev/secondskill/service/api/StockService.java index 5a77e0d..c895f96 100644 --- a/src/main/java/com/daydreamdev/secondskill/service/api/StockService.java +++ b/src/main/java/com/daydreamdev/secondskill/service/api/StockService.java @@ -2,6 +2,8 @@ import com.daydreamdev.secondskill.pojo.Stock; +import java.util.List; + /** * @auther G.Fukang * @date 6/7 12:35 @@ -22,6 +24,19 @@ public interface StockService { */ Stock getStockById(int id); + /** + * 查询所有商品 + * @return List + */ + List getAllStocks(); + + /** + * 添加商品 + * @param stock + * @return int + */ + int addStock(Stock stock); + /** * 根据 id 更新库存信息 * @param stock @@ -29,6 +44,13 @@ public interface StockService { */ int updateStockById(Stock stock); + /** + * 根据 id 删除商品 + * @param id + * @return int + */ + int deleteStockById(int id); + /** * 乐观锁更新库存,解决超卖问题 */ diff --git a/src/main/java/com/daydreamdev/secondskill/service/impl/OrderServiceImpl.java b/src/main/java/com/daydreamdev/secondskill/service/impl/OrderServiceImpl.java index be89dda..69dda26 100644 --- a/src/main/java/com/daydreamdev/secondskill/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/daydreamdev/secondskill/service/impl/OrderServiceImpl.java @@ -1,7 +1,7 @@ package com.daydreamdev.secondskill.service.impl; -import com.daydreamdev.secondskill.common.stockWithRedis.RedisKeysConstant; -import com.daydreamdev.secondskill.common.stockWithRedis.StockWithRedis; +import com.daydreamdev.secondskill.common.StockWithRedis.RedisKeysConstant; +import com.daydreamdev.secondskill.common.StockWithRedis.StockWithRedis; import com.daydreamdev.secondskill.common.utils.RedisPoolUtil; import com.daydreamdev.secondskill.dao.StockOrderMapper; import com.daydreamdev.secondskill.pojo.Stock; @@ -57,13 +57,16 @@ public int createWrongOrder(int sid) throws Exception { @Override public int createOptimisticOrder(int sid) throws Exception { + log.info("开始处理秒杀请求,商品ID: {}", sid); // 校验库存 Stock stock = checkStock(sid); + log.info("库存校验通过,商品ID: {}, 当前库存: {}", sid, stock.getCount()); // 乐观锁更新 saleStockOptimstic(stock); + log.info("库存更新成功,商品ID: {}, 已售数量: {}", sid, stock.getSale() + 1); // 创建订单 int id = createOrder(stock); - + log.info("订单创建成功,商品ID: {}, 订单ID: {}", sid, id); return id; } @@ -141,7 +144,7 @@ private void saleStockOptimsticWithRedis(Stock stock) throws Exception { /** * 校验库存 */ - private Stock checkStock(int sid) throws Exception { +private Stock checkStock(int sid) throws Exception { Stock stock = stockService.getStockById(sid); if (stock.getCount() < 1) { throw new RuntimeException("库存不足"); diff --git a/src/main/java/com/daydreamdev/secondskill/service/impl/StockServiceImpl.java b/src/main/java/com/daydreamdev/secondskill/service/impl/StockServiceImpl.java index 7e31520..dbfc0f6 100644 --- a/src/main/java/com/daydreamdev/secondskill/service/impl/StockServiceImpl.java +++ b/src/main/java/com/daydreamdev/secondskill/service/impl/StockServiceImpl.java @@ -6,6 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; + /** * @auther G.Fukang * @date 6/7 12:45 @@ -24,25 +26,36 @@ public int getStockCount(int id) { @Override public Stock getStockById(int id) { - return stockMapper.selectByPrimaryKey(id); } @Override - public int updateStockById(Stock stock) { + public List getAllStocks() { + return stockMapper.selectAll(); + } + + @Override + public int addStock(Stock stock) { + return stockMapper.insertSelective(stock); + } + @Override + public int updateStockById(Stock stock) { return stockMapper.updateByPrimaryKeySelective(stock); } @Override - public int updateStockByOptimistic(Stock stock) { + public int deleteStockById(int id) { + return stockMapper.deleteByPrimaryKey(id); + } + @Override + public int updateStockByOptimistic(Stock stock) { return stockMapper.updateByOptimistic(stock); } @Override public int initDBBefore() { - return stockMapper.initDBBefore(); } } diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties new file mode 100644 index 0000000..18cbcf1 --- /dev/null +++ b/src/main/resources/application-prod.properties @@ -0,0 +1,32 @@ +# 日志 +logging.file=secondkill.log +logging.level.root=info +logging.level.com.daydreamdev.secondskill=info + +# 数据库 +spring.datasource.url=jdbc:mysql://119.3.214.253:3306/seconds_kill?useUnicode=true&characterEncoding=utf8 +spring.datasource.username=root +spring.datasource.password=123456789qwER# +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource + +# redis 配置 +spring.redis.host=119.3.214.253 +spring.redis.port=6379 +spring.redis.password= +redis.maxIdle=100 +redis.maxTotal=300 +redis.maxWait=10000 +redis.testOnBorrow=true +redis.timeout=100000 +# 限流 +redis.limit=5 + +# kafka +spring.kafka.bootstrap-servers=119.3.214.253:9092 +spring.kafka.consumer.group-id=seconds-kill +spring.kafka.template.default-topic=SECONDS-KILL-TOPIC +spring.kafka.listener.concurrency=3 + +# 关闭mock功能 +mock.enabled=false \ No newline at end of file diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 0000000..9f49011 --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1,33 @@ +# 日志 +logging.file=secondkill.log +logging.level.root=debug +logging.level.com.daydreamdev.secondskill=debug + +# 数据库 - 使用H2内存数据库进行测试 +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.username=sa +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource + +# H2控制台配置 +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +# redis 配置 - 使用mock +spring.redis.host=localhost +spring.redis.port=6379 +spring.redis.password= +redis.maxIdle=100 +redis.maxTotal=300 +redis.maxWait=10000 +redis.testOnBorrow=true +redis.timeout=100000 +# 限流 +redis.limit=5 + +# kafka - 禁用 +spring.kafka.enabled=false + +# 开启mock功能 +mock.enabled=true \ No newline at end of file diff --git a/src/main/resources/static/admin.html b/src/main/resources/static/admin.html new file mode 100644 index 0000000..1341f10 --- /dev/null +++ b/src/main/resources/static/admin.html @@ -0,0 +1,504 @@ + + + + + + 秒杀后台管理系统 + + + +
+
+

秒杀后台管理系统

+

商品管理 | 库存管理 | 订单管理

+
+ + + +
+ +
+

商品管理

+
+ + +
+
+ + +
+
+ + +
+ +
+

商品列表

+ + + + + + + + + + + + + +
ID名称价格状态操作
+
+
+ + +
+

库存管理

+
+ + +
+
+ + +
+ +
+

库存列表

+ + + + + + + + + + + + +
商品ID库存数量已售数量操作
+
+
+ + +
+

订单管理

+
+

订单列表

+ + + + + + + + + + + + + +
订单ID商品ID商品名称创建时间操作
+
+
+
+
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/seckill.html b/src/main/resources/static/seckill.html new file mode 100644 index 0000000..4160257 --- /dev/null +++ b/src/main/resources/static/seckill.html @@ -0,0 +1,213 @@ + + + + + + 秒杀活动 + + + +
+
+

限时秒杀活动

+
+ 距离秒杀结束还有:00:00:00 +
+
+
+
+
📱
+
+
智能手机
+
¥999
+
库存:50
+ +
+
+
+
+
+ + + + \ No newline at end of file