diff --git a/api/pom.xml b/api/pom.xml
index bb08630..7929fae 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -80,7 +80,7 @@
org.bouncycastle
bcprov-jdk15on
- 1.57
+ 1.69
cn.dev33
diff --git a/api/src/main/java/me/xiaoyan/point/api/controller/ShopGoodsController.java b/api/src/main/java/me/xiaoyan/point/api/controller/ShopGoodsController.java
new file mode 100644
index 0000000..1dfb0e1
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/controller/ShopGoodsController.java
@@ -0,0 +1,28 @@
+package me.xiaoyan.point.api.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import me.xiaoyan.point.api.pojo.Goods;
+import me.xiaoyan.point.api.pojo.vo.PageParam;
+import me.xiaoyan.point.api.service.GoodsService;
+import org.springframework.web.bind.annotation.GetMapping;
+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;
+
+@RestController
+@RequestMapping("shop/goods")
+public class ShopGoodsController {
+ @Resource
+ private GoodsService goodsService;
+
+ @GetMapping("query")
+ public Page query(
+ int category,
+ int page,
+ int pageSize
+ ) {
+ return goodsService.queryByPage(category, Page.of(page, pageSize));
+ }
+}
diff --git a/api/src/main/java/me/xiaoyan/point/api/controller/ShopOrderInfoController.java b/api/src/main/java/me/xiaoyan/point/api/controller/ShopOrderInfoController.java
new file mode 100644
index 0000000..32224d7
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/controller/ShopOrderInfoController.java
@@ -0,0 +1,76 @@
+package me.xiaoyan.point.api.controller;
+
+import cn.dev33.satoken.stp.StpUtil;
+import lombok.extern.slf4j.Slf4j;
+import me.xiaoyan.point.api.error.BizException;
+import me.xiaoyan.point.api.pojo.OrderInfo;
+import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
+import me.xiaoyan.point.api.service.GoodsService;
+import me.xiaoyan.point.api.service.OrderInfoService;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 订单表(OrderInfo)表控制层
+ *
+ * @author makejava
+ * @since 2022-11-24 09:32:38
+ */
+@Slf4j
+@RestController
+@RequestMapping("shop/order")
+public class ShopOrderInfoController {
+ @Resource
+ private OrderInfoService orderInfoService;
+ @Resource
+ private GoodsService goodsService;
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+
+ // 是否已经没有库存
+ private ConcurrentHashMap stockOutMap = new ConcurrentHashMap<>();
+ private static final String CACHE_STOCK_KEY = "goods:stock:";
+
+ private String cacheKey(long gid) {
+ return CACHE_STOCK_KEY + gid;
+ }
+
+ @PostConstruct // 初始化执行一次
+ private void initGoodsStockCache() {
+ //TODO 应该定时更新缓存数据
+ goodsService.queryAllGoodsIdAndStock().forEach(g -> {
+ log.info("缓存 id:{} stock:{} ", g.getId(), g.getStock());
+ // 缓存库存
+ stringRedisTemplate.opsForValue().set(cacheKey(g.getId()), g.getStock().toString());
+ });
+ }
+
+ @PostMapping("create")
+ public OrderInfo create(@Validated @RequestBody CreateOrderData data) {
+ if (data.getGoodsId() <= 0 || data.getBuyCount() <= 0) {
+ throw BizException.create("订单参数不正确");
+ }
+ //1.内存判断
+ if (stockOutMap.get(data.getGoodsId())) {
+ throw BizException.create("库存不足");
+ }
+ //2.缓存(redis)判断
+ long count = stringRedisTemplate.opsForValue().decrement(cacheKey(data.getGoodsId()));
+ if (count < 0) {
+ // 此时库存没有了 , 保存到已买完的对象
+ stockOutMap.put(data.getGoodsId(),true);
+ log.info("stock count ===>" + count);
+ // 对缓存进行库存 + 1
+ stringRedisTemplate.opsForValue().increment(cacheKey(data.getGoodsId())); //
+ throw BizException.create("库存不足");
+ }
+ //3.数据库
+ return orderInfoService.create(StpUtil.getLoginIdAsInt(), data);
+ }
+}
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/mapper/GoodsMapper.java b/api/src/main/java/me/xiaoyan/point/api/mapper/GoodsMapper.java
new file mode 100644
index 0000000..00dee12
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/mapper/GoodsMapper.java
@@ -0,0 +1,30 @@
+package me.xiaoyan.point.api.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import me.xiaoyan.point.api.pojo.Goods;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @Entity me.xiaoyan.point.api.pojo.Goods
+ */
+@Mapper
+public interface GoodsMapper extends BaseMapper {
+ public Page queryByCategory(@Param("category") int category,Page page);
+
+ /**
+ * 扣除商品库存
+ * @param id
+ * @param count
+ * @return
+ */
+ public int deductCount(@Param("id") int id, @Param("count") int count);
+ public List queryAllGoodsIdAndStock();
+}
+
+
+
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/mapper/OrderInfoMapper.java b/api/src/main/java/me/xiaoyan/point/api/mapper/OrderInfoMapper.java
new file mode 100644
index 0000000..88d36a9
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/mapper/OrderInfoMapper.java
@@ -0,0 +1,17 @@
+package me.xiaoyan.point.api.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import me.xiaoyan.point.api.pojo.OrderInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 订单表(OrderInfo)表数据库访问层
+ *
+ * @author makejava
+ * @since 2022-11-24 09:32:38
+ */
+@Mapper
+public interface OrderInfoMapper extends BaseMapper {
+
+}
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/pojo/Goods.java b/api/src/main/java/me/xiaoyan/point/api/pojo/Goods.java
new file mode 100644
index 0000000..b2b40f7
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/pojo/Goods.java
@@ -0,0 +1,107 @@
+package me.xiaoyan.point.api.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 商品表
+ * @TableName goods
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@TableName(value ="goods")
+public class Goods implements Serializable {
+ /**
+ *
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 商品类别(1:普通 2:精选 3:秒杀 4:抽奖)
+ */
+ private Integer category;
+
+ /**
+ * 商品类型(1:实物 2:虚拟)
+ */
+ private Integer type;
+
+ /**
+ *
+ */
+ private String title;
+
+ /**
+ * 原价
+ */
+ private Integer originPrice;
+
+ /**
+ * 价格
+ */
+ private Integer price;
+
+ /**
+ * 库存数量
+ */
+ private Integer stock;
+
+ /**
+ * 购买最大数量(0表示不限制)
+ */
+ private Integer limitCount;
+
+ /**
+ * 商品图
+ */
+ private String cover;
+
+ /**
+ * 描述
+ */
+ private String description;
+
+ /**
+ * 提示
+ */
+ private String notice;
+
+ /**
+ * 上架时间
+ */
+ private Date onlineTime;
+
+ /**
+ * 下架时间
+ */
+ private Date offlineTime;
+
+ /**
+ *
+ */
+ private Date createTime;
+
+ /**
+ *
+ */
+ private Date updateTime;
+
+ /**
+ *
+ */
+ private Integer status;
+}
\ No newline at end of file
diff --git a/api/src/main/java/me/xiaoyan/point/api/pojo/OrderInfo.java b/api/src/main/java/me/xiaoyan/point/api/pojo/OrderInfo.java
new file mode 100644
index 0000000..1da5846
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/pojo/OrderInfo.java
@@ -0,0 +1,50 @@
+package me.xiaoyan.point.api.pojo;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 订单表(OrderInfo)表实体类
+ *
+ * @author makejava
+ * @since 2022-11-24 09:32:42
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@TableName(value ="order_info")
+public class OrderInfo {
+ @TableId
+ //订单编号
+ private String id;
+ //商品编号
+ private Long gid;
+ //价格
+ private Integer price;
+ //购买数量
+ private Integer count;
+ //用户编号
+ private Integer uid;
+ //订单数据
+ private String data;
+
+ private Date createTime;
+
+ private Date updateTime;
+ //订单状态(0:已删除 1:已取消 2:待确认 3:已完成)
+ private Integer status;
+
+}
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/pojo/dto/OrderStatus.java b/api/src/main/java/me/xiaoyan/point/api/pojo/dto/OrderStatus.java
new file mode 100644
index 0000000..c3656ec
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/pojo/dto/OrderStatus.java
@@ -0,0 +1,8 @@
+package me.xiaoyan.point.api.pojo.dto;
+
+public class OrderStatus {
+ public static final int DELETE = 0;
+ public static final int CANCEL = 1;
+ public static final int CONFIRM = 2;
+ public static final int DONE = 3;
+}
diff --git a/api/src/main/java/me/xiaoyan/point/api/pojo/vo/CreateOrderData.java b/api/src/main/java/me/xiaoyan/point/api/pojo/vo/CreateOrderData.java
new file mode 100644
index 0000000..0b3bfd5
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/pojo/vo/CreateOrderData.java
@@ -0,0 +1,11 @@
+package me.xiaoyan.point.api.pojo.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class CreateOrderData implements Serializable {
+ private int goodsId;
+ private int buyCount;
+}
diff --git a/api/src/main/java/me/xiaoyan/point/api/service/GoodsService.java b/api/src/main/java/me/xiaoyan/point/api/service/GoodsService.java
new file mode 100644
index 0000000..ec61724
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/service/GoodsService.java
@@ -0,0 +1,26 @@
+package me.xiaoyan.point.api.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import me.xiaoyan.point.api.pojo.Goods;
+import com.baomidou.mybatisplus.extension.service.IService;
+import me.xiaoyan.point.api.pojo.vo.PageParam;
+
+import java.util.List;
+
+/**
+ *
+ */
+public interface GoodsService extends IService {
+
+ Page queryByPage(int category, Page page);
+
+ /**
+ * 减库存
+ * @param id
+ * @param count
+ * @return
+ */
+ boolean deductStock(int id,int count);
+
+ List queryAllGoodsIdAndStock();
+}
diff --git a/api/src/main/java/me/xiaoyan/point/api/service/OrderInfoService.java b/api/src/main/java/me/xiaoyan/point/api/service/OrderInfoService.java
new file mode 100644
index 0000000..bfa072a
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/service/OrderInfoService.java
@@ -0,0 +1,17 @@
+package me.xiaoyan.point.api.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import me.xiaoyan.point.api.pojo.OrderInfo;
+import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
+
+/**
+ * 订单表(OrderInfo)表服务接口
+ *
+ * @author makejava
+ * @since 2022-11-24 09:32:44
+ */
+public interface OrderInfoService extends IService {
+
+ OrderInfo create(int uid, CreateOrderData data);
+}
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/service/impl/GoodsServiceImpl.java b/api/src/main/java/me/xiaoyan/point/api/service/impl/GoodsServiceImpl.java
new file mode 100644
index 0000000..4e0fa91
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/service/impl/GoodsServiceImpl.java
@@ -0,0 +1,37 @@
+package me.xiaoyan.point.api.service.impl;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import me.xiaoyan.point.api.pojo.Goods;
+import me.xiaoyan.point.api.service.GoodsService;
+import me.xiaoyan.point.api.mapper.GoodsMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ *
+ */
+@Service
+public class GoodsServiceImpl extends ServiceImpl
+ implements GoodsService {
+
+ @Override
+ public Page queryByPage(int category, Page page) {
+ return this.getBaseMapper().queryByCategory(category, page);
+ }
+
+ @Override
+ public boolean deductStock(int id, int count) {
+ return getBaseMapper().deductCount(id,count) == 1;
+ }
+
+ @Override
+ public List queryAllGoodsIdAndStock() {
+ return getBaseMapper().queryAllGoodsIdAndStock();
+ }
+}
+
+
+
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/service/impl/OrderInfoServiceImpl.java b/api/src/main/java/me/xiaoyan/point/api/service/impl/OrderInfoServiceImpl.java
new file mode 100644
index 0000000..d6183ce
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/service/impl/OrderInfoServiceImpl.java
@@ -0,0 +1,84 @@
+package me.xiaoyan.point.api.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import me.xiaoyan.point.api.error.BizException;
+import me.xiaoyan.point.api.mapper.OrderInfoMapper;
+import me.xiaoyan.point.api.pojo.Goods;
+import me.xiaoyan.point.api.pojo.OrderInfo;
+import me.xiaoyan.point.api.pojo.UserInfo;
+import me.xiaoyan.point.api.pojo.dto.OrderStatus;
+import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
+import me.xiaoyan.point.api.service.GoodsService;
+import me.xiaoyan.point.api.service.OrderInfoService;
+import me.xiaoyan.point.api.service.UserInfoService;
+import me.xiaoyan.point.api.util.OrderIdGenerator;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * 订单表(OrderInfo)表服务实现类
+ *
+ * @author makejava
+ * @since 2022-11-24 09:32:44
+ */
+@Service
+public class OrderInfoServiceImpl extends ServiceImpl implements OrderInfoService {
+
+ @Resource
+ private UserInfoService userInfoService;
+ @Resource
+ private GoodsService goodsService;
+
+ @Transactional
+ @Override
+ public OrderInfo create(int uid, CreateOrderData data) {
+ // 1.查询用户信息
+ final UserInfo user = userInfoService.getInfoById(uid);
+ // 判断用户信息
+ if (user == null) throw BizException.create("用户信息不存在");
+ if (user.getStatus() != 1) throw BizException.create("用户状态不正确");
+ // 2.查询商品信息
+ final Goods goods = goodsService.getById(data.getGoodsId());
+ if (goods == null) throw BizException.create("兑换的商品不存在");
+ long now = new Date().getTime();
+ if (goods.getOnlineTime().getTime() > now || goods.getOfflineTime().getTime() < now) {
+ throw BizException.create("商品未上架或已下架");
+ }
+ if (goods.getStock() < data.getBuyCount()) throw BizException.create("商品存库不足");
+ // 判断购买数量的限制
+ if(buyHistoryCount(uid,data.getGoodsId()) + data.getBuyCount() > goods.getLimitCount()){
+ throw BizException.create("最多兑换" + goods.getLimitCount() + "件");
+ }
+ // 3.减库存
+ if (!goodsService.deductStock(data.getGoodsId(), data.getBuyCount())) {
+ throw BizException.create("商品库存不足");
+ }
+ // 4.创建订单
+ OrderInfo orderInfo = OrderInfo.builder()
+ .id(OrderIdGenerator.next())
+ .gid((long) data.getGoodsId())
+ .uid(uid)
+ .count(data.getBuyCount())
+ .price(goods.getPrice())
+ .status(OrderStatus.CONFIRM)
+ .build();
+ if (save(orderInfo)) {
+ return orderInfo;
+ }
+ throw BizException.create("创建订单失败");
+ }
+
+ public long buyHistoryCount(int uid, int gid) {
+ QueryWrapper q = new QueryWrapper();
+ q.eq("uid", gid);
+ q.eq("gid", gid);
+ q.ge("status", OrderStatus.CONFIRM); // 状态为2(待确认)和3(已完成)
+ return count(q);
+ }
+}
+
diff --git a/api/src/main/java/me/xiaoyan/point/api/service/impl/UserInfoServiceImpl.java b/api/src/main/java/me/xiaoyan/point/api/service/impl/UserInfoServiceImpl.java
index 8192dad..6bdf2b1 100644
--- a/api/src/main/java/me/xiaoyan/point/api/service/impl/UserInfoServiceImpl.java
+++ b/api/src/main/java/me/xiaoyan/point/api/service/impl/UserInfoServiceImpl.java
@@ -135,6 +135,7 @@ public class UserInfoServiceImpl extends ServiceImpl
final CodeSessionData data = gson.fromJson(content, CodeSessionData.class);
if (!StringUtils.hasLength(data.getOpenid()) || !StringUtils.hasLength(data.getSessionKey())
|| (data.getErrcode() != null && data.getErrcode() != 0)) {
+ System.out.println(content);
throw BizException.create(1101, "换取session失败");
}
return data;
diff --git a/api/src/main/java/me/xiaoyan/point/api/util/OrderIdGenerator.java b/api/src/main/java/me/xiaoyan/point/api/util/OrderIdGenerator.java
new file mode 100644
index 0000000..7609e73
--- /dev/null
+++ b/api/src/main/java/me/xiaoyan/point/api/util/OrderIdGenerator.java
@@ -0,0 +1,28 @@
+package me.xiaoyan.point.api.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class OrderIdGenerator {
+ private static AtomicInteger atomic = new AtomicInteger();
+ private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss");
+ private static long prevTime = 0;
+
+ public static String next() {
+ long now = System.currentTimeMillis() / 1000;
+ if (now > prevTime) {
+ prevTime = now;
+ atomic.set(0);
+ }
+ return dateFormat.format(new Date()) + String.format("%05d", atomic.addAndGet(1));
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+ for (int i = 0; i < 1000; i++) {
+ System.out.println(next());
+ Thread.sleep(1);
+ }
+ }
+}
diff --git a/api/src/main/resources/db.sql b/api/src/main/resources/db.sql
index 1a6e820..7764622 100644
--- a/api/src/main/resources/db.sql
+++ b/api/src/main/resources/db.sql
@@ -1,4 +1,4 @@
-create database if not exists points_sys;
+create database points_sys;
use points_sys;
create table userinfo
(
@@ -42,4 +42,39 @@ create table sign_record
point int(10) not null,
ip varchar(50) not null,
create_time datetime default current_timestamp
-) engine = innodb collate = 'utf8mb4_general_ci' comment '打卡记录表';
\ No newline at end of file
+) engine = innodb collate = 'utf8mb4_general_ci' comment '打卡记录表';
+ create_time datetime default current_timestamp
+) engine = innodb comment '打卡记录表';
+
+create table goods
+(
+ id bigint(15) primary key auto_increment,
+ category tinyint(2) null default 1 comment '商品类别(1:普通 2:精选 3:秒杀 4:抽奖)',
+ type tinyint(2) null default 1 comment '商品类型(1:实物 2:虚拟)',
+ title varchar(50) not null,
+ origin_price int(10) unsigned comment '原价' default 0,
+ price int(10) unsigned not null comment '价格',
+ stock int(10) unsigned not null comment '库存数量',
+ limit_count int(10) unsigned null default 1 comment '购买最大数量(0表示不限制)',
+ cover varchar(200) not null comment '商品图',
+ description text not null comment '描述',
+ notice varchar(500) null comment '提示',
+ online_time datetime not null comment '上架时间',
+ offline_time datetime not null comment '下架时间',
+ create_time datetime default current_timestamp,
+ update_time datetime null on update current_timestamp,
+ status tinyint(2) default 1,
+ index ix_title (title)
+) engine = innodb comment '商品表';
+
+create table order_info
+(
+ id varchar(50) not null comment '订单编号',
+ gid bigint(15) not null comment '商品编号',
+ price int(10) not null comment '价格',
+ uid int(10) not null comment '用户编号',
+ data json null comment '订单数据',
+ create_time datetime default current_timestamp,
+ update_time datetime null on update current_timestamp,
+ status tinyint(2) default 1 comment '订单状态(0:已删除 1:待确认 2:已取消 3:已完成)'
+) comment '订单表';
\ No newline at end of file
diff --git a/api/src/main/resources/docs/process/create_order.svg b/api/src/main/resources/docs/process/create_order.svg
new file mode 100644
index 0000000..480d239
--- /dev/null
+++ b/api/src/main/resources/docs/process/create_order.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/api/src/main/resources/docs/process/创建订单.svg b/api/src/main/resources/docs/process/创建订单.svg
new file mode 100644
index 0000000..7160e69
--- /dev/null
+++ b/api/src/main/resources/docs/process/创建订单.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/api/src/main/resources/mapper/GoodsMapper.xml b/api/src/main/resources/mapper/GoodsMapper.xml
new file mode 100644
index 0000000..d513a46
--- /dev/null
+++ b/api/src/main/resources/mapper/GoodsMapper.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id,category,type,
+ title,origin_price,price,
+ stock,limit_count,cover,
+ description,notice,online_time,
+ offline_time,create_time,update_time,
+ status
+
+
+ update points_sys.goods
+ set stock=stock - #{count}
+ where id = #{id}
+ and stock >= #{count}
+
+
+
+
+
diff --git a/api/src/main/resources/mapper/OrderInfoMapper.xml b/api/src/main/resources/mapper/OrderInfoMapper.xml
new file mode 100644
index 0000000..3120edb
--- /dev/null
+++ b/api/src/main/resources/mapper/OrderInfoMapper.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/api/src/test/java/me/xiaoyan/point/api/ApiApplicationTests.java b/api/src/test/java/me/xiaoyan/point/api/ApiApplicationTests.java
index 2202460..0cbf998 100644
--- a/api/src/test/java/me/xiaoyan/point/api/ApiApplicationTests.java
+++ b/api/src/test/java/me/xiaoyan/point/api/ApiApplicationTests.java
@@ -2,12 +2,42 @@ package me.xiaoyan.point.api;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import javax.annotation.Resource;
@SpringBootTest
class ApiApplicationTests {
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
@Test
void contextLoads() {
}
+ void testBuy(long buyCount){
+ long count = stringRedisTemplate.opsForValue().decrement("a",buyCount);
+ System.out.println(count);
+ if(count<0){
+ System.out.println("库存不足");
+ stringRedisTemplate.opsForValue().increment("a",buyCount);
+ return;
+ }
+ if(count == 0){
+ System.out.println("下一次就没有存库了");
+ return;
+ }
+ System.out.println("购买成功");
+ }
+
+ @Test
+ void testRedis(){
+ stringRedisTemplate.opsForValue().set("a","1");
+ System.out.println("----------第1次----------");
+ testBuy(2);
+ System.out.println("----------第2次----------");
+ testBuy(1);
+ System.out.println("----------第3次----------");
+ testBuy(1);
+ }
}
diff --git a/api/src/test/java/me/xiaoyan/point/api/WechatTests.java b/api/src/test/java/me/xiaoyan/point/api/WechatTests.java
index c7107ad..f8d7e60 100644
--- a/api/src/test/java/me/xiaoyan/point/api/WechatTests.java
+++ b/api/src/test/java/me/xiaoyan/point/api/WechatTests.java
@@ -1,10 +1,20 @@
package me.xiaoyan.point.api;
+import lombok.SneakyThrows;
import me.xiaoyan.point.api.pojo.dto.WechatUserInfo;
import me.xiaoyan.point.api.util.WechatDecryptDataUtil;
+import org.apache.commons.codec.binary.Base64;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.Security;
+
public class WechatTests {
@@ -16,9 +26,11 @@ public class WechatTests {
String sessionKey= "091WPNkl23zoha4xbpnl2cev9l4WPNk7";
String encryptedData = "3mmRZjsqy3Tpgw78jm7HNB3n6/pb8nX9jS1GgngV4tHGSe+yhKIXy7u7kxXz7nKS5lwNqt+UQCXF3EHHd1PQJowtpYWNhLBjNZcGjEdIi6a5pxntmwmFsjTX+SjPNmq5Th4iKSwSyMjLIByZqJt7N3hB5OyT5YAo54lsJrln8DJoPE1m6kddHcLqnJy+g12QQTP1u3tFvCEostrCpb109Bhe889wAxm55ekPHTQ+JWYCsPy0TsjmyvqZCQZyB+RNtlW/ohCpLe4oCOF0Nz9Id6N+Kj6bXvgDcEMBf3vwMXSnbWHuqJAuLUWwbsspB/2T";
String iv = "qfrpHwHjjqPQVlzzxE9D1A==";
-// sessionKey= "PKX9EeH6y+pzz8qYrga2jQ==";
-// encryptedData = "SCK0Ik7THl+USkwTRqTQ9BYGe6rWlXosQ8fWA3I3AsFHTCuPnjbsjFooIEZVcS6mq911XeP5BJJBpPU6A1O3aNuC9L7ebXqTMQX83bVBtaDQySvCIlyyq26xhm8AbWWexl5994NJDpKkNml9ilbYia99bF8bXzXvLCksQQkz82EpZTqztzmCrTdFBZOIrJ+lDnl7rSBWJvVVtoagzgSq2Ux59LcJtxCukIUoZ8fz54//Hm4GhrLucO4zPKTi087f77Pd9K9Rz3LLJ79NMQHHQLtZ38Ws79IKoHBZ7xHXbl3O8xPeTBrrWeHbNfNs1CbOyoe0RwXVjs/fMR9451PeLVM5jg4fj3IDyTFjpx5aUzQRaIrSY/BjVFJoxU/viwQC6LsCBOyXl5uV5h+qIPC5suFbmhl5Q56eU07wbOjNxktEIJsIgbrT+GWRZVPba3dUo+6RoZySxCMA16TRKfuTwjXceV3oNueFdTNyw05s9N43OkrLeKcz1dFeNnpA9DHEVngB1J7MY4RkazdKaWzrld1DjxW6+rk01GgtAr3+H88=";
-// iv = "Ql/m+Ksll5ziCCZj+07J6g==";
+
+
+ sessionKey= "mu1qLLcPuMVfahKOyAdbvQ==";
+ encryptedData = "ld6dARTybGQ2qCBxUBahqsj7SEm5rschi5u+B2c373dwPf/scWDxPcrOevbzyRLIt3e/K5SVHakl992Uq1KsjBSFI+3A6UV3g5mqgoWePt2xwgUwacfpe7XLYw96qTXxGBAoPH306hRkfpo1zjN34tGVhjTj8LIyCH1llbefqlD+deSXvpRgrwhL2GDUAVs++9U3Mz9wSiSImYOUIZuguvSw0SWtqf5SsRDFI9yfGPzB9KubNX8kzRRvV5Aei8pUuhpgeIs9xKlNFVI5syKRQwprYDK9RLO5dq2G0h3CSrNzPfrI62h7vfb/72aUVu+a";
+ iv = "Spu1dAS7ieC/RQ1BYFb0Lw==";
WechatUserInfo wechatUserInfo = WechatDecryptDataUtil.decryptData(
encryptedData,
@@ -28,4 +40,44 @@ public class WechatTests {
);
// System.out.println(wechatUserInfo);
}
+ //解密手机号
+ private static boolean initialized = false;
+
+ @Test
+ void testAesDecode(){
+ String sessionKey= "mu1qLLcPuMVfahKOyAdbvQ==";
+ String encryptedData = "ld6dARTybGQ2qCBxUBahqsj7SEm5rschi5u+B2c373dwPf/scWDxPcrOevbzyRLIt3e/K5SVHakl992Uq1KsjBSFI+3A6UV3g5mqgoWePt2xwgUwacfpe7XLYw96qTXxGBAoPH306hRkfpo1zjN34tGVhjTj8LIyCH1llbefqlD+deSXvpRgrwhL2GDUAVs++9U3Mz9wSiSImYOUIZuguvSw0SWtqf5SsRDFI9yfGPzB9KubNX8kzRRvV5Aei8pUuhpgeIs9xKlNFVI5syKRQwprYDK9RLO5dq2G0h3CSrNzPfrI62h7vfb/72aUVu+a";
+ String iv = "Spu1dAS7ieC/RQ1BYFb0Lw==";
+
+ byte[] encData = Base64.decodeBase64(encryptedData);
+ byte[] ivData = Base64.decodeBase64(iv);
+ byte[] session = Base64.decodeBase64(sessionKey);
+ String str = decrypt(encData,session,ivData);
+ System.out.println(str);
+ }
+ @SneakyThrows
+ public String decrypt(byte[] encData, byte[] key, byte[] iv) {
+ initialize();
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
+ Key sKeySpec = new SecretKeySpec(key, "AES");
+
+ cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(iv));// 初始化
+ byte[] result = cipher.doFinal(encData);
+ return new String(result, "UTF-8");
+ }
+
+
+ public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
+ params.init(new IvParameterSpec(iv));
+ return params;
+ }
+
+ public static void initialize(){
+ if (initialized){
+ return;
+ }
+ Security.addProvider(new BouncyCastleProvider());
+ initialized = true;
+ }
}