5.22 拆分交易、支付
This commit is contained in:
parent
9bd4c9beaf
commit
5698a1d597
@ -44,6 +44,7 @@ public class CartController {
|
||||
public List<CartVO> queryMyCarts(){
|
||||
return cartService.queryMyCarts();
|
||||
}
|
||||
|
||||
@ApiOperation("批量删除购物车中商品")
|
||||
@ApiImplicitParam(name = "ids", value = "购物车条目id集合")
|
||||
@DeleteMapping
|
||||
|
@ -6,7 +6,7 @@ spring:
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
|
13
hm-api/src/main/java/com/hmall/api/client/CartClient.java
Normal file
13
hm-api/src/main/java/com/hmall/api/client/CartClient.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.hmall.api.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@FeignClient("cart-service")
|
||||
public interface CartClient {
|
||||
@DeleteMapping("/carts")
|
||||
void deleteCartItemByIds(@RequestParam("ids") Collection<Long> ids);
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package com.hmall.api.client;
|
||||
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -13,4 +16,6 @@ public interface ItemClient {
|
||||
|
||||
@GetMapping("/items")
|
||||
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
|
||||
@PutMapping("/items/stock/deduct")
|
||||
void deductStock(@RequestBody List<OrderDetailDTO> items);
|
||||
}
|
||||
|
11
hm-api/src/main/java/com/hmall/api/client/TradeClient.java
Normal file
11
hm-api/src/main/java/com/hmall/api/client/TradeClient.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.hmall.api.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
|
||||
@FeignClient("trade-service")
|
||||
public interface TradeClient {
|
||||
@PutMapping("/orders/{orderId}")
|
||||
void markOrderPaySuccess(@PathVariable("orderId") Long orderId);
|
||||
}
|
11
hm-api/src/main/java/com/hmall/api/client/UserClient.java
Normal file
11
hm-api/src/main/java/com/hmall/api/client/UserClient.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.hmall.api.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@FeignClient("user-service")
|
||||
public interface UserClient {
|
||||
@PutMapping("/users/money/deduct")
|
||||
void deductMoney(@RequestParam("pw") String pw,@RequestParam("amount") Integer amount);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.hmall.item.domain.dto;
|
||||
package com.hmall.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
@ -6,7 +6,7 @@ spring:
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3306/hmall?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hmall?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
|
@ -16,6 +16,11 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!--common-->
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.hmall.item.controller;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import com.hmall.common.domain.PageDTO;
|
||||
import com.hmall.common.domain.PageQuery;
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.item.domain.dto.ItemDTO;
|
||||
import com.hmall.item.domain.dto.OrderDetailDTO;
|
||||
import com.hmall.item.domain.po.Item;
|
||||
import com.hmall.item.service.IItemService;
|
||||
import io.swagger.annotations.Api;
|
||||
|
@ -1,34 +0,0 @@
|
||||
package com.hmall.item.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ApiModel(description = "商品实体")
|
||||
public class ItemDTO {
|
||||
@ApiModelProperty("商品id")
|
||||
private Long id;
|
||||
@ApiModelProperty("SKU名称")
|
||||
private String name;
|
||||
@ApiModelProperty("价格(分)")
|
||||
private Integer price;
|
||||
@ApiModelProperty("库存数量")
|
||||
private Integer stock;
|
||||
@ApiModelProperty("商品图片")
|
||||
private String image;
|
||||
@ApiModelProperty("类目名称")
|
||||
private String category;
|
||||
@ApiModelProperty("品牌名称")
|
||||
private String brand;
|
||||
@ApiModelProperty("规格")
|
||||
private String spec;
|
||||
@ApiModelProperty("销量")
|
||||
private Integer sold;
|
||||
@ApiModelProperty("评论数")
|
||||
private Integer commentCount;
|
||||
@ApiModelProperty("是否是推广广告,true/false")
|
||||
private Boolean isAD;
|
||||
@ApiModelProperty("商品状态 1-正常,2-下架,3-删除")
|
||||
private Integer status;
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package com.hmall.item.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hmall.item.domain.dto.ItemDTO;
|
||||
import com.hmall.item.domain.dto.OrderDetailDTO;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import com.hmall.item.domain.po.Item;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -2,11 +2,11 @@ package com.hmall.item.service.impl;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import com.hmall.common.exception.BizIllegalException;
|
||||
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.item.domain.dto.ItemDTO;
|
||||
import com.hmall.item.domain.dto.OrderDetailDTO;
|
||||
import com.hmall.item.domain.po.Item;
|
||||
import com.hmall.item.mapper.ItemMapper;
|
||||
import com.hmall.item.service.IItemService;
|
||||
|
@ -10,7 +10,7 @@ spring:
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3306/hm-item?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hm-item?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
|
67
pay-service/pom.xml
Normal file
67
pay-service/pom.xml
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hmall</artifactId>
|
||||
<groupId>com.heima</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>pay-service</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!--common-->
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!--web-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--数据库-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--mybatis-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-service</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!--nacos 服务注册发现-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
16
pay-service/src/main/java/com/hmall/pay/PayApplication.java
Normal file
16
pay-service/src/main/java/com/hmall/pay/PayApplication.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.hmall.pay;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@MapperScan("com.hmall.pay.mapper")
|
||||
@EnableFeignClients(basePackages= "com.hmall.api.client")
|
||||
@SpringBootApplication
|
||||
public class PayApplication {
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplication.run(PayApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.hmall.pay.controller;
|
||||
|
||||
import com.hmall.common.exception.BizIllegalException;
|
||||
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.pay.domain.dto.PayApplyDTO;
|
||||
import com.hmall.pay.domain.dto.PayOrderFormDTO;
|
||||
import com.hmall.pay.domain.vo.PayOrderVO;
|
||||
import com.hmall.pay.enums.PayType;
|
||||
import com.hmall.pay.service.IPayOrderService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Api(tags = "支付相关接口")
|
||||
@RestController
|
||||
@RequestMapping("pay-orders")
|
||||
@RequiredArgsConstructor
|
||||
public class PayController {
|
||||
|
||||
private final IPayOrderService payOrderService;
|
||||
|
||||
@ApiOperation("生成支付单")
|
||||
@PostMapping
|
||||
public String applyPayOrder(@RequestBody PayApplyDTO applyDTO){
|
||||
if(!PayType.BALANCE.equalsValue(applyDTO.getPayType())){
|
||||
// 目前只支持余额支付
|
||||
throw new BizIllegalException("抱歉,目前只支持余额支付");
|
||||
}
|
||||
return payOrderService.applyPayOrder(applyDTO);
|
||||
}
|
||||
@ApiOperation("查询支付单")
|
||||
@GetMapping
|
||||
public List<PayOrderVO> queryPayOrders(){
|
||||
return BeanUtils.copyList(payOrderService.list(), PayOrderVO.class);
|
||||
}
|
||||
|
||||
@ApiOperation("尝试基于用户余额支付")
|
||||
@ApiImplicitParam(value = "支付单id", name = "id")
|
||||
@PostMapping("{id}")
|
||||
public void tryPayOrderByBalance(@PathVariable("id") Long id, @RequestBody PayOrderFormDTO payOrderFormDTO){
|
||||
payOrderFormDTO.setId(id);
|
||||
payOrderService.tryPayOrderByBalance(payOrderFormDTO);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.hmall.pay.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ApiModel(description = "支付下单表单实体")
|
||||
public class PayApplyDTO {
|
||||
@ApiModelProperty("业务订单id不能为空")
|
||||
@NotNull(message = "业务订单id不能为空")
|
||||
private Long bizOrderNo;
|
||||
@ApiModelProperty("支付金额必须为正数")
|
||||
@Min(value = 1, message = "支付金额必须为正数")
|
||||
private Integer amount;
|
||||
@ApiModelProperty("支付渠道编码不能为空")
|
||||
@NotNull(message = "支付渠道编码不能为空")
|
||||
private String payChannelCode;
|
||||
@ApiModelProperty("支付方式不能为空")
|
||||
@NotNull(message = "支付方式不能为空")
|
||||
private Integer payType;
|
||||
@ApiModelProperty("订单中的商品信息不能为空")
|
||||
@NotNull(message = "订单中的商品信息不能为空")
|
||||
private String orderInfo;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.hmall.pay.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ApiModel(description = "支付确认表单实体")
|
||||
public class PayOrderFormDTO {
|
||||
@ApiModelProperty("支付订单id不能为空")
|
||||
@NotNull(message = "支付订单id不能为空")
|
||||
private Long id;
|
||||
@ApiModelProperty("支付密码")
|
||||
@NotNull(message = "支付密码")
|
||||
private String pw;
|
||||
}
|
123
pay-service/src/main/java/com/hmall/pay/domain/po/PayOrder.java
Normal file
123
pay-service/src/main/java/com/hmall/pay/domain/po/PayOrder.java
Normal file
@ -0,0 +1,123 @@
|
||||
package com.hmall.pay.domain.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单
|
||||
* </p>
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_order")
|
||||
public class PayOrder implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 业务订单号
|
||||
*/
|
||||
private Long bizOrderNo;
|
||||
|
||||
/**
|
||||
* 支付单号
|
||||
*/
|
||||
private Long payOrderNo;
|
||||
|
||||
/**
|
||||
* 支付用户id
|
||||
*/
|
||||
private Long bizUserId;
|
||||
|
||||
/**
|
||||
* 支付渠道编码
|
||||
*/
|
||||
private String payChannelCode;
|
||||
|
||||
/**
|
||||
* 支付金额,单位分
|
||||
*/
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 支付类型,1:h5,2:小程序,3:公众号,4:扫码,5:余额支付
|
||||
*/
|
||||
private Integer payType;
|
||||
|
||||
/**
|
||||
* 支付状态,0:待提交,1:待支付,2:支付超时或取消,3:支付成功
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 拓展字段,用于传递不同渠道单独处理的字段
|
||||
*/
|
||||
private String expandJson;
|
||||
|
||||
/**
|
||||
* 第三方返回业务码
|
||||
*/
|
||||
private String resultCode;
|
||||
|
||||
/**
|
||||
* 第三方返回提示信息
|
||||
*/
|
||||
private String resultMsg;
|
||||
|
||||
/**
|
||||
* 支付成功时间
|
||||
*/
|
||||
private LocalDateTime paySuccessTime;
|
||||
|
||||
/**
|
||||
* 支付超时时间
|
||||
*/
|
||||
private LocalDateTime payOverTime;
|
||||
|
||||
/**
|
||||
* 支付二维码链接
|
||||
*/
|
||||
private String qrCodeUrl;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private Long creater;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private Long updater;
|
||||
|
||||
/**
|
||||
* 逻辑删除
|
||||
*/
|
||||
private Boolean isDelete;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("address")
|
||||
public class Address implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 省
|
||||
*/
|
||||
private String province;
|
||||
|
||||
/**
|
||||
* 市
|
||||
*/
|
||||
private String city;
|
||||
|
||||
/**
|
||||
* 县/区
|
||||
*/
|
||||
private String town;
|
||||
|
||||
/**
|
||||
* 手机
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 详细地址
|
||||
*/
|
||||
private String street;
|
||||
|
||||
/**
|
||||
* 联系人
|
||||
*/
|
||||
private String contact;
|
||||
|
||||
/**
|
||||
* 是否是默认 1默认 0否
|
||||
*/
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String notes;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("cart")
|
||||
public class Cart implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 购物车条目id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* sku商品id
|
||||
*/
|
||||
private Long itemId;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
private Integer num;
|
||||
|
||||
/**
|
||||
* 商品标题
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 商品动态属性键值集
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
/**
|
||||
* 价格,单位:分
|
||||
*/
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String image;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
113
pay-service/src/main/java/com/hmall/pay/domain/po/po/Item.java
Normal file
113
pay-service/src/main/java/com/hmall/pay/domain/po/po/Item.java
Normal file
@ -0,0 +1,113 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
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.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 商品表
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("item")
|
||||
public class Item implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 商品id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* SKU名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 价格(分)
|
||||
*/
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
private Integer stock;
|
||||
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String image;
|
||||
|
||||
/**
|
||||
* 类目名称
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 品牌名称
|
||||
*/
|
||||
private String brand;
|
||||
|
||||
/**
|
||||
* 规格
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
/**
|
||||
* 销量
|
||||
*/
|
||||
private Integer sold;
|
||||
|
||||
/**
|
||||
* 评论数
|
||||
*/
|
||||
private Integer commentCount;
|
||||
|
||||
/**
|
||||
* 是否是推广广告,true/false
|
||||
*/
|
||||
@TableField("isAD")
|
||||
private Boolean isAD;
|
||||
|
||||
/**
|
||||
* 商品状态 1-正常,2-下架,3-删除
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private Long creater;
|
||||
|
||||
/**
|
||||
* 修改人
|
||||
*/
|
||||
private Long updater;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("`order`")
|
||||
public class Order implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 总金额,单位为分
|
||||
*/
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* 支付类型,1、支付宝,2、微信,3、扣减余额
|
||||
*/
|
||||
private Integer paymentType;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
private LocalDateTime payTime;
|
||||
|
||||
/**
|
||||
* 发货时间
|
||||
*/
|
||||
private LocalDateTime consignTime;
|
||||
|
||||
/**
|
||||
* 交易完成时间
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 交易关闭时间
|
||||
*/
|
||||
private LocalDateTime closeTime;
|
||||
|
||||
/**
|
||||
* 评价时间
|
||||
*/
|
||||
private LocalDateTime commentTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("order_detail")
|
||||
public class OrderDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单详情id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* sku商品id
|
||||
*/
|
||||
private Long itemId;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
private Integer num;
|
||||
|
||||
/**
|
||||
* 商品标题
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 商品动态属性键值集
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
/**
|
||||
* 价格,单位:分
|
||||
*/
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String image;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("order_logistics")
|
||||
public class OrderLogistics implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单id,与订单表一对一
|
||||
*/
|
||||
@TableId(value = "order_id", type = IdType.INPUT)
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 物流单号
|
||||
*/
|
||||
private String logisticsNumber;
|
||||
|
||||
/**
|
||||
* 物流公司名称
|
||||
*/
|
||||
private String logisticsCompany;
|
||||
|
||||
/**
|
||||
* 收件人
|
||||
*/
|
||||
private String contact;
|
||||
|
||||
/**
|
||||
* 收件人手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 省
|
||||
*/
|
||||
private String province;
|
||||
|
||||
/**
|
||||
* 市
|
||||
*/
|
||||
private String city;
|
||||
|
||||
/**
|
||||
* 区
|
||||
*/
|
||||
private String town;
|
||||
|
||||
/**
|
||||
* 街道
|
||||
*/
|
||||
private String street;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.hmall.pay.domain.po.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.hmall.enums.UserStatus;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户表
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("user")
|
||||
public class User implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码,加密存储
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 注册手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 使用状态(1正常 2冻结)
|
||||
*/
|
||||
private UserStatus status;
|
||||
|
||||
/**
|
||||
* 账户余额
|
||||
*/
|
||||
private Integer balance;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.hmall.pay.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单
|
||||
* </p>
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "支付单vo实体")
|
||||
public class PayOrderVO {
|
||||
@ApiModelProperty("id")
|
||||
private Long id;
|
||||
@ApiModelProperty("业务订单号")
|
||||
private Long bizOrderNo;
|
||||
@ApiModelProperty("支付单号")
|
||||
private Long payOrderNo;
|
||||
@ApiModelProperty("支付用户id")
|
||||
private Long bizUserId;
|
||||
@ApiModelProperty("支付渠道编码")
|
||||
private String payChannelCode;
|
||||
@ApiModelProperty("支付金额,单位分")
|
||||
private Integer amount;
|
||||
@ApiModelProperty("付类型,1:h5,2:小程序,3:公众号,4:扫码,5:余额支付")
|
||||
private Integer payType;
|
||||
@ApiModelProperty("付状态,0:待提交,1:待支付,2:支付超时或取消,3:支付成功")
|
||||
private Integer status;
|
||||
@ApiModelProperty("拓展字段,用于传递不同渠道单独处理的字段")
|
||||
private String expandJson;
|
||||
@ApiModelProperty("第三方返回业务码")
|
||||
private String resultCode;
|
||||
@ApiModelProperty("第三方返回提示信息")
|
||||
private String resultMsg;
|
||||
@ApiModelProperty("支付成功时间")
|
||||
private LocalDateTime paySuccessTime;
|
||||
@ApiModelProperty("支付超时时间")
|
||||
private LocalDateTime payOverTime;
|
||||
@ApiModelProperty("支付二维码链接")
|
||||
private String qrCodeUrl;
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.hmall.pay.enums;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum PayChannel {
|
||||
wxPay("微信支付"),
|
||||
aliPay("支付宝支付"),
|
||||
balance("余额支付"),
|
||||
;
|
||||
|
||||
private final String desc;
|
||||
|
||||
PayChannel(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static String desc(String value){
|
||||
if (StrUtil.isBlank(value)) {
|
||||
return "";
|
||||
}
|
||||
return PayChannel.valueOf(value).getDesc();
|
||||
}
|
||||
}
|
27
pay-service/src/main/java/com/hmall/pay/enums/PayStatus.java
Normal file
27
pay-service/src/main/java/com/hmall/pay/enums/PayStatus.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.hmall.pay.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum PayStatus {
|
||||
NOT_COMMIT(0, "未提交"),
|
||||
WAIT_BUYER_PAY(1, "待支付"),
|
||||
TRADE_CLOSED(2, "已关闭"),
|
||||
TRADE_SUCCESS(3, "支付成功"),
|
||||
TRADE_FINISHED(3, "支付成功"),
|
||||
;
|
||||
private final int value;
|
||||
private final String desc;
|
||||
|
||||
PayStatus(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean equalsValue(Integer value){
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return getValue() == value;
|
||||
}
|
||||
}
|
27
pay-service/src/main/java/com/hmall/pay/enums/PayType.java
Normal file
27
pay-service/src/main/java/com/hmall/pay/enums/PayType.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.hmall.pay.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum PayType{
|
||||
JSAPI(1, "网页支付JS"),
|
||||
MINI_APP(2, "小程序支付"),
|
||||
APP(3, "APP支付"),
|
||||
NATIVE(4, "扫码支付"),
|
||||
BALANCE(5, "余额支付"),
|
||||
;
|
||||
private final int value;
|
||||
private final String desc;
|
||||
|
||||
PayType(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean equalsValue(Integer value){
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return getValue() == value;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.pay.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hmall.pay.domain.po.PayOrder;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-16
|
||||
*/
|
||||
public interface PayOrderMapper extends BaseMapper<PayOrder> {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.hmall.pay.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hmall.pay.domain.dto.PayApplyDTO;
|
||||
import com.hmall.pay.domain.dto.PayOrderFormDTO;
|
||||
import com.hmall.pay.domain.po.PayOrder;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-16
|
||||
*/
|
||||
public interface IPayOrderService extends IService<PayOrder> {
|
||||
|
||||
String applyPayOrder(PayApplyDTO applyDTO);
|
||||
|
||||
void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO);
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
package com.hmall.pay.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import com.hmall.api.client.TradeClient;
|
||||
import com.hmall.api.client.UserClient;
|
||||
import com.hmall.common.exception.BizIllegalException;
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.common.utils.UserContext;
|
||||
import com.hmall.enums.PayStatus;
|
||||
import com.hmall.pay.domain.dto.PayApplyDTO;
|
||||
import com.hmall.pay.domain.dto.PayOrderFormDTO;
|
||||
import com.hmall.pay.domain.po.PayOrder;
|
||||
import com.hmall.pay.mapper.PayOrderMapper;
|
||||
import com.hmall.pay.service.IPayOrderService;
|
||||
import com.hmall.service.IOrderService;
|
||||
import com.hmall.service.IUserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-16
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
|
||||
|
||||
private final UserClient userClient;
|
||||
|
||||
private final TradeClient tradeClient;
|
||||
|
||||
@Override
|
||||
public String applyPayOrder(PayApplyDTO applyDTO) {
|
||||
// 1.幂等性校验
|
||||
PayOrder payOrder = checkIdempotent(applyDTO);
|
||||
// 2.返回结果
|
||||
return payOrder.getId().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO) {
|
||||
// 1.查询支付单
|
||||
PayOrder po = getById(payOrderFormDTO.getId());
|
||||
// 2.判断状态
|
||||
if(!PayStatus.WAIT_BUYER_PAY.equalsValue(po.getStatus())){
|
||||
// 订单不是未支付,状态异常
|
||||
throw new BizIllegalException("交易已支付或关闭!");
|
||||
}
|
||||
// 3.尝试扣减余额
|
||||
userClient.deductMoney(payOrderFormDTO.getPw(), po.getAmount());
|
||||
// 4.修改支付单状态
|
||||
boolean success = markPayOrderSuccess(payOrderFormDTO.getId(), LocalDateTime.now());
|
||||
if (!success) {
|
||||
throw new BizIllegalException("交易已支付或关闭!");
|
||||
}
|
||||
// 5.修改订单状态
|
||||
tradeClient.markOrderPaySuccess(po.getBizOrderNo());
|
||||
}
|
||||
|
||||
public boolean markPayOrderSuccess(Long id, LocalDateTime successTime) {
|
||||
return lambdaUpdate()
|
||||
.set(PayOrder::getStatus, PayStatus.TRADE_SUCCESS.getValue())
|
||||
.set(PayOrder::getPaySuccessTime, successTime)
|
||||
.eq(PayOrder::getId, id)
|
||||
// 支付状态的乐观锁判断
|
||||
.in(PayOrder::getStatus, PayStatus.NOT_COMMIT.getValue(), PayStatus.WAIT_BUYER_PAY.getValue())
|
||||
.update();
|
||||
}
|
||||
|
||||
|
||||
private PayOrder checkIdempotent(PayApplyDTO applyDTO) {
|
||||
// 1.首先查询支付单
|
||||
PayOrder oldOrder = queryByBizOrderNo(applyDTO.getBizOrderNo());
|
||||
// 2.判断是否存在
|
||||
if (oldOrder == null) {
|
||||
// 不存在支付单,说明是第一次,写入新的支付单并返回
|
||||
PayOrder payOrder = buildPayOrder(applyDTO);
|
||||
payOrder.setPayOrderNo(IdWorker.getId());
|
||||
save(payOrder);
|
||||
return payOrder;
|
||||
}
|
||||
// 3.旧单已经存在,判断是否支付成功
|
||||
if (PayStatus.TRADE_SUCCESS.equalsValue(oldOrder.getStatus())) {
|
||||
// 已经支付成功,抛出异常
|
||||
throw new BizIllegalException("订单已经支付!");
|
||||
}
|
||||
// 4.旧单已经存在,判断是否已经关闭
|
||||
if (PayStatus.TRADE_CLOSED.equalsValue(oldOrder.getStatus())) {
|
||||
// 已经关闭,抛出异常
|
||||
throw new BizIllegalException("订单已关闭");
|
||||
}
|
||||
// 5.旧单已经存在,判断支付渠道是否一致
|
||||
if (!StringUtils.equals(oldOrder.getPayChannelCode(), applyDTO.getPayChannelCode())) {
|
||||
// 支付渠道不一致,需要重置数据,然后重新申请支付单
|
||||
PayOrder payOrder = buildPayOrder(applyDTO);
|
||||
payOrder.setId(oldOrder.getId());
|
||||
payOrder.setQrCodeUrl("");
|
||||
updateById(payOrder);
|
||||
payOrder.setPayOrderNo(oldOrder.getPayOrderNo());
|
||||
return payOrder;
|
||||
}
|
||||
// 6.旧单已经存在,且可能是未支付或未提交,且支付渠道一致,直接返回旧数据
|
||||
return oldOrder;
|
||||
}
|
||||
|
||||
private PayOrder buildPayOrder(PayApplyDTO payApplyDTO) {
|
||||
// 1.数据转换
|
||||
PayOrder payOrder = BeanUtils.toBean(payApplyDTO, PayOrder.class);
|
||||
// 2.初始化数据
|
||||
payOrder.setPayOverTime(LocalDateTime.now().plusMinutes(120L));
|
||||
payOrder.setStatus(PayStatus.WAIT_BUYER_PAY.getValue());
|
||||
payOrder.setBizUserId(UserContext.getUser());
|
||||
return payOrder;
|
||||
}
|
||||
public PayOrder queryByBizOrderNo(Long bizOrderNo) {
|
||||
return lambdaQuery()
|
||||
.eq(PayOrder::getBizOrderNo, bizOrderNo)
|
||||
.one();
|
||||
}
|
||||
}
|
4
pay-service/src/main/resources/application-dev.yaml
Normal file
4
pay-service/src/main/resources/application-dev.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
hm:
|
||||
db:
|
||||
host: mysql
|
||||
pw: 123
|
4
pay-service/src/main/resources/application-local.yaml
Normal file
4
pay-service/src/main/resources/application-local.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
hm:
|
||||
db:
|
||||
host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
|
||||
pw: 123456 # 修改为docker中的MySQL密码
|
51
pay-service/src/main/resources/application.yaml
Normal file
51
pay-service/src/main/resources/application.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
server:
|
||||
port: 8086
|
||||
spring:
|
||||
application:
|
||||
name: pay-service
|
||||
cloud:
|
||||
nacos:
|
||||
server-addr: 124.71.159.195:8848 # nacos地址
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hm-pay?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
|
||||
global-config:
|
||||
db-config:
|
||||
update-strategy: not_null
|
||||
id-type: auto
|
||||
logging:
|
||||
level:
|
||||
com.hmall: debug
|
||||
pattern:
|
||||
dateformat: HH:mm:ss:SSS
|
||||
file:
|
||||
path: "logs/${spring.application.name}"
|
||||
knife4j:
|
||||
enable: true
|
||||
openapi:
|
||||
title: 黑马商城支付服务接口文档
|
||||
description: "黑马商城支付服务接口文档"
|
||||
email: zhangsan@itcast.cn
|
||||
concat: 宇哥
|
||||
url: https://www.itcast.cn
|
||||
version: v1.0.0
|
||||
group:
|
||||
default:
|
||||
group-name: default
|
||||
api-rule: package
|
||||
api-rule-resources:
|
||||
- com.hmall.pay.controller
|
||||
|
||||
feign:
|
||||
httpclient:
|
||||
enabled: true # 使用 Apache HttpClient(默认关闭)
|
||||
|
||||
|
||||
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
|
2
pom.xml
2
pom.xml
@ -15,6 +15,8 @@
|
||||
<module>cart-service</module>
|
||||
<module>user-service</module>
|
||||
<module>hm-api</module>
|
||||
<module>trade-service</module>
|
||||
<module>pay-service</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
|
67
trade-service/pom.xml
Normal file
67
trade-service/pom.xml
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hmall</artifactId>
|
||||
<groupId>com.heima</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>trade-service</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!--common-->
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!--web-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--数据库-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--mybatis-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.heima</groupId>
|
||||
<artifactId>hm-service</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!--nacos 服务注册发现-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,16 @@
|
||||
package com.hmall.trade;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@MapperScan("com.hmall.trade.mapper")
|
||||
@EnableFeignClients(basePackages= "com.hmall.api.client")
|
||||
@SpringBootApplication
|
||||
public class TradeApplication {
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplication.run(TradeApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.hmall.trade.controller;
|
||||
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
|
||||
import com.hmall.trade.domain.dto.OrderFormDTO;
|
||||
import com.hmall.trade.domain.vo.OrderVO;
|
||||
import com.hmall.trade.service.IOrderService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Api(tags = "订单管理接口")
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
@RequiredArgsConstructor
|
||||
public class OrderController {
|
||||
private final IOrderService orderService;
|
||||
|
||||
@ApiOperation("根据id查询订单")
|
||||
@GetMapping("{id}")
|
||||
public OrderVO queryOrderById(@Param ("订单id")@PathVariable("id") Long orderId) {
|
||||
return BeanUtils.copyBean(orderService.getById(orderId), OrderVO.class);
|
||||
}
|
||||
|
||||
@ApiOperation("创建订单")
|
||||
@PostMapping
|
||||
public Long createOrder(@RequestBody OrderFormDTO orderFormDTO){
|
||||
return orderService.createOrder(orderFormDTO);
|
||||
}
|
||||
|
||||
@ApiOperation("标记订单已支付")
|
||||
@ApiImplicitParam(name = "orderId", value = "订单id", paramType = "path")
|
||||
@PutMapping("/{orderId}")
|
||||
public void markOrderPaySuccess(@PathVariable("orderId") Long orderId) {
|
||||
orderService.markOrderPaySuccess(orderId);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.hmall.trade.domain.dto;
|
||||
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel(description = "交易下单表单实体")
|
||||
public class OrderFormDTO {
|
||||
@ApiModelProperty("收货地址id")
|
||||
private Long addressId;
|
||||
@ApiModelProperty("支付类型")
|
||||
private Integer paymentType;
|
||||
@ApiModelProperty("下单商品列表")
|
||||
private List<OrderDetailDTO> details;
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.hmall.trade.domain.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("`order`")
|
||||
public class Order implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 总金额,单位为分
|
||||
*/
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* 支付类型,1、支付宝,2、微信,3、扣减余额
|
||||
*/
|
||||
private Integer paymentType;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
private LocalDateTime payTime;
|
||||
|
||||
/**
|
||||
* 发货时间
|
||||
*/
|
||||
private LocalDateTime consignTime;
|
||||
|
||||
/**
|
||||
* 交易完成时间
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 交易关闭时间
|
||||
*/
|
||||
private LocalDateTime closeTime;
|
||||
|
||||
/**
|
||||
* 评价时间
|
||||
*/
|
||||
private LocalDateTime commentTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.hmall.trade.domain.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("order_detail")
|
||||
public class OrderDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单详情id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* sku商品id
|
||||
*/
|
||||
private Long itemId;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
private Integer num;
|
||||
|
||||
/**
|
||||
* 商品标题
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 商品动态属性键值集
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
/**
|
||||
* 价格,单位:分
|
||||
*/
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String image;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.hmall.trade.domain.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("order_logistics")
|
||||
public class OrderLogistics implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 订单id,与订单表一对一
|
||||
*/
|
||||
@TableId(value = "order_id", type = IdType.INPUT)
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 物流单号
|
||||
*/
|
||||
private String logisticsNumber;
|
||||
|
||||
/**
|
||||
* 物流公司名称
|
||||
*/
|
||||
private String logisticsCompany;
|
||||
|
||||
/**
|
||||
* 收件人
|
||||
*/
|
||||
private String contact;
|
||||
|
||||
/**
|
||||
* 收件人手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 省
|
||||
*/
|
||||
private String province;
|
||||
|
||||
/**
|
||||
* 市
|
||||
*/
|
||||
private String city;
|
||||
|
||||
/**
|
||||
* 区
|
||||
*/
|
||||
private String town;
|
||||
|
||||
/**
|
||||
* 街道
|
||||
*/
|
||||
private String street;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.hmall.trade.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@ApiModel(description = "订单页面VO")
|
||||
public class OrderVO {
|
||||
@ApiModelProperty("订单id")
|
||||
private Long id;
|
||||
@ApiModelProperty("总金额,单位为分")
|
||||
private Integer totalFee;
|
||||
@ApiModelProperty("支付类型,1、支付宝,2、微信,3、扣减余额")
|
||||
private Integer paymentType;
|
||||
@ApiModelProperty("用户id")
|
||||
private Long userId;
|
||||
@ApiModelProperty("订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价")
|
||||
private Integer status;
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty("支付时间")
|
||||
private LocalDateTime payTime;
|
||||
@ApiModelProperty("发货时间")
|
||||
private LocalDateTime consignTime;
|
||||
@ApiModelProperty("交易完成时间")
|
||||
private LocalDateTime endTime;
|
||||
@ApiModelProperty("交易关闭时间")
|
||||
private LocalDateTime closeTime;
|
||||
@ApiModelProperty("评价时间")
|
||||
private LocalDateTime commentTime;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.trade.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hmall.trade.domain.po.OrderDetail;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.trade.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hmall.trade.domain.po.OrderLogistics;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface OrderLogisticsMapper extends BaseMapper<OrderLogistics> {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.trade.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hmall.trade.domain.po.Order;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface OrderMapper extends BaseMapper<Order> {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.trade.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hmall.trade.domain.po.OrderDetail;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface IOrderDetailService extends IService<OrderDetail> {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hmall.trade.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hmall.trade.domain.po.OrderLogistics;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface IOrderLogisticsService extends IService<OrderLogistics> {
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.hmall.trade.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hmall.trade.domain.dto.OrderFormDTO;
|
||||
import com.hmall.trade.domain.po.Order;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface IOrderService extends IService<Order> {
|
||||
|
||||
Long createOrder(OrderFormDTO orderFormDTO);
|
||||
|
||||
void markOrderPaySuccess(Long orderId);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.hmall.trade.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import com.hmall.trade.domain.po.OrderDetail;
|
||||
import com.hmall.trade.mapper.OrderDetailMapper;
|
||||
import com.hmall.trade.service.IOrderDetailService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单详情表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Service
|
||||
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements IOrderDetailService {
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.hmall.trade.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import com.hmall.trade.domain.po.OrderLogistics;
|
||||
import com.hmall.trade.mapper.OrderLogisticsMapper;
|
||||
import com.hmall.trade.service.IOrderLogisticsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Service
|
||||
public class OrderLogisticsServiceImpl extends ServiceImpl<OrderLogisticsMapper, OrderLogistics> implements IOrderLogisticsService {
|
||||
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package com.hmall.trade.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hmall.api.client.CartClient;
|
||||
import com.hmall.api.client.ItemClient;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import com.hmall.common.exception.BadRequestException;
|
||||
import com.hmall.common.utils.UserContext;
|
||||
|
||||
|
||||
import com.hmall.trade.domain.dto.OrderFormDTO;
|
||||
import com.hmall.trade.domain.po.Order;
|
||||
import com.hmall.trade.domain.po.OrderDetail;
|
||||
import com.hmall.trade.mapper.OrderMapper;
|
||||
import com.hmall.trade.service.IOrderDetailService;
|
||||
import com.hmall.trade.service.IOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 虎哥
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
|
||||
|
||||
private final ItemClient itemClient;
|
||||
private final IOrderDetailService detailService;
|
||||
private final CartClient cartClient;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createOrder(OrderFormDTO orderFormDTO) {
|
||||
// 1.订单数据
|
||||
Order order = new Order();
|
||||
// 1.1.查询商品
|
||||
List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
|
||||
// 1.2.获取商品id和数量的Map
|
||||
Map<Long, Integer> itemNumMap = detailDTOS.stream()
|
||||
.collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
|
||||
Set<Long> itemIds = itemNumMap.keySet();
|
||||
// 1.3.查询商品
|
||||
List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
|
||||
if (items == null || items.size() < itemIds.size()) {
|
||||
throw new BadRequestException("商品不存在");
|
||||
}
|
||||
// 1.4.基于商品价格、购买数量计算商品总价:totalFee
|
||||
int total = 0;
|
||||
for (ItemDTO item : items) {
|
||||
total += item.getPrice() * itemNumMap.get(item.getId());
|
||||
}
|
||||
order.setTotalFee(total);
|
||||
// 1.5.其它属性
|
||||
order.setPaymentType(orderFormDTO.getPaymentType());
|
||||
order.setUserId(UserContext.getUser());
|
||||
order.setStatus(1);
|
||||
// 1.6.将Order写入数据库order表中
|
||||
save(order);
|
||||
|
||||
// 2.保存订单详情
|
||||
List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
|
||||
detailService.saveBatch(details);
|
||||
|
||||
// 3.清理购物车商品
|
||||
cartClient.deleteCartItemByIds(itemIds);
|
||||
|
||||
// 4.扣减库存
|
||||
try {
|
||||
itemClient.deductStock(detailDTOS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("库存不足!");
|
||||
}
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markOrderPaySuccess(Long orderId) {
|
||||
Order order = new Order();
|
||||
order.setId(orderId);
|
||||
order.setStatus(2);
|
||||
order.setPayTime(LocalDateTime.now());
|
||||
updateById(order);
|
||||
}
|
||||
|
||||
private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
|
||||
List<OrderDetail> details = new ArrayList<>(items.size());
|
||||
for (ItemDTO item : items) {
|
||||
OrderDetail detail = new OrderDetail();
|
||||
detail.setName(item.getName());
|
||||
detail.setSpec(item.getSpec());
|
||||
detail.setPrice(item.getPrice());
|
||||
detail.setNum(numMap.get(item.getId()));
|
||||
detail.setItemId(item.getId());
|
||||
detail.setImage(item.getImage());
|
||||
detail.setOrderId(orderId);
|
||||
details.add(detail);
|
||||
}
|
||||
return details;
|
||||
}
|
||||
}
|
4
trade-service/src/main/resources/application-dev.yaml
Normal file
4
trade-service/src/main/resources/application-dev.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
hm:
|
||||
db:
|
||||
host: mysql
|
||||
pw: 123
|
4
trade-service/src/main/resources/application-local.yaml
Normal file
4
trade-service/src/main/resources/application-local.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
hm:
|
||||
db:
|
||||
host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
|
||||
pw: 123456 # 修改为docker中的MySQL密码
|
51
trade-service/src/main/resources/application.yaml
Normal file
51
trade-service/src/main/resources/application.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
server:
|
||||
port: 8085
|
||||
spring:
|
||||
application:
|
||||
name: trade-service
|
||||
cloud:
|
||||
nacos:
|
||||
server-addr: 124.71.159.195:8848 # nacos地址
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hm-trade?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
|
||||
global-config:
|
||||
db-config:
|
||||
update-strategy: not_null
|
||||
id-type: auto
|
||||
logging:
|
||||
level:
|
||||
com.hmall: debug
|
||||
pattern:
|
||||
dateformat: HH:mm:ss:SSS
|
||||
file:
|
||||
path: "logs/${spring.application.name}"
|
||||
knife4j:
|
||||
enable: true
|
||||
openapi:
|
||||
title: 黑马商城交易服务接口文档
|
||||
description: "黑马商城交易服务接口文档"
|
||||
email: zhangsan@itcast.cn
|
||||
concat: 宇哥
|
||||
url: https://www.itcast.cn
|
||||
version: v1.0.0
|
||||
group:
|
||||
default:
|
||||
group-name: default
|
||||
api-rule: package
|
||||
api-rule-resources:
|
||||
- com.hmall.trade.controller
|
||||
|
||||
feign:
|
||||
httpclient:
|
||||
enabled: true # 使用 Apache HttpClient(默认关闭)
|
||||
|
||||
|
||||
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
|
@ -9,7 +9,7 @@ spring:
|
||||
profiles:
|
||||
active: local
|
||||
datasource:
|
||||
url: jdbc:mysql://${hm.db.host}:3306/hm-user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://${hm.db.host}:3307/hm-user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${hm.db.pw}
|
||||
|
Loading…
x
Reference in New Issue
Block a user