diff --git a/pom.xml b/pom.xml index f353a07..703543d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 2.4.4 + 2.5.2 waynboot-common @@ -38,7 +38,7 @@ ${java.version} 2.4.4 8.0.19 - 6.1.2.RELEASE + 6.1.3.RELEASE 7.12.1 1.18.6 3.4.2 @@ -81,11 +81,6 @@ lettuce-core ${lettuce.version} - - org.apache.commons - commons-pool2 - 2.9.0 - org.springframework.boot diff --git a/readme.md b/readme.md index b2aa118..93434eb 100644 --- a/readme.md +++ b/readme.md @@ -136,11 +136,12 @@ private static String encryptUserId(String userId, int num) { ``` ### 5. 下单流程处理过程,通过rabbitMQ异步生成订单,提高系统下单处理能力 -1. 用户点击提交订单按钮,后台生成订单编号和订单金额跳转到订单支付页面,并将订单编号等信息发送rabbitMQ消息(生产订单) -2. 订单消费者接受到订单消息后,获取订单编号生成订单记录(用户待支付) -3. 用户点击支付按钮时,前端根据订单编号轮询订单信息查询接口,如果订单编号记录已经入库则进行后续支付操作,如果订单编号未入库则返回错误信息(订单异常) -4. 前端调用微信/支付宝完成支付操作 -5. 用户支付完成后在回调通知里更新订单状态为已支付(已成功) +1. 用户点击提交订单按钮,后台生成订单编号和订单金额跳转到订单支付页面,并将订单编号等信息发送rabbitMQ消息(生成订单编号,还未生成订单) +2. 订单消费者接受到订单消息后,获取订单编号生成订单记录(订单创建成功,用户待支付) +3. 下单页面,前端根据订单编号轮询订单接口,订单已创建则跳转支付页面,否则提示下单失败(订单创建失败) +4. 支付页面,用户点击支付按钮时,后台调用微信/支付宝下单接口后,前端唤醒微信/支付宝支付,用户输入密码 +5. 用户支付完成后在微信/支付宝下回调通知里更新订单状态为已支付(订单已支付) +6. 用户支付完成后,返回支付状态查看页面。 ### 6. 金刚区跳转使用策略模式 ```java diff --git a/waynboot-common/src/main/java/com/wayn/common/core/domain/shop/Order.java b/waynboot-common/src/main/java/com/wayn/common/core/domain/shop/Order.java index 3e8d5ce..586edd2 100644 --- a/waynboot-common/src/main/java/com/wayn/common/core/domain/shop/Order.java +++ b/waynboot-common/src/main/java/com/wayn/common/core/domain/shop/Order.java @@ -111,9 +111,14 @@ public class Order extends ShopBaseEntity implements Serializable { private String payId; /** - * 微信付款时间 + * 支付方式 1微信 2支付宝 */ - @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Integer payType; + + /** + * 付款时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime payTime; /** @@ -129,7 +134,7 @@ public class Order extends ShopBaseEntity implements Serializable { /** * 发货开始时间 */ - @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime shipTime; /** @@ -150,13 +155,13 @@ public class Order extends ShopBaseEntity implements Serializable { /** * 退款时间 */ - @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime refundTime; /** * 用户确认收货时间 */ - @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime confirmTime; /** @@ -167,7 +172,7 @@ public class Order extends ShopBaseEntity implements Serializable { /** * 订单关闭时间 */ - @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime orderEndTime; /** diff --git a/waynboot-common/src/main/java/com/wayn/common/core/domain/vo/OrderVO.java b/waynboot-common/src/main/java/com/wayn/common/core/domain/vo/OrderVO.java index 15d7c85..3961da7 100644 --- a/waynboot-common/src/main/java/com/wayn/common/core/domain/vo/OrderVO.java +++ b/waynboot-common/src/main/java/com/wayn/common/core/domain/vo/OrderVO.java @@ -31,4 +31,9 @@ public class OrderVO { private Long addressId; private String message; + + /** + * 支付方式 1微信 2支付宝 + */ + private Integer payType; } diff --git a/waynboot-common/src/main/java/com/wayn/common/enums/PayTypeEnum.java b/waynboot-common/src/main/java/com/wayn/common/enums/PayTypeEnum.java new file mode 100644 index 0000000..603b931 --- /dev/null +++ b/waynboot-common/src/main/java/com/wayn/common/enums/PayTypeEnum.java @@ -0,0 +1,23 @@ +package com.wayn.common.enums; + +/** + * 支付方式枚举 + */ +public enum PayTypeEnum { + WX(1), + ALI(2); + + private int code; + + PayTypeEnum(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/waynboot-common/src/main/java/com/wayn/common/util/R.java b/waynboot-common/src/main/java/com/wayn/common/util/R.java index 3c2ae59..1503c1e 100644 --- a/waynboot-common/src/main/java/com/wayn/common/util/R.java +++ b/waynboot-common/src/main/java/com/wayn/common/util/R.java @@ -2,11 +2,13 @@ package com.wayn.common.util; import org.apache.commons.lang3.builder.ToStringBuilder; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; -public class R { +public class R implements Serializable { + private static final long serialVersionUID = -5316597326293972581L; private int code; private String msg; private Map map = new HashMap<>(); diff --git a/waynboot-data/waynboot-data-redis/pom.xml b/waynboot-data/waynboot-data-redis/pom.xml index aa51118..b194a93 100644 --- a/waynboot-data/waynboot-data-redis/pom.xml +++ b/waynboot-data/waynboot-data-redis/pom.xml @@ -21,10 +21,6 @@ io.lettuce lettuce-core - - org.apache.commons - commons-pool2 - diff --git a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/controller/OrderController.java b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/controller/OrderController.java index 01a2113..78f0fed 100644 --- a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/controller/OrderController.java +++ b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/controller/OrderController.java @@ -26,6 +26,11 @@ public class OrderController extends BaseController { return iOrderService.selectListPage(page, showType); } + @PostMapping("info") + public R info(@RequestBody OrderVO orderVO) { + return R.success().add("data", iOrderService.getById(orderVO.getOrderSn())); + } + @PostMapping("statusCount") public R statusCount() { return iOrderService.statusCount(); @@ -36,19 +41,26 @@ public class OrderController extends BaseController { return iOrderService.asyncSubmit(orderVO); } - @PostMapping("info") - public R info(@RequestBody OrderVO orderVO) { - return R.success().add("data", iOrderService.getById(orderVO.getOrderSn())); - } - + /** + * JSAPI支付 + * + * @param orderVO + * @return + */ @PostMapping("prepay") public R prepay(@RequestBody OrderVO orderVO) { - return iOrderService.prepay(orderVO.getOrderSn(), request); + return iOrderService.prepay(orderVO.getOrderSn(), orderVO.getPayType(), request); } + /** + * H5支付 + * + * @param orderVO + * @return + */ @PostMapping("h5pay") public R h5pay(@RequestBody OrderVO orderVO) { - return iOrderService.h5pay(orderVO.getOrderSn(), request); + return iOrderService.h5pay(orderVO.getOrderSn(), orderVO.getPayType(), request); } @PostMapping("payNotify") @@ -56,9 +68,9 @@ public class OrderController extends BaseController { return iOrderService.payNotify(request, response); } - @GetMapping("testPayNotify/{orderSn}") - public R payNotify(@PathVariable String orderSn) { - return iOrderService.testPayNotify(orderSn); + @GetMapping("searchResult/{orderSn}") + public R searchResult(@PathVariable String orderSn) { + return iOrderService.searchResult(orderSn); } @PostMapping("cancel/{orderId}") diff --git a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/IOrderService.java b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/IOrderService.java index 378e5d6..26ecf4b 100644 --- a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/IOrderService.java +++ b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/IOrderService.java @@ -43,7 +43,7 @@ public interface IOrderService extends IService { * @param request 请求 * @return r */ - R h5pay(String orderSn, HttpServletRequest request); + R h5pay(String orderSn, Integer payType, HttpServletRequest request); /** * 付款订单的预支付会话标识 @@ -56,7 +56,7 @@ public interface IOrderService extends IService { * @param request 请求 * @return r */ - R prepay(String orderSn, HttpServletRequest request); + R prepay(String orderSn, Integer payType, HttpServletRequest request); /** * 获取订单列表 @@ -82,7 +82,7 @@ public interface IOrderService extends IService { * @param orderSn 订单编号 * @return r */ - R testPayNotify(String orderSn); + R searchResult(String orderSn); /** * 取消订单 diff --git a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/impl/OrderServiceImpl.java b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/impl/OrderServiceImpl.java index 20fefee..0d33f75 100644 --- a/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/impl/OrderServiceImpl.java +++ b/waynboot-mobile-api/src/main/java/com/wayn/mobile/api/service/impl/OrderServiceImpl.java @@ -22,6 +22,7 @@ import com.wayn.common.core.domain.vo.OrderVO; import com.wayn.common.core.service.shop.*; import com.wayn.common.core.util.OrderHandleOption; import com.wayn.common.core.util.OrderUtil; +import com.wayn.common.enums.PayTypeEnum; import com.wayn.common.exception.BusinessException; import com.wayn.common.task.TaskService; import com.wayn.common.util.IdUtil; @@ -355,7 +356,7 @@ public class OrderServiceImpl extends ServiceImpl implements @Override @Transactional(rollbackFor = Exception.class) - public R prepay(String orderSn, HttpServletRequest request) { + public R prepay(String orderSn, Integer payType, HttpServletRequest request) { // 获取订单详情 Order order = getOne(new QueryWrapper().eq("order_sn", orderSn)); String checkMsg = checkOrderOperator(order); @@ -367,36 +368,42 @@ public class OrderServiceImpl extends ServiceImpl implements if (!handleOption.isPay()) { return R.error("订单不能支付"); } - Member member = iMemberService.getById(MobileSecurityUtils.getUserId()); - String openid = member.getWeixinOpenid(); - if (openid == null) { - return R.error("订单不能支付"); - } - WxPayMpOrderResult result; - try { - WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); - orderRequest.setOutTradeNo(order.getOrderSn()); - orderRequest.setOpenid(openid); - orderRequest.setBody("订单:" + order.getOrderSn()); - // 元转成分 - int fee; - BigDecimal actualPrice = order.getActualPrice(); - fee = actualPrice.multiply(new BigDecimal(100)).intValue(); - orderRequest.setTotalFee(fee); - orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(request)); - - result = wxPayService.createOrder(orderRequest); - } catch (Exception e) { - e.printStackTrace(); - return R.error("订单不能支付"); + // 设置支付方式 + order.setPayType(payType); + if (PayTypeEnum.WX.getCode() == payType) { + Member member = iMemberService.getById(MobileSecurityUtils.getUserId()); + String openid = member.getWeixinOpenid(); + if (openid == null) { + return R.error("订单不能支付"); + } + WxPayMpOrderResult result; + try { + WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); + orderRequest.setOutTradeNo(order.getOrderSn()); + orderRequest.setOpenid(openid); + orderRequest.setBody("订单:" + order.getOrderSn()); + // 元转成分 + int fee; + BigDecimal actualPrice = order.getActualPrice(); + fee = actualPrice.multiply(new BigDecimal(100)).intValue(); + orderRequest.setTotalFee(fee); + orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(request)); + + result = wxPayService.createOrder(orderRequest); + return R.success().add("result", result); + } catch (Exception e) { + e.printStackTrace(); + return R.error("订单不能支付"); + } + } else { + return R.success(); } - return R.success().add("result", result); } @Override @Transactional(rollbackFor = Exception.class) - public R h5pay(String orderSn, HttpServletRequest request) { + public R h5pay(String orderSn, Integer payType, HttpServletRequest request) { // 获取订单详情 Order order = getOne(new QueryWrapper().eq("order_sn", orderSn)); String checkMsg = checkOrderOperator(order); @@ -408,24 +415,48 @@ public class OrderServiceImpl extends ServiceImpl implements if (!handleOption.isPay()) { return R.error("订单不能支付"); } + // 设置支付方式 + order.setPayType(payType); + if (PayTypeEnum.WX.getCode() == payType) { + WxPayMwebOrderResult result; + try { + WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); + orderRequest.setOutTradeNo(order.getOrderSn()); + orderRequest.setTradeType("MWEB"); + orderRequest.setBody("订单:" + order.getOrderSn()); + // 元转成分 + int fee; + BigDecimal actualPrice = order.getActualPrice(); + fee = actualPrice.multiply(new BigDecimal(100)).intValue(); + orderRequest.setTotalFee(fee); + orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(request)); + result = wxPayService.createOrder(orderRequest); + return R.success().add("data", result); + } catch (Exception e) { + log.error(e.getMessage(), e); + return R.error("支付失败"); + } + } else { + // todo 暂时没有实现支付宝支付,直接更新支付状态为已支付 + order.setPayId("xxxxx0987654321-ali"); + order.setPayTime(LocalDateTime.now()); + order.setOrderStatus(OrderUtil.STATUS_PAY); + order.setUpdateTime(new Date()); + if (!updateById(order)) { + return R.error("更新数据已失效"); + } - WxPayMwebOrderResult result; - try { - WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); - orderRequest.setOutTradeNo(order.getOrderSn()); - orderRequest.setTradeType("MWEB"); - orderRequest.setBody("订单:" + order.getOrderSn()); - // 元转成分 - int fee; - BigDecimal actualPrice = order.getActualPrice(); - fee = actualPrice.multiply(new BigDecimal(100)).intValue(); - orderRequest.setTotalFee(fee); - orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(request)); - result = wxPayService.createOrder(orderRequest); - return R.success().add("data", result); - } catch (Exception e) { - log.error(e.getMessage(), e); - return R.error("支付失败"); + // 订单支付成功以后,会发送短信给用户,以及发送邮件给管理员 + String email = iMemberService.getById(order.getUserId()).getEmail(); + if (StringUtils.isNotBlank(email)) { + iMailService.sendEmail("新订单通知", order.toString(), email, WaynConfig.getMobileUrl() + "/message/email"); + } + + // 删除redis中订单id + redisCache.deleteZsetObject("order_zset", order.getId()); + // 取消订单超时未支付任务 + taskService.removeTask(new OrderUnpaidTask(order.getId())); + return R.success(); } } @@ -495,36 +526,17 @@ public class OrderServiceImpl extends ServiceImpl implements } @Override - public R testPayNotify(String orderSn) { + public R searchResult(String orderSn) { Order order = getOne(new QueryWrapper().eq("order_sn", orderSn)); if (order == null) { return R.error(ErrorCode.ORDER_NOT_EXISTS_ERROR, "订单不存在,编号:" + orderSn); } // 检查这个订单是否已经处理过 - if (OrderUtil.hasPayed(order)) { - return R.error("订单已经处理成功!"); + if (!OrderUtil.isCreateStatus(order)) { + return R.error(ErrorCode.ORDER_NOT_EXISTS_ERROR, "订单创建失败!"); } - - order.setPayId("xxxxx0987654321-wx"); - order.setPayTime(LocalDateTime.now()); - order.setOrderStatus(OrderUtil.STATUS_PAY); - order.setUpdateTime(new Date()); - if (!updateById(order)) { - return R.error("更新数据已失效"); - } - - // 订单支付成功以后,会发送短信给用户,以及发送邮件给管理员 - String email = iMemberService.getById(order.getUserId()).getEmail(); - if (StringUtils.isNotBlank(email)) { - iMailService.sendEmail("新订单通知", order.toString(), email, WaynConfig.getMobileUrl() + "/message/email"); - } - - // 删除redis中订单id - redisCache.deleteZsetObject("order_zset", order.getId()); - // 取消订单超时未支付任务 - taskService.removeTask(new OrderUnpaidTask(order.getId())); - return R.success("处理成功!"); + return R.success("订单创建成功!"); } @Override diff --git a/waynboot-mobile-api/src/main/resources/mapper/OrderMapper.xml b/waynboot-mobile-api/src/main/resources/mapper/OrderMapper.xml index b9da7a1..3f7007e 100644 --- a/waynboot-mobile-api/src/main/resources/mapper/OrderMapper.xml +++ b/waynboot-mobile-api/src/main/resources/mapper/OrderMapper.xml @@ -21,6 +21,7 @@ + @@ -40,7 +41,10 @@ select id, - user_id, order_sn, order_status, aftersale_status, consignee, mobile, address, message, goods_price, freight_price, coupon_price, integral_price, groupon_price, order_price, actual_price, pay_id, pay_time, ship_sn, ship_channel, ship_time, refund_amount, refund_type, refund_content, refund_time, confirm_time, comments, order_end_time, create_time, update_time, del_flag + user_id, order_sn, order_status, aftersale_status, consignee, mobile, address, message, + goods_price, freight_price, coupon_price, integral_price, groupon_price, order_price, + actual_price, pay_id, pay_time, ship_sn, ship_channel, ship_time, refund_amount, refund_type, pay_type, + refund_content, refund_time, confirm_time, comments, order_end_time, create_time, update_time, del_flag from shop_order @@ -51,6 +55,9 @@ AND order_status = #{order.orderStatus} + + AND pay_type = #{order.payType} + AND user_id = #{order.userId}