ruoyi-api/ruoyi-api-order/src/main/java/model/Order.java
@@ -84,6 +84,10 @@ @TableField("express_json") private String expressJson; @ApiModelProperty(value = "收货地址信息") @TableField("address_json") private String addressJson; @ApiModelProperty(value = "平台分佣") @TableField("share_amount") private BigDecimal shareAmount; ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TechnicianSubscribe.java
@@ -38,7 +38,7 @@ @ApiModelProperty(value = "技师id") @TableField("technician_id") private Integer technicianId; private Long technicianId; @ApiModelProperty(value = "预约时间") @TableField("subscribe_time") ruoyi-common/ruoyi-common-redis/pom.xml
@@ -22,6 +22,12 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.10.1</version> </dependency> <!-- RuoYi Common Core--> <dependency> ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/annotation/DistributedLock.java
New file @@ -0,0 +1,34 @@ package com.ruoyi.common.redis.annotation; import java.lang.annotation.*; /** * @Descreption: 分布式锁注解 * @Author: luofl * @Date: 2024/11/26 16:43 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributedLock { /** * 锁名字(没有EL解析) */ String lockName() default ""; /** * 锁前缀(有EL解析) */ String lockNamePre() default ""; /** * 锁后缀(有EL解析) */ String lockNamePost() default ""; /** * 锁前后缀拼接分隔符 */ String separator() default "_"; } ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/aspectj/DistributedLockAspect.java
New file @@ -0,0 +1,142 @@ package com.ruoyi.common.redis.aspectj; import com.ruoyi.common.redis.annotation.DistributedLock; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import javax.annotation.Resource; import java.lang.reflect.Method; import java.util.Objects; /** * @Description 分布式锁切面 * 注意!!!分布式锁不能加在事务方法当中:因为当锁释放,事务还没有提交 * @Author luofl * @Date 2024/11/26 16:42 */ @Aspect @Component @Slf4j public class DistributedLockAspect { @Resource private RedissonClient redissonClient; /** * @Descreption: 定义切面:以注解为切面 * @Author: luofl * @Date: 2024/11/26 16:44 */ @Pointcut("@annotation(com.ruoyi.common.redis.annotation.DistributedLock)") public void distributedLockAspect() { } @Around(value = "distributedLockAspect()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { //切点所在的类 MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method method = methodSignature.getMethod(); // DistributedLock annotation = method.getAnnotation(DistributedLock.class); String lockName = getLockName(annotation, pjp.getArgs(), method); //log.info("lockName:"+lockName); RLock lock = redissonClient.getLock(lockName); lock.lock(); try { return pjp.proceed(); } finally { if (lock.isLocked() && lock.isHeldByCurrentThread()) { //释放锁 lock.unlock(); } } } /** * @Descreption: 获取锁名字,优先获取注解中锁名 * @Author: luofl * @Date: 2024/11/26 16:45 */ private String getLockName(DistributedLock distributedLock, Object[] args, Method method) { //优先获取注解名称 if (StringUtils.isNotBlank(distributedLock.lockName())) { return distributedLock.lockName(); } //根据参数匹配有参数就使用动态参数,没有就使用定义参数 String lockNamePre = distributedLock.lockNamePre(); String lockNamePost = distributedLock.lockNamePost(); String separator = distributedLock.separator(); String preExpression = parseExpression(lockNamePre, method, args); String postExpression = parseExpression(lockNamePost, method, args); StringBuilder sb = new StringBuilder(); if (StringUtils.isNotBlank(preExpression)) { sb.append(preExpression); } else { sb.append(lockNamePre); } sb.append(separator); if (StringUtils.isNotBlank(postExpression)) { sb.append(postExpression); } else { sb.append(lockNamePost); } return sb.toString(); } /** * el表达式解析 * * @param expressionString 解析值 * @param method 方法 * @param args 参数 */ private String parseExpression(String expressionString, Method method, Object[] args) { //获取被拦截方法参数名列表 LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); String[] paramNameArr = discoverer.getParameterNames(method); //SPEL解析 ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); for (int i = 0; i < Objects.requireNonNull(paramNameArr).length; i++) { context.setVariable(paramNameArr[i], args[i]); } return parser.parseExpression(expressionString).getValue(context, String.class); } // ==========================示例============================= //固定静态参数锁:product_lock @DistributedLock(lockName = "product_lock") @GetMapping(value = "/test1") public void test1() { System.out.println("执行事务"); } //未匹配到参数,因此仍然是静态参数锁:#param1_#param2 @DistributedLock(lockNamePre = "#param1", lockNamePost = "#param2") @GetMapping(value = "/test2") public void test2() { System.out.println("执行事务"); } //匹配到参数,动态参数锁:hello_world @DistributedLock(lockNamePre = "#order", lockNamePost = "#param2") @GetMapping(value = "/test3") public void test3(String param1, String param2) { System.out.println("执行事务"); } } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/UserPointController.java
@@ -1,9 +1,23 @@ package com.ruoyi.account.controller; import com.ruoyi.account.service.UserPointService; import com.ruoyi.account.vo.UserPointDetailVO; import com.ruoyi.account.vo.UserPointVO; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.security.utils.SecurityUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; /** * <p> @@ -16,10 +30,39 @@ @RestController @RequestMapping("/user-point") @Api("用户积分") public class UserPointController { public class UserPointController extends BaseController { @Resource private UserPointService userPointService; /** * 积分 * 获取个人积分 */ @GetMapping("/getUserPoint") @ApiOperation("获取个人积分") public R<UserPointVO> getUserPoint(){ return R.ok(userPointService.getUserPoint(SecurityUtils.getUserId())); } /** * 获取变更明细 */ @GetMapping("/getUserPointDetail") @ApiOperation("获取变更明细") public R<UserPointDetailVO> getUserPointDetail(@ApiParam("指定日期") LocalDateTime date, @ApiParam("变动类型(1=消费积分,2=返佣积分,3=拉新人积分,4=兑换商品 " + "5 = 门店业绩积分 6 =门店返佣积分7=技师业绩积分8 =转赠积分 9 =做工积分 " + "10 =注册积分)") Integer type){ return R.ok(); } /** * 转赠积分 */ @PostMapping("/transferPoint") @ApiOperation("转赠积分") public R<Void> transferPoint(@ApiParam("积分") BigDecimal point, @ApiParam("手机号") Long phone){ return R.ok(); } } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/UserPointService.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.account.api.model.UserPoint; import com.ruoyi.account.vo.UserPointVO; /** * <p> @@ -13,4 +14,5 @@ */ public interface UserPointService extends IService<UserPoint> { UserPointVO getUserPoint(Long userId); } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/UserPointServiceImpl.java
@@ -4,6 +4,7 @@ import com.ruoyi.account.mapper.UserPointMapper; import com.ruoyi.account.api.model.UserPoint; import com.ruoyi.account.service.UserPointService; import com.ruoyi.account.vo.UserPointVO; import org.springframework.stereotype.Service; /** @@ -17,4 +18,8 @@ @Service public class UserPointServiceImpl extends ServiceImpl<UserPointMapper, UserPoint> implements UserPointService { @Override public UserPointVO getUserPoint(Long userId) { return null; } } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/vo/UserPointDetailVO.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.account.vo; import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @ApiModel(value="UserPointDetail对象", description="") public class UserPointDetailVO { @ApiModelProperty(value = "变动类型(1=消费积分,2=返佣积分,3=拉新人积分,4=兑换商品 5 = 门店业绩积分 6 =门店返佣积分7=技师业绩积分8 =转赠积分 9 =做工积分 10 =注册积分)") private Integer type; @ApiModelProperty(value = "变动金额") private BigDecimal variablePoint; @ApiModelProperty(value = "变动时间") private LocalDateTime createTime; } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/vo/UserPointVO.java
New file @@ -0,0 +1,31 @@ package com.ruoyi.account.vo; import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel(value="UserPoint对象", description="") public class UserPointVO { @ApiModelProperty(value = "总积分") private Integer totalPoint; @ApiModelProperty(value = "消费积分数") private BigDecimal shopPoint; @ApiModelProperty(value = "返佣积分数") private BigDecimal sharePoint; @ApiModelProperty(value = "拉新积分") private BigDecimal pullNewPoint; @ApiModelProperty(value = "门店业绩积分") private BigDecimal shopAchievementPoint; @ApiModelProperty(value = "门店返佣积分") private BigDecimal shopSharePoint; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java
@@ -1,8 +1,10 @@ package com.ruoyi.order.controller; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.domain.R; import com.ruoyi.order.service.OrderService; import com.ruoyi.order.vo.OrderDetailVO; import com.ruoyi.order.vo.OrderVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -13,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; /** * <p> @@ -31,6 +34,30 @@ /** * 我的订单列表 */ @ApiOperation(value = "我的订单列表", tags = {"小程序-个人中心-我的订单"}) @ApiImplicitParams({ @ApiImplicitParam(value = "订单状态", name = "status", required = true, dataType = "int"), }) @GetMapping("/list/{status}") public R<List<OrderVO>> list(@PathVariable("status") Integer status){ return R.ok(orderService.getOrderList(status)); } /** * 订单详情 */ @ApiOperation(value = "订单详情", tags = {"小程序-订单详情"}) @ApiImplicitParams({ @ApiImplicitParam(value = "订单id", name = "orderId", required = true, dataType = "int"), }) @GetMapping("/detail/{orderId}") public R<OrderDetailVO> detail(@PathVariable("orderId") Long orderId){ return R.ok(orderService.getOrderDetail(orderId)); } /** * 扫码校验 */ @ApiOperation(value = "扫码校验", tags = {"小程序-个人中心-门店管理-扫码核销校验"}) @@ -38,21 +65,35 @@ @ApiImplicitParam(value = "分享id", name = "shareId", required = true, dataType = "int"), }) @GetMapping("/check/{orderId}/{shopId}") public AjaxResult check(@PathVariable("orderId") Integer orderId, @PathVariable("shopId") Integer shopId){ return AjaxResult.ok(orderService.check(orderId, shopId)); public R<Boolean> check(@PathVariable("orderId") Long orderId, @PathVariable("shopId") Long shopId){ return R.ok(orderService.check(orderId, shopId)); } /** * 订单详情 * 订单核销 */ @ApiOperation(value = "订单详情", tags = {"订单详情"}) @ApiOperation(value = "订单核销", tags = {"小程序-个人中心-门店管理-扫码核销"}) @ApiImplicitParams({ @ApiImplicitParam(value = "核销码", name = "code", required = true, dataType = "String"), }) @GetMapping("/writeOff/{code}") public R<Void> writeOff(@PathVariable("code") String code){ return R.ok(); } /** * 取消订单 */ @ApiOperation(value = "取消订单", tags = {"小程序-个人中心-我的订单-取消订单"}) @ApiImplicitParams({ @ApiImplicitParam(value = "订单id", name = "orderId", required = true, dataType = "int"), }) @GetMapping("/detail/{orderId}") public AjaxResult detail(@PathVariable("orderId") Integer orderId){ return AjaxResult.success(orderService.getById(orderId)); @GetMapping("/cancel/{orderId}") public R<Void> cancel(@PathVariable("orderId") Long orderId){ return R.ok(); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java
@@ -1,7 +1,11 @@ package com.ruoyi.order.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.order.vo.OrderDetailVO; import com.ruoyi.order.vo.OrderVO; import model.Order; import java.util.List; /** * <p> @@ -12,5 +16,9 @@ * @since 2024-11-21 */ public interface OrderService extends IService<Order> { boolean check(Integer orderId, Integer shopId); List<OrderVO> getOrderList(Integer status); OrderDetailVO getOrderDetail(Long orderId); boolean check(Long orderId, Long shopId); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
@@ -3,8 +3,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.order.mapper.OrderMapper; import com.ruoyi.order.service.OrderService; import com.ruoyi.order.vo.OrderDetailVO; import com.ruoyi.order.vo.OrderVO; import model.Order; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.List; /** * <p> @@ -18,7 +23,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService { @Override public boolean check(Integer orderId, Integer shopId) { public List<OrderVO> getOrderList(Integer status) { return Collections.emptyList(); } @Override public OrderDetailVO getOrderDetail(Long orderId) { return null; } @Override public boolean check(Long orderId, Long shopId) { // TODO 待实现 return false; } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/OrderDetailVO.java
New file @@ -0,0 +1,61 @@ package com.ruoyi.order.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @ApiModel(value = "订单明细") public class OrderDetailVO { @ApiModelProperty(value = "订单id") private Long id; @ApiModelProperty(value = "订单商品") private List<OrderGoodsVO> goodsList; @ApiModelProperty(value = "使用积分") private BigDecimal point; @ApiModelProperty(value = "收货地址id") private Long addressId; @ApiModelProperty(value = "收货联系人") private String recieveName; @ApiModelProperty(value = "收货联系电话") private String recievePhone; @ApiModelProperty(value = "收货地址") private String recieveAddress; @ApiModelProperty(value = "订单编号") private String orderNumber; @ApiModelProperty("下单时间") private String createTime; @ApiModelProperty(value = "订单总金额") private BigDecimal totalAmount; @ApiModelProperty(value = "优惠券名称") private String couponName; @ApiModelProperty(value = "参与活动名称") private String activityName; @ApiModelProperty(value = "抵扣金额") private BigDecimal couponAmount; @ApiModelProperty(value = "快递费") private BigDecimal expressAmount; @ApiModelProperty(value = "可获得积分") private BigDecimal pointAmount; @ApiModelProperty(value = "实际支付价格") private BigDecimal paymentAmount; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/OrderGoodsVO.java
New file @@ -0,0 +1,32 @@ package com.ruoyi.order.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel(value = "订单商品") public class OrderGoodsVO { @ApiModelProperty(value = "商品id") private Long goodsId; @ApiModelProperty(value = "商品名称") private String goodsName; @ApiModelProperty(value = "类型(1=服务商品,2=单品商品)") private Integer type; @ApiModelProperty(value = "数量") private Integer num; @ApiModelProperty(value = "商品图片") private String goodsPic; @ApiModelProperty(value = "基础售价") private BigDecimal sellingPrice; @ApiModelProperty(value = "划线价") private BigDecimal originalPrice; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/OrderVO.java
New file @@ -0,0 +1,34 @@ package com.ruoyi.order.vo; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data public class OrderVO { @ApiModelProperty(value = "订单id") private Long id; @ApiModelProperty(value = "订单编号") private String orderNumber; @ApiModelProperty(value = "1待发货2待收货3待使用4已完成待评论5已取消6已退款7售后中8已完成已评论") private Integer orderStatus; @ApiModelProperty(value = "商品图片") private List<String> goodsPics; @ApiModelProperty(value = "商品名称") private String goodsName; @ApiModelProperty(value = "使用积分") private BigDecimal point; @ApiModelProperty(value = "实际支付价格") private BigDecimal paymentAmount; @ApiModelProperty(value = "商品数量") private Integer num; } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TechnicianSubscribeController.java
@@ -7,15 +7,13 @@ import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.other.api.domain.TechnicianSubscribe; import com.ruoyi.other.distributedservice.DistributedTechnicianService; import com.ruoyi.other.service.TechnicianSubscribeService; import com.ruoyi.other.vo.TechnicianSubscribeVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; @@ -34,6 +32,8 @@ public class TechnicianSubscribeController extends BaseController { @Resource private TechnicianSubscribeService technicianSubscribeService; @Resource private DistributedTechnicianService distributedTechnicianService; /** * 预约列表 @@ -49,6 +49,16 @@ } /** * 预约技师 */ @PostMapping("/subscribe") @ApiOperation(value = "预约技师", notes = "预约技师", tags = {"小程序-个人中心-门店管理-预约列表-预约技师"}) public R<Void> subscribe(@RequestBody TechnicianSubscribe technicianSubscribe){ distributedTechnicianService.subscribe(technicianSubscribe,technicianSubscribe.getTechnicianId()); return R.ok(); } /** * 取消服务 */ @GetMapping("/cancel") ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/distributedservice/DistributedTechnicianService.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.other.distributedservice; import com.ruoyi.common.redis.annotation.DistributedLock; import com.ruoyi.other.api.domain.TechnicianSubscribe; import com.ruoyi.other.service.TechnicianSubscribeService; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @Desecription: 技师业务分布式锁业务处理 * 由于service被事务包裹,因此需要单独建立包来存放分布式锁业务, * 分布式锁不能在业务方法中执行 * 事务隔离问题: 如果将分布式锁放在业务方法内部,并且业务方法处于事务中,那么在事务提交之前,分布式锁可能无法释放,导致其他事务无法获取到该锁,从而造成死锁或长时间的阻塞。 * @Autor: luofl * @Date: 2024/11/26 16:50 */ @Service public class DistributedTechnicianService { @Resource private TechnicianSubscribeService technicianSubscribeService; @DistributedLock(lockNamePre = "#TECHNICIAN_SUBSCRIBE_LOCK", lockNamePost = "#technicianId") public void subscribe(TechnicianSubscribe technicianSubscribe,Long technicianId){ technicianSubscribeService.subscribe(technicianSubscribe); } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TechnicianSubscribeService.java
@@ -21,4 +21,5 @@ */ List<TechnicianSubscribeVO> getTechnicianSubscribeByUserAndShop(Long userId, Long shopId); void subscribe(TechnicianSubscribe technicianSubscribe); } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TechnicianSubscribeServiceImpl.java
@@ -1,19 +1,25 @@ package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.other.api.domain.Technician; import com.ruoyi.other.mapper.TechnicianMapper; import com.ruoyi.other.mapper.TechnicianSubscribeMapper; import com.ruoyi.other.api.domain.TechnicianSubscribe; import com.ruoyi.other.service.TechnicianSubscribeService; import com.ruoyi.other.vo.TechnicianSubscribeVO; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.Collections; import java.time.LocalDateTime; import java.util.List; /** * <p> * 服务实现类 * 服务实现类 * </p> * * @author luodangjia @@ -23,9 +29,32 @@ public class TechnicianSubscribeServiceImpl extends ServiceImpl<TechnicianSubscribeMapper, TechnicianSubscribe> implements TechnicianSubscribeService { @Resource private TechnicianSubscribeMapper technicianSubscribeMapper; @Resource private TechnicianMapper technicianMapper; @Override public List<TechnicianSubscribeVO> getTechnicianSubscribeByUserAndShop(Long userId, Long shopId) { return technicianSubscribeMapper.getTechnicianSubscribeByUserAndShop(userId, shopId); } @Override @Transactional(rollbackFor = Exception.class) public void subscribe(TechnicianSubscribe technicianSubscribe) { Long technicianId = technicianSubscribe.getTechnicianId(); Technician technician = technicianMapper.selectOne(new LambdaQueryWrapper<Technician>() .eq(Technician::getId, technicianId) .eq(Technician::getStatus, 1) .eq(Technician::getSubscribeStatus, 1)); if (null == technician) { throw new ServiceException("不满足预约条件"); } Long userId = SecurityUtils.getUserId(); TechnicianSubscribe subscribe = new TechnicianSubscribe(); subscribe.setAppUserId(userId); subscribe.setDelFlag(0); subscribe.setCreateTime(LocalDateTime.now()); technicianSubscribeMapper.insert(subscribe); technician.setSubscribeStatus(2); technicianMapper.updateById(technician); } }