Day18(订单微服务)

所有代码发布在 [https://github.com/hades0525/leyou]

购物车

4.5 修改购物车的数量
• controller

/**
*修改购物车商品数量
*@paramspuId
*@paramnum
*@return
*/
@PutMapping
publicResponseEntity<Void>updateCartNum(@RequestParam("id")LongspuId,@RequestParam("num")intnum){
cartService.updateCartNum(spuId,num);
returnResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

• service

/**
*修改购物车商品数量
*@paramspuId
*@paramnum
*/
publicvoidupdateCartNum(LongspuId,intnum){
//获取登录的用户
UserInfouser=UserInterceptor.getUser();
//key
Stringkey=KEY_PREFIX+user.getId();
//hashKey
StringhashKey=spuId.toString();
//获取操作
BoundHashOperations<String,Object,Object>operations=redisTemplate.boundHashOps(key);
//判断是否存在
if(!operations.hasKey(hashKey)){
thrownewLyException(ExceptionEnum.CART_NOT_FOUND);
}
//查询
Cartcart=JsonUtils.toBean(operations.get(hashKey).toString(),Cart.class);
cart.setNum(num);
//写回redis
operations.put(hashKey,JsonUtils.toString(cart));
}

4.6 删除购物车
• controller

/**
*删除购物车
*@paramskuId
*@return
*/
@DeleteMapping("{skuId}")
publicResponseEntity<Void>deleteCart(@PathVariable("skuId")LongskuId){
cartService.deleteCart(skuId);
returnResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

• service

/**
*删除购物车
*@paramskuId
*/
publicvoiddeleteCart(LongskuId){
//获取登录的用户
UserInfouser=UserInterceptor.getUser();
//key
Stringkey=KEY_PREFIX+user.getId();
//删除
redisTemplate.opsForHash().delete(key,skuId.toString());
}

订单微服务

在这里插入图片描述

  1. 订单微服务搭建
    • pom
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.leyou.service</groupId>
<artifactId>ly-item-interface</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.leyou.common</groupId>
<artifactId>ly-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.leyou.service</groupId>
<artifactId>ly-auth-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!--<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
</dependency>-->
</dependencies>

• 配置文件

server:
  port: 8089
spring:
  application:
    name: order-service
  datasource:
    url: jdbc:mysql://localhost:3306/yun61
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  jackson:
    default-property-inclusion: non_null
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 5
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
mybatis:
  type-aliases-package: com.leyou.order.pojo
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
ly:
  jwt:
    pubKeyPath: D:/MY_IDEA/rsa/rsa.pub # 公钥地址
    cookieName: LY_TOKEN # cookie的名称
  worker:
    workedId: 1
    dataCenterId: 1

• 启动类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.leyou.order.mapper")
publicclassLyOrderApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(LyOrderApplication.class);
}
}
  1. 实体类
    • Order
@Data
@Table(name="tb_order")
publicclassOrder{
 
@Id
privateLongorderId;//id
privateLongtotalPay;//总金额
privateLongactualPay;//实付金额
privateIntegerpaymentType;//支付类型,1、在线支付,2、货到付款
 
privateStringpromotionIds;//参与促销活动的id
privateLongpostFee=0L;//邮费todo实际项目中应该根据具体地点生成具体邮费
privateDatecreateTime;//创建时间
privateStringshippingName;//物流名称
privateStringshippingCode;//物流单号
privateLonguserId;//用户id
privateStringbuyerMessage;//买家留言
privateStringbuyerNick;//买家昵称
privateBooleanbuyerRate;//买家是否已经评价
privateStringreceiver;//收货人全名
privateStringreceiverMobile;//移动电话
privateStringreceiverState;//省份
privateStringreceiverCity;//城市
privateStringreceiverDistrict;//区/县
privateStringreceiverAddress;//收货地址,如:xx路xx号
privateStringreceiverZip;//邮政编码,如:310001
privateIntegerinvoiceType=0;//发票类型,0无发票,1普通发票,2电子发票,3增值税发票
privateIntegersourceType=1;//订单来源1:app端,2:pc端,3:M端,4:微信端,5:手机qq端
 
@Transient
privateOrderStatusorderStatus;
 
@Transient
privateList<OrderDetail>orderDetails;
}

• OrderDtail

@Data
@Table(name="tb_order_detail")
publicclassOrderDetail{
 
@Id
@KeySql(useGeneratedKeys=true)
privateLongid;
 
privateLongorderId;//订单id
 
privateLongskuId;//商品id
 
privateIntegernum;//商品购买数量
 
privateStringtitle;//商品标题
 
privateLongprice;//商品单价
 
privateStringownSpec;//商品规格数据
 
privateStringimage;//图片
}

• OrderStatus

@Data
@Table(name="tb_order_status")
publicclassOrderStatus{
 
@Id
privateLongorderId;
 
privateIntegerstatus;//1、未付款2、已付款,未发货3、已发货,未确认4、交易成功5、交易关闭6、已评价'
 
privateDatecreateTime;//创建时间
 
privateDatepaymentTime;//付款时间
 
privateDateconsignTime;//发货时间
 
privateDateendTime;//交易结束时间
 
privateDatecloseTime;//交易关闭时间
 
privateDatecommentTime;//评价时间
}
  1. DTO (页面接受的数据)
    • OrderDto
@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassOrderDto{
@NotNull
privateLongaddressId;//收获人地址id
@NotNull
privateIntegerpaymentType;//付款类型
@NotNull
privateList<CartDto>carts;//订单详情
}
•	AddressDTO
@Data
publicclassAddressDTO{
privateLongid;
privateStringname;//收件人姓名
privateStringphone;//电话
privateStringstate;//省份
privateStringcity;//城市
privateStringdistrict;//区
privateStringaddress;//街道地址
privateStringzipCode;//邮编
privateBooleanisDefault;
}
•	CartDto    放在ly-common中
@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassCartDto{
privateLongskuId;//商品skuId
privateIntegernum;//购买数量
}
  1. 用户校验
•	把JwtProperties,UserInterceptor和MvcConfig放到ly-order中
  1. CartController
@RestController
@RequestMapping("order")
publicclassOrderController{
@Autowired
privateOrderServiceorderService;
 
/**
*创建订单
*@paramorderDto
*@return
*/
@PostMapping
publicResponseEntity<Long>createOrder(@RequestBodyOrderDtoorderDto){
//创建订单
returnResponseEntity.ok(orderService.createOrder(orderDto));
 
}
}
  1. 生成订单号的工具
    • 订单数据非常庞大,将来一定会做分库分表。那么这种情况下, 要保证id的唯一,就不能靠数据库自增,而是自己来实现算法,生成唯一id。
    • 在ly-common中IdWorker工具类 通过雪花算法
    • IdWorker中需要的两个参数写在配置文件中

• IdWorkerProperties

@Data
@ConfigurationProperties(prefix="ly.worker")
publicclassIdWorkerProperties{
 
privatelongworkerId;//当前机器id
 
privatelongdataCenterId;//序列号
}

• IdWorkerConfig

@Configuration
@EnableConfigurationProperties(IdWorkerProperties.class)
publicclassIdWorkerConfig{
/**
*注册IdWorker
*@paramprop
*@return
*/
@Bean
publicIdWorkeridWorker(IdWorkerPropertiesprop){
returnnewIdWorker(prop.getWorkerId(),prop.getDataCenterId());
}
}
  1. CartService 生成订单的方法
@Slf4j
@Service
@Transactional
publicclassOrderService{
 
@Autowired
privateOrderMapperorderMapper;
 
@Autowired
privateOrderDetailMapperdetailMapper;
 
@Autowired
privateOrderStatusMapperstatusMapper;
 
@Autowired
privateGoodsClientgoodsClient;
 
@Autowired
privateIdWorkeridWorker;
 
 
@Transactional
publicLongcreateOrder(OrderDtoorderDto){
//1.新增订单
Order order = new Order();
//1.1订单编号基本信息
long orderId = idWorker.nextId();
order.setOrderId(orderId);
order.setCreateTime(newDate());
order.setPaymentType(orderDto.getPaymentType());
 
//1.2用户信息
UserInfo user = UserInterceptor.getUser();
order.setUserId(user.getId());
order.setBuyerNick(user.getUsername());
order.setBuyerRate(false);
 
//1.3收货人地址
AddressDTO addr = AddressClient.findById(orderDto.getAddressId());
order.setReceiver(addr.getName());
order.setReceiverAddress(addr.getAddress());
order.setReceiverDistrict(addr.getDistrict());
order.setReceiverCity(addr.getCity());
order.setReceiverState(addr.getState());
order.setReceiverMobile(addr.getPhone());
order.setReceiverZip(addr.getZipCode());
 
//1.4金额
//把cartdto转为一个map,key是skuId,value是num
Map<Long,Integer>numMap=orderDto.getCarts().stream()
.collect(Collectors.toMap(CartDto::getSkuId,CartDto::getNum));
//获取所有sku的id
Set<Long>ids=numMap.keySet();
//根据id查询sku
List<Sku> skus = goodsClient.querySkuByIds(newArrayList<>(ids));
 
//准备orderDtail集合
List<OrderDetail>details=newArrayList<>();
 
LongtotalPay=0L;
for(Skusku:skus){
totalPay=sku.getPrice()*numMap.get(sku.getId());
 
//封装orderDtail
OrderDetaildetail=newOrderDetail();
detail.setOrderId(orderId);
detail.setImage(StringUtils.substringBefore(sku.getImages(),","));
detail.setNum(numMap.get(sku.getId()));
detail.setOwnSpec(sku.getOwnSpec());
detail.setSkuId(sku.getId());
detail.setTitle(sku.getTitle());
detail.setPrice(sku.getPrice().longValue());
details.add(detail);
}
 
order.setTotalPay(totalPay);
//实付金额:总金额+邮费-优惠金额
order.setActualPay(totalPay+order.getPostFee()-0);
 
//1.5写入数据库
intcount=orderMapper.insertSelective(order);
if(count!=1){
log.error("[创建订单服务order]创建订单失败,orderId:{}",orderId);
thrownewLyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
//2.新增订单详情
count=detailMapper.insertList(details);
 
if(count!=details.size()){
log.error("[创建订单服务detail]创建订单失败,orderId:{}",orderId);
thrownewLyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
//3.新增订单状态
OrderStatusorderStatus=newOrderStatus();
orderStatus.setCreateTime(order.getCreateTime());
orderStatus.setOrderId(orderId);
orderStatus.setStatus(OrderStatusEnum.UN_PAY.value());
count=statusMapper.insertSelective(orderStatus);
if(count!=1){
log.error("[创建订单服务status]创建订单失败,orderId:{}",orderId);
thrownewLyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
 
//4.减库存采用同步,在数据库判断
List<CartDto> cartDto s= orderDto.getCarts();
goodsClient.decreaseStock(cartDtos);
 
returnorderId;
 
}
  1. 收货人地址信息 造的假数据
publicabstractclassAddressClient{
publicstaticfinalList<AddressDTO>addressList=newArrayList<AddressDTO>(){
{
AddressDTOaddress=newAddressDTO();
address.setId(1L);
address.setAddress("航头镇航头路18号传智播客3号楼");
address.setCity("上海");
address.setDistrict("浦东新区");
address.setName("虎哥");
address.setPhone("15800000000");
address.setState("上海");
address.setZipCode("21000");
address.setIsDefault(true);
add(address);
 
AddressDTOaddress2=newAddressDTO();
address2.setId(2L);
address2.setAddress("天堂路3号楼");
address2.setCity("北京");
address2.setDistrict("朝阳区");
address2.setName("张三");
address2.setPhone("13600000000");
address2.setState("北京");
address2.setZipCode("100000");
address2.setIsDefault(false);
add(address2);
}
};
 
publicstaticAddressDTOfindById(Longid){
for(AddressDTOaddressDTO:addressList){
if(addressDTO.getId()==id)returnaddressDTO;
}
returnnull;
}
}
  1. 需要远程调用goods中的方法
    • 在goodsApi中添加接口
/**
*根据spu的id集合查询下面所有sku
*@paramids
*@return
*/
@GetMapping("/sku/list/ids")
List<Sku>querySkuByIds(@RequestParam("ids")List<Long>ids);
•	goodsClient
@FeignClient(value="item-service")
publicinterfaceGoodsClientextendsGoodsApi{
}
  1. 订单状态的枚举
publicenumOrderStatusEnum{
UN_PAY(1,"未付款"),
PAYED(2,"已付款,未确认"),
UN_CONFIRM(3,"已发货,未确认"),
SUCCESS(4,"已确认,交易成功"),
CLOSED(5,"已关闭,交易失败"),
RATED(6,"已评价"),
;
privateintcode;
privateStringdesc;
 
OrderStatusEnum(intcode,Stringdesc){
this.code=code;
this.desc=desc;
}
 
publicintvalue(){
returnthis.code;
}
}
  1. 减少库存 通过数据库里判断来解决事务问题
    • GoodsController.decreaseStock
/**
*减少库存
*@paramcartDtos
*@return
*/
@PostMapping("stock/decrease")
publicResponseEntity<Void>decreaseStock(@RequestBodyList<CartDto>cartDtos){
goodsService.decreaseStock(cartDtos);
returnResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

• GoodsService.decreaseStock

/**
*减少库存
*@paramcartDtos
*/
@Transactional
publicvoiddecreaseStock(List<CartDto>cartDtos){
for(CartDtocartDto:cartDtos){
//减库存
intcount=stockMapper.decreaseStock(cartDto.getSkuId(),cartDto.getNum());
if(count!=1){
thrownewLyException(ExceptionEnum.STOCK_NOT_ENOUGH);
}
}
}

• StockMapper

publicinterfaceStockMapperextendsBaseMapper<Stock>{
@Update("updatetb_stocksetstock=stock-#{num}wheresku_id=#{skuId}andstock>=#{num}")
intdecreaseStock(@Param("skuId")LongskuId,@Param("num")Integernum);
}

• GoodsApi

/**
*减少库存
*@paramcartDtos
*@return
*/
@PostMapping("stock/decrease")
voiddecreaseStock(@RequestBodyList<CartDto>cartDtos);
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值