From ed04f0ce5a4a7b2288eee6c507e248b71fe8a4ea Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 29 Apr 2024 09:46:30 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91RPC=20?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=97=B6=EF=BC=8C=E4=B8=8D=E5=86=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=20tenant-id=20=E6=A0=A1=E9=AA=8C=EF=BC=8C=E5=86=85?= =?UTF-8?q?=E9=83=A8=E4=BD=BF=E7=94=A8=EF=BC=8C=E6=97=A0=E9=9C=80=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/security/TenantSecurityWebFilter.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java index 784856fc1..7f57b7fb3 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java @@ -1,8 +1,6 @@ package cn.iocoder.yudao.framework.tenant.core.security; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.RpcConstants; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; @@ -15,13 +13,13 @@ import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.AntPathMatcher; - import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.AntPathMatcher; + import java.io.IOException; import java.util.Objects; @@ -56,12 +54,6 @@ public class TenantSecurityWebFilter extends ApiRequestFilter { this.tenantFrameworkService = tenantFrameworkService; } - @Override - protected boolean shouldNotFilter(HttpServletRequest request) { - return super.shouldNotFilter(request) && - !StrUtil.startWithAny(request.getRequestURI(), RpcConstants.RPC_API_PREFIX); // 因为 RPC API 也会透传租户编号 - } - @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { @@ -75,8 +67,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter { tenantId = user.getTenantId(); TenantContextHolder.setTenantId(tenantId); // 如果传递了租户编号,则进行比对租户编号,避免越权问题 - } else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId()) - && !isRpcRequest) { // Cloud 特殊逻辑:如果是 RPC 请求,就不校验了。主要考虑,一些场景下,会调用 TenantUtils 去切换租户 + } else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) { log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]", user.getTenantId(), user.getId(), user.getUserType(), TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod()); From b500bb7da134ae76a8a169bec8d64daaa07b4f13 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 29 Apr 2024 12:48:46 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=90=E5=A2=9E=E5=BC=BA=E3=80=91?= =?UTF-8?q?=E4=B8=80=E9=94=AE=E6=94=B9=E5=8C=85=EF=BC=9A=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20site=E3=80=81org=20=E7=AD=89=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/core/security/TenantSecurityWebFilter.java | 4 ---- .../mybatis/config/YudaoMybatisAutoConfiguration.java | 4 ++-- .../redis/config/YudaoRedisAutoConfiguration.java | 3 ++- .../security/config/YudaoSecurityAutoConfiguration.java | 2 ++ .../security/config/YudaoWebSecurityConfigurerAdapter.java | 7 ++++--- .../swagger/config/YudaoSwaggerAutoConfiguration.java | 2 ++ .../framework/web/config/YudaoWebAutoConfiguration.java | 3 +++ .../src/test/java/cn/iocoder/yudao/ProjectReactor.java | 3 ++- .../iocoder/yudao/module/crm/enums/ErrorCodeConstants.java | 2 +- .../crm/service/product/CrmProductCategoryServiceImpl.java | 4 ++-- .../module/promotion/service/coupon/CouponServiceImpl.java | 2 +- 11 files changed, 21 insertions(+), 15 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java index 7f57b7fb3..146b9cdd5 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java @@ -12,7 +12,6 @@ import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -29,8 +28,6 @@ import java.util.Objects; * 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。 * 3. 校验租户是合法,例如说被禁用、到期 * - * 校验用户访问的租户,是否是其所在的租户, - * * @author 芋道源码 */ @Slf4j @@ -58,7 +55,6 @@ public class TenantSecurityWebFilter extends ApiRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { Long tenantId = TenantContextHolder.getTenantId(); - boolean isRpcRequest = WebFrameworkUtils.isRpcRequest(request); // 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。 LoginUser user = SecurityFrameworkUtils.getLoginUser(); if (user != null) { diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java index bf15bfa5f..d685fd81a 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.mybatis.config; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; import com.baomidou.mybatisplus.extension.incrementer.*; @@ -13,7 +14,6 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; /** @@ -21,7 +21,7 @@ import org.springframework.core.env.ConfigurableEnvironment; * * @author 芋道源码 */ -@AutoConfiguration +@AutoConfiguration(before = MybatisPlusAutoConfiguration.class) // 目的:先于 MyBatis Plus 自动配置,避免 @MapperScan 可能扫描不到 Mapper 打印 warn 日志 @MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class, lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试 public class YudaoMybatisAutoConfiguration { diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java index 5904a3a2b..01eeb049d 100644 --- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.redis.config; import cn.hutool.core.util.ReflectUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.redisson.spring.starter.RedissonAutoConfigurationV2; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -12,7 +13,7 @@ import org.springframework.data.redis.serializer.RedisSerializer; /** * Redis 配置类 */ -@AutoConfiguration +@AutoConfiguration(before = RedissonAutoConfigurationV2.class) // 目的:使用自己定义的 RedisTemplate Bean public class YudaoRedisAutoConfiguration { /** diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java index 70d2b74f2..a24999176 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.security.core.context.SecurityContextHolder; @@ -31,6 +32,7 @@ import jakarta.annotation.Resource; * @author 芋道源码 */ @AutoConfiguration +@AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 @EnableConfigurationProperties(SecurityProperties.class) public class YudaoSecurityAutoConfiguration { diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java index eaeef8325..ab4c3f9e9 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -5,14 +5,16 @@ import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter import cn.iocoder.yudao.framework.web.config.WebProperties; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; @@ -27,8 +29,6 @@ import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import jakarta.annotation.Resource; -import jakarta.annotation.security.PermitAll; import java.util.List; import java.util.Map; import java.util.Set; @@ -39,6 +39,7 @@ import java.util.Set; * @author 芋道源码 */ @AutoConfiguration +@AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 @EnableMethodSecurity(securedEnabled = true) public class YudaoWebSecurityConfigurerAdapter { diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java index 2ab128c50..093303e54 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java @@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; import org.springframework.http.HttpHeaders; import java.util.HashMap; @@ -91,6 +92,7 @@ public class YudaoSwaggerAutoConfiguration { * 自定义 OpenAPI 处理器 */ @Bean + @Primary // 目的:以我们创建的 OpenAPIService Bean 为主,避免一键改包后,启动报错! public OpenAPIService openApiBuilder(Optional openAPI, SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 9f143ff04..8c784d9f2 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -122,7 +123,9 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { * @param restTemplateBuilder {@link RestTemplateAutoConfiguration#restTemplateBuilder} */ @Bean + @ConditionalOnMissingBean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder.build(); } + } diff --git a/yudao-gateway/src/test/java/cn/iocoder/yudao/ProjectReactor.java b/yudao-gateway/src/test/java/cn/iocoder/yudao/ProjectReactor.java index edcb06598..70b7ce3a0 100644 --- a/yudao-gateway/src/test/java/cn/iocoder/yudao/ProjectReactor.java +++ b/yudao-gateway/src/test/java/cn/iocoder/yudao/ProjectReactor.java @@ -34,7 +34,8 @@ public class ProjectReactor { * 白名单文件,不进行重写,避免出问题 */ private static final Set WHITE_FILE_TYPES = SetUtils.asSet("gif", "jpg", "svg", "png", // 图片 - "eot", "woff2", "ttf", "woff"); // 字体 + "eot", "woff2", "ttf", "woff", // 字体 + "xdb"); // IP 库 public static void main(String[] args) { long start = System.currentTimeMillis(); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 27fb6f9ce..07a6dad60 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -87,7 +87,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_CATEGORY_USED = new ErrorCode(1_020_009_002, "产品分类已关联产品"); ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_020_009_003, "父分类不存在"); ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); - ErrorCode product_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); + ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); // ========== 商机状态 1_020_010_000 ========== ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态组不存在"); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java index 6399039ba..ce168883a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java @@ -110,10 +110,10 @@ public class CrmProductCategoryServiceImpl implements CrmProductCategoryService validateProductCategoryExists(id); // 1.2 校验是否还有子分类 if (productCategoryMapper.selectCountByParentId(id) > 0) { - throw exception(product_CATEGORY_EXISTS_CHILDREN); + throw exception(PRODUCT_CATEGORY_EXISTS_CHILDREN); } // 1.3 校验是否被产品使用 - if (crmProductService.getProductByCategoryId(id) !=null) { + if (crmProductService.getProductByCategoryId(id) > 0) { throw exception(PRODUCT_CATEGORY_USED); } // 2. 删除 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index 6d5961ff1..ef466172e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -119,7 +119,7 @@ public class CouponServiceImpl implements CouponService { Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) ? CouponStatusEnum.EXPIRE.getStatus() // 退还时可能已经过期了 : CouponStatusEnum.UNUSED.getStatus(); - int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.USED.getStatus(), new CouponDO().setStatus(status)); if (updateCount == 0) { throw exception(COUPON_STATUS_NOT_USED);