diff --git a/src/main/java/com/cultural/heritage/constant/OrderStatusConstant.java b/src/main/java/com/cultural/heritage/constant/OrderStatusConstant.java new file mode 100644 index 0000000..eeb9258 --- /dev/null +++ b/src/main/java/com/cultural/heritage/constant/OrderStatusConstant.java @@ -0,0 +1,24 @@ +package com.cultural.heritage.constant; + +public interface OrderStatusConstant { + + + String PENDING_PAYMENT = "待支付"; + + + String PENDING_SHIPMENT = "待发货"; + + + String PENDING_DELIVERY = "待收货"; + + + String TRANSACTION_CLOSED = "交易关闭"; + + + String TRANSACTION_SUCCESSFUL = "交易成功"; + + + String PAYMENT_REFUNDED = "已退款"; + + +} diff --git a/src/main/java/com/cultural/heritage/controller/order/OrderController.java b/src/main/java/com/cultural/heritage/controller/order/OrderController.java index 800bf9f..263d377 100644 --- a/src/main/java/com/cultural/heritage/controller/order/OrderController.java +++ b/src/main/java/com/cultural/heritage/controller/order/OrderController.java @@ -7,6 +7,7 @@ import com.cultural.heritage.annotation.AuthCheck; import com.cultural.heritage.common.BaseResponse; import com.cultural.heritage.common.ErrorCode; import com.cultural.heritage.common.ResultUtils; +import com.cultural.heritage.constant.OrderStatusConstant; import com.cultural.heritage.constant.UserConstant; import com.cultural.heritage.exception.BusinessException; import com.cultural.heritage.exception.ThrowUtils; @@ -23,6 +24,7 @@ import com.cultural.heritage.model.vo.order.OrderVO; import com.cultural.heritage.service.order.OrderItemService; import com.cultural.heritage.service.order.OrderService; import com.cultural.heritage.service.user.UserService; +import com.cultural.heritage.utils.OrderNumberUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -78,6 +80,11 @@ public class OrderController { Order order = new Order(); BeanUtils.copyProperties(orderAddRequest, order); order.setUserId(loginUser.getId()); + // 生成订单编号 + String orderNumber = OrderNumberUtils.generateOrderId(); + order.setOrderNumber(orderNumber); + // 设置订单状态 + order.setOrderStatus(OrderStatusConstant.PENDING_PAYMENT); // 校验订单 orderService.validOrder(order); boolean result = orderService.save(order); diff --git a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java index ad5b75d..9a19695 100644 --- a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java +++ b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java @@ -4,6 +4,7 @@ package com.cultural.heritage.controller.wx; import com.cultural.heritage.common.BaseResponse; import com.cultural.heritage.common.ErrorCode; import com.cultural.heritage.common.ResultUtils; +import com.cultural.heritage.constant.OrderStatusConstant; import com.cultural.heritage.exception.BusinessException; import com.cultural.heritage.exception.ThrowUtils; import com.cultural.heritage.model.dto.CommonRequest; @@ -55,7 +56,7 @@ public class WeChatPayController { Long orderId = commonRequest.getId(); Order order = ordersService.getById(orderId); ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在"); -// ThrowUtils.throwIf(order.getState() != 0, ErrorCode.OPERATION_ERROR, "订单状态错误"); + ThrowUtils.throwIf(!order.getOrderStatus().equals(OrderStatusConstant.PENDING_PAYMENT), ErrorCode.OPERATION_ERROR, "订单状态错误"); if (!loginUser.getId().equals(order.getUserId())) { throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "你不是该订单用户!"); } diff --git a/src/main/java/com/cultural/heritage/model/dto/order/capital/OrderMainInfoAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/order/capital/OrderMainInfoAddRequest.java index dd9fa6c..c3bad9e 100644 --- a/src/main/java/com/cultural/heritage/model/dto/order/capital/OrderMainInfoAddRequest.java +++ b/src/main/java/com/cultural/heritage/model/dto/order/capital/OrderMainInfoAddRequest.java @@ -34,12 +34,12 @@ public class OrderMainInfoAddRequest implements Serializable { @Schema(description = "用户昵称", example = "Hello") private String userName; - - /** - * 订单编号 - */ - @Schema(description = "订单编号", example = "1432442845453453") - private String orderNumber; +// +// /** +// * 订单编号 +// */ +// @Schema(description = "订单编号", example = "1432442845453453") +// private String orderNumber; /** @@ -69,11 +69,11 @@ public class OrderMainInfoAddRequest implements Serializable { @Schema(description = "订单总金额", example = "560") private BigDecimal totalAmount; - /** - * 订单状态 - */ - @Schema(description = "订单状态", example = "已支付") - private String orderStatus; +// /** +// * 订单状态 +// */ +// @Schema(description = "订单状态", example = "已支付") +// private String orderStatus; /** * 订单备注 diff --git a/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java b/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java index 9f78265..ae0df72 100644 --- a/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java +++ b/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java @@ -97,8 +97,6 @@ public class OrderServiceImpl extends ServiceImpl implements Long contactsId = orderMainInfoAddRequest.getContactsId(); Long couponId = orderMainInfoAddRequest.getCouponId(); String orderType = orderMainInfoAddRequest.getOrderType(); - String orderNumber = orderMainInfoAddRequest.getOrderNumber(); - String orderStatus = orderMainInfoAddRequest.getOrderStatus(); String note = orderMainInfoAddRequest.getNote(); BigDecimal totalAmount = orderMainInfoAddRequest.getTotalAmount(); List orderItemMainInfoAddRequestList = orderMainInfoAddRequest.getOrderItemMainInfoAddRequestList(); @@ -144,8 +142,6 @@ public class OrderServiceImpl extends ServiceImpl implements // 创建订单详细信息请求体 OrderAddRequest orderAddRequest = new OrderAddRequest(); orderAddRequest.setUserName(userName); - orderAddRequest.setOrderNumber(orderNumber); - orderAddRequest.setOrderStatus(orderStatus); orderAddRequest.setOrderType(orderType); orderAddRequest.setNote(note); orderAddRequest.setTotalAmount(totalAmount); diff --git a/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java index 3af5025..efa1ab3 100644 --- a/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java +++ b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java @@ -4,11 +4,13 @@ package com.cultural.heritage.service.wxpay.impl; import cn.binarywang.wx.miniapp.api.WxMaMsgService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; -import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.cultural.heritage.common.ErrorCode; import com.cultural.heritage.config.WxOpenConfig; import com.cultural.heritage.config.WxPayConfig; +import com.cultural.heritage.constant.OrderStatusConstant; import com.cultural.heritage.exception.BusinessException; +import com.cultural.heritage.exception.ThrowUtils; import com.cultural.heritage.model.entity.Order; import com.cultural.heritage.service.order.OrderService; import com.cultural.heritage.service.wxpay.WeChatService; @@ -31,11 +33,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.BufferedReader; -import java.io.IOException; import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; import java.util.ArrayList; import java.util.List; @@ -53,9 +51,8 @@ public class WeChatServiceImpl implements WeChatService { private WxOpenConfig wxOpenConfig; @Resource - private OrderService ordersService; + private OrderService orderService; - private String orderNumber; /** * 请求参数 @@ -80,12 +77,15 @@ public class WeChatServiceImpl implements WeChatService { Payer payer = new Payer(); payer.setOpenid(miniOpenId); request.setPayer(payer); + // 获取订单号 + Order order = orderService.getById(orderId); + String orderNumber = order.getOrderNumber(); // 描述 - request.setDescription("订单号:" + orderId); + request.setDescription("订单号:" + orderNumber); // 微信回调地址 request.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/payment/callback"); // 商户订单号 - this.orderNumber = RandomUtil.randomNumbers(12); + request.setOutTradeNo(orderNumber); //返回数据,前端调起支付 return wxPayConfig.getJsapiServiceExtension().prepayWithRequestPayment(request); @@ -99,54 +99,32 @@ public class WeChatServiceImpl implements WeChatService { @Override @Transactional(rollbackFor = Exception.class) - public synchronized boolean paymentCallback(Transaction transaction) throws IOException { + public synchronized boolean paymentCallback(Transaction transaction) { System.out.println("---------------------------微信支付回调(开始)-------------------------------"); // 获取订单信息 String orderIdByString = transaction.getOutTradeNo(); - Order order = ordersService.getById(orderIdByString); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orderNumber", orderIdByString); + Order order = orderService.getOne(queryWrapper); if (order == null) { log.error("订单不存在"); throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在,订单号:" + transaction.getOutTradeNo()); } - // 生成取餐码 - // 获取当日的日期 - LocalDate today = LocalDate.now(); - // 获取当日的 00:00 时间 - LocalDateTime startTime = today.atStartOfDay(); - // 获取当日的 23:59 时间 - LocalDateTime endTime = today.atTime(LocalTime.MAX); -// // 生成取餐码 -// QueryWrapper queryWrapper = new QueryWrapper<>(); -// queryWrapper.eq("businessId", order.getBusinessId()); -// queryWrapper.between("createTime", startTime, endTime); -// queryWrapper.in("state", 1, 2); -// long count = ordersService.count(queryWrapper); -// String pickupCode = String.format("%04d", count + 1); -// // 修改订单信息 -// order.setState(1); -// order.setPickupCode(pickupCode); -// Date date = new Date(); -// order.setUpdateTime(date); -// boolean update = ordersService.updateById(order); -// ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "修改订单状态失败"); -// // 通知商家新订单 -// Business business = businessService.getById(order.getBusinessId()); -// Long userId = order.getUserId(); -// Long businessId = business.getUserId(); -// MessageVO messageVO = new MessageVO(); -// messageVO.setType(1); -// messageVO.setUserId(userId); -// messageVO.setToUserId(businessId); -// messageVO.setContent(orderIdByString); -// String message = JSONUtil.toJsonStr(messageVO); -// // 通知商家新订单 -// webSocketServer.onMessage(message); + // 修改订单状态 + order.setOrderStatus(OrderStatusConstant.PENDING_SHIPMENT); + boolean update = orderService.updateById(order); + ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "订单状态修改失败"); + System.out.println("---------------------------微信支付回调(结束)-------------------------------"); return true; } @Override public Refund refundPayment(String orderId, BigDecimal amount) { + // 获取订单号 + Order order = orderService.getById(orderId); + ThrowUtils.throwIf(order == null, ErrorCode.OPERATION_ERROR, "该订单不存在"); + String orderNumber = order.getOrderNumber(); // 退款请求 CreateRequest createRequest = new CreateRequest(); // 商户订单号 @@ -181,10 +159,18 @@ public class WeChatServiceImpl implements WeChatService { System.out.println("---------------------------微信退款回调(开始)-------------------------------"); // 获取订单信息 String orderIdByString = refundNotification.getOutTradeNo(); - Order order = ordersService.getById(orderIdByString); - // 修改订单信息 - order.setOrderStatus("已退款"); - ordersService.updateById(order); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orderNumber", orderIdByString); + Order order = orderService.getOne(queryWrapper); + if (order == null) { + log.error("订单不存在"); + throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在,订单号:" + orderIdByString); + } + + // 修改订单状态 + order.setOrderStatus(OrderStatusConstant.PAYMENT_REFUNDED); + boolean update = orderService.updateById(order); + ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "订单状态修改失败"); System.out.println("---------------------------微信退款回调(结束)-------------------------------"); return true; } diff --git a/src/main/java/com/cultural/heritage/utils/OrderNumberUtils.java b/src/main/java/com/cultural/heritage/utils/OrderNumberUtils.java new file mode 100644 index 0000000..f50c364 --- /dev/null +++ b/src/main/java/com/cultural/heritage/utils/OrderNumberUtils.java @@ -0,0 +1,82 @@ +package com.cultural.heritage.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class OrderNumberUtils { + + + // 定义日期格式化器,精确到秒 + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + // 定义序列号最大值 + private static final int MAX_SEQUENCE = 999999; + + // 当前日期,初始化为当天 + private static String currentDate = getCurrentDate(); + + // 自增序列号,线程安全 + private static final AtomicInteger sequence = new AtomicInteger(0); + + // 锁对象,用于保护自增序列号的生成 + private static final Lock lock = new ReentrantLock(); + + + public static String generateOrderId() { + // 获取当前日期 + String today = getCurrentDate(); + + // 如果日期发生变化,重置序列号 + if (!today.equals(currentDate)) { + currentDate = today; + sequence.set(0); // 重置序列号 + } + + // 获取时间戳(精确到秒) + String timestamp = DATE_FORMAT.format(new Date()); + + // 获取4位随机数 + String randomNumber = generateRandomNumber(); + + // 获取6位自增序列号,并确保不超过最大值 + int seq = getNextSequence(); + + // 格式化序列号为6位 + String formattedSequence = String.format("%06d", seq); + + // 拼接生成订单号 + return timestamp + randomNumber + formattedSequence; + } + + // 获取当前日期(格式:yyyyMMdd) + private static String getCurrentDate() { + return new SimpleDateFormat("yyyyMMdd").format(new Date()); + } + + // 生成4位随机数(范围:0000到9999) + private static String generateRandomNumber() { + int random = (int) (Math.random() * 10000); // 生成0到9999之间的随机数 + return String.format("%04d", random); // 格式化为4位 + } + + // 获取下一个自增序列号,使用ReentrantLock来确保线程安全 + private static int getNextSequence() { + lock.lock(); // 获取锁 + try { + int seq = sequence.incrementAndGet(); + if (seq > MAX_SEQUENCE) { + sequence.set(0); // 达到最大值后重置 + seq = sequence.incrementAndGet(); + } + return seq; + } finally { + lock.unlock(); // 确保在最终释放锁 + } + } + + + +} diff --git a/src/test/java/com/cultural/heritage/order/OrderIdGenerator.java b/src/test/java/com/cultural/heritage/order/OrderIdGenerator.java new file mode 100644 index 0000000..4b329aa --- /dev/null +++ b/src/test/java/com/cultural/heritage/order/OrderIdGenerator.java @@ -0,0 +1,135 @@ +package com.cultural.heritage.order; + +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.exception.BusinessException; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class OrderIdGenerator { + + // 定义日期格式化器,精确到秒 + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + // 定义序列号最大值 + private static final int MAX_SEQUENCE = 999999; + + // 当前日期,初始化为当天 + private static String currentDate = getCurrentDate(); + + // 自增序列号,线程安全 + private static final AtomicInteger sequence = new AtomicInteger(0); + + // 锁对象,用于保护自增序列号的生成 + private static final Lock lock = new ReentrantLock(); + + + public static String generateOrderId() { + // 获取当前日期 + String today = getCurrentDate(); + + // 如果日期发生变化,重置序列号 + if (!today.equals(currentDate)) { + currentDate = today; + sequence.set(0); // 重置序列号 + } + + // 获取时间戳(精确到秒) + String timestamp = DATE_FORMAT.format(new Date()); + + // 获取4位随机数 + String randomNumber = generateRandomNumber(); + + // 获取6位自增序列号,并确保不超过最大值 + int seq = getNextSequence(); + + // 格式化序列号为6位 + String formattedSequence = String.format("%06d", seq); + + // 拼接生成订单号 + return timestamp + randomNumber + formattedSequence; + } + + // 获取当前日期(格式:yyyyMMdd) + private static String getCurrentDate() { + return new SimpleDateFormat("yyyyMMdd").format(new Date()); + } + + // 生成4位随机数(范围:0000到9999) + private static String generateRandomNumber() { + int random = (int) (Math.random() * 10000); // 生成0到9999之间的随机数 + return String.format("%04d", random); // 格式化为4位 + } + + // 获取下一个自增序列号,使用ReentrantLock来确保线程安全 + private static int getNextSequence() { + lock.lock(); // 获取锁 + try { + int seq = sequence.incrementAndGet(); + if (seq > MAX_SEQUENCE) { + sequence.set(0); // 达到最大值后重置 + seq = sequence.incrementAndGet(); + } + return seq; + } finally { + lock.unlock(); // 确保在最终释放锁 + } + } + + + + // 模拟高并发生成订单号 + public static void main(String[] args) throws InterruptedException { + // 创建一个线程池 + ExecutorService executorService = Executors.newFixedThreadPool(100); + ConcurrentHashMap map = new ConcurrentHashMap<>(); + // 记录生成的订单号数量 + final int totalOrders = 999999; + final CountDownLatch latch = new CountDownLatch(totalOrders); + + // 使用线程池并发生成订单号 + for (int i = 0; i < totalOrders; i++) { + executorService.submit(() -> { + // 每个线程生成一个订单号 + String orderId = generateOrderId(); + + map.compute(orderId.substring(orderId.length() - 6), (key, value) -> { + if (value == null) { + return 1; + } else { + return value + 1; // 如果有重复,则计数 + } + }); + + System.out.println(orderId.substring(orderId.length() - 6)); + latch.countDown(); // 完成一个订单号生成 + }); + } + + + // 等待所有订单号生成完成 + latch.await(); + + // 关闭线程池 + executorService.shutdown(); + + System.out.println("所有订单号生成完毕!"); + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() > 1) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单号重复, 订单号为:" + entry.getKey()); + } + } + System.out.println("订单号唯一性验证通过!"); + } + +} +