diff --git a/model/src/main/java/com/atguigu/tingshu/vo/order/TradeVo.java b/model/src/main/java/com/atguigu/tingshu/vo/order/TradeVo.java index 24543f1..0cc46bf 100644 --- a/model/src/main/java/com/atguigu/tingshu/vo/order/TradeVo.java +++ b/model/src/main/java/com/atguigu/tingshu/vo/order/TradeVo.java @@ -4,9 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Positive; import lombok.Data; +import org.springframework.stereotype.Component; @Data @Schema(description = "订单确认对象") + +@Component public class TradeVo { @NotEmpty(message = "付款项目类型不能为空") diff --git a/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/AccountFeignClient.java b/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/AccountFeignClient.java index 68c1f42..94ee3e3 100644 --- a/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/AccountFeignClient.java +++ b/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/AccountFeignClient.java @@ -1,7 +1,11 @@ package com.atguigu.tingshu.account; import com.atguigu.tingshu.account.impl.AccountDegradeFeignClient; +import com.atguigu.tingshu.common.result.Result; +import com.atguigu.tingshu.vo.account.AccountDeductVo; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; /** *

@@ -10,7 +14,14 @@ import org.springframework.cloud.openfeign.FeignClient; * * @author atguigu */ -@FeignClient(value = "service-account", fallback = AccountDegradeFeignClient.class) +@FeignClient(value = "service-account", path = "api/account", fallback = AccountDegradeFeignClient.class) public interface AccountFeignClient { + /** + * 检查扣减账户余额 + * @param accountDeductVo + * @return + */ + @PostMapping("/userAccount/checkAndDeduct") + public Result checkAndDeduct(@RequestBody AccountDeductVo accountDeductVo); } diff --git a/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.java b/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.java index 2c7217f..13e5d93 100644 --- a/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.java +++ b/service-client/service-account-client/src/main/java/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.java @@ -2,9 +2,18 @@ package com.atguigu.tingshu.account.impl; import com.atguigu.tingshu.account.AccountFeignClient; +import com.atguigu.tingshu.common.result.Result; +import com.atguigu.tingshu.vo.account.AccountDeductVo; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class AccountDegradeFeignClient implements AccountFeignClient { + @Override + public Result checkAndDeduct(AccountDeductVo accountDeductVo) { + log.error("[账户服务]checkAndDeduct服务调用失败"); + return null; + } } diff --git a/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/AccountFeignClient.class b/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/AccountFeignClient.class index 887c9e0..73b23f2 100644 Binary files a/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/AccountFeignClient.class and b/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/AccountFeignClient.class differ diff --git a/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.class b/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.class index dd71bc7..a6bf8ae 100644 Binary files a/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.class and b/service-client/service-account-client/target/classes/com/atguigu/tingshu/account/impl/AccountDegradeFeignClient.class differ diff --git a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java index 4013307..51a1efd 100644 --- a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java +++ b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java @@ -51,6 +51,8 @@ public interface AlbumFeignClient { @GetMapping("/trackInfo/findPaidTrackInfoList/{trackId}/{trackCount}") public Result> findWaitBuyTrackList(@PathVariable Long trackId, @PathVariable Integer trackCount); + @GetMapping("/trackInfo/getTrackInfo/{id}") + public Result getTrackInfo(@PathVariable Long id); } diff --git a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java index 4a5c3ec..16ebc29 100644 --- a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java +++ b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java @@ -52,4 +52,10 @@ public class AlbumDegradeFeignClient implements AlbumFeignClient { return null; } + @Override + public Result getTrackInfo(Long id) { + log.error("[专辑服务]提供远程调用方法getTrackInfo执行服务降级"); + return null; + } + } diff --git a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class index b4bb2b8..f280565 100644 Binary files a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class and b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class differ diff --git a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class index 6a985bc..8d1eff6 100644 Binary files a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class and b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class differ diff --git a/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java b/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java index b48302f..ce1cb4e 100644 --- a/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java +++ b/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java @@ -4,6 +4,7 @@ import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.model.user.VipServiceConfig; import com.atguigu.tingshu.user.client.impl.UserDegradeFeignClient; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -46,5 +47,7 @@ public interface UserFeignClient { @GetMapping("/userInfo/findUserPaidTrackList/{albumId}") public Result> findUserPaidTrackList(@PathVariable Long albumId); + @PostMapping("/userInfo/savePaidRecord") + public Result savePaidRecord(@RequestBody UserPaidRecordVo userPaidRecordVo); } diff --git a/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java b/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java index 1ab1b00..358ec06 100644 --- a/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java +++ b/service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java @@ -5,6 +5,7 @@ import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.model.user.VipServiceConfig; import com.atguigu.tingshu.user.client.UserFeignClient; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -44,4 +45,10 @@ public class UserDegradeFeignClient implements UserFeignClient { log.error("[用户服务]提供远程调用方法findUserPaidTrackList执行服务降级"); return null; } + + @Override + public Result savePaidRecord(UserPaidRecordVo userPaidRecordVo) { + log.error("[用户服务]提供远程调用方法savePaidRecord执行服务降级"); + return null; + } } diff --git a/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/UserFeignClient.class b/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/UserFeignClient.class index 8c65149..6e698b7 100644 Binary files a/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/UserFeignClient.class and b/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/UserFeignClient.class differ diff --git a/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.class b/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.class index 31de6ac..dc35739 100644 Binary files a/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.class and b/service-client/service-user-client/target/classes/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.class differ diff --git a/service/service-account/src/main/java/com/atguigu/tingshu/account/api/UserAccountApiController.java b/service/service-account/src/main/java/com/atguigu/tingshu/account/api/UserAccountApiController.java index b493aa1..054fc75 100644 --- a/service/service-account/src/main/java/com/atguigu/tingshu/account/api/UserAccountApiController.java +++ b/service/service-account/src/main/java/com/atguigu/tingshu/account/api/UserAccountApiController.java @@ -4,12 +4,11 @@ import com.atguigu.tingshu.account.service.UserAccountService; import com.atguigu.tingshu.common.login.GuiGuLogin; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.common.util.AuthContextHolder; +import com.atguigu.tingshu.vo.account.AccountDeductVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; @@ -30,6 +29,20 @@ public class UserAccountApiController { return Result.ok(Amount); } + /** + * 检查扣减账户余额 + * @param accountDeductVo + * @return + */ + @GuiGuLogin + @Operation(summary = "检查扣减账户余额") + @PostMapping("/userAccount/checkAndDeduct") + public Result checkAndDeduct(@RequestBody AccountDeductVo accountDeductVo){ + userAccountService.checkAndDeduct(accountDeductVo); + return Result.ok(); + + } + } diff --git a/service/service-account/src/main/java/com/atguigu/tingshu/account/mapper/UserAccountMapper.java b/service/service-account/src/main/java/com/atguigu/tingshu/account/mapper/UserAccountMapper.java index c98dbcb..c03faa6 100644 --- a/service/service-account/src/main/java/com/atguigu/tingshu/account/mapper/UserAccountMapper.java +++ b/service/service-account/src/main/java/com/atguigu/tingshu/account/mapper/UserAccountMapper.java @@ -4,7 +4,10 @@ import com.atguigu.tingshu.model.account.UserAccount; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import java.math.BigDecimal; + @Mapper public interface UserAccountMapper extends BaseMapper { + UserAccount checkDeduction(Long userId, BigDecimal amount); } diff --git a/service/service-account/src/main/java/com/atguigu/tingshu/account/service/UserAccountService.java b/service/service-account/src/main/java/com/atguigu/tingshu/account/service/UserAccountService.java index 01bbbf0..a11a0e3 100644 --- a/service/service-account/src/main/java/com/atguigu/tingshu/account/service/UserAccountService.java +++ b/service/service-account/src/main/java/com/atguigu/tingshu/account/service/UserAccountService.java @@ -1,6 +1,7 @@ package com.atguigu.tingshu.account.service; import com.atguigu.tingshu.model.account.UserAccount; +import com.atguigu.tingshu.vo.account.AccountDeductVo; import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; @@ -24,4 +25,7 @@ public interface UserAccountService extends IService { void saveUserAccountDetail(Long userId, String title, BigDecimal amount, String orderNo); BigDecimal getAvailableAmount(Long userId); + + void checkAndDeduct(AccountDeductVo accountDeductVo); + } diff --git a/service/service-account/src/main/java/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.java b/service/service-account/src/main/java/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.java index d1c2575..ee8c7f2 100644 --- a/service/service-account/src/main/java/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.java +++ b/service/service-account/src/main/java/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.java @@ -6,7 +6,9 @@ import com.atguigu.tingshu.account.service.UserAccountService; import com.atguigu.tingshu.common.constant.SystemConstant; import com.atguigu.tingshu.model.account.UserAccount; import com.atguigu.tingshu.model.account.UserAccountDetail; +import com.atguigu.tingshu.vo.account.AccountDeductVo; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -68,5 +70,33 @@ public class UserAccountServiceImpl extends ServiceImpl() + .eq(UserAccount::getUserId, accountDeductVo.getUserId()) + .setSql("total_amount = total_amount - " + accountDeductVo.getAmount()) + .setSql("available_amount = available_amount - " + accountDeductVo.getAmount()) + .setSql("total_pay_amount = total_pay_amount + " + accountDeductVo.getAmount()) + ); + if (rows == 0) { + throw new RuntimeException("账户余额不足!"); + } + //3.保存账户变动日志 + this.saveUserAccountDetail(accountDeductVo.getUserId(), accountDeductVo.getContent(), accountDeductVo.getAmount(), accountDeductVo.getOrderNo()); + + + } } diff --git a/service/service-account/src/main/resources/mapper/UserAccountMapper.xml b/service/service-account/src/main/resources/mapper/UserAccountMapper.xml index a52f377..da865a2 100644 --- a/service/service-account/src/main/resources/mapper/UserAccountMapper.xml +++ b/service/service-account/src/main/resources/mapper/UserAccountMapper.xml @@ -12,5 +12,10 @@ id,user_id,total_amount,lock_amount,available_amount,total_income_amount,total_pay_amount,create_time,update_time,is_deleted + + + diff --git a/service/service-account/target/classes/com/atguigu/tingshu/account/api/UserAccountApiController.class b/service/service-account/target/classes/com/atguigu/tingshu/account/api/UserAccountApiController.class index 55e36dd..d643586 100644 Binary files a/service/service-account/target/classes/com/atguigu/tingshu/account/api/UserAccountApiController.class and b/service/service-account/target/classes/com/atguigu/tingshu/account/api/UserAccountApiController.class differ diff --git a/service/service-account/target/classes/com/atguigu/tingshu/account/mapper/UserAccountMapper.class b/service/service-account/target/classes/com/atguigu/tingshu/account/mapper/UserAccountMapper.class index 5a7ff30..94cb8f2 100644 Binary files a/service/service-account/target/classes/com/atguigu/tingshu/account/mapper/UserAccountMapper.class and b/service/service-account/target/classes/com/atguigu/tingshu/account/mapper/UserAccountMapper.class differ diff --git a/service/service-account/target/classes/com/atguigu/tingshu/account/service/UserAccountService.class b/service/service-account/target/classes/com/atguigu/tingshu/account/service/UserAccountService.class index 26f3849..725537f 100644 Binary files a/service/service-account/target/classes/com/atguigu/tingshu/account/service/UserAccountService.class and b/service/service-account/target/classes/com/atguigu/tingshu/account/service/UserAccountService.class differ diff --git a/service/service-account/target/classes/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.class b/service/service-account/target/classes/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.class index 303251f..c1c6efe 100644 Binary files a/service/service-account/target/classes/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.class and b/service/service-account/target/classes/com/atguigu/tingshu/account/service/impl/UserAccountServiceImpl.class differ diff --git a/service/service-account/target/classes/mapper/UserAccountMapper.xml b/service/service-account/target/classes/mapper/UserAccountMapper.xml index a52f377..da865a2 100644 --- a/service/service-account/target/classes/mapper/UserAccountMapper.xml +++ b/service/service-account/target/classes/mapper/UserAccountMapper.xml @@ -12,5 +12,10 @@ id,user_id,total_amount,lock_amount,available_amount,total_income_amount,total_pay_amount,create_time,update_time,is_deleted + + + diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/task/ReviewTask.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/task/ReviewTask.java index 52f59c1..717e492 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/task/ReviewTask.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/task/ReviewTask.java @@ -41,30 +41,35 @@ public class ReviewTask { RLock lock = redissonClient.getLock("reviewtask:lock"); boolean b = lock.tryLock(); if (b) { - log.info("开始检查审核任务"); - //1.查询审核状态为"审核中"声音列表 - List trackInfoList = trackInfoMapper.selectList( - new LambdaQueryWrapper() - .eq(TrackInfo::getStatus, SystemConstant.TRACK_STATUS_REVIEWING) - .select(TrackInfo::getId, TrackInfo::getReviewTaskId) - .last("limit 100") - ); - //2.遍历列表,查询审核结果 - if (CollUtil.isNotEmpty(trackInfoList)) { - for (TrackInfo trackInfo : trackInfoList) { - String suggestion = auditService.getReviewResult(trackInfo.getReviewTaskId()); - if (StringUtils.isNotBlank(suggestion)) { - //3.根据审核任务结果更新声音审核状态 - if ("pass".equals(suggestion)) { - trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS); - } else if ("block".equals(suggestion)) { - trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS); - } else if ("review".equals(suggestion)) { - trackInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL); + try { + log.info("开始检查审核任务"); + //1.查询审核状态为"审核中"声音列表 + List trackInfoList = trackInfoMapper.selectList( + new LambdaQueryWrapper() + .eq(TrackInfo::getStatus, SystemConstant.TRACK_STATUS_REVIEWING) + .select(TrackInfo::getId, TrackInfo::getReviewTaskId) + .last("limit 100") + ); + //2.遍历列表,查询审核结果 + if (CollUtil.isNotEmpty(trackInfoList)) { + for (TrackInfo trackInfo : trackInfoList) { + String suggestion = auditService.getReviewResult(trackInfo.getReviewTaskId()); + if (StringUtils.isNotBlank(suggestion)) { + //3.根据审核任务结果更新声音审核状态 + if ("pass".equals(suggestion)) { + trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS); + } else if ("block".equals(suggestion)) { + trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS); + } else if ("review".equals(suggestion)) { + trackInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL); + } + trackInfoMapper.updateById(trackInfo); } - trackInfoMapper.updateById(trackInfo); } } + } finally { + lock.unlock(); + } } } diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class index 560fe4d..433725a 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/task/ReviewTask.class b/service/service-album/target/classes/com/atguigu/tingshu/album/task/ReviewTask.class index cf1d1b2..d3abd20 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/task/ReviewTask.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/task/ReviewTask.class differ diff --git a/service/service-order/pom.xml b/service/service-order/pom.xml index d8ed73c..dedfb8c 100644 --- a/service/service-order/pom.xml +++ b/service/service-order/pom.xml @@ -28,6 +28,22 @@ service-account-client 1.0 + + com.alibaba.cloud + spring-cloud-starter-alibaba-seata + + + + io.seata + seata-spring-boot-starter + + + + + io.seata + seata-spring-boot-starter + + diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/api/OrderInfoApiController.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/api/OrderInfoApiController.java index 2b58f73..ec8d13f 100644 --- a/service/service-order/src/main/java/com/atguigu/tingshu/order/api/OrderInfoApiController.java +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/api/OrderInfoApiController.java @@ -2,6 +2,7 @@ package com.atguigu.tingshu.order.api; import com.atguigu.tingshu.common.login.GuiGuLogin; import com.atguigu.tingshu.common.result.Result; +import com.atguigu.tingshu.common.util.AuthContextHolder; import com.atguigu.tingshu.order.service.OrderInfoService; import com.atguigu.tingshu.vo.order.OrderInfoVo; import com.atguigu.tingshu.vo.order.TradeVo; @@ -13,6 +14,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; + @Tag(name = "订单管理") @RestController @RequestMapping("api/order") @@ -31,6 +34,20 @@ public class OrderInfoApiController { return Result.ok(orderInfoVo); } + /** + * 提交订单(付款方式:1.余额 2.微信) + * @param orderInfoVo + * @return + */ + @GuiGuLogin + @Operation(summary = "提交订单(付款方式:1.余额 2.微信)") + @PostMapping("/orderInfo/submitOrder") + public Result> submitOrder(@RequestBody OrderInfoVo orderInfoVo) { + Long userId = AuthContextHolder.getUserId(); + Map result = orderInfoService.submitOrder(orderInfoVo, userId); + return Result.ok(result); + } + } diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/TradeTypeStrategy.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/TradeTypeStrategy.java new file mode 100644 index 0000000..9bf676e --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/TradeTypeStrategy.java @@ -0,0 +1,10 @@ +package com.atguigu.tingshu.order.pattern; + +import com.atguigu.tingshu.vo.order.OrderInfoVo; +import com.atguigu.tingshu.vo.order.TradeVo; + +public interface TradeTypeStrategy { + + OrderInfoVo trade(TradeVo tradeVo); + +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/factory/TradeTypeStrategyFactory.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/factory/TradeTypeStrategyFactory.java new file mode 100644 index 0000000..d8600fe --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/factory/TradeTypeStrategyFactory.java @@ -0,0 +1,28 @@ +package com.atguigu.tingshu.order.pattern.factory; + +import com.atguigu.tingshu.order.pattern.TradeTypeStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class TradeTypeStrategyFactory { + + + @Autowired + private Map tradeTypeStrategyMap; + + + public TradeTypeStrategy getTradeTypeStrategy(String itemType) + { + log.info("itemType:{}",itemType); + if (tradeTypeStrategyMap.containsKey(itemType)) { + return tradeTypeStrategyMap.get(itemType); + } + log.error("当前商品类型不支持处理!"); + throw new RuntimeException("当前商品类型不支持处理!"); + } +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/AlbumTradeType.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/AlbumTradeType.java new file mode 100644 index 0000000..e0a6a83 --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/AlbumTradeType.java @@ -0,0 +1,150 @@ +package com.atguigu.tingshu.order.pattern.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.album.AlbumFeignClient; +import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.common.util.AuthContextHolder; +import com.atguigu.tingshu.model.album.AlbumInfo; +import com.atguigu.tingshu.order.helper.SignHelper; +import com.atguigu.tingshu.order.pattern.TradeTypeStrategy; +import com.atguigu.tingshu.user.client.UserFeignClient; +import com.atguigu.tingshu.vo.order.OrderDerateVo; +import com.atguigu.tingshu.vo.order.OrderDetailVo; +import com.atguigu.tingshu.vo.order.OrderInfoVo; +import com.atguigu.tingshu.vo.order.TradeVo; +import com.atguigu.tingshu.vo.user.UserInfoVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Component(SystemConstant.ORDER_ITEM_TYPE_ALBUM) +@Slf4j +public class AlbumTradeType implements TradeTypeStrategy { + + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private UserFeignClient userFeignClient; + @Autowired + private AlbumFeignClient albumFeignClient; + @Override + public OrderInfoVo trade(TradeVo tradeVo) { + //从线程中取出userid来 + Long userId = AuthContextHolder.getUserId(); + //1.创建订单VO对象,创建初始三个金额,两个集合(商品、优惠) + OrderInfoVo orderInfoVo = new OrderInfoVo(); + //1.1 初始化原价金额 + // 必须是BigDecimal类型且必须是字符串 + BigDecimal originalAmount = new BigDecimal("0.00"); + //1.2 初始化减免金额 + BigDecimal derateAmount = new BigDecimal("0.00"); + //1.3 初始化订单金额 + BigDecimal orderAmount = new BigDecimal("0.00"); + + //1.4.初始化订单明细 + List orderDetailVoList = new ArrayList<>(); + //1.5.初始化订单减免明细列表 + List orderDerateVoList = new ArrayList<>(); + + //1.6 获取购买项目类型 付款项目类型: 1001-专辑 1002-声音 1003-vip会员 + String itemType = tradeVo.getItemType(); + //3. 处理购买项目类型:专辑 + //3.1 远程调用用户服务,判断是否重复购买专辑,如果已购过,则业务终止 + Long albumId = tradeVo.getItemId(); + Boolean data = userFeignClient.isPaidAlbum(albumId).getData(); + //如果data为true的话就走断言 + Assert.isFalse(data, "用户已购买专辑{}", albumId); + //3.2 远程调用专辑服务,获取专辑价格以及折扣(普通用户折扣,VIP会员折扣) + AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData(); + BigDecimal price = albumInfo.getPrice(); + BigDecimal discount = albumInfo.getDiscount(); + BigDecimal vipDiscount = albumInfo.getVipDiscount(); + //判断用户是否为vip 如果是vip就走vip折扣 如果不是就走普通用户的折扣 + Boolean isVIP = false; + UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData(); + Assert.notNull(userInfoVo, "用户{}不存在", userId); + //判断一下用户是否为vip以及vip的过期时间是否超过了当时的时间 + if (userInfoVo.getIsVip().intValue() == 1 + && userInfoVo.getVipExpireTime().after(new Date())) { + isVIP = true; + } + //3.4 计算相关价格 + //3.4.1 暂时将订单价=原价 + originalAmount = price; + orderAmount = originalAmount; + //当你是普通客户 但是专辑是有普通用户折扣的时候 计算一下专辑价格 + //discount.doubleValue()!=-1 + //BigDecimal.doubleValue() 是将 BigDecimal 转换为 double 类型的操作 + + //如果是普通用户且有折扣,则订单价=原价 100 *折扣 6 + //..divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP)是保留两位小数的标准写法 + if (!isVIP && discount.doubleValue() != -1) { + orderAmount = originalAmount.multiply(discount) + .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP); + } + //如果是会员,则按照会员折扣走 + if (isVIP && vipDiscount.doubleValue() != -1) { + orderAmount = originalAmount.multiply(vipDiscount) + .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP); + } + //3.5 封装商品信息列表 + OrderDetailVo orderDetailVo = new OrderDetailVo(); + orderDetailVo.setItemId(albumId); + orderDetailVo.setItemName("专辑:" + albumInfo.getAlbumTitle()); + orderDetailVo.setItemUrl(albumInfo.getCoverUrl()); + orderDetailVo.setItemPrice(originalAmount); + orderDetailVoList.add(orderDetailVo); + + //2.4 如果存在优惠,封装优惠列表 + if (originalAmount.compareTo(orderAmount) == 1) { + OrderDerateVo orderDerateVo = new OrderDerateVo(); + orderDerateVo.setRemarks(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT); + orderDerateVo.setDerateType("VIP套餐限时优惠:" + derateAmount); + orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount)); + orderDerateVoList.add(orderDerateVo); + } + + //5.封装订单VO对象 + //5.1 封装相关价格信息 + orderInfoVo.setOriginalAmount(originalAmount); + orderInfoVo.setOrderAmount(orderAmount); + orderInfoVo.setDerateAmount(derateAmount); + //5.2 封装商品相关集合 + orderInfoVo.setOrderDetailVoList(orderDetailVoList); + orderInfoVo.setOrderDerateVoList(orderDerateVoList); + //5.3 TODO 封装其他信息:流水号、时间戳及签名、项目类型等 + //5.3.1 封装项目的类型 + orderInfoVo.setItemType(itemType); + //5.3.2 流水号机制,防止订单重复提交(1.用户网络卡连续点击结算按钮2.成功提交订单,回退到订单确认页再次提交) + //5.3.2.1 构建当前用户当前订单流水号Key + String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId; + //5.3.2.2 采用UUID生成本次订单流水号值 + String tradeNo = IdUtil.randomUUID(); + //5.3.2.3 将流水号值保存到Redis中,设置过期时间(5分钟),防止订单重复提交 + redisTemplate.opsForValue().set(tradeKey, tradeNo, 5, TimeUnit.MINUTES); + orderInfoVo.setTradeNo(tradeNo); + + //5.3.3 签名机制,时间戳+签名值,防止订单结算页数据被篡改 + orderInfoVo.setTimestamp(System.currentTimeMillis()); + //5.3.1 将订单VO转为Map对象,由于无法确定支付方式,固将VO中payWay为空属性排除掉 + Map map = BeanUtil.beanToMap(orderInfoVo, false, true); + String sign = SignHelper.getSign(map); + orderInfoVo.setSign(sign); + + //6.响应订单VO对象 + return orderInfoVo; + + } +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/TrackTradeType.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/TrackTradeType.java new file mode 100644 index 0000000..fa8da99 --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/TrackTradeType.java @@ -0,0 +1,116 @@ +package com.atguigu.tingshu.order.pattern.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.album.AlbumFeignClient; +import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.common.util.AuthContextHolder; +import com.atguigu.tingshu.model.album.AlbumInfo; +import com.atguigu.tingshu.model.album.TrackInfo; +import com.atguigu.tingshu.order.helper.SignHelper; +import com.atguigu.tingshu.order.pattern.TradeTypeStrategy; +import com.atguigu.tingshu.vo.order.OrderDerateVo; +import com.atguigu.tingshu.vo.order.OrderDetailVo; +import com.atguigu.tingshu.vo.order.OrderInfoVo; +import com.atguigu.tingshu.vo.order.TradeVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Component(SystemConstant.ORDER_ITEM_TYPE_TRACK) +@Slf4j +public class TrackTradeType implements TradeTypeStrategy { + @Autowired + private AlbumFeignClient albumFeignClient; + @Autowired + private RedisTemplate redisTemplate; + @Override + public OrderInfoVo trade(TradeVo tradeVo) { + //从线程中取出userid来 + Long userId = AuthContextHolder.getUserId(); + //1.创建订单VO对象,创建初始三个金额,两个集合(商品、优惠) + OrderInfoVo orderInfoVo = new OrderInfoVo(); + //1.1 初始化原价金额 + // 必须是BigDecimal类型且必须是字符串 + BigDecimal originalAmount = new BigDecimal("0.00"); + //1.2 初始化减免金额 + BigDecimal derateAmount = new BigDecimal("0.00"); + //1.3 初始化订单金额 + BigDecimal orderAmount = new BigDecimal("0.00"); + + //1.4.初始化订单明细 + List orderDetailVoList = new ArrayList<>(); + //1.5.初始化订单减免明细列表 + List orderDerateVoList = new ArrayList<>(); + + //1.6 获取购买项目类型 付款项目类型: 1001-专辑 1002-声音 1003-vip会员 + String itemType = tradeVo.getItemType(); + + //4.处理购买项目类型:声音 + //4.1 远程调用专辑服务,获取未购买声音列表 + Long trackId = tradeVo.getItemId(); + List trackInfoList = + albumFeignClient.findWaitBuyTrackList(trackId, tradeVo.getTrackCount()).getData(); + Assert.notNull(trackInfoList, "不存在待结算声音", trackId); + //4.2 远程调用专辑服务获取,专辑价格(声音单价)声音不支持折扣 + AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData(); + Assert.notNull(albumInfo, "专辑{}不存在", albumInfo.getId()); + BigDecimal price = albumInfo.getPrice(); + //4.3 计算相关价格 + originalAmount = price.multiply(new BigDecimal(trackInfoList.size())); + orderAmount = originalAmount; + //4.4 封装订单明细列表 + orderDetailVoList = trackInfoList.stream().map( + trackInfo -> { + OrderDetailVo orderDetailVo = new OrderDetailVo(); + orderDetailVo.setItemId(trackInfo.getId()); + orderDetailVo.setItemName("声音:" + trackInfo.getTrackTitle()); + orderDetailVo.setItemUrl(trackInfo.getCoverUrl()); + orderDetailVo.setItemPrice(price); + return orderDetailVo; + } + ).collect(Collectors.toList()); + + //5.封装订单VO对象 + //5.1 封装相关价格信息 + orderInfoVo.setOriginalAmount(originalAmount); + orderInfoVo.setOrderAmount(orderAmount); + orderInfoVo.setDerateAmount(derateAmount); + //5.2 封装商品相关集合 + orderInfoVo.setOrderDetailVoList(orderDetailVoList); + orderInfoVo.setOrderDerateVoList(orderDerateVoList); + //5.3 TODO 封装其他信息:流水号、时间戳及签名、项目类型等 + //5.3.1 封装项目的类型 + orderInfoVo.setItemType(itemType); + //5.3.2 流水号机制,防止订单重复提交(1.用户网络卡连续点击结算按钮2.成功提交订单,回退到订单确认页再次提交) + //5.3.2.1 构建当前用户当前订单流水号Key + String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId; + //5.3.2.2 采用UUID生成本次订单流水号值 + String tradeNo = IdUtil.randomUUID(); + //5.3.2.3 将流水号值保存到Redis中,设置过期时间(5分钟),防止订单重复提交 + redisTemplate.opsForValue().set(tradeKey, tradeNo, 5, TimeUnit.MINUTES); + orderInfoVo.setTradeNo(tradeNo); + + //5.3.3 签名机制,时间戳+签名值,防止订单结算页数据被篡改 + orderInfoVo.setTimestamp(System.currentTimeMillis()); + //5.3.1 将订单VO转为Map对象,由于无法确定支付方式,固将VO中payWay为空属性排除掉 + Map map = BeanUtil.beanToMap(orderInfoVo, false, true); + String sign = SignHelper.getSign(map); + orderInfoVo.setSign(sign); + + return orderInfoVo; + + + + } +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/VIPTradeType.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/VIPTradeType.java new file mode 100644 index 0000000..842d8d3 --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/impl/VIPTradeType.java @@ -0,0 +1,119 @@ +package com.atguigu.tingshu.order.pattern.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.common.util.AuthContextHolder; +import com.atguigu.tingshu.model.user.VipServiceConfig; +import com.atguigu.tingshu.order.helper.SignHelper; +import com.atguigu.tingshu.order.pattern.TradeTypeStrategy; +import com.atguigu.tingshu.user.client.UserFeignClient; +import com.atguigu.tingshu.vo.order.OrderDerateVo; +import com.atguigu.tingshu.vo.order.OrderDetailVo; +import com.atguigu.tingshu.vo.order.OrderInfoVo; +import com.atguigu.tingshu.vo.order.TradeVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Component(SystemConstant.ORDER_ITEM_TYPE_VIP) +@Slf4j +public class VIPTradeType implements TradeTypeStrategy { + + @Autowired + private UserFeignClient userFeignClient; + @Autowired + private RedisTemplate redisTemplate; + + @Override + public OrderInfoVo trade(TradeVo tradeVo) { + //从线程中取出userid来 + Long userId = AuthContextHolder.getUserId(); + //1.创建订单VO对象,创建初始三个金额,两个集合(商品、优惠) + OrderInfoVo orderInfoVo = new OrderInfoVo(); + //1.1 初始化原价金额 + // 必须是BigDecimal类型且必须是字符串 + BigDecimal originalAmount = new BigDecimal("0.00"); + //1.2 初始化减免金额 + BigDecimal derateAmount = new BigDecimal("0.00"); + //1.3 初始化订单金额 + BigDecimal orderAmount = new BigDecimal("0.00"); + + //1.4.初始化订单明细 + List orderDetailVoList = new ArrayList<>(); + //1.5.初始化订单减免明细列表 + List orderDerateVoList = new ArrayList<>(); + //1.6 获取购买项目类型 付款项目类型: 1001-专辑 1002-声音 1003-vip会员 + String itemType = tradeVo.getItemType(); + //2.1 远程调用用户服务得到VIP套餐信息 + VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(tradeVo.getItemId()).getData(); + Assert.notNull(vipServiceConfig, "VIP套餐{}不存在", tradeVo.getItemId()); + //2.2 计算原金额、订单金额、减免金额 + originalAmount = vipServiceConfig.getPrice(); + orderAmount = vipServiceConfig.getDiscountPrice(); + //2.3 封装商品信息列表 + OrderDetailVo orderDetailVo = new OrderDetailVo(); + //套餐的ID + orderDetailVo.setItemId(tradeVo.getItemId()); + //套餐的名字 + orderDetailVo.setItemName("VIP套餐:" + vipServiceConfig.getName()); + //套餐图片的url + orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl()); + //套餐的折后价 + orderDetailVo.setItemPrice(orderAmount); + orderDetailVoList.add(orderDetailVo); + //2.4 如果存在优惠,封装优惠列表 + //bigdecimal是不能用equals判断的 因为1.10和1.1不相等 + //compareTo(orderAmount)==0是相等 + //compareTo(orderAmount)==-1小于 + //compareTo(orderAmount)==1是大于 如果大于的话说明有了折扣 + if (originalAmount.compareTo(orderAmount) == 1) { + derateAmount = originalAmount.subtract(orderAmount); + //存在优惠 我们要封装优惠列表 + OrderDerateVo orderDerateVo = new OrderDerateVo(); + orderDerateVo.setDerateAmount(derateAmount); + orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT); + orderDerateVo.setRemarks("VIP套餐限时优惠:" + derateAmount); + orderDerateVoList.add(orderDerateVo); + } + //5.封装订单VO对象 + //5.1 封装相关价格信息 + orderInfoVo.setOriginalAmount(originalAmount); + orderInfoVo.setOrderAmount(orderAmount); + orderInfoVo.setDerateAmount(derateAmount); + //5.2 封装商品相关集合 + orderInfoVo.setOrderDetailVoList(orderDetailVoList); + orderInfoVo.setOrderDerateVoList(orderDerateVoList); + //5.3 TODO 封装其他信息:流水号、时间戳及签名、项目类型等 + //5.3.1 封装项目的类型 + orderInfoVo.setItemType(itemType); + //5.3.2 流水号机制,防止订单重复提交(1.用户网络卡连续点击结算按钮2.成功提交订单,回退到订单确认页再次提交) + //5.3.2.1 构建当前用户当前订单流水号Key + String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId; + //5.3.2.2 采用UUID生成本次订单流水号值 + String tradeNo = IdUtil.randomUUID(); + //5.3.2.3 将流水号值保存到Redis中,设置过期时间(5分钟),防止订单重复提交 + redisTemplate.opsForValue().set(tradeKey, tradeNo, 5, TimeUnit.MINUTES); + orderInfoVo.setTradeNo(tradeNo); + + //5.3.3 签名机制,时间戳+签名值,防止订单结算页数据被篡改 + orderInfoVo.setTimestamp(System.currentTimeMillis()); + //5.3.1 将订单VO转为Map对象,由于无法确定支付方式,固将VO中payWay为空属性排除掉 + Map map = BeanUtil.beanToMap(orderInfoVo, false, true); + String sign = SignHelper.getSign(map); + orderInfoVo.setSign(sign); + + //6.响应订单VO对象 + return orderInfoVo; + + } +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDerateService.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDerateService.java new file mode 100644 index 0000000..bee5afc --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDerateService.java @@ -0,0 +1,7 @@ +package com.atguigu.tingshu.order.service; + +import com.atguigu.tingshu.model.order.OrderDerate; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface OrderDerateService extends IService { +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDetailService.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDetailService.java new file mode 100644 index 0000000..6b6fead --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderDetailService.java @@ -0,0 +1,7 @@ +package com.atguigu.tingshu.order.service; + +import com.atguigu.tingshu.model.order.OrderDetail; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface OrderDetailService extends IService { +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderInfoService.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderInfoService.java index a9dbb8b..1c6923c 100644 --- a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderInfoService.java +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/OrderInfoService.java @@ -5,8 +5,14 @@ import com.atguigu.tingshu.vo.order.OrderInfoVo; import com.atguigu.tingshu.vo.order.TradeVo; import com.baomidou.mybatisplus.extension.service.IService; +import java.util.Map; + public interface OrderInfoService extends IService { OrderInfoVo trade(TradeVo tradeVo); + + Map submitOrder(OrderInfoVo orderInfoVo, Long userId); + + OrderInfo saveOrderInfo(OrderInfoVo orderInfoVo, Long userId); } diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDerateServiceImpl.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDerateServiceImpl.java new file mode 100644 index 0000000..6192666 --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDerateServiceImpl.java @@ -0,0 +1,17 @@ +package com.atguigu.tingshu.order.service.impl; + +import com.atguigu.tingshu.model.order.OrderDerate; +import com.atguigu.tingshu.order.mapper.OrderDerateMapper; +import com.atguigu.tingshu.order.service.OrderDerateService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author: atguigu + * @create: 2025-08-02 11:35 + */ +@Slf4j +@Service +public class OrderDerateServiceImpl extends ServiceImpl implements OrderDerateService { +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDetailServiceImpl.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDetailServiceImpl.java new file mode 100644 index 0000000..2db34ef --- /dev/null +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderDetailServiceImpl.java @@ -0,0 +1,13 @@ +package com.atguigu.tingshu.order.service.impl; + +import com.atguigu.tingshu.model.order.OrderDetail; +import com.atguigu.tingshu.order.mapper.OrderDetailMapper; +import com.atguigu.tingshu.order.service.OrderDetailService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class OrderDetailServiceImpl extends ServiceImpl implements OrderDetailService { +} diff --git a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.java b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.java index 5bb11d1..1e8af2a 100644 --- a/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.java +++ b/service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.java @@ -1,34 +1,51 @@ package com.atguigu.tingshu.order.service.impl; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.account.AccountFeignClient; import com.atguigu.tingshu.album.AlbumFeignClient; +import com.atguigu.tingshu.common.constant.RedisConstant; import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.common.execption.GuiguException; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.common.util.AuthContextHolder; import com.atguigu.tingshu.model.album.AlbumInfo; import com.atguigu.tingshu.model.album.TrackInfo; +import com.atguigu.tingshu.model.order.OrderDerate; +import com.atguigu.tingshu.model.order.OrderDetail; import com.atguigu.tingshu.model.order.OrderInfo; import com.atguigu.tingshu.model.user.VipServiceConfig; +import com.atguigu.tingshu.order.helper.SignHelper; import com.atguigu.tingshu.order.mapper.OrderInfoMapper; +import com.atguigu.tingshu.order.pattern.TradeTypeStrategy; +import com.atguigu.tingshu.order.pattern.factory.TradeTypeStrategyFactory; +import com.atguigu.tingshu.order.service.OrderDerateService; +import com.atguigu.tingshu.order.service.OrderDetailService; import com.atguigu.tingshu.order.service.OrderInfoService; import com.atguigu.tingshu.user.client.UserFeignClient; +import com.atguigu.tingshu.vo.account.AccountDeductVo; import com.atguigu.tingshu.vo.order.OrderDerateVo; import com.atguigu.tingshu.vo.order.OrderDetailVo; import com.atguigu.tingshu.vo.order.OrderInfoVo; import com.atguigu.tingshu.vo.order.TradeVo; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import io.seata.spring.annotation.GlobalTransactional; import lombok.extern.slf4j.Slf4j; -import org.aspectj.weaver.ast.Or; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @@ -40,163 +57,162 @@ public class OrderInfoServiceImpl extends ServiceImpl orderDetailVoList = new ArrayList<>(); - //1.5.初始化订单减免明细列表 - List orderDerateVoList = new ArrayList<>(); - //todo 流水号 签名之类的还未添加 - //1.6 获取购买项目类型 付款项目类型: 1001-专辑 1002-声音 1003-vip会员 String itemType = tradeVo.getItemType(); - //2. 处理购买项目类型:VIP套餐 - if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(itemType)) { - //2.1 远程调用用户服务得到VIP套餐信息 - VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(tradeVo.getItemId()).getData(); - Assert.notNull(vipServiceConfig, "VIP套餐{}不存在", tradeVo.getItemId()); - //2.2 计算原金额、订单金额、减免金额 - originalAmount = vipServiceConfig.getPrice(); - orderAmount = vipServiceConfig.getDiscountPrice(); - //2.3 封装商品信息列表 - OrderDetailVo orderDetailVo = new OrderDetailVo(); - //套餐的ID - orderDetailVo.setItemId(tradeVo.getItemId()); - //套餐的名字 - orderDetailVo.setItemName("VIP套餐:" + vipServiceConfig.getName()); - //套餐图片的url - orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl()); - //套餐的折后价 - orderDetailVo.setItemPrice(orderAmount); - orderDetailVoList.add(orderDetailVo); - //2.4 如果存在优惠,封装优惠列表 - //bigdecimal是不能用equals判断的 因为1.10和1.1不相等 - //compareTo(orderAmount)==0是相等 - //compareTo(orderAmount)==-1小于 - //compareTo(orderAmount)==1是大于 如果大于的话说明有了折扣 - if (originalAmount.compareTo(orderAmount) == 1) { - derateAmount = originalAmount.subtract(orderAmount); - //存在优惠 我们要封装优惠列表 - OrderDerateVo orderDerateVo = new OrderDerateVo(); - orderDerateVo.setDerateAmount(derateAmount); - orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT); - orderDerateVo.setRemarks("VIP套餐限时优惠:" + derateAmount); - orderDerateVoList.add(orderDerateVo); + //从策略工厂获取具体实现类对象 + TradeTypeStrategy tradeTypeStrategy = tradeTypeStrategyFactory.getTradeTypeStrategy(itemType); + OrderInfoVo trade = tradeTypeStrategy.trade(tradeVo); + //返回订单信息 + return trade; + } + + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public Map submitOrder(OrderInfoVo orderInfoVo, Long userId) { + //1.业务校验:验证流水号,防止订单重复提交 采用Lua脚本保证判断删除原子性 + String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId; + //1.1 定义lua脚本 + String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" + + "then\n" + + " return redis.call(\"del\",KEYS[1])\n" + + "else\n" + + " return 0\n" + + "end"; + //1.2 创建脚本对象 + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(luaScript); + redisScript.setResultType(Boolean.class); + //1.3 执行Lua脚本 + Boolean flag = (Boolean) redisTemplate.execute(redisScript, Arrays.asList(tradeKey), orderInfoVo.getTradeNo()); + if (!flag) { + throw new GuiguException(500, "验证流水号失败"); + } + //2.业务校验:`验证签名`,防止订单数据被篡改 + //2.1 将订单VO转为Map对象 由于当时加签将payWay排除掉,并未加入到签名中 + //为何在初始化初始数值时候要用bigdecimal数值中要写String类型,如果数值写了int类型的话 + //会导致数值不一样 比如说0.00会变成0 导致md5编码过程中编码错误 结果导致验签失败 + Map stringObjectMap = BeanUtil.beanToMap(orderInfoVo); + stringObjectMap.remove("payWay"); + //2.2 调用验证签名工具方法 + SignHelper.checkSign(stringObjectMap); + + //当校验流水号和验证签名成功以后 执行核心业务 + //3.核心业务:保存订单以及订单明细,优惠列表等 -- 此时订单:未支付 + OrderInfo orderInfo = this.saveOrderInfo(orderInfoVo, userId); + //支付方式:1101-微信 1102-支付宝 1103-账户余额 + String payWay = orderInfoVo.getPayWay(); + //4.TODO 判断支付方式:余额扣减核心业务 + if(SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay)){ + //余额扣减 + //4.1 远程调用账户服务扣减账户余额 + AccountDeductVo accountDeductVo = new AccountDeductVo(); + accountDeductVo.setAmount(orderInfo.getOrderAmount()); + accountDeductVo.setOrderNo(orderInfo.getOrderNo()); + accountDeductVo.setContent(orderInfo.getOrderTitle()); + accountDeductVo.setUserId(orderInfo.getUserId()); + + + Result result = accountFeignClient.checkAndDeduct(accountDeductVo); + //判断是否为扣减成功 + if(result.getCode().intValue()!=200){ + throw new GuiguException(result.getCode(), result.getMessage()); + } + //4.2 如果扣减余额成功,修改订单状态改为:已支付 + orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID); + orderInfoMapper.updateById(orderInfo); + + //4.3 远程调用用户服务虚拟物品发货 + //4.3.1 构建虚拟发货VO对象 + UserPaidRecordVo userPaidRecordVo =new UserPaidRecordVo(); + userPaidRecordVo.setOrderNo(orderInfo.getOrderNo()); + userPaidRecordVo.setUserId(orderInfo.getUserId()); + userPaidRecordVo.setItemType(orderInfo.getItemType()); + //根据订单编号查询订单明细获取购买项目ID列表 + List orderDetailList = orderDetailService.list( + new LambdaQueryWrapper() + .eq(OrderDetail::getOrderId, orderInfo.getId()) + .select(OrderDetail::getItemId) + ); + List itemIdList = orderDetailList.stream() + .map(OrderDetail::getItemId).collect(Collectors.toList()); + userPaidRecordVo.setItemIdList(itemIdList); + //4.3.2 远程调用用户服务,发放用户权益 + result = userFeignClient.savePaidRecord(userPaidRecordVo); + //4.3.3 判断远程调用结果业务状态码是否为200 + if (result.getCode().intValue() != 200) { + throw new GuiguException(result.getCode(), result.getMessage()); } - } else if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(itemType)) { - //3. 处理购买项目类型:专辑 - //3.1 远程调用用户服务,判断是否重复购买专辑,如果已购过,则业务终止 - Long albumId = tradeVo.getItemId(); - Boolean data = userFeignClient.isPaidAlbum(albumId).getData(); - //如果data为true的话就走断言 - Assert.isFalse(data, "用户已购买专辑{}", albumId); - //3.2 远程调用专辑服务,获取专辑价格以及折扣(普通用户折扣,VIP会员折扣) - AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData(); - BigDecimal price = albumInfo.getPrice(); - BigDecimal discount = albumInfo.getDiscount(); - BigDecimal vipDiscount = albumInfo.getVipDiscount(); - //判断用户是否为vip 如果是vip就走vip折扣 如果不是就走普通用户的折扣 - Boolean isVIP = false; - UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData(); - Assert.notNull(userInfoVo, "用户{}不存在", userId); - //判断一下用户是否为vip以及vip的过期时间是否超过了当时的时间 - if (userInfoVo.getIsVip().intValue() == 1 - && userInfoVo.getVipExpireTime().after(new Date())) { - isVIP = true; - } - //3.4 计算相关价格 - //3.4.1 暂时将订单价=原价 - originalAmount = price; - orderAmount = originalAmount; - //当你是普通客户 但是专辑是有普通用户折扣的时候 计算一下专辑价格 - //discount.doubleValue()!=-1 - //BigDecimal.doubleValue() 是将 BigDecimal 转换为 double 类型的操作 - - //如果是普通用户且有折扣,则订单价=原价 100 *折扣 6 - //..divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP)是保留两位小数的标准写法 - if (!isVIP && discount.doubleValue() != -1) { - orderAmount =originalAmount.multiply(discount) - .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP); - } - //如果是会员,则按照会员折扣走 - if (isVIP && vipDiscount.doubleValue() != -1) { - orderAmount = originalAmount.multiply(vipDiscount) - .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP); - } - //3.5 封装商品信息列表 - OrderDetailVo orderDetailVo = new OrderDetailVo(); - orderDetailVo.setItemId(albumId); - orderDetailVo.setItemName("专辑:"+albumInfo.getAlbumTitle()); - orderDetailVo.setItemUrl(albumInfo.getCoverUrl()); - orderDetailVo.setItemPrice(originalAmount); - orderDetailVoList.add(orderDetailVo); - - //2.4 如果存在优惠,封装优惠列表 - if(originalAmount.compareTo(orderAmount)==1){ - OrderDerateVo orderDerateVo = new OrderDerateVo(); - orderDerateVo.setRemarks(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT); - orderDerateVo.setDerateType("VIP套餐限时优惠:" + derateAmount); - orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount)); - orderDerateVoList.add(orderDerateVo); - } - - } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(itemType)) { - //4.处理购买项目类型:声音 - //4.1 远程调用专辑服务,获取未购买声音列表 - Long trackId = tradeVo.getItemId(); - List trackInfoList = - albumFeignClient.findWaitBuyTrackList(trackId, tradeVo.getTrackCount()).getData(); - Assert.notNull(trackInfoList, "不存在待结算声音",trackId); - //4.2 远程调用专辑服务获取,专辑价格(声音单价)声音不支持折扣 - AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData(); - Assert.notNull(albumInfo, "专辑{}不存在", albumInfo.getId()); - BigDecimal price = albumInfo.getPrice(); - //4.3 计算相关价格 - originalAmount = price.multiply(new BigDecimal(trackInfoList.size())); - orderAmount = originalAmount; - //4.4 封装订单明细列表 - orderDetailVoList = trackInfoList.stream().map( - trackInfo -> { - OrderDetailVo orderDetailVo = new OrderDetailVo(); - orderDetailVo.setItemId(trackInfo.getId()); - orderDetailVo.setItemName("声音:" + trackInfo.getTrackTitle()); - orderDetailVo.setItemUrl(trackInfo.getCoverUrl()); - orderDetailVo.setItemPrice(price); - return orderDetailVo; - } - ).collect(Collectors.toList()); } - //5.封装订单VO对象 - //5.1 封装相关价格信息 - orderInfoVo.setOriginalAmount(originalAmount); - orderInfoVo.setOrderAmount(orderAmount); - orderInfoVo.setDerateAmount(derateAmount); - //5.2 封装商品相关集合 - orderInfoVo.setOrderDetailVoList(orderDetailVoList); - orderInfoVo.setOrderDerateVoList(orderDerateVoList); - //5.3 TODO 封装其他信息:流水号、时间戳及签名、项目类型等 - - //6.响应订单VO对象 - return orderInfoVo; + //5.TODO 判断支付方式:微信 + //else if(SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)){ + //} + //6.响应结果 + return Map.of("orderNo", orderInfo.getOrderNo()); } + + @Override + public OrderInfo saveOrderInfo(OrderInfoVo orderInfoVo, Long userId) { + //1.保存订单 + //2.1 创建订单对象 + OrderInfo orderInfo = BeanUtil.copyProperties(orderInfoVo, OrderInfo.class); + //2.2 设置用户ID + orderInfo.setUserId(userId); + //2.3 设置订单标题 + List orderDetailVoList = orderInfoVo.getOrderDetailVoList(); + if (CollUtil.isNotEmpty(orderDetailVoList)) { + String itemName = orderDetailVoList.get(0).getItemName(); + orderInfo.setOrderTitle(itemName); + } + //2.4 订单状态:未支付 + orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID); + //2.5 设置订单编号 确保全局唯一且趋势递增 形式:当天日期+雪花算法 + String code = DateUtil.today().replaceAll("-", "") + IdUtil.getSnowflakeNextId(); + orderInfo.setOrderNo(code); + //2.6 保存订单,获取订单ID + orderInfoMapper.insert(orderInfo); + Long orderId = orderInfo.getId(); + + if (CollUtil.isNotEmpty(orderDetailVoList)) { + List collect = orderDetailVoList.stream().map( + m -> { + OrderDetail orderDetail = BeanUtil.copyProperties(m, OrderDetail.class); + orderDetail.setOrderId(orderId); + return orderDetail; + } + ).collect(Collectors.toList()); + orderDetailService.saveBatch(collect); + } + List orderDerateVoList = orderInfoVo.getOrderDerateVoList(); + if (CollUtil.isNotEmpty(orderDerateVoList)) { + List collect = orderDerateVoList.stream().map( + m -> { + OrderDerate orderDerate = BeanUtil.copyProperties(m, OrderDerate.class); + orderDerate.setOrderId(orderId); + return orderDerate; + } + ).collect(Collectors.toList()); + orderDerateService.saveBatch(collect); + } + return orderInfo; + } + } diff --git a/service/service-order/target/classes/com/atguigu/tingshu/order/api/OrderInfoApiController.class b/service/service-order/target/classes/com/atguigu/tingshu/order/api/OrderInfoApiController.class index a0c131e..da6d1fe 100644 Binary files a/service/service-order/target/classes/com/atguigu/tingshu/order/api/OrderInfoApiController.class and b/service/service-order/target/classes/com/atguigu/tingshu/order/api/OrderInfoApiController.class differ diff --git a/service/service-order/target/classes/com/atguigu/tingshu/order/service/OrderInfoService.class b/service/service-order/target/classes/com/atguigu/tingshu/order/service/OrderInfoService.class index 193e70d..c02e15a 100644 Binary files a/service/service-order/target/classes/com/atguigu/tingshu/order/service/OrderInfoService.class and b/service/service-order/target/classes/com/atguigu/tingshu/order/service/OrderInfoService.class differ diff --git a/service/service-order/target/classes/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.class b/service/service-order/target/classes/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.class index b3a1e5e..d15be6b 100644 Binary files a/service/service-order/target/classes/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.class and b/service/service-order/target/classes/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.class differ diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java index 2c285ab..33aa507 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java @@ -5,6 +5,7 @@ import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.common.util.AuthContextHolder; import com.atguigu.tingshu.user.service.UserInfoService; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; @@ -83,8 +84,18 @@ public class UserInfoApiController { Long userId = AuthContextHolder.getUserId(); List list = userInfoService.findUserPaidTrackList(userId, albumId); return Result.ok(list); - - + } + /** + * 用户支付成功后,权益方法,虚拟物品(VIP会员、专辑、声音)发货 + * 如果支付方式是微信,微信支付会异步回调,没有token造成接口无法调用,故不加@GuiGuLogin注解 + * @param userPaidRecordVo + * @return + */ + @Operation(summary = "用户支付成功后,权益方法,虚拟物品(VIP会员、专辑、声音)发货") + @PostMapping("/userInfo/savePaidRecord") + public Result savePaidRecord(@RequestBody UserPaidRecordVo userPaidRecordVo){ + userInfoService.savePaidRecord(userPaidRecordVo); + return Result.ok(); } } diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/DeliveryStrategy.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/DeliveryStrategy.java new file mode 100644 index 0000000..15a7f11 --- /dev/null +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/DeliveryStrategy.java @@ -0,0 +1,12 @@ +package com.atguigu.tingshu.user.pattern; + +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; + +public interface DeliveryStrategy { + + /** + * 虚拟物品"发货"抽象方法 + * @param userPaidRecordVo + */ + void delivery(UserPaidRecordVo userPaidRecordVo); +} diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/factory/DeliveryStrategyFactory.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/factory/DeliveryStrategyFactory.java new file mode 100644 index 0000000..8557caa --- /dev/null +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/factory/DeliveryStrategyFactory.java @@ -0,0 +1,29 @@ +package com.atguigu.tingshu.user.pattern.factory; + +import com.atguigu.tingshu.user.pattern.DeliveryStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class DeliveryStrategyFactory { + + @Autowired + private Map deliveryStrategyMap; + + + public DeliveryStrategy getDeliveryStrategy(String itemType){ + log.info("itemType:{}", itemType); + if (deliveryStrategyMap.containsKey(itemType)) { + return deliveryStrategyMap.get(itemType); + } + log.error("当前商品类型不支持处理!"); + throw new RuntimeException("当前商品类型不支持处理!"); + } + + } + + diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/AlbumDelivery.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/AlbumDelivery.java new file mode 100644 index 0000000..ba0e08a --- /dev/null +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/AlbumDelivery.java @@ -0,0 +1,39 @@ +package com.atguigu.tingshu.user.pattern.impl; + +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.model.user.UserPaidAlbum; +import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper; +import com.atguigu.tingshu.user.pattern.DeliveryStrategy; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component(SystemConstant.ORDER_ITEM_TYPE_ALBUM) +@Slf4j +public class AlbumDelivery implements DeliveryStrategy { + + @Autowired + private UserPaidAlbumMapper userPaidAlbumMapper; + + @Override + public void delivery(UserPaidRecordVo userPaidRecordVo) { + log.info("专辑发货"); + //1.1 根据订单编号查询是否存在购买记录,如果存在则忽略 + Long count = userPaidAlbumMapper.selectCount( + new LambdaQueryWrapper() + .eq(UserPaidAlbum::getOrderNo, userPaidRecordVo.getOrderNo()) + .select(UserPaidAlbum::getId) + ); + if (count > 0){ + return; + } + UserPaidAlbum userPaidAlbum =new UserPaidAlbum(); + userPaidAlbum.setUserId(userPaidRecordVo.getUserId()); + userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo()); + userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0)); + userPaidAlbumMapper.insert(userPaidAlbum); + + } +} diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/TrackDelivery.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/TrackDelivery.java new file mode 100644 index 0000000..c80d4a2 --- /dev/null +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/TrackDelivery.java @@ -0,0 +1,52 @@ +package com.atguigu.tingshu.user.pattern.impl; + +import com.atguigu.tingshu.album.AlbumFeignClient; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.model.album.TrackInfo; +import com.atguigu.tingshu.model.user.UserPaidTrack; +import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper; +import com.atguigu.tingshu.user.pattern.DeliveryStrategy; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component(SystemConstant.ORDER_ITEM_TYPE_TRACK) +public class TrackDelivery implements DeliveryStrategy { + + @Autowired + private UserPaidTrackMapper userPaidTrackMapper; + @Autowired + private AlbumFeignClient albumFeignClient; + + + @Override + public void delivery(UserPaidRecordVo userPaidRecordVo) { + log.info("声音发货"); + //2. 处理购买项目类型为声音 + //2.1 根据订单编号查询是否存在购买记录,如果存在则忽略 + Long count = userPaidTrackMapper.selectCount( + new LambdaQueryWrapper() + .eq(UserPaidTrack::getOrderNo, userPaidRecordVo.getOrderNo()) + .select(UserPaidTrack::getId) + ); + if(count>0){ + return; + } + //2.2 新增声音购买记录 + //远程调用专辑服务获取声音信息,得到所属专辑ID + TrackInfo trackInfo = albumFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0)).getData(); + Long albumId = trackInfo.getAlbumId(); + userPaidRecordVo.getItemIdList().forEach(trackId -> { + UserPaidTrack userPaidTrack = new UserPaidTrack(); + userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo()); + userPaidTrack.setUserId(userPaidRecordVo.getUserId()); + userPaidTrack.setAlbumId(albumId); + userPaidTrack.setTrackId(trackId); + userPaidTrackMapper.insert(userPaidTrack); + }); + + } +} diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/VIPDelivery.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/VIPDelivery.java new file mode 100644 index 0000000..4266f2e --- /dev/null +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/pattern/impl/VIPDelivery.java @@ -0,0 +1,83 @@ +package com.atguigu.tingshu.user.pattern.impl; + +import cn.hutool.core.date.DateUtil; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.model.user.UserInfo; +import com.atguigu.tingshu.model.user.UserVipService; +import com.atguigu.tingshu.model.user.VipServiceConfig; +import com.atguigu.tingshu.user.mapper.UserInfoMapper; +import com.atguigu.tingshu.user.mapper.UserVipServiceMapper; +import com.atguigu.tingshu.user.mapper.VipServiceConfigMapper; +import com.atguigu.tingshu.user.pattern.DeliveryStrategy; +import com.atguigu.tingshu.user.service.impl.UserInfoServiceImpl; +import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; + +@Slf4j +@Component(SystemConstant.ORDER_ITEM_TYPE_VIP) +public class VIPDelivery implements DeliveryStrategy { + @Autowired + private UserVipServiceMapper userVipServiceMapper; + @Autowired + private VipServiceConfigMapper vipServiceConfigMapper; + @Autowired + private UserInfoMapper userInfoMapper; + + + + @Override + public void delivery(UserPaidRecordVo userPaidRecordVo) { + //3.TODO 处理购买项目类型为VIP会员 + //3.1 根据订单编号查询是否存在购买记录,如果存在则忽略 + Long cout = userVipServiceMapper.selectCount( + new LambdaQueryWrapper() + .eq(UserVipService::getOrderNo, userPaidRecordVo.getOrderNo()) + .select(UserVipService::getId) + ); + if (cout > 0) { + return; + } + //3.2 新增会员购买记录 + UserVipService userVipService = new UserVipService(); + userVipService.setOrderNo(userPaidRecordVo.getOrderNo()); + userVipService.setUserId(userPaidRecordVo.getUserId()); + //3.2.1 获取当前用户身份,判断是否为VIP + Boolean isVIP = false; + UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId()); + if (userInfo.getIsVip().intValue() == 1 && userInfo.getVipExpireTime().after(new Date())) { + isVIP = true; + } + //3.2.2 获取用户购买套餐信息,得到套餐服务月 + Long vipID = userPaidRecordVo.getItemIdList().get(0); + VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(vipID); + Integer serviceMonth = vipServiceConfig.getServiceMonth(); + //3.2.3 本次会员生效时间 + if (!isVIP) { + // 如果是普通用户,生效时间为当前时间 + userVipService.setStartTime(new Date()); + //3.2.4 本次会员到期时间 + userVipService.setExpireTime(DateUtil.offsetMonth(new Date(), serviceMonth)); + } else { + // 如果是VIP用户 + // 生效时间=现有会员到期时间+1天 + userVipService.setStartTime(DateUtil.offsetDay(userInfo.getVipExpireTime(), 1)); + userVipService.setExpireTime(DateUtil.offsetMonth(userVipService.getStartTime(), serviceMonth)); + } + userVipServiceMapper.insert(userVipService); + + //3.3 更新用户表会员标识以及会员到期时间 + UserInfo userInfo1 = new UserInfo(); + userInfo1.setId(userPaidRecordVo.getUserId()); + userInfo1.setIsVip(1); + userInfo1.setVipExpireTime(userVipService.getExpireTime()); + userInfoMapper.updateById(userInfo1); + + + } +} diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java index de32c4c..85cb791 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java @@ -2,6 +2,7 @@ package com.atguigu.tingshu.user.service; import com.atguigu.tingshu.model.user.UserInfo; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -20,4 +21,7 @@ public interface UserInfoService extends IService { Boolean isPaidAlbum(Long userId, Long albumId); List findUserPaidTrackList(Long userId, Long albumId); + + void savePaidRecord(UserPaidRecordVo userPaidRecordVo); + } diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java index 472650c..2350e15 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java @@ -6,18 +6,20 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.album.AlbumFeignClient; import com.atguigu.tingshu.common.cache.GuiGuCache; import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.constant.SystemConstant; import com.atguigu.tingshu.common.rabbit.constant.MqConst; import com.atguigu.tingshu.common.rabbit.service.RabbitService; -import com.atguigu.tingshu.model.user.UserInfo; -import com.atguigu.tingshu.model.user.UserPaidAlbum; -import com.atguigu.tingshu.model.user.UserPaidTrack; -import com.atguigu.tingshu.user.mapper.UserInfoMapper; -import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper; -import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper; +import com.atguigu.tingshu.model.album.TrackInfo; +import com.atguigu.tingshu.model.user.*; +import com.atguigu.tingshu.user.mapper.*; +import com.atguigu.tingshu.user.pattern.DeliveryStrategy; +import com.atguigu.tingshu.user.pattern.factory.DeliveryStrategyFactory; import com.atguigu.tingshu.user.service.UserInfoService; import com.atguigu.tingshu.vo.user.UserInfoVo; +import com.atguigu.tingshu.vo.user.UserPaidRecordVo; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; @@ -27,6 +29,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.math.BigDecimal; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,6 +53,12 @@ public class UserInfoServiceImpl extends ServiceImpl i private UserPaidAlbumMapper userPaidAlbumMapper; @Autowired private UserPaidTrackMapper userPaidTrackMapper; + @Autowired + private VipServiceConfigMapper vipServiceConfigMapper; + @Autowired + private UserVipServiceMapper userVipServiceMapper; + @Autowired + private DeliveryStrategyFactory deliveryStrategyFactory; @Override public Map wxLogin(String code) { @@ -202,5 +211,16 @@ public class UserInfoServiceImpl extends ServiceImpl i } return null; } + + @Override + public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) { + //项目类型: 1001-专辑 1002-声音 1003-vip会员 + String itemType = userPaidRecordVo.getItemType(); + //1.从策略工厂获取具体策略实现类对象 + DeliveryStrategy strategy = deliveryStrategyFactory.getDeliveryStrategy(itemType); + //2.调用策略实现类对象,进行发货方法调用 + strategy.delivery(userPaidRecordVo); + + } } diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserInfoApiController.class b/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserInfoApiController.class index d1ef641..7b8d3e1 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserInfoApiController.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserInfoApiController.class differ diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserInfoService.class b/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserInfoService.class index b64a6aa..246c58c 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserInfoService.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserInfoService.class differ diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class index ae93408..ed51420 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class differ