!257 通过注解增加多租户缓存
parent
239c38cf64
commit
b5474d1d84
|
@ -64,6 +64,7 @@
|
|||
<jsch.version>0.1.55</jsch.version>
|
||||
<tika-core.version>2.4.1</tika-core.version>
|
||||
<aj-captcha.version>1.3.0</aj-captcha.version>
|
||||
<netty-all.version>4.1.75.Final</netty-all.version>
|
||||
<!-- 三方云服务相关 -->
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<aliyun-java-sdk-core.version>4.6.0</aliyun-java-sdk-core.version>
|
||||
|
@ -563,6 +564,12 @@
|
|||
<version>${jsch.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${netty-all.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
|
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
|
|||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
|
||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantChannelInterceptor;
|
||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantFunctionAroundWrapper;
|
||||
import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
|
||||
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
|
||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl;
|
||||
|
@ -25,8 +26,16 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|||
import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户
|
||||
@EnableConfigurationProperties(TenantProperties.class)
|
||||
|
@ -122,4 +131,17 @@ public class YudaoTenantAutoConfiguration {
|
|||
return new TenantJobAspect(tenantFrameworkService);
|
||||
}
|
||||
|
||||
// ========== Redis ==========
|
||||
|
||||
@Bean
|
||||
@Primary // 引入租户时,tenantRedisCacheManager 为主 Bean
|
||||
public RedisCacheManager tenantRedisCacheManager(RedisTemplate<String, Object> redisTemplate,
|
||||
RedisCacheConfiguration redisCacheConfiguration) {
|
||||
// 创建 RedisCacheWriter 对象
|
||||
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
|
||||
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
|
||||
// 创建 TenantRedisCacheManager 对象
|
||||
return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package cn.iocoder.yudao.framework.tenant.core.redis;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
|
||||
/**
|
||||
* 多租户的 {@link RedisCacheManager} 实现类
|
||||
*
|
||||
* 操作指定 name 的 {@link Cache} 时,自动拼接租户后缀,格式为 name + ":" + tenantId + 后缀
|
||||
*
|
||||
* @author airhead
|
||||
*/
|
||||
@Slf4j
|
||||
public class TenantRedisCacheManager extends RedisCacheManager {
|
||||
|
||||
public TenantRedisCacheManager(RedisCacheWriter cacheWriter,
|
||||
RedisCacheConfiguration defaultCacheConfiguration) {
|
||||
super(cacheWriter, defaultCacheConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cache getCache(String name) {
|
||||
// 如果开启多租户,则 name 拼接租户后缀
|
||||
if (!TenantContextHolder.isIgnore()
|
||||
&& TenantContextHolder.getTenantId() != null) {
|
||||
name = name + ":" + TenantContextHolder.getTenantId();
|
||||
}
|
||||
|
||||
// 继续基于父方法
|
||||
return super.getCache(name);
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,11 @@
|
|||
<artifactId>spring-boot-starter-cache</artifactId> <!-- 实现对 Caches 的自动化配置 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.75.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.redis.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -13,6 +14,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
|
|||
* Cache 配置类,基于 Redis 实现
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({CacheProperties.class})
|
||||
@EnableCaching
|
||||
public class YudaoCacheAutoConfiguration {
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package cn.iocoder.mall.product.application.convert;
|
||||
|
||||
import cn.iocoder.mall.product.api.bo.ProductAttrBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductAttrValueBO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrPageVO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrSimpleVO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrVO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrValueVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ProductAttrConvert {
|
||||
|
||||
ProductAttrConvert INSTANCE = Mappers.getMapper(ProductAttrConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
AdminsProductAttrPageVO convert2(ProductAttrPageBO result);
|
||||
|
||||
@Mappings({})
|
||||
List<AdminsProductAttrSimpleVO> convert(List<ProductAttrSimpleBO> result);
|
||||
|
||||
@Mappings({})
|
||||
AdminsProductAttrVO convert3(ProductAttrBO productAttrBO);
|
||||
|
||||
@Mappings({})
|
||||
AdminsProductAttrValueVO convert4(ProductAttrValueBO productAttrValueBO);
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package cn.iocoder.mall.product.application.convert;
|
||||
|
||||
import cn.iocoder.mall.product.api.bo.ProductSpuBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductSpuPageBO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuDetailVO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuPageVO;
|
||||
import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuVO;
|
||||
import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO;
|
||||
import cn.iocoder.mall.product.application.vo.users.UsersProductSpuPageVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ProductSpuConvert {
|
||||
|
||||
ProductSpuConvert INSTANCE = Mappers.getMapper(ProductSpuConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
AdminsProductSpuDetailVO convert(ProductSpuDetailBO productSpuDetailBO);
|
||||
|
||||
// @Mappings({})
|
||||
// CommonResult<AdminsProductSpuDetailVO> convert(CommonResult<ProductSpuDetailBO> result);
|
||||
|
||||
@Mappings({})
|
||||
AdminsProductSpuPageVO convert2(ProductSpuPageBO result);
|
||||
|
||||
@Mappings({})
|
||||
List<AdminsProductSpuVO> convert3(List<ProductSpuBO> result);
|
||||
|
||||
@Mappings({})
|
||||
UsersProductSpuPageVO convert3(ProductSpuPageBO result);
|
||||
|
||||
@Mappings({})
|
||||
UsersProductSpuDetailVO convert4(ProductSpuDetailBO result);
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package cn.iocoder.mall.promotion.api.enums.activity;
|
||||
|
||||
/**
|
||||
* 促销活动状态枚举
|
||||
*/
|
||||
public enum PromotionActivityStatusEnum {
|
||||
|
||||
WAIT(10, "未开始"),
|
||||
RUN(20, "进行中"),
|
||||
END(30, "已结束"),
|
||||
/**
|
||||
* 1. WAIT、RUN、END 可以转换成 INVALID 状态。
|
||||
* 2. INVALID 只可以转换成 DELETED 状态。
|
||||
*/
|
||||
INVALID(40, "已撤销"),
|
||||
DELETED(50, "已删除"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 状态值
|
||||
*/
|
||||
private final Integer value;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
PromotionActivityStatusEnum(Integer value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package cn.iocoder.mall.promotion.api.enums.activity;
|
||||
|
||||
/**
|
||||
* 促销活动类型枚举
|
||||
*/
|
||||
public enum PromotionActivityTypeEnum {
|
||||
|
||||
TIME_LIMITED_DISCOUNT(1, "限时折扣"),
|
||||
FULL_PRIVILEGE(2, "满减送"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 类型值
|
||||
*/
|
||||
private final Integer value;
|
||||
/**
|
||||
* 类型名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
PromotionActivityTypeEnum(Integer value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package cn.iocoder.mall.promotionservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync(proxyTargetClass = true) // 开启 Spring Async 异步的功能
|
||||
public class AsyncConfiguration {
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package cn.iocoder.mall.promotionservice.config;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("cn.iocoder.mall.promotionservice.dal.mysql.mapper") // 扫描对应的 Mapper 接口
|
||||
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
// 数据库连接池 Druid
|
||||
|
||||
@Bean
|
||||
public ISqlInjector sqlInjector() {
|
||||
return new DefaultSqlInjector(); // MyBatis Plus 逻辑删除
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
return new PaginationInterceptor(); // MyBatis Plus 分页插件
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Banner 广告页
|
||||
*/
|
||||
@TableName("banner")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class BannerDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 跳转链接
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 图片链接
|
||||
*/
|
||||
private String picUrl;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* {@link cn.iocoder.common.framework.enums.CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String memo;
|
||||
|
||||
// TODO 芋艿 点击次数。&& 其他数据相关
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.banner;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerPageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner.BannerDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface BannerMapper extends BaseMapper<BannerDO> {
|
||||
|
||||
default List<BannerDO> selectList(BannerListReqDTO listReqDTO) {
|
||||
return selectList(new QueryWrapperX<BannerDO>().eqIfPresent("status", listReqDTO.getStatus()));
|
||||
}
|
||||
|
||||
default IPage<BannerDO> selectPage(BannerPageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<BannerDO>().likeIfPresent("title", pageReqDTO.getTitle()));
|
||||
}
|
||||
|
||||
}
|
|
@ -48,26 +48,12 @@ public class PriceManager {
|
|||
private CouponTemplateService couponTemplateService;
|
||||
|
||||
public PriceProductCalcRespDTO calcProductPrice(PriceProductCalcReqDTO calcReqDTO) {
|
||||
// TODO 芋艿,补充一些表单校验。例如说,需要传入用户编号。
|
||||
// 校验商品都存在
|
||||
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap = CollectionUtils.convertMap(
|
||||
calcReqDTO.getItems(), PriceProductCalcReqDTO.Item::getSkuId);
|
||||
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult = productSkuFeign.listProductSkus(
|
||||
new ProductSkuListQueryReqDTO().setProductSkuIds(calcProductItemDTOMap.keySet()));
|
||||
listProductSkusResult.checkError();
|
||||
if (calcReqDTO.getItems().size() != listProductSkusResult.getData().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRICE_PRODUCT_SKU_NOT_EXISTS);
|
||||
}
|
||||
// TODO 库存相关
|
||||
// 查询促销活动
|
||||
// 拼装结果(主要是计算价格)
|
||||
PriceProductCalcRespDTO calcRespDTO = new PriceProductCalcRespDTO();
|
||||
|
||||
List<PromotionActivityRespDTO> activityRespDTOs = promotionActivityService.listPromotionActivitiesBySpuIds(
|
||||
CollectionUtils.convertSet(listProductSkusResult.getData(), ProductSkuRespDTO::getSpuId),
|
||||
Collections.singleton(PromotionActivityStatusEnum.RUN.getValue()));
|
||||
// 拼装结果(主要是计算价格)
|
||||
PriceProductCalcRespDTO calcRespDTO = new PriceProductCalcRespDTO();
|
||||
// 1. 创建初始的每一项的数组
|
||||
List<PriceProductCalcRespDTO.Item> calcItemRespDTOs = this.initCalcOrderPriceItems(
|
||||
listProductSkusResult.getData(), calcProductItemDTOMap);
|
||||
// 2. 计算【限时折扣】促销
|
||||
this.modifyPriceByTimeLimitDiscount(calcItemRespDTOs, activityRespDTOs);
|
||||
// 3. 计算【满减送】促销
|
||||
|
@ -93,35 +79,6 @@ public class PriceManager {
|
|||
return calcRespDTO;
|
||||
}
|
||||
|
||||
private List<PriceProductCalcRespDTO.Item> initCalcOrderPriceItems(List<ProductSkuRespDTO> skus,
|
||||
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap) {
|
||||
// 获得商品分类 Map
|
||||
CommonResult<List<ProductSpuRespDTO>> listProductSpusResult = productSpuFeign.listProductSpus(CollectionUtils.convertSet(skus, ProductSkuRespDTO::getSpuId));
|
||||
listProductSpusResult.checkError();
|
||||
Map<Integer, Integer> spuIdCategoryIdMap = CollectionUtils.convertMap(listProductSpusResult.getData(), // SPU 编号与 Category 编号的映射
|
||||
ProductSpuRespDTO::getId, ProductSpuRespDTO::getCid);
|
||||
// 生成商品列表
|
||||
List<PriceProductCalcRespDTO.Item> items = new ArrayList<>();
|
||||
for (ProductSkuRespDTO sku : skus) {
|
||||
PriceProductCalcRespDTO.Item item = new PriceProductCalcRespDTO.Item();
|
||||
items.add(item);
|
||||
// 将基本信息,复制到 item 中
|
||||
PriceProductCalcReqDTO.Item calcOrderItem = calcProductItemDTOMap.get(sku.getId());
|
||||
item.setSpuId(sku.getSpuId()).setSkuId(sku.getId());
|
||||
item.setCid(spuIdCategoryIdMap.get(sku.getSpuId()));
|
||||
item.setSelected(calcOrderItem.getSelected());
|
||||
item.setBuyQuantity(calcOrderItem.getQuantity());
|
||||
// 计算初始价格
|
||||
item.setOriginPrice(sku.getPrice());
|
||||
item.setBuyPrice(sku.getPrice());
|
||||
item.setPresentPrice(sku.getPrice());
|
||||
item.setBuyTotal(sku.getPrice() * calcOrderItem.getQuantity());
|
||||
item.setDiscountTotal(0);
|
||||
item.setPresentTotal(item.getBuyTotal());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private void modifyPriceByTimeLimitDiscount(List<PriceProductCalcRespDTO.Item> items, List<PromotionActivityRespDTO> activityList) {
|
||||
for (PriceProductCalcRespDTO.Item item : items) {
|
||||
// 获得符合条件的限时折扣
|
||||
|
|
|
@ -34,16 +34,7 @@ public class CartManager {
|
|||
* @return 商品列表
|
||||
*/
|
||||
public CartDetailVO getCartDetail(Integer userId) {
|
||||
// 获得购物车的商品
|
||||
CommonResult<List<CartItemRespDTO>> listCartItemsResult = cartFeign.listCartItems(new CartItemListReqDTO().setUserId(userId));
|
||||
listCartItemsResult.checkError();
|
||||
// 购物车为空时,构造空的 UsersOrderConfirmCreateVO 返回
|
||||
if (CollectionUtils.isEmpty(listCartItemsResult.getData())) {
|
||||
CartDetailVO result = new CartDetailVO();
|
||||
result.setItemGroups(Collections.emptyList());
|
||||
result.setFee(new CartDetailVO.Fee(0, 0, 0, 0));
|
||||
return result;
|
||||
}
|
||||
|
||||
// 计算商品价格
|
||||
CommonResult<PriceProductCalcRespDTO> calcProductPriceResult = priceFeign.calcProductPrice(new PriceProductCalcReqDTO().setUserId(userId)
|
||||
.setItems(listCartItemsResult.getData().stream()
|
||||
|
|
Loading…
Reference in New Issue