src/main/java/com/mzl/flower/constant/LockConstants.java
对比新文件 @@ -0,0 +1,8 @@ package com.mzl.flower.constant; public class LockConstants { // 钱包ID锁 public static final String WALLET_ID_KEY = "WALLET_ID_KEY:%s"; } src/main/java/com/mzl/flower/dto/request/wallet/QueryWalletDTO.java
@@ -1,42 +1,7 @@ package com.mzl.flower.dto.request.wallet; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; @Data public class QueryWalletDTO { @ApiModelProperty(value = "供应商Id") private String supplierId; @ApiModelProperty(value = "供应商名称") private String supplierName; @ApiModelProperty(value = "提交日期-开始日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate createStartDate; @ApiModelProperty(value = "提交日期-结束日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate endEndDate; @ApiModelProperty(value = "审核时间-开始日期") @JsonFormat(pattern="yyyy-MM-dd" ,timezone="GMT+8") @DateTimeFormat(pattern="yyyy-MM-dd") private LocalDate approveStartDate; @ApiModelProperty(value = "审核时间-结束日期") @JsonFormat(pattern="yyyy-MM-dd" ,timezone="GMT+8") @DateTimeFormat(pattern="yyyy-MM-dd") private LocalDate approveEndDate; @ApiModelProperty(value = "提现状态") private String withdrawState; } src/main/java/com/mzl/flower/dto/request/wallet/QueryWalletWithdrawDTO.java
对比新文件 @@ -0,0 +1,42 @@ package com.mzl.flower.dto.request.wallet; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; @Data public class QueryWalletWithdrawDTO { @ApiModelProperty(value = "供应商Id") private Long supplierId; @ApiModelProperty(value = "供应商名称") private String supplierName; @ApiModelProperty(value = "提交日期-开始日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate createStartDate; @ApiModelProperty(value = "提交日期-结束日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate endEndDate; @ApiModelProperty(value = "审核时间-开始日期") @JsonFormat(pattern="yyyy-MM-dd" ,timezone="GMT+8") @DateTimeFormat(pattern="yyyy-MM-dd") private LocalDate approveStartDate; @ApiModelProperty(value = "审核时间-结束日期") @JsonFormat(pattern="yyyy-MM-dd" ,timezone="GMT+8") @DateTimeFormat(pattern="yyyy-MM-dd") private LocalDate approveEndDate; @ApiModelProperty(value = "提现状态") private String withdrawState; } src/main/java/com/mzl/flower/entity/wallet/WalletDO.java
@@ -74,5 +74,11 @@ @ApiModelProperty(value = "总交易金额") private BigDecimal totalTransactionAmount; /** * 总交易金额 */ @ApiModelProperty(value = "已结算金额") private BigDecimal settledAmount; } src/main/java/com/mzl/flower/mapper/wallet/WalletWithdrawRecordMapper.java
@@ -1,11 +1,11 @@ package com.mzl.flower.mapper.wallet; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mzl.flower.dto.request.wallet.QueryWalletDTO; import com.mzl.flower.dto.response.member.MemberVO; import com.mzl.flower.dto.request.wallet.QueryWalletWithdrawDTO; import com.mzl.flower.dto.response.wallet.WalletWithdrawRecordVO; import com.mzl.flower.entity.wallet.WalletWithdrawRecordDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -19,5 +19,5 @@ */ public interface WalletWithdrawRecordMapper extends BaseMapper<WalletWithdrawRecordDO> { List<WalletWithdrawRecordVO> queryPage(QueryWalletDTO queryWalletDTO, Page page); List<WalletWithdrawRecordVO> queryPage(@Param("dto")QueryWalletWithdrawDTO queryWalletDTO, Page page); } src/main/java/com/mzl/flower/service/impl/wallet/WalletServiceImpl.java
@@ -32,7 +32,7 @@ private SupplierService supplierService; @Override public WalletDO getBySupplierId() { public WalletDO getCurrentSupplier() { final SupplierDTO currentSupplier = supplierService.getCurrentSupplier(); // 根据供应商ID获取钱包信息 @@ -53,6 +53,7 @@ walletDO.setSettlingAmount(BigDecimal.ZERO); walletDO.setTotalDeduction(BigDecimal.ZERO); walletDO.setTotalTransactionAmount(BigDecimal.ZERO); walletDO.setSettlingAmount(BigDecimal.ZERO); walletDO.create(SecurityUtils.getUserId()); baseMapper.insert(walletDO); // 将再次查询的结果返回 @@ -63,7 +64,7 @@ return walletDO; } @Override public WalletDO getBySupplierId(Long supplierId){ // 不用getOne,用获取list的第一个元素 @@ -74,8 +75,5 @@ return walletDOS.get(0); }else return null; } } src/main/java/com/mzl/flower/service/impl/wallet/WalletWithdrawRecordServiceImpl.java
@@ -7,10 +7,11 @@ import com.mzl.flower.config.exception.ValidationException; import com.mzl.flower.config.security.SecurityUtils; import com.mzl.flower.constant.Constants; import com.mzl.flower.constant.LockConstants; import com.mzl.flower.dto.request.payment.TransferDetailReqDTO; import com.mzl.flower.dto.request.payment.TransferReqDTO; import com.mzl.flower.dto.request.wallet.CreateWalletWithdrawRecordDTO; import com.mzl.flower.dto.request.wallet.QueryWalletDTO; import com.mzl.flower.dto.request.wallet.QueryWalletWithdrawDTO; import com.mzl.flower.dto.request.wallet.WalletWithdrawRecordDTO; import com.mzl.flower.dto.response.supplier.SupplierDTO; import com.mzl.flower.dto.response.wallet.WalletWithdrawRecordVO; @@ -25,12 +26,16 @@ import com.mzl.flower.mapper.wallet.WalletWithdrawRecordMapper; import com.mzl.flower.service.payment.UserPaymentV3Service; import com.mzl.flower.service.supplier.SupplierService; import com.mzl.flower.service.wallet.WalletBillRecordService; import com.mzl.flower.service.wallet.WalletService; import com.mzl.flower.service.wallet.WalletWithdrawRecordService; import com.mzl.flower.utils.UUIDGenerator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -41,6 +46,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; /** * <p> @@ -55,6 +61,7 @@ @Transactional @RequiredArgsConstructor public class WalletWithdrawRecordServiceImpl extends ServiceImpl<WalletWithdrawRecordMapper, WalletWithdrawRecordDO> implements WalletWithdrawRecordService { private final WalletWithdrawRecordMapper walletWithdrawRecordMapper; private final WalletService walletService; private final SupplierService supplierService; @@ -64,15 +71,22 @@ private final WalletBillRecordMapper walletBillRecordMapper; private final WalletBillRecordService walletBillRecordService; @Autowired RedissonClient redissonClient; @Transactional @Override public boolean create(CreateWalletWithdrawRecordDTO dto) { SupplierDTO supplierDTO = supplierService.getCurrentSupplier(); if (null == supplierDTO) { throw new ValidationException("供应商不能为空"); } final WalletDO walletDO = walletService.getBySupplierId(); WalletDO walletDO = walletService.getCurrentSupplier(); if (null == walletDO) { throw new ValidationException("钱包不能为空"); } @@ -80,17 +94,72 @@ if (null != walletDO.getWithdrawableAmount() && null != dto.getAmount() && walletDO.getWithdrawableAmount().compareTo(dto.getAmount()) < 0) { throw new ValidationException("钱包金额不足"); } RLock lock = redissonClient.getLock(String.format(LockConstants.WALLET_ID_KEY, walletDO.getId())); // 获取锁,最多等待 10 秒,锁自动释放时间 30 秒 try { if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { try { // 加锁了之后需要二次查询,防止未加锁之前 someone else 已经修改了 walletDO = walletService.getCurrentSupplier(); if (null == walletDO) { throw new ValidationException("钱包不能为空"); } // 查看钱包的金额是不是大于要提现的金额 if (null != walletDO.getWithdrawableAmount() && null != dto.getAmount() && walletDO.getWithdrawableAmount().compareTo(dto.getAmount()) < 0) { throw new ValidationException("钱包金额不足"); } // 1.新增一条余额提现记录 WalletWithdrawRecordDO withdrawRecordDO = new WalletWithdrawRecordDO(); withdrawRecordDO.setAmount(dto.getAmount()); withdrawRecordDO.setSupplierId(supplierDTO.getId()); withdrawRecordDO.setWithdrawState(Constants.WALLET_WITHDRAW_STATE.WAITING.name()); withdrawRecordDO.setMethod(Constants.WALLET_WITHDRAW_METHOD.WEIXIN.name()); withdrawRecordDO.create(SecurityUtils.getUserId()); return save(withdrawRecordDO); // 保存余额提现记录 save(withdrawRecordDO); /* // 2.新增一条账单明细 WalletBillRecordDO walletBillRecordDO=new WalletBillRecordDO(); walletBillRecordDO.setSupplierId(supplierDTO.getId()); walletBillRecordDO.setWalletId(walletDO.getId()); // 提现 walletBillRecordDO.setType(Constants.BILL_CHANGE_TYPE.withdraw.name()); walletBillRecordDO.setMethod(Constants.BILL_CHANGE_METHOD.add.name()); walletBillRecordDO.setOriginalAmount(walletDO.getWithdrawableAmount()); walletBillRecordDO.setChangeAmount(dto.getAmount()); walletBillRecordDO.setBalance(walletDO.getWithdrawableAmount().subtract(dto.getAmount())); // 保存账单明细 walletBillRecordService.save(walletBillRecordDO); */ // 3. 钱包更新 // 钱包可提现的钱等于当前钱包可提现的钱-提现的钱 walletDO.setWithdrawableAmount(walletDO.getWithdrawableAmount().subtract(dto.getAmount())); // 提现中的钱等于原有可提现的钱+提现的钱 walletDO.setWithdrawingAmount(walletDO.getWithdrawingAmount().add(dto.getAmount())); walletDO.update(SecurityUtils.getUserId()); // 更新钱包 return walletService.updateById(walletDO); } finally { lock.unlock(); } } } catch (InterruptedException e) { throw new RuntimeException(e); } return false; } @Override public Page<WalletWithdrawRecordVO> queryPage(QueryWalletDTO queryWalletDTO, Page page) { public Page<WalletWithdrawRecordVO> queryPage(QueryWalletWithdrawDTO queryWalletDTO, Page page) { List<WalletWithdrawRecordVO> list = walletWithdrawRecordMapper.queryPage(queryWalletDTO, page); page.setRecords(list); return page; src/main/java/com/mzl/flower/service/wallet/WalletService.java
@@ -13,5 +13,8 @@ */ public interface WalletService extends IService<WalletDO> { WalletDO getBySupplierId(); WalletDO getCurrentSupplier(); WalletDO getBySupplierId(Long supplierId); } src/main/java/com/mzl/flower/service/wallet/WalletWithdrawRecordService.java
@@ -1,7 +1,7 @@ package com.mzl.flower.service.wallet; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mzl.flower.dto.request.wallet.QueryWalletDTO; import com.mzl.flower.dto.request.wallet.QueryWalletWithdrawDTO; import com.mzl.flower.dto.request.wallet.WalletWithdrawRecordDTO; import com.mzl.flower.dto.response.wallet.WalletWithdrawRecordVO; import com.mzl.flower.dto.request.wallet.CreateWalletWithdrawRecordDTO; @@ -17,7 +17,7 @@ * @since 2024-10-22 */ public interface WalletWithdrawRecordService extends IService<WalletWithdrawRecordDO> { Page<WalletWithdrawRecordVO> queryPage(QueryWalletDTO dto, Page page); Page<WalletWithdrawRecordVO> queryPage(QueryWalletWithdrawDTO dto, Page page); void updateWallet(WalletWithdrawRecordDTO walletWithdrawRecordDTO); src/main/java/com/mzl/flower/web/v2/wallet/WalletController.java
@@ -8,17 +8,16 @@ import com.mzl.flower.config.exception.ValidationException; import com.mzl.flower.dto.request.wallet.QueryWalletDTO; import com.mzl.flower.dto.response.supplier.SupplierDTO; import com.mzl.flower.entity.wallet.WalletBillRecordDO; import com.mzl.flower.service.supplier.SupplierService; import com.mzl.flower.service.wallet.WalletService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import com.mzl.flower.entity.wallet.WalletDO; import javax.validation.constraints.Min; import javax.validation.constraints.Max; import javax.validation.constraints.Positive; /** @@ -27,6 +26,8 @@ */ @RestController @RequestMapping("/v2/wallet") @Api(value = "供应商-钱包", tags = "供应商-钱包") @Validated public class WalletController extends BaseController { @Autowired @@ -53,20 +54,21 @@ } @GetMapping("/{id}") public WalletDO get(@PathVariable(value = "id") @Positive(message = "{id.positive}") Integer id) { public ResponseEntity<ReturnDataDTO> get(@PathVariable(value = "id") @Positive(message = "{id.positive}") Integer id) { return null; } @GetMapping("/supplier") @ApiOperation(value = "获取供应商钱包", notes = "获取供应商钱包") public WalletDO getWalletBySupplierId() { public ResponseEntity<ReturnDataDTO> getWalletBySupplierId() { // 判断供应商是否存在 final SupplierDTO currentSupplier = supplierService.getCurrentSupplier(); if(null==currentSupplier){ throw new ValidationException("供应商不能为空"); } return walletService.getBySupplierId(); return returnData(R.SUCCESS.getCode(), walletService.getCurrentSupplier()); } @GetMapping("/page") src/main/java/com/mzl/flower/web/v2/wallet/WalletWithdrawRecordController.java
@@ -5,7 +5,7 @@ import com.mzl.flower.base.BaseController; import com.mzl.flower.base.R; import com.mzl.flower.base.ReturnDataDTO; import com.mzl.flower.dto.request.wallet.QueryWalletDTO; import com.mzl.flower.dto.request.wallet.QueryWalletWithdrawDTO; import com.mzl.flower.dto.request.wallet.WalletWithdrawRecordDTO; import com.mzl.flower.dto.response.wallet.WalletWithdrawRecordVO; import com.mzl.flower.service.wallet.WalletWithdrawRecordService; @@ -51,8 +51,8 @@ private WalletService walletService; @GetMapping("/list") @ApiOperation(value = "查询提现记录", httpMethod = "GET") public ResponseEntity<ReturnDataDTO<Page<WalletWithdrawRecordVO>>> getMemberList(Page page, QueryWalletDTO dto) { @ApiOperation(value = "查询提现记录-分页", httpMethod = "GET") public ResponseEntity<ReturnDataDTO<Page<WalletWithdrawRecordVO>>> getMemberList(Page page, QueryWalletWithdrawDTO dto) { return returnData(R.SUCCESS.getCode(), walletWithdrawRecordService.queryPage(dto, page)); } @@ -64,7 +64,7 @@ } @PostMapping("") public ResponseEntity<ReturnDataDTO> create(@Validated CreateWalletWithdrawRecordDTO walletWithdrawRecordDTO) { public ResponseEntity<ReturnDataDTO> create(@Validated @RequestBody CreateWalletWithdrawRecordDTO walletWithdrawRecordDTO) { walletWithdrawRecordService.create(walletWithdrawRecordDTO); @@ -86,15 +86,12 @@ return null; } @GetMapping("/page") public ResponseEntity<ReturnDataDTO<Page<WalletWithdrawRecordDO>>> page( @RequestParam(name = "page", required = false, defaultValue = "0") @Min(value = 0, message = "{page.number.min}") Integer page, @RequestParam(name = "count", required = false, defaultValue = "10") @Min(value = 1, message = "{page.count.min}") @Max(value = 30, message = "{page.count.max}") Integer count @GetMapping("/supplier/page") public ResponseEntity<ReturnDataDTO<Page<WalletWithdrawRecordDO>>> page(Page page, QueryWalletWithdrawDTO dto ) { return null; // 根据当前用户获取供应商 dto.setSupplierId(supplierService.getCurrentSupplier().getId()); return returnData(R.SUCCESS.getCode(), walletWithdrawRecordService.queryPage(dto, page)); } } src/main/resources/mapper/wallet/WalletMapper.xml
@@ -19,6 +19,8 @@ <result column="settling_amount" property="settlingAmount" /> <result column="total_deduction" property="totalDeduction" /> <result column="total_transaction_amount" property="totalTransactionAmount" /> <result column="settled_amount" property="settledAmount" /> </resultMap> </mapper> src/main/resources/mapper/wallet/WalletWithdrawRecordMapper.xml
@@ -35,22 +35,22 @@ </if> <if test="dto.createStartDate!=null "> <![CDATA[ AND t.create_time >= #{dto.createStartDate} AND t.create_time >= #{dto.createStartDate} ]]> </if> <if test="dto.endEndDate!=null "> <![CDATA[ AND t.create_time <= #{dto.endEndDate} AND t.create_time <= #{dto.endEndDate} ]]> </if> <if test="dto.approveStartDate!=null "> <![CDATA[ AND t.approve_time >= #{dto.approveStartDate} AND t.approve_time >= #{dto.approveStartDate} ]]> </if> <if test="dto.approveEndDate!=null "> <![CDATA[ AND t.approve_time <= #{dto.approveStartDate} AND t.approve_time <= #{dto.approveStartDate} ]]> </if>