18 changed files with 881 additions and 73 deletions
@ -0,0 +1,66 @@ |
|||||
|
package cc.hiver.mall.controller; |
||||
|
|
||||
|
import cc.hiver.core.common.utils.ResultUtil; |
||||
|
import cc.hiver.core.common.vo.Result; |
||||
|
import cc.hiver.mall.entity.MallAdPosition; |
||||
|
import cc.hiver.mall.pojo.query.MallAdPositionQuery; |
||||
|
import cc.hiver.mall.service.mybatis.MallAdPositionService; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import io.swagger.annotations.Api; |
||||
|
import io.swagger.annotations.ApiOperation; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Slf4j |
||||
|
@RestController |
||||
|
@RequestMapping("/hiver/mall/adPosition") |
||||
|
@Api(tags = "广告位接口") |
||||
|
public class MallAdPositionController { |
||||
|
|
||||
|
@Autowired |
||||
|
private MallAdPositionService mallAdPositionService; |
||||
|
|
||||
|
@PostMapping("/add") |
||||
|
@ApiOperation(value = "新增广告位") |
||||
|
public Result<Object> add(@RequestBody MallAdPosition adPosition) { |
||||
|
mallAdPositionService.addAdPosition(adPosition); |
||||
|
return ResultUtil.success("新增成功"); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/update") |
||||
|
@ApiOperation(value = "修改广告位") |
||||
|
public Result<Object> update(@RequestBody MallAdPosition adPosition) { |
||||
|
mallAdPositionService.updateAdPosition(adPosition); |
||||
|
return ResultUtil.success("修改成功"); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/delete/{id}") |
||||
|
@ApiOperation(value = "删除广告位") |
||||
|
public Result<Object> delete(@PathVariable String id) { |
||||
|
mallAdPositionService.deleteAdPosition(id); |
||||
|
return ResultUtil.success("删除成功"); |
||||
|
} |
||||
|
|
||||
|
@GetMapping("/detail/{id}") |
||||
|
@ApiOperation(value = "获取广告位详情") |
||||
|
public Result<MallAdPosition> detail(@PathVariable String id) { |
||||
|
MallAdPosition detail = mallAdPositionService.getAdPositionDetail(id); |
||||
|
return new ResultUtil<MallAdPosition>().setData(detail); |
||||
|
} |
||||
|
|
||||
|
@RequestMapping(value = "/list", method = RequestMethod.POST) |
||||
|
@ApiOperation(value = "分页查询广告位列表") |
||||
|
public Result<IPage<MallAdPosition>> list(@RequestBody MallAdPositionQuery query) { |
||||
|
return new ResultUtil<IPage<MallAdPosition>>().setData(mallAdPositionService.selectPageVO(query)); |
||||
|
} |
||||
|
|
||||
|
@GetMapping("/region") |
||||
|
@ApiOperation(value = "根据区域ID获取广告位列表(缓存优先)") |
||||
|
public Result<List<MallAdPosition>> getByRegionId(@RequestParam(value = "regionId", required = true) String regionId , |
||||
|
@RequestParam(value = "paths", required = true) List<String> paths) { |
||||
|
return new ResultUtil<List<MallAdPosition>>().setData(mallAdPositionService.getAdsByRegionId(regionId,paths)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package cc.hiver.mall.dao.mapper; |
||||
|
|
||||
|
import cc.hiver.mall.entity.MallAdPosition; |
||||
|
import cc.hiver.mall.pojo.query.MallAdPositionQuery; |
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
import org.springframework.stereotype.Repository; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Repository |
||||
|
public interface MallAdPositionMapper extends BaseMapper<MallAdPosition> { |
||||
|
IPage<MallAdPosition> selectPageVO(IPage<?> page, @Param("q") MallAdPositionQuery q); |
||||
|
|
||||
|
List<MallAdPosition> selectByRegionId(@Param("regionId") String regionId); |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package cc.hiver.mall.dao.mapper; |
||||
|
|
||||
|
import cc.hiver.mall.entity.MallAdProduct; |
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
import org.springframework.stereotype.Repository; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Repository |
||||
|
public interface MallAdProductMapper extends BaseMapper<MallAdProduct> { |
||||
|
List<MallAdProduct> selectByAdId(@Param("adId") String adId); |
||||
|
|
||||
|
List<MallAdProduct> selectByAdIds(@Param("adIds") List<String> adIds); |
||||
|
|
||||
|
int deleteByAdId(@Param("adId") String adId); |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
package cc.hiver.mall.entity; |
||||
|
|
||||
|
import cc.hiver.core.base.HiverBaseEntity; |
||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@ApiModel(value = "广告位表") |
||||
|
@TableName(value = "t_mall_ad_position", autoResultMap = true) |
||||
|
public class MallAdPosition extends HiverBaseEntity { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@ApiModelProperty(value = "放置位置:如 home_banner, home_popup, category_top 等") |
||||
|
private String position; |
||||
|
|
||||
|
@ApiModelProperty(value = "商家名称") |
||||
|
private String merchantName; |
||||
|
|
||||
|
@ApiModelProperty(value = "商家id") |
||||
|
private String merchantId; |
||||
|
|
||||
|
@ApiModelProperty(value = "商家主图") |
||||
|
private String merchantImage; |
||||
|
|
||||
|
@ApiModelProperty(value = "广告图片") |
||||
|
private String adImage; |
||||
|
|
||||
|
@ApiModelProperty(value = "广告标题") |
||||
|
private String title; |
||||
|
|
||||
|
@ApiModelProperty(value = "跳转链接") |
||||
|
private String linkUrl; |
||||
|
|
||||
|
@ApiModelProperty(value = "跳转链接参数(JSON格式)") |
||||
|
private String linkParams; |
||||
|
|
||||
|
@ApiModelProperty(value = "区域id") |
||||
|
private String regionId; |
||||
|
|
||||
|
@ApiModelProperty(value = "排序值(越小越靠前)") |
||||
|
private Integer sortOrder; |
||||
|
|
||||
|
@ApiModelProperty(value = "状态:0-下架,1-上架") |
||||
|
private Integer status; |
||||
|
|
||||
|
@ApiModelProperty(value = "广告关联商品列表") |
||||
|
@TableField(exist = false) |
||||
|
private List<MallAdProduct> productList; |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
package cc.hiver.mall.entity; |
||||
|
|
||||
|
import cc.hiver.core.base.HiverBaseEntity; |
||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@ApiModel(value = "广告位商品表") |
||||
|
@TableName(value = "t_mall_ad_product", autoResultMap = true) |
||||
|
public class MallAdProduct extends HiverBaseEntity { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@ApiModelProperty(value = "广告位id") |
||||
|
private String adId; |
||||
|
|
||||
|
@ApiModelProperty(value = "商品图片") |
||||
|
private String productImage; |
||||
|
|
||||
|
@ApiModelProperty(value = "商品名称") |
||||
|
private String productName; |
||||
|
|
||||
|
@ApiModelProperty(value = "商品原价") |
||||
|
private BigDecimal originalPrice; |
||||
|
|
||||
|
@ApiModelProperty(value = "商品拼团价格") |
||||
|
private BigDecimal groupPrice; |
||||
|
|
||||
|
@ApiModelProperty(value = "几人团") |
||||
|
private Integer groupMembers; |
||||
|
|
||||
|
@ApiModelProperty(value = "排序值") |
||||
|
private Integer sortOrder; |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
package cc.hiver.mall.pojo.query; |
||||
|
|
||||
|
import cc.hiver.core.base.HiverBasePageQuery; |
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* 广告位分页查询对象 |
||||
|
*/ |
||||
|
@ApiModel("广告位分页查询对象") |
||||
|
@Data |
||||
|
public class MallAdPositionQuery extends HiverBasePageQuery { |
||||
|
|
||||
|
@ApiModelProperty(value = "放置位置") |
||||
|
private String position; |
||||
|
|
||||
|
@ApiModelProperty(value = "商家名称") |
||||
|
private String merchantName; |
||||
|
|
||||
|
@ApiModelProperty(value = "商家id") |
||||
|
private String merchantId; |
||||
|
|
||||
|
@ApiModelProperty(value = "广告标题") |
||||
|
private String title; |
||||
|
|
||||
|
@ApiModelProperty(value = "区域id") |
||||
|
private String regionId; |
||||
|
|
||||
|
@ApiModelProperty(value = "状态:0-下架,1-上架") |
||||
|
private Integer status; |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
package cc.hiver.mall.service.mybatis; |
||||
|
|
||||
|
import cc.hiver.mall.entity.MallAdPosition; |
||||
|
import cc.hiver.mall.pojo.query.MallAdPositionQuery; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public interface MallAdPositionService extends IService<MallAdPosition> { |
||||
|
|
||||
|
/** |
||||
|
* 新增广告位(含商品列表) |
||||
|
*/ |
||||
|
void addAdPosition(MallAdPosition adPosition); |
||||
|
|
||||
|
/** |
||||
|
* 修改广告位(含商品列表) |
||||
|
*/ |
||||
|
void updateAdPosition(MallAdPosition adPosition); |
||||
|
|
||||
|
/** |
||||
|
* 删除广告位(级联删除商品) |
||||
|
*/ |
||||
|
void deleteAdPosition(String id); |
||||
|
|
||||
|
/** |
||||
|
* 获取广告位详情(含商品列表) |
||||
|
*/ |
||||
|
MallAdPosition getAdPositionDetail(String id); |
||||
|
|
||||
|
/** |
||||
|
* 分页查询广告位 |
||||
|
*/ |
||||
|
IPage<MallAdPosition> selectPageVO(MallAdPositionQuery query); |
||||
|
|
||||
|
/** |
||||
|
* 根据 regionId 获取该区域所有广告位(优先缓存) |
||||
|
*/ |
||||
|
List<MallAdPosition> getAdsByRegionId(String regionId,List<String> paths); |
||||
|
} |
||||
@ -0,0 +1,191 @@ |
|||||
|
package cc.hiver.mall.serviceimpl.mybatis; |
||||
|
|
||||
|
import cc.hiver.mall.dao.mapper.MallAdPositionMapper; |
||||
|
import cc.hiver.mall.dao.mapper.MallAdProductMapper; |
||||
|
import cc.hiver.mall.entity.MallAdPosition; |
||||
|
import cc.hiver.mall.entity.MallAdProduct; |
||||
|
import cc.hiver.mall.pojo.query.MallAdPositionQuery; |
||||
|
import cc.hiver.mall.service.mybatis.MallAdPositionService; |
||||
|
import cc.hiver.mall.utils.AdPositionCacheUtil; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class MallAdPositionServiceImpl extends ServiceImpl<MallAdPositionMapper, MallAdPosition> |
||||
|
implements MallAdPositionService { |
||||
|
|
||||
|
@Autowired |
||||
|
private MallAdPositionMapper mallAdPositionMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private MallAdProductMapper mallAdProductMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private AdPositionCacheUtil adPositionCacheUtil; |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void addAdPosition(MallAdPosition adPosition) { |
||||
|
// 1. 保存广告位主表
|
||||
|
this.save(adPosition); |
||||
|
|
||||
|
// 2. 保存关联商品
|
||||
|
if (adPosition.getProductList() != null && !adPosition.getProductList().isEmpty()) { |
||||
|
for (MallAdProduct product : adPosition.getProductList()) { |
||||
|
product.setAdId(adPosition.getId()); |
||||
|
mallAdProductMapper.insert(product); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 3. 更新缓存:将新广告位加入对应 regionId 的缓存
|
||||
|
if (StringUtils.isNotBlank(adPosition.getRegionId())) { |
||||
|
// 重新组装完整对象(包含productList)
|
||||
|
adPosition.setProductList(mallAdProductMapper.selectByAdId(adPosition.getId())); |
||||
|
adPositionCacheUtil.put(adPosition.getRegionId(), adPosition); |
||||
|
} |
||||
|
|
||||
|
log.info("新增广告位成功: id={}, regionId={}", adPosition.getId(), adPosition.getRegionId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void updateAdPosition(MallAdPosition adPosition) { |
||||
|
// 获取旧数据,用于处理 regionId 变更时清除旧缓存
|
||||
|
MallAdPosition oldAd = this.getById(adPosition.getId()); |
||||
|
|
||||
|
// 1. 更新广告位主表
|
||||
|
this.updateById(adPosition); |
||||
|
|
||||
|
// 2. 先删除旧的商品关联,再重新插入
|
||||
|
mallAdProductMapper.deleteByAdId(adPosition.getId()); |
||||
|
if (adPosition.getProductList() != null && !adPosition.getProductList().isEmpty()) { |
||||
|
for (MallAdProduct product : adPosition.getProductList()) { |
||||
|
product.setAdId(adPosition.getId()); |
||||
|
mallAdProductMapper.insert(product); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 3. 更新缓存
|
||||
|
if (oldAd != null && StringUtils.isNotBlank(oldAd.getRegionId())) { |
||||
|
// 如果 regionId 发生变化,先删除旧 regionId 下的缓存
|
||||
|
if (!oldAd.getRegionId().equals(adPosition.getRegionId())) { |
||||
|
adPositionCacheUtil.remove(oldAd.getRegionId(), adPosition.getId()); |
||||
|
} |
||||
|
} |
||||
|
if (StringUtils.isNotBlank(adPosition.getRegionId())) { |
||||
|
adPosition.setProductList(mallAdProductMapper.selectByAdId(adPosition.getId())); |
||||
|
adPositionCacheUtil.update(adPosition.getRegionId(), adPosition); |
||||
|
} |
||||
|
|
||||
|
log.info("修改广告位成功: id={}, regionId={}", adPosition.getId(), adPosition.getRegionId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void deleteAdPosition(String id) { |
||||
|
MallAdPosition adPosition = this.getById(id); |
||||
|
if (adPosition == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 1. 删除关联商品
|
||||
|
mallAdProductMapper.deleteByAdId(id); |
||||
|
|
||||
|
// 2. 删除广告位主表
|
||||
|
this.removeById(id); |
||||
|
|
||||
|
// 3. 删除缓存
|
||||
|
if (StringUtils.isNotBlank(adPosition.getRegionId())) { |
||||
|
adPositionCacheUtil.remove(adPosition.getRegionId(), id); |
||||
|
} |
||||
|
|
||||
|
log.info("删除广告位成功: id={}, regionId={}", id, adPosition.getRegionId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public MallAdPosition getAdPositionDetail(String id) { |
||||
|
MallAdPosition adPosition = this.getById(id); |
||||
|
if (adPosition == null) { |
||||
|
return null; |
||||
|
} |
||||
|
// 查询关联商品
|
||||
|
List<MallAdProduct> productList = mallAdProductMapper.selectByAdId(id); |
||||
|
adPosition.setProductList(productList); |
||||
|
return adPosition; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public IPage<MallAdPosition> selectPageVO(MallAdPositionQuery query) { |
||||
|
IPage<MallAdPosition> page = new Page<>(query.getPageNum(), query.getPageSize()); |
||||
|
IPage<MallAdPosition> result = mallAdPositionMapper.selectPageVO(page, query); |
||||
|
|
||||
|
// 为每条广告位填充商品列表
|
||||
|
if (result.getRecords() != null && !result.getRecords().isEmpty()) { |
||||
|
List<String> adIds = result.getRecords().stream() |
||||
|
.map(MallAdPosition::getId) |
||||
|
.collect(Collectors.toList()); |
||||
|
List<MallAdProduct> allProducts = mallAdProductMapper.selectByAdIds(adIds); |
||||
|
Map<String, List<MallAdProduct>> productMap = allProducts.stream() |
||||
|
.collect(Collectors.groupingBy(MallAdProduct::getAdId)); |
||||
|
for (MallAdPosition ad : result.getRecords()) { |
||||
|
ad.setProductList(productMap.getOrDefault(ad.getId(), Collections.emptyList())); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MallAdPosition> getAdsByRegionId(String regionId,List<String> paths) { |
||||
|
if (StringUtils.isBlank(regionId)) { |
||||
|
return Collections.emptyList(); |
||||
|
} |
||||
|
|
||||
|
// 1. 优先查询缓存
|
||||
|
List<MallAdPosition> cached = adPositionCacheUtil.getAll(regionId); |
||||
|
List<MallAdPosition> cachedReturn = new ArrayList<>(); |
||||
|
if (cached != null && !cached.isEmpty()) { |
||||
|
for(MallAdPosition ad : cached){ |
||||
|
if(paths.contains(ad.getPosition())){ |
||||
|
cachedReturn.add(ad); |
||||
|
} |
||||
|
} |
||||
|
return cachedReturn; |
||||
|
} |
||||
|
|
||||
|
// 2. 缓存不存在,查询数据库
|
||||
|
List<MallAdPosition> dbList = mallAdPositionMapper.selectByRegionId(regionId); |
||||
|
if (dbList != null && !dbList.isEmpty()) { |
||||
|
// 填充商品列表
|
||||
|
List<String> adIds = dbList.stream() |
||||
|
.map(MallAdPosition::getId) |
||||
|
.collect(Collectors.toList()); |
||||
|
List<MallAdProduct> allProducts = mallAdProductMapper.selectByAdIds(adIds); |
||||
|
Map<String, List<MallAdProduct>> productMap = allProducts.stream() |
||||
|
.collect(Collectors.groupingBy(MallAdProduct::getAdId)); |
||||
|
for (MallAdPosition ad : dbList) { |
||||
|
ad.setProductList(productMap.getOrDefault(ad.getId(), Collections.emptyList())); |
||||
|
if(paths.contains(ad.getPosition())){ |
||||
|
cachedReturn.add(ad); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 3. 写入缓存
|
||||
|
adPositionCacheUtil.putAll(regionId, dbList); |
||||
|
log.info("从数据库加载广告位并写入缓存: regionId={}, count={}", regionId, dbList.size()); |
||||
|
} |
||||
|
return cachedReturn; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,231 @@ |
|||||
|
package cc.hiver.mall.utils; |
||||
|
|
||||
|
import cc.hiver.core.common.redis.RedisTemplateHelper; |
||||
|
import cc.hiver.mall.entity.MallAdPosition; |
||||
|
import cn.hutool.json.JSONUtil; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 广告位缓存工具类 |
||||
|
* <p> |
||||
|
* 底层使用 Redis Hash 结构,按 regionId 维度管理广告位缓存。 |
||||
|
* <pre> |
||||
|
* Key = AD_POSITION:{regionId} |
||||
|
* Field = adPositionId |
||||
|
* Value = MallAdPosition 的 JSON 序列化(含 productList) |
||||
|
* </pre> |
||||
|
* |
||||
|
* @author system |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
public class AdPositionCacheUtil { |
||||
|
|
||||
|
/** Redis Key 前缀 */ |
||||
|
private static final String KEY_PREFIX = "AD_POSITION:"; |
||||
|
|
||||
|
@Autowired |
||||
|
private RedisTemplateHelper redisTemplateHelper; |
||||
|
|
||||
|
// ================================================================
|
||||
|
// Key 构建
|
||||
|
// ================================================================
|
||||
|
|
||||
|
private String buildKey(String regionId) { |
||||
|
return KEY_PREFIX + regionId; |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 存放(put)
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 存放单个广告位到缓存 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @param adPosition 广告位(必须包含有效的 id) |
||||
|
*/ |
||||
|
public void put(String regionId, MallAdPosition adPosition) { |
||||
|
if (StringUtils.isBlank(regionId) || adPosition == null || StringUtils.isBlank(adPosition.getId())) { |
||||
|
log.info("AdPositionCacheUtil.put 参数无效, regionId={}, adPosition={}", regionId, adPosition); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
String key = buildKey(regionId); |
||||
|
String json = JSONUtil.toJsonStr(adPosition); |
||||
|
redisTemplateHelper.hPut(key, adPosition.getId(), json); |
||||
|
log.info("缓存广告位: regionId={}, adId={}", regionId, adPosition.getId()); |
||||
|
} catch (Exception e) { |
||||
|
log.info("缓存广告位失败: regionId={}, adId={}", regionId, adPosition.getId(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量存放广告位到缓存(通常用于缓存预热 / 首次加载) |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @param ads 广告位列表 |
||||
|
*/ |
||||
|
public void putAll(String regionId, List<MallAdPosition> ads) { |
||||
|
if (StringUtils.isBlank(regionId) || ads == null || ads.isEmpty()) { |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
String key = buildKey(regionId); |
||||
|
Map<String, String> map = new java.util.LinkedHashMap<>(ads.size()); |
||||
|
for (MallAdPosition ad : ads) { |
||||
|
if (ad != null && StringUtils.isNotBlank(ad.getId())) { |
||||
|
map.put(ad.getId(), JSONUtil.toJsonStr(ad)); |
||||
|
} |
||||
|
} |
||||
|
if (!map.isEmpty()) { |
||||
|
redisTemplateHelper.hPutAll(key, map); |
||||
|
log.info("批量缓存广告位: regionId={}, count={}", regionId, map.size()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.info("批量缓存广告位失败: regionId={}", regionId, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 删除(remove)
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 根据 regionId 和广告位ID 从缓存中删除指定广告位 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @param adId 广告位ID |
||||
|
*/ |
||||
|
public void remove(String regionId, String adId) { |
||||
|
if (StringUtils.isBlank(regionId) || StringUtils.isBlank(adId)) { |
||||
|
log.info("AdPositionCacheUtil.remove 参数无效, regionId={}, adId={}", regionId, adId); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
String key = buildKey(regionId); |
||||
|
redisTemplateHelper.hDelete(key, adId); |
||||
|
log.info("删除广告位缓存: regionId={}, adId={}", regionId, adId); |
||||
|
} catch (Exception e) { |
||||
|
log.info("删除广告位缓存失败: regionId={}, adId={}", regionId, adId, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 清除指定区域的所有广告位缓存 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
*/ |
||||
|
public void removeAll(String regionId) { |
||||
|
if (StringUtils.isBlank(regionId)) { |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
redisTemplateHelper.delete(buildKey(regionId)); |
||||
|
log.info("清除全部广告位缓存: regionId={}", regionId); |
||||
|
} catch (Exception e) { |
||||
|
log.info("清除全部广告位缓存失败: regionId={}", regionId, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 更新(update)
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 更新缓存中的广告位信息(覆盖写入) |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @param adPosition 更新后的广告位 |
||||
|
*/ |
||||
|
public void update(String regionId, MallAdPosition adPosition) { |
||||
|
if (StringUtils.isBlank(regionId) || adPosition == null || StringUtils.isBlank(adPosition.getId())) { |
||||
|
log.info("AdPositionCacheUtil.update 参数无效, regionId={}, adPosition={}", regionId, adPosition); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
put(regionId, adPosition); |
||||
|
log.info("更新广告位缓存: regionId={}, adId={}", regionId, adPosition.getId()); |
||||
|
} catch (Exception e) { |
||||
|
log.info("更新广告位缓存失败: regionId={}, adId={}", regionId, adPosition.getId(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 查询(get)
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 获取指定区域的全部广告位缓存 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @return 缓存的广告位列表,缓存不存在时返回 null(调用方可据此判断是否需要回源查库) |
||||
|
*/ |
||||
|
public List<MallAdPosition> getAll(String regionId) { |
||||
|
if (StringUtils.isBlank(regionId)) { |
||||
|
return null; |
||||
|
} |
||||
|
try { |
||||
|
String key = buildKey(regionId); |
||||
|
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key); |
||||
|
if (entries == null || entries.isEmpty()) { |
||||
|
return null; |
||||
|
} |
||||
|
List<MallAdPosition> result = new ArrayList<>(entries.size()); |
||||
|
for (Object value : entries.values()) { |
||||
|
if (value != null) { |
||||
|
result.add(JSONUtil.toBean(value.toString(), MallAdPosition.class)); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
log.info("获取广告位缓存失败: regionId={}", regionId, e); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取缓存中的单个广告位 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @param adId 广告位ID |
||||
|
* @return 缓存的广告位,不存在时返回 null |
||||
|
*/ |
||||
|
public MallAdPosition get(String regionId, String adId) { |
||||
|
if (StringUtils.isBlank(regionId) || StringUtils.isBlank(adId)) { |
||||
|
return null; |
||||
|
} |
||||
|
try { |
||||
|
String key = buildKey(regionId); |
||||
|
Object value = redisTemplateHelper.hGet(key, adId); |
||||
|
if (value == null) { |
||||
|
return null; |
||||
|
} |
||||
|
return JSONUtil.toBean(value.toString(), MallAdPosition.class); |
||||
|
} catch (Exception e) { |
||||
|
log.info("获取单个广告位缓存失败: regionId={}, adId={}", regionId, adId, e); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断该区域的广告位缓存是否已存在 |
||||
|
* |
||||
|
* @param regionId 区域ID |
||||
|
* @return true 表示缓存存在 |
||||
|
*/ |
||||
|
public boolean exists(String regionId) { |
||||
|
if (StringUtils.isBlank(regionId)) { |
||||
|
return false; |
||||
|
} |
||||
|
Boolean hasKey = redisTemplateHelper.hasKey(buildKey(regionId)); |
||||
|
return hasKey != null && hasKey; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="cc.hiver.mall.dao.mapper.MallAdPositionMapper"> |
||||
|
|
||||
|
<resultMap id="adPositionMap" type="cc.hiver.mall.entity.MallAdPosition"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="position" property="position"/> |
||||
|
<result column="merchant_name" property="merchantName"/> |
||||
|
<result column="merchant_id" property="merchantId"/> |
||||
|
<result column="merchant_image" property="merchantImage"/> |
||||
|
<result column="ad_image" property="adImage"/> |
||||
|
<result column="title" property="title"/> |
||||
|
<result column="link_url" property="linkUrl"/> |
||||
|
<result column="link_params" property="linkParams"/> |
||||
|
<result column="region_id" property="regionId"/> |
||||
|
<result column="sort_order" property="sortOrder"/> |
||||
|
<result column="status" property="status"/> |
||||
|
<result column="create_time" property="createTime"/> |
||||
|
<result column="update_time" property="updateTime"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<sql id="selectColumns"> |
||||
|
id, position, merchant_name, merchant_id, merchant_image, |
||||
|
ad_image, title, link_url, link_params, region_id, |
||||
|
sort_order, status, create_time, update_time |
||||
|
</sql> |
||||
|
|
||||
|
<select id="selectPageVO" resultMap="adPositionMap"> |
||||
|
SELECT <include refid="selectColumns"/> |
||||
|
FROM t_mall_ad_position |
||||
|
<where> |
||||
|
del_flag = 0 |
||||
|
<if test="q.position != null and q.position != ''"> |
||||
|
AND position = #{q.position} |
||||
|
</if> |
||||
|
<if test="q.merchantName != null and q.merchantName != ''"> |
||||
|
AND merchant_name LIKE CONCAT('%', #{q.merchantName}, '%') |
||||
|
</if> |
||||
|
<if test="q.merchantId != null and q.merchantId != ''"> |
||||
|
AND merchant_id = #{q.merchantId} |
||||
|
</if> |
||||
|
<if test="q.title != null and q.title != ''"> |
||||
|
AND title LIKE CONCAT('%', #{q.title}, '%') |
||||
|
</if> |
||||
|
<if test="q.regionId != null and q.regionId != ''"> |
||||
|
AND region_id = #{q.regionId} |
||||
|
</if> |
||||
|
<if test="q.status != null"> |
||||
|
AND status = #{q.status} |
||||
|
</if> |
||||
|
</where> |
||||
|
ORDER BY sort_order ASC, id DESC |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectByRegionId" resultMap="adPositionMap"> |
||||
|
SELECT <include refid="selectColumns"/> |
||||
|
FROM t_mall_ad_position |
||||
|
WHERE del_flag = 0 AND status = 1 AND region_id = #{regionId} |
||||
|
ORDER BY sort_order ASC, id DESC |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,44 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="cc.hiver.mall.dao.mapper.MallAdProductMapper"> |
||||
|
|
||||
|
<resultMap id="adProductMap" type="cc.hiver.mall.entity.MallAdProduct"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="ad_id" property="adId"/> |
||||
|
<result column="product_image" property="productImage"/> |
||||
|
<result column="product_name" property="productName"/> |
||||
|
<result column="original_price" property="originalPrice"/> |
||||
|
<result column="group_price" property="groupPrice"/> |
||||
|
<result column="group_members" property="groupMembers"/> |
||||
|
<result column="sort_order" property="sortOrder"/> |
||||
|
<result column="create_time" property="createTime"/> |
||||
|
<result column="update_time" property="updateTime"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<sql id="selectColumns"> |
||||
|
id, ad_id, product_image, product_name, original_price, |
||||
|
group_price, group_members, sort_order, create_time, update_time |
||||
|
</sql> |
||||
|
|
||||
|
<select id="selectByAdId" resultMap="adProductMap"> |
||||
|
SELECT <include refid="selectColumns"/> |
||||
|
FROM t_mall_ad_product |
||||
|
WHERE del_flag = 0 AND ad_id = #{adId} |
||||
|
ORDER BY sort_order ASC, id ASC |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectByAdIds" resultMap="adProductMap"> |
||||
|
SELECT <include refid="selectColumns"/> |
||||
|
FROM t_mall_ad_product |
||||
|
WHERE del_flag = 0 AND ad_id IN |
||||
|
<foreach collection="adIds" item="adId" open="(" separator="," close=")"> |
||||
|
#{adId} |
||||
|
</foreach> |
||||
|
ORDER BY sort_order ASC, id ASC |
||||
|
</select> |
||||
|
|
||||
|
<delete id="deleteByAdId"> |
||||
|
DELETE FROM t_mall_ad_product WHERE ad_id = #{adId} |
||||
|
</delete> |
||||
|
|
||||
|
</mapper> |
||||
Loading…
Reference in new issue