import com.leyou.common.mapper.BaseMapper;
import com.leyou.order.pojo.OrderStatus;
public interface OrderStatusMapper extends BaseMapper {
}
package com.leyou.order.service;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper detailMapper;
@Autowired
private OrderStatusMapper statusMapper;
}
2.0.实现orderService的createOrder方法
创建订单逻辑比较复杂,需要组装订单数据,基本步骤如下:
-
获取登录用户信息
-
生成订单编号,初始化订单基本信息
-
查询收货人信息
-
查询商品信息
-
封装OrderDetail信息
-
计算总金额、实付金额
-
保存订单状态信息
-
删除购物车中已购买商品减库存
2.0.1生成订单编号(雪花算法)
雪花算法是由Twitter公司开源的snowflake(雪花)算法。
- 雪花算法的原理
雪花算法会生成一个64位的二进制数据,为一个Long型。
(转换成字符串后长度最多19),其基本结构:
第一位:为未使用
第二部分:41位为毫秒级时间(41位的长度可以使用69年)
第三部分:5位datacenterld
和5位workerld
(10位的长度最多支持部署1024个节点)
第四部分:最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
snowflake
生成的ID整体上按照时间自增排序,
并且整个分布式系统内不会产生ID碰撞(由datacenter
和workerld
作区分),
并且效率较高。
经测试snowflake
每秒能够产生26万个ID。
- 配置
ly:
worker:
workerId : 1
dataCenterId : 1
- 加载属性
package com.leyou.order.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = “ly.worker”)
public class IdWorkerProperties {
private long workerId;
private long dataCenterId;
}
- 编写配置类
package com.leyou.order.config;
import com.leyou.common.utils.IdWorker;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(IdWorkerProperties.class)
public class IdWorkerConfig {
@Bean
public IdWorker idWorker(IdWorkerProperties prop){
return new IdWorker(prop.getWorkerId(),prop.getDataCenterId());
}
}
2.0.2 准备假物流数据
我们前端页面传来的是addressld,我们需要根据id查询物流信息,
但是因为还没做物流地址管理。
所以我们准备一些假数据。
首先是实体类:
package com.leyou.order.dto;
import lombok.Data;
@Data
public class AddressDTO {
private Long id;
private String name;//收件人姓名
private String phone;//电话
private String state;//省份
private String city;//城市
private String district;//区
private String address;//街道地址
private String zipCode;//邮编
private Boolean isDefault;
}
package com.leyou.order.client;
import com.leyou.order.dto.AddressDTO;
import java.util.ArrayList;
import java.util.List;
public abstract class AddressClient {
public static final List addressList = new ArrayList() {
{
AddressDTO address = new AddressDTO();
address.setId(1L);
address.setAddress(“太阳系”);
address.setCity(“银河系”);
address.setDistrict(“火星”);
address.setName(“大哥”);
address.setPhone(“15800000000”);
address.setState(“阿拉比亚大陆(Arabia Terra)”);
address.setZipCode(“210000” ) ;
address.setIsDefault(true) ;
add(address);
AddressDTO address2 = new AddressDTO();address2.setId(2L);
address.setAddress(“太阳系”);
address.setCity(“银河系”);
address2.setDistrict(“天王星”);
address2.setName(“张三”);
address2.setPhone(“13600000000” );
address2.setState(“北京”);
address2.setZipCode(“100000”);
address2.setIsDefault(false);
add(address2);
}
};
public static AddressDTO findById(Long id) {
for (AddressDTO addressDTO : addressList) {
if (addressDTO.getId() == id)
return addressDTO;
}
return null;
}
}
2.0.3 在ly-item的ly-item-interface当中新增通过sku的id集合查询其所有sku的接口
/*
通过sku的id集合查询其所有sku
*/
@GetMapping(“sku/list/ids”)
List querySkuBySpuId(@RequestParam(“ids”) List ids);
2.0.4 在Order当中定义对应client使用上述的接口
package com.leyou.order.client;
import com.leyou.item.api.GoodsApi;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient(“item-service”)
public interface GoodsClient extends GoodsApi {
}
2.0.5 完善OrderService相关的工具类
2.0.5.1 定义异常枚举
CREATE_ORDER_ERROR(500,“创建订单失败”),
2.0.5.2 定义订单状态枚举
package com.leyou.order.enums;
public enum OrderStatusEnum {
UN_PAY(1,“未付款”),
PAYED(2,“已付款,未发货”),
DELIVERED(3,“已发货,未确认”),
SUCCESS(4,“已确认,未评价”),
CLOSED(5,“已关闭,交易失败”),
RATED(6,“已评价”),
;
private int code;
private String desc;
OrderStatusEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int value(){
return this.code;
}
}
2.0.5.3 在StockMapper当中编写键库存的代码
public interface StockMapper extends BaseMapper{
@Update(“UPDATE tb_stock SET stock = stock - #{num} WHERE sku_id = #{id} AND stock >= #{num}”)
int decreaseStock(@Param(“id”) Long id, @Param(“num”) Integer num);
}
这里减库存并没有采用先查询库存,判断充足才减库存的方案,那样会有线程安全问题,当然可以通过加锁解决。不过我们此处为了效率,并没有使用悲观锁,而是对库存采用了乐观锁方案
2.0.5.4 在商品微服务当中定义减库存的内容
- 在ly-common当中创建CartDTO,将下面order当中CartDTO复制一份到ly-common当中
- GoodsController当中创建decreaseStock方法
/*
减库存
*/
@PostMapping(“stock/decrease”)
public ResponseEntity decreaseStock(@RequestBody List carts){
goodsService.decreaseStock(carts);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
- GoodsService