sql/xc_mall.sql
@@ -210,3 +210,18 @@ alter table mall_order_info add pay_order_no varchar(500) null comment '支付订单号' after pay_method; alter table mall_order_info add pay_result int null comment '支付结果 1-成功2-未成功' after pay_order_no; alter table mall_member add trade_password varchar(500) null comment '支付密码' after password; DROP TABLE IF EXISTS mall_member_wallet; CREATE TABLE mall_member_wallet( REVISION INT COMMENT '乐观锁' , CREATED_BY VARCHAR(32) COMMENT '创建人' , CREATED_TIME DATETIME COMMENT '创建时间' , UPDATED_BY VARCHAR(32) COMMENT '更新人' , UPDATED_TIME DATETIME COMMENT '更新时间' , ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键' , balance DECIMAL(20,2) COMMENT '余额' , member_id bigint null comment '用户ID', PRIMARY KEY (ID) ) COMMENT = '用户钱包'; src/main/java/cc/mrbird/febs/mall/controller/ApiMallOrderController.java
@@ -2,6 +2,7 @@ import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.mall.dto.AddOrderDto; import cc.mrbird.febs.mall.dto.PayOrderDto; import cc.mrbird.febs.mall.service.IApiMallOrderInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -10,7 +11,9 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author wzy @@ -41,5 +44,15 @@ return new FebsResponse().success(); } @ApiOperation(value = "支付订单", notes = "支付订单") @PostMapping(value = "/payOrder") public FebsResponse payOrder(@RequestBody PayOrderDto payOrderDto) { String result = mallOrderInfoService.payOrder(payOrderDto); Map<String, Object> map = new HashMap<>(); map.put("orderNo", result); map.put("type", payOrderDto.getType()); return new FebsResponse().success().data(map).message("支付成功"); } } src/main/java/cc/mrbird/febs/mall/dto/PayOrderDto.java
New file @@ -0,0 +1,28 @@ package cc.mrbird.febs.mall.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; /** * @author wzy * @date 2021-09-22 **/ @Data @ApiModel(value = "PayOrderDto", description = "支付订单接口参数接口类") public class PayOrderDto { @NotNull(message = "参数不能为空") @ApiModelProperty(value = "订单ID") private Long id; @NotBlank(message = "参数不能为空") @ApiModelProperty(value = "支付类型", example = "1微信2支付宝3余额") private String type; @ApiModelProperty(value = "支付密码", example = "如果选择余额支付需要输入") private String tradePwd; } src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -36,6 +36,11 @@ private String password; /** * 资金密码 */ private String tradePassword; /** * 头像 */ private String avatar; src/main/java/cc/mrbird/febs/mall/entity/MallMemberWallet.java
New file @@ -0,0 +1,26 @@ package cc.mrbird.febs.mall.entity; import cc.mrbird.febs.common.entity.BaseEntity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; /** * @author wzy * @date 2021-09-22 **/ @Data @TableName("mall_member_wallet") public class MallMemberWallet extends BaseEntity { /** * 用户ID */ private Long memberId; /** * 余额 */ private BigDecimal balance; } src/main/java/cc/mrbird/febs/mall/mapper/MallMemberWalletMapper.java
New file @@ -0,0 +1,12 @@ package cc.mrbird.febs.mall.mapper; import cc.mrbird.febs.mall.entity.MallMemberWallet; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; public interface MallMemberWalletMapper extends BaseMapper<MallMemberWallet> { MallMemberWallet selectWalletByMemberId(@Param("memberId") Long memberId); int updateBalanceWithVersion(@Param("record") MallMemberWallet wallet); } src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberWalletService.java
New file @@ -0,0 +1,13 @@ package cc.mrbird.febs.mall.service; import cc.mrbird.febs.mall.entity.MallMemberWallet; import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; public interface IApiMallMemberWalletService extends IService<MallMemberWallet> { void addBalance(BigDecimal amount, Long member); void reduceBalance(BigDecimal amount, Long memberId); } src/main/java/cc/mrbird/febs/mall/service/IApiMallOrderInfoService.java
@@ -1,6 +1,7 @@ package cc.mrbird.febs.mall.service; import cc.mrbird.febs.mall.dto.AddOrderDto; import cc.mrbird.febs.mall.dto.PayOrderDto; import cc.mrbird.febs.mall.entity.MallOrderInfo; import com.baomidou.mybatisplus.extension.service.IService; @@ -9,4 +10,6 @@ Long createOrder(AddOrderDto addOrderDto); void cancelOrder(Long id); String payOrder(PayOrderDto payOrderDto); } src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberWalletServiceImpl.java
New file @@ -0,0 +1,53 @@ package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.mall.entity.MallMemberWallet; import cc.mrbird.febs.mall.mapper.MallMemberWalletMapper; import cc.mrbird.febs.mall.service.IApiMallMemberWalletService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; /** * @author wzy * @date 2021-09-22 **/ @Slf4j @Service @RequiredArgsConstructor public class ApiMallMemberWalletServiceImpl extends ServiceImpl<MallMemberWalletMapper, MallMemberWallet> implements IApiMallMemberWalletService { @Override public void addBalance(BigDecimal amount, Long memberId) { } @Override public void reduceBalance(BigDecimal amount, Long memberId) { int i = 0; boolean flag = true; while (flag) { i++; MallMemberWallet wallet = this.baseMapper.selectWalletByMemberId(memberId); if (amount.compareTo(wallet.getBalance()) < 0) { throw new FebsException("余额不足"); } wallet.setBalance(wallet.getBalance().subtract(amount)); int result = this.baseMapper.updateBalanceWithVersion(wallet); if (result > 0) { flag = false; } else { if (i > 2) { throw new FebsException("余额支付失败"); } } } } } src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
@@ -6,10 +6,14 @@ import cc.mrbird.febs.common.utils.MallUtils; import cc.mrbird.febs.mall.dto.AddOrderDto; import cc.mrbird.febs.mall.dto.AddOrderItemDto; import cc.mrbird.febs.mall.dto.PayOrderDto; import cc.mrbird.febs.mall.entity.*; import cc.mrbird.febs.mall.mapper.*; import cc.mrbird.febs.mall.service.IApiMallMemberWalletService; import cc.mrbird.febs.mall.service.IApiMallOrderInfoService; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,6 +37,8 @@ private final MallGoodsSkuMapper mallGoodsSkuMapper; private final MallAddressInfoMapper mallAddressInfoMapper; private final MallOrderItemMapper mallOrderItemMapper; private final MallMemberMapper memberMapper; private final IApiMallMemberWalletService memberWalletService; @Override public Long createOrder(AddOrderDto addOrderDto) { @@ -110,4 +116,45 @@ orderInfo.setCancelType(MallOrderInfo.CANCEL_BY_SELF); this.baseMapper.updateById(orderInfo); } @Override public String payOrder(PayOrderDto payOrderDto) { MallMember member = LoginUserUtil.getLoginUser(); MallOrderInfo orderInfo = this.baseMapper.selectOrderByMemberIdAndId(member.getId(), payOrderDto.getId()); if (orderInfo == null) { throw new FebsException("订单不存在"); } if (OrderStatusEnum.WAIT_PAY.getValue() != orderInfo.getStatus()) { throw new FebsException("订单状态不能支付"); } switch (payOrderDto.getType()) { case "1": // TODO 微信支付 break; case "2": // TODO 支付宝支付 break; case "3": return balancePay(orderInfo, payOrderDto.getTradePwd()); default: } return ""; } private String balancePay(MallOrderInfo orderInfo, String tradePwd) { if (StrUtil.isBlank(tradePwd)) { throw new FebsException("支付密码错误"); } MallMember mallMember = memberMapper.selectById(orderInfo.getMemberId()); if (!mallMember.getTradePassword().equals(SecureUtil.md5(tradePwd))) { throw new FebsException("支付密码错误"); } memberWalletService.reduceBalance(orderInfo.getAmount(), mallMember.getId()); return orderInfo.getOrderNo(); } } src/main/resources/mapper/modules/MallMemberWalletMapper.xml
New file @@ -0,0 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.mrbird.febs.mall.mapper.MallMemberWalletMapper"> <select id="selectWalletByMemberId" resultType="cc.mrbird.febs.mall.entity.MallMemberWallet"> select * from mall_member_wallet where member_id=#{memberId} </select> <update id="updateBalanceWithVersion"> update mall_member_wallet set REVISION = REVISION + 1, balance = #{record.balance} where id=#{record.id} and REVISION=#{record.REVISION} </update> </mapper>