首先创建用户下单的交易模型
@Data
public class OrderModel {
//要用string
private String id;
private Integer userId;
private Integer itemId;
private BigDecimal itemPrice;
private Integer amount;
private BigDecimal orderPrice;
}
创建订单表并初始化部分数据用于测试
DROP TABLE IF EXISTS `order_info`;
CREATE TABLE `order_info` (
`id` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`user_id` int(11) NOT NULL DEFAULT '0',
`item_id` int(11) NOT NULL DEFAULT '0',
`item_price` decimal(10,2) NOT NULL DEFAULT '0.00',
`amount` int(11) NOT NULL DEFAULT '0',
`order_price` decimal(10,2) NOT NULL DEFAULT '0.00',
`promo_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*Data for the table `order_info` */
insert into `order_info`(`id`,`user_id`,`item_id`,`item_price`,`amount`,`order_price`,`promo_id`) values
('2019041000000000',9,36,6999.00,1,6999.00,0),
('2019041000000100',9,36,6999.00,1,6999.00,0),
('2019041000000200',9,36,6999.00,1,6999.00,0),
('2019041200000300',9,40,200.00,1,200.00,2);
修改pom.xml将允许自动覆盖文件改为false,然后修改mybatis-generator.xml中的表为order_info,最后使用mybatis自动生成器生成基础服务。使用方式在秒杀第三节有说明
生成mapper文件和DO文件后新增OrderService类
public interface OrderService {
//1.通过前端url上传过来秒杀活动id,然后
//2.直接在下单接口内判断对应商品是否在秒杀
OrderModel createOrder(Integer userId, Integer itemId,Integer amount) throws BussinessException;
}
实现OrderService 中的创建订单方法。创建订单分为以下几步:
1.校验下单状态(用户是否合法,下单商品是否存在,购买数量是否正确)
2.落单减库存
3.订单入库(生成交易流水号,订单号)
4.商品销量增加
5.返回前端
代码实现
首先在itemService中定义落单减库存和商品下单后对应销量增加接口
//库存扣减
boolean decreaseStock(Integer itemId,Integer amount);
//商品下单后对应销量增加
void increaseSales(Integer itemId,Integer amount) throws BussinessException;
在ItemServiceImpl中实现itemService中的落单减库存和商品下单后对应销量增加接口
@Override
@Transactional
public boolean decreaseStock(Integer itemId, Integer amount) {
int affectedRow = itemStockDOMapper.decreaseStock(itemId,amount);
if(affectedRow > 0){
return true;
}else {
return false;
}
}
@Override
@Transactional
public void increaseSales(Integer itemId, Integer amount) throws BussinessException {
itemDOMapper.increaseSales(itemId,amount);
}
然后在对应itemStockDOMapper和itemDOMapper中实现落单减库存和商品下单后对应销量增加
int increaseSales(@Param("id")Integer id, @Param("amount")Integer amount);
int decreaseStock(@Param("itemId") Integer itemId, @Param("amount") Integer amount);
<update id="increaseSales">
update item
set sales = sales + #{amount}
where id = #{id,jdbcType=INTEGER}
</update>
<update id="decreaseStock">
update item_stock
set stock = stock - #{amount}
where item_id = #{itemId} and stock >= #{amount}
</update>
在订单入库的时候一般会生成交易流水号和订单号,订单号有16位,中间六位为自增序列,最后两位分库分表位
因为中间六位为自增序列,我们会设计一个表sequence_info来获取当前sequence,表结构如下:
DROP TABLE IF EXISTS `sequence_info`;
CREATE TABLE `sequence_info` (
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`current_value` int(11) NOT NULL DEFAULT '0',
`step` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*Data for the table `sequence_info` */
insert into `sequence_info`(`name`,`current_value`,`step`) values
('order_info',4,1);
修改pom.xml将允许自动覆盖文件改为false,然后修改mybatis-generator.xml中的表为sequence_info,最后使用mybatis自动生成器生成基础服务。使用方式在秒杀第三节有说明
OrderServiceImpl实现创建订单
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private ItemService itemService;
@Autowired
private UserService userService;
@Autowired
private OrderDOMapper orderDOMapper;
@Autowired
private SequenceDOMapper sequenceDOMapper;
@Override
@Transactional
public OrderModel createOrder(Integer userId, Integer itemId,Integer amount) throws BussinessException {
//1.校验下单状态(用户是否合法,下单商品是否存在,购买数量是否正确)
ItemModel itemModel = itemService.getItemById(itemId);
if(itemModel == null) {
throw new BussinessException((EmBusinessError.PARAMETER_VALIDATION_ERROR),"商品不存在");
}
UserModel userModel = userService.getUserById(userId);
if(userId == null) {
throw new BussinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"用户不存在");
}
if(amount <= 0 || amount > 99){
throw new BussinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"数量信息不正确");
}
//2.落单减库存,
boolean result = itemService.decreaseStock(itemId,amount);
if(!result) {
throw new BussinessException(EmBusinessError.STOCK_NOT_ENOUGH);
}
//3.订单入库
OrderModel orderModel = new OrderModel();
orderModel.setUserId(userId);
orderModel.setItemId(itemId);
orderModel.setAmount(amount);
orderModel.setItemPrice(itemModel.getPrice());
orderModel.setOrderPrice(orderModel.getItemPrice().multiply(BigDecimal.valueOf(amount)));
//生成交易流水号,订单号
orderModel.setId(generatorOrderNo());
OrderDO orderDO = convertFromOrderModel(orderModel);
orderDOMapper.insertSelective(orderDO);
//商品销量增加
itemService.increaseSales(itemId,amount);
//返回前端
return orderModel;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
String generatorOrderNo(){
//1.订单号有16位
StringBuilder stringBuilder = new StringBuilder();
//前8位为时间信息,年月日
LocalDateTime now = LocalDateTime.now();
String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-","");
stringBuilder.append(nowDate);
//2.中间六位为自增序列
//获取当前sequence
int sequence = 0;
SequenceDO sequenceDO = sequenceDOMapper.selectByPrimaryKey("order_info");
sequence = sequenceDO.getCurrentValue();
sequenceDO.setCurrentValue(sequenceDO.getCurrentValue()+sequenceDO.getStep());
sequenceDOMapper.updateByPrimaryKeySelective(sequenceDO);
//凑足六位
String sequenceStr = String.valueOf(sequence);
for(int i = 0; i < 6 - sequenceStr.length(); i++) {
stringBuilder.append(0);
}
stringBuilder.append(sequenceStr);
//3.最后两位分库分表位
stringBuilder.append("00");
return stringBuilder.toString();
}
private OrderDO convertFromOrderModel(OrderModel orderModel){
if(orderModel == null){
return null;
}
OrderDO orderDO = new OrderDO();
BeanUtils.copyProperties(orderModel,orderDO);
return orderDO;
}
}
OrderController封装下单
@Controller("/order")
@RequestMapping("/order")
@CrossOrigin(origins = {"*"}, allowCredentials = "true")
public class OrderController extends BaseController {
@Autowired
private OrderService orderService;
@Autowired
private HttpServletRequest httpServletRequest;
//封装下单请求
@RequestMapping(value = "/createorder", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType createOrder(@RequestParam(name="itemId")Integer itemId,
@RequestParam(name="promoId",required = false)Integer promoId,
@RequestParam(name="amount")Integer amount) throws BussinessException {
//获取登录信息(Boolean)
Boolean isLogin = (Boolean) this.httpServletRequest.getSession().getAttribute("IS_LOGIN");
if(isLogin == null || !isLogin.booleanValue()){
throw new BussinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能下单");
}
UserModel userModel = (UserModel) this.httpServletRequest.getSession().getAttribute("LOGIN_USER");
OrderModel orderModel = orderService.createOrder(userModel.getId(),itemId,amount);
return CommonReturnType.create(null);
}
}
下单测试参数:http://localhost:8080/order/createorder?itemId=41&amount=2
结果:
网友评论