feat(order): 添加订单列表查询功能

- 新增 OrderQueryRequestDTO 请求对象,支持多条件查询和分页参数
- 新增 OrderListResponseDTO 响应对象,包含客户订单和 PayPal 订单信息
- 在 CustomerOrderController 中添加 /query 接口,支持 POST 方式查询订单列表
- 在 CustomerOrderService 和实现类中添加 queryOrders 方法,实现订单查询逻辑
- 支持按订单号、状态、客户信息、商品名称等条件查询
- 支持按 PayPal 订单相关条件查询,关联查询 PayPal 支付信息
- 实现分页查询功能,限制每页最大数量为 100
- 添加时间范围查询和多种排序功能
- 优化 N+1 查询问题,批量查询 PayPal 订单信息
- 添加详细的查询日志记录和性能监控
- 更新项目完善计划文档,记录待办功能和优化项
This commit is contained in:
2025-12-25 18:11:57 +08:00
parent 10d0bfa9f6
commit f8d116f9a3
8 changed files with 2769 additions and 0 deletions

View File

@@ -3,8 +3,10 @@ package com.mtkj.mtpay.controller;
import com.mtkj.mtpay.common.Result;
import com.mtkj.mtpay.dto.request.CalculateCurrencyConversionRequestDTO;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.request.OrderQueryRequestDTO;
import com.mtkj.mtpay.dto.response.CurrencyConversionDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
import com.mtkj.mtpay.dto.response.PageResult;
import com.mtkj.mtpay.service.CustomerOrderService;
import com.mtkj.mtpay.service.ExchangeRateService;
import jakarta.validation.Valid;
@@ -134,6 +136,18 @@ public class CustomerOrderController {
return Result.success(order);
}
/**
* 查询订单列表(支持多条件查询和分页)
*/
@PostMapping("/query")
public Result<PageResult<com.mtkj.mtpay.dto.response.OrderListResponseDTO>> queryOrders(
@RequestBody OrderQueryRequestDTO query) {
log.info("查询订单列表,查询条件:{}", query);
PageResult<com.mtkj.mtpay.dto.response.OrderListResponseDTO> pageResult =
customerOrderService.queryOrders(query);
return Result.success(pageResult);
}
/**
* 构建汇率说明文本
*/

View File

@@ -0,0 +1,96 @@
package com.mtkj.mtpay.dto.request;
import lombok.Data;
/**
* 订单列表查询请求DTO
*/
@Data
public class OrderQueryRequestDTO {
/**
* 订单号(精确查询)
*/
private String orderNo;
/**
* PayPal订单ID精确查询
*/
private String paypalOrderId;
/**
* 商户订单号精确查询等同于orderNo
*/
private String merchantOrderNo;
/**
* 订单状态PENDING-待支付PAID-已支付SHIPPED-已发货COMPLETED-已完成CANCELLED-已取消)
*/
private String status;
/**
* 支付状态UNPAID-未支付PAID-已支付FAILED-支付失败)
*/
private String paymentStatus;
/**
* PayPal订单状态CREATED-已创建APPROVED-已批准COMPLETED-已完成VOIDED-已取消等)
*/
private String paypalStatus;
/**
* PayPal支付状态COMPLETED-已完成DENIED-被拒绝PENDING-待处理等)
*/
private String paypalPaymentStatus;
/**
* 客户姓名(模糊查询)
*/
private String customerName;
/**
* 客户电话(模糊查询)
*/
private String customerPhone;
/**
* 客户邮箱(模糊查询)
*/
private String customerEmail;
/**
* 商品名称(模糊查询)
*/
private String productName;
/**
* 支付者邮箱PayPal模糊查询
*/
private String payerEmail;
/**
* 支付者姓名PayPal模糊查询
*/
private String payerName;
/**
* 开始时间(订单创建时间)
*/
private String startTime;
/**
* 结束时间(订单创建时间)
*/
private String endTime;
/**
* 当前页码从1开始默认1
*/
private Integer pageNum = 1;
/**
* 每页大小默认10
*/
private Integer pageSize = 10;
}

View File

@@ -0,0 +1,155 @@
package com.mtkj.mtpay.dto.response;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单列表响应DTO包含客户订单和PayPal订单信息
*/
@Data
public class OrderListResponseDTO implements Serializable {
/**
* 客户订单ID
*/
private Long id;
/**
* 订单号
*/
private String orderNo;
/**
* 商品ID
*/
private Long productId;
/**
* 商品名称
*/
private String productName;
/**
* SKU名称
*/
private String skuName;
/**
* 购买数量
*/
private Integer quantity;
/**
* 订单总金额(原始货币)
*/
private BigDecimal totalAmount;
/**
* 原始货币代码
*/
private String originalCurrency;
/**
* 原始订单金额
*/
private BigDecimal originalAmount;
/**
* 支付货币代码
*/
private String paymentCurrency;
/**
* 支付金额
*/
private BigDecimal paymentAmount;
/**
* 订单状态PENDING-待支付PAID-已支付SHIPPED-已发货COMPLETED-已完成CANCELLED-已取消)
*/
private String status;
/**
* 支付状态UNPAID-未支付PAID-已支付FAILED-支付失败)
*/
private String paymentStatus;
/**
* 客户姓名
*/
private String customerName;
/**
* 客户电话
*/
private String customerPhone;
/**
* 客户邮箱
*/
private String customerEmail;
/**
* 收货国家
*/
private String shippingCountry;
/**
* 收货城市
*/
private String shippingCity;
/**
* PayPal订单ID
*/
private String paypalOrderId;
/**
* PayPal订单状态CREATED-已创建APPROVED-已批准COMPLETED-已完成VOIDED-已取消等)
*/
private String paypalStatus;
/**
* PayPal支付状态COMPLETED-已完成DENIED-被拒绝PENDING-待处理等)
*/
private String paypalPaymentStatus;
/**
* 支付者邮箱PayPal
*/
private String payerEmail;
/**
* 支付者姓名PayPal
*/
private String payerName;
/**
* 支付捕获IDPayPal
*/
private String captureId;
/**
* 订单创建时间
*/
private LocalDateTime createTime;
/**
* 订单更新时间
*/
private LocalDateTime updateTime;
/**
* PayPal订单创建时间
*/
private LocalDateTime paypalCreateTime;
/**
* PayPal订单更新时间
*/
private LocalDateTime paypalUpdateTime;
}

View File

@@ -1,7 +1,9 @@
package com.mtkj.mtpay.service;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.request.OrderQueryRequestDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
import com.mtkj.mtpay.dto.response.PageResult;
/**
* 客户订单服务接口
@@ -58,5 +60,12 @@ public interface CustomerOrderService {
String paymentCurrency,
java.math.BigDecimal paymentAmount,
java.math.BigDecimal exchangeRate);
/**
* 查询订单列表(支持多条件查询和分页)
* @param query 查询条件(包含分页参数)
* @return 分页结果
*/
PageResult<com.mtkj.mtpay.dto.response.OrderListResponseDTO> queryOrders(OrderQueryRequestDTO query);
}

View File

@@ -3,8 +3,14 @@ package com.mtkj.mtpay.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mtkj.mtpay.common.ResultCode;
import com.mtkj.mtpay.common.enums.ProductStatus;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.request.OrderQueryRequestDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
import com.mtkj.mtpay.dto.response.OrderListResponseDTO;
import com.mtkj.mtpay.dto.response.PageResult;
import com.mtkj.mtpay.entity.PayPalPaymentOrder;
import com.mtkj.mtpay.entity.CustomerOrder;
import com.mtkj.mtpay.entity.MtProduct;
import com.mtkj.mtpay.entity.MtProductSku;
@@ -12,6 +18,7 @@ import com.mtkj.mtpay.exception.BusinessException;
import com.mtkj.mtpay.mapper.CustomerOrderMapper;
import com.mtkj.mtpay.mapper.MtProductMapper;
import com.mtkj.mtpay.mapper.MtProductSkuMapper;
import com.mtkj.mtpay.mapper.PayPalPaymentOrderMapper;
import com.mtkj.mtpay.service.CustomerOrderService;
import com.mtkj.mtpay.util.BaiduTranslatorUtils;
import com.mtkj.mtpay.util.OrderIdGenerator;
@@ -38,6 +45,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
private final CustomerOrderMapper customerOrderMapper;
private final MtProductMapper productMapper;
private final MtProductSkuMapper productSkuMapper;
private final PayPalPaymentOrderMapper payPalPaymentOrderMapper;
private final BaiduTranslatorUtils baiduTranslatorUtils;
@Override
@@ -319,5 +327,203 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
log.info("订单状态更新成功,订单号: {}", orderNo);
}
@Override
public PageResult<OrderListResponseDTO> queryOrders(OrderQueryRequestDTO query) {
long startTime = System.currentTimeMillis();
// 处理分页参数
int pageNum = query.getPageNum() != null && query.getPageNum() > 0 ? query.getPageNum() : 1;
int pageSize = query.getPageSize() != null && query.getPageSize() > 0 ? query.getPageSize() : 10;
// 限制每页最大数量
if (pageSize > 100) {
pageSize = 100;
log.warn("每页大小超过限制已调整为100原始值: {}", query.getPageSize());
}
log.info("查询订单列表,查询条件: {}, 页码: {}, 每页大小: {}", query, pageNum, pageSize);
// 1. 构建客户订单查询条件
LambdaQueryWrapper<CustomerOrder> orderWrapper = new LambdaQueryWrapper<>();
// 订单号查询
if (query.getOrderNo() != null && !query.getOrderNo().trim().isEmpty()) {
orderWrapper.eq(CustomerOrder::getOrderNo, query.getOrderNo().trim());
}
// 订单状态查询
if (query.getStatus() != null && !query.getStatus().trim().isEmpty()) {
orderWrapper.eq(CustomerOrder::getStatus, query.getStatus().trim());
}
// 支付状态查询
if (query.getPaymentStatus() != null && !query.getPaymentStatus().trim().isEmpty()) {
orderWrapper.eq(CustomerOrder::getPaymentStatus, query.getPaymentStatus().trim());
}
// 客户姓名模糊查询
if (query.getCustomerName() != null && !query.getCustomerName().trim().isEmpty()) {
orderWrapper.like(CustomerOrder::getCustomerName, query.getCustomerName().trim());
}
// 客户电话模糊查询
if (query.getCustomerPhone() != null && !query.getCustomerPhone().trim().isEmpty()) {
orderWrapper.like(CustomerOrder::getCustomerPhone, query.getCustomerPhone().trim());
}
// 客户邮箱模糊查询
if (query.getCustomerEmail() != null && !query.getCustomerEmail().trim().isEmpty()) {
orderWrapper.like(CustomerOrder::getCustomerEmail, query.getCustomerEmail().trim());
}
// 商品名称模糊查询
if (query.getProductName() != null && !query.getProductName().trim().isEmpty()) {
orderWrapper.like(CustomerOrder::getProductName, query.getProductName().trim());
}
// 时间范围查询
if (query.getStartTime() != null && !query.getStartTime().trim().isEmpty()) {
try {
java.time.LocalDateTime start = java.time.LocalDateTime.parse(query.getStartTime().trim());
orderWrapper.ge(CustomerOrder::getCreateTime, start);
} catch (Exception e) {
log.warn("开始时间格式错误: {}", query.getStartTime(), e);
}
}
if (query.getEndTime() != null && !query.getEndTime().trim().isEmpty()) {
try {
java.time.LocalDateTime end = java.time.LocalDateTime.parse(query.getEndTime().trim());
orderWrapper.le(CustomerOrder::getCreateTime, end);
} catch (Exception e) {
log.warn("结束时间格式错误: {}", query.getEndTime(), e);
}
}
// 如果指定了PayPal相关查询条件需要先查询PayPal订单获取对应的商户订单号
java.util.List<String> merchantOrderNos = null;
if (query.getPaypalOrderId() != null && !query.getPaypalOrderId().trim().isEmpty() ||
query.getMerchantOrderNo() != null && !query.getMerchantOrderNo().trim().isEmpty() ||
query.getPaypalStatus() != null && !query.getPaypalStatus().trim().isEmpty() ||
query.getPaypalPaymentStatus() != null && !query.getPaypalPaymentStatus().trim().isEmpty() ||
query.getPayerEmail() != null && !query.getPayerEmail().trim().isEmpty() ||
query.getPayerName() != null && !query.getPayerName().trim().isEmpty()) {
// 构建PayPal订单查询条件
LambdaQueryWrapper<PayPalPaymentOrder> paypalWrapper = new LambdaQueryWrapper<>();
if (query.getPaypalOrderId() != null && !query.getPaypalOrderId().trim().isEmpty()) {
paypalWrapper.eq(PayPalPaymentOrder::getPaypalOrderId, query.getPaypalOrderId().trim());
}
if (query.getMerchantOrderNo() != null && !query.getMerchantOrderNo().trim().isEmpty()) {
paypalWrapper.eq(PayPalPaymentOrder::getMerchantOrderNo, query.getMerchantOrderNo().trim());
}
if (query.getPaypalStatus() != null && !query.getPaypalStatus().trim().isEmpty()) {
paypalWrapper.eq(PayPalPaymentOrder::getStatus, query.getPaypalStatus().trim());
}
if (query.getPaypalPaymentStatus() != null && !query.getPaypalPaymentStatus().trim().isEmpty()) {
paypalWrapper.eq(PayPalPaymentOrder::getPaymentStatus, query.getPaypalPaymentStatus().trim());
}
if (query.getPayerEmail() != null && !query.getPayerEmail().trim().isEmpty()) {
paypalWrapper.like(PayPalPaymentOrder::getPayerEmail, query.getPayerEmail().trim());
}
if (query.getPayerName() != null && !query.getPayerName().trim().isEmpty()) {
paypalWrapper.like(PayPalPaymentOrder::getPayerName, query.getPayerName().trim());
}
// 查询PayPal订单获取商户订单号列表
java.util.List<PayPalPaymentOrder> paypalOrders = payPalPaymentOrderMapper.selectList(paypalWrapper);
merchantOrderNos = paypalOrders.stream()
.map(PayPalPaymentOrder::getMerchantOrderNo)
.filter(java.util.Objects::nonNull)
.distinct()
.collect(java.util.stream.Collectors.toList());
if (merchantOrderNos.isEmpty()) {
// 如果PayPal订单查询结果为空直接返回空分页结果
log.debug("PayPal订单查询结果为空返回空列表");
return new PageResult<>((long) pageNum, (long) pageSize, 0L, new java.util.ArrayList<>());
}
// 将商户订单号作为客户订单的查询条件
orderWrapper.in(CustomerOrder::getOrderNo, merchantOrderNos);
}
// 按创建时间降序排序
orderWrapper.orderByDesc(CustomerOrder::getCreateTime);
// 使用MyBatis-Plus分页查询
Page<CustomerOrder> page = new Page<>(pageNum, pageSize);
IPage<CustomerOrder> orderPage = customerOrderMapper.selectPage(page, orderWrapper);
java.util.List<CustomerOrder> orders = orderPage.getRecords();
log.debug("查询到订单数量: {}/{}, 总记录数: {}", orders.size(), pageSize, orderPage.getTotal());
if (orders.isEmpty()) {
log.info("订单列表为空,耗时: {}ms", System.currentTimeMillis() - startTime);
return new PageResult<>((long) pageNum, (long) pageSize, orderPage.getTotal(), new java.util.ArrayList<>());
}
// 2. 批量查询PayPal订单信息优化N+1问题
java.util.List<String> orderNos = orders.stream()
.map(CustomerOrder::getOrderNo)
.filter(java.util.Objects::nonNull)
.collect(java.util.stream.Collectors.toList());
java.util.Map<String, PayPalPaymentOrder> paypalOrderMap = new java.util.HashMap<>();
if (!orderNos.isEmpty()) {
LambdaQueryWrapper<PayPalPaymentOrder> paypalWrapper = new LambdaQueryWrapper<>();
paypalWrapper.in(PayPalPaymentOrder::getMerchantOrderNo, orderNos);
java.util.List<PayPalPaymentOrder> paypalOrders = payPalPaymentOrderMapper.selectList(paypalWrapper);
paypalOrderMap = paypalOrders.stream()
.collect(java.util.stream.Collectors.toMap(
PayPalPaymentOrder::getMerchantOrderNo,
order -> order,
(existing, replacement) -> existing // 如果有重复,保留第一个
));
log.debug("批量查询到PayPal订单数量: {}", paypalOrderMap.size());
}
// 3. 组装响应数据
java.util.List<OrderListResponseDTO> result = new java.util.ArrayList<>();
for (CustomerOrder order : orders) {
OrderListResponseDTO dto = new OrderListResponseDTO();
BeanUtils.copyProperties(order, dto);
// 设置PayPal订单信息
PayPalPaymentOrder paypalOrder = paypalOrderMap.get(order.getOrderNo());
if (paypalOrder != null) {
dto.setPaypalOrderId(paypalOrder.getPaypalOrderId());
dto.setPaypalStatus(paypalOrder.getStatus());
dto.setPaypalPaymentStatus(paypalOrder.getPaymentStatus());
dto.setPayerEmail(paypalOrder.getPayerEmail());
dto.setPayerName(paypalOrder.getPayerName());
dto.setCaptureId(paypalOrder.getCaptureId());
dto.setPaypalCreateTime(paypalOrder.getCreateTime());
dto.setPaypalUpdateTime(paypalOrder.getUpdateTime());
}
result.add(dto);
}
long endTime = System.currentTimeMillis();
log.info("查询订单列表完成,查询条件: {}, 结果数量: {}/{}, 总记录数: {}, 耗时: {}ms",
query, result.size(), pageSize, orderPage.getTotal(), endTime - startTime);
// 构建分页结果
return new PageResult<>(
orderPage.getCurrent(),
orderPage.getSize(),
orderPage.getTotal(),
result
);
}
}