mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-14 05:42:06 +08:00
广告管理service、controller单元测试完善
This commit is contained in:
-54
@@ -1,54 +0,0 @@
|
||||
package com.cf.imes.module.system.config;
|
||||
|
||||
import org.springframework.amqp.core.Binding;
|
||||
import org.springframework.amqp.core.BindingBuilder;
|
||||
import org.springframework.amqp.core.CustomExchange;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.core.QueueBuilder;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE;
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_QUEUE;
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY;
|
||||
|
||||
/**
|
||||
* @author Gqr
|
||||
* @since 2025/5/13 11:42
|
||||
*/
|
||||
@Configuration
|
||||
public class ChenfengRabbitMQSystemConfiguration {
|
||||
/**
|
||||
* 广告状态修改 延迟队列
|
||||
*/
|
||||
// @Bean
|
||||
// public Queue advertisementUpdateDelayedQueue(){
|
||||
// return QueueBuilder.durable(SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_QUEUE).build();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 广告状态修改 定义延迟交换机
|
||||
// */
|
||||
// @Bean
|
||||
// public CustomExchange advertisementUpdateDelayExchange() {
|
||||
// Map<String, Object> args = new HashMap<>();
|
||||
// args.put("x-delayed-type", "direct");
|
||||
// return new CustomExchange(SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE, "x-delayed-message", true, false, args);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 广告状态修改 队列与交换机绑定
|
||||
// */
|
||||
// @Bean
|
||||
// public Binding advertisementUpdateQueueABindingX(@Qualifier("advertisementUpdateDelayedQueue") Queue queue,
|
||||
// @Qualifier("advertisementUpdateDelayExchange") CustomExchange delayedExchange){
|
||||
// return BindingBuilder.bind(queue)
|
||||
// .to(delayedExchange)
|
||||
// .with(SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY)
|
||||
// .noargs();
|
||||
// }
|
||||
}
|
||||
+2
-1
@@ -4,6 +4,7 @@ import com.cf.imes.framework.common.validation.InScope;
|
||||
import com.cf.imes.framework.common.validation.NumberValid;
|
||||
import com.cf.imes.module.system.enums.advertisement.AdvertisementPositionEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
@@ -30,7 +31,7 @@ public class AdvertisementSaveReqVO {
|
||||
|
||||
|
||||
@Schema(description = "广告位置,字典键值", example = "[1,2]")
|
||||
@NotNull(message = "广告位置不能为空")
|
||||
@NotEmpty(message = "广告位置不能为空")
|
||||
@InScope(value = AdvertisementPositionEnum.class, desc = "广告位置")
|
||||
private List<Integer> adPosition;
|
||||
|
||||
|
||||
-8
@@ -1,7 +1,6 @@
|
||||
package com.cf.imes.module.system.dal.mysql.funds.advertisement;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
@@ -41,13 +40,6 @@ public interface AdvertisementMapper extends BaseMapperX<AdvertisementDO> {
|
||||
|
||||
}
|
||||
|
||||
default int updateAdStatus(Long id, Integer newStatus) {
|
||||
return update(new LambdaUpdateWrapper<AdvertisementDO>()
|
||||
.set(AdvertisementDO::getStatus, newStatus)
|
||||
.eq(AdvertisementDO::getId, id)
|
||||
.eq(AdvertisementDO::getDeleted, false));
|
||||
}
|
||||
|
||||
default List<AdvertisementDO> selectList(LocalDateTime now, Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<AdvertisementDO>()
|
||||
.le(AdvertisementDO::getStartTime, now)
|
||||
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
package com.cf.imes.module.system.mq.producer.advertisement;
|
||||
|
||||
import com.cf.imes.module.system.mq.message.advertisement.AdvertisementSendMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE;
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY;
|
||||
|
||||
/**
|
||||
* Advertisement 广告相关消息的 Producer
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AdvertisementProducer {
|
||||
|
||||
@Resource
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* 发送 {@link AdvertisementSendMessage} 消息
|
||||
*
|
||||
* @param adId 广告id
|
||||
* @param action 类型
|
||||
* @param triggerTime 到期时间
|
||||
*/
|
||||
|
||||
public String sendAdvertisementSendMessage(Long adId, String action, LocalDate triggerTime) {
|
||||
|
||||
String messageId = UUID.randomUUID().toString();
|
||||
|
||||
|
||||
long delay = Duration.between(LocalDateTime.now(), triggerTime).toMillis();
|
||||
|
||||
if (delay > 0) {
|
||||
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
|
||||
AdvertisementSendMessage message = new AdvertisementSendMessage(adId, messageId, action);
|
||||
|
||||
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
// 数据库操作全部完成发送消息
|
||||
rabbitTemplate.convertAndSend(
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE,
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY,
|
||||
message,
|
||||
correlationData -> {
|
||||
correlationData.getMessageProperties().setMessageId(messageId);
|
||||
correlationData.getMessageProperties().setDelayLong(Long.valueOf(delay));
|
||||
return correlationData;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 数据库操作全部完成发送消息
|
||||
rabbitTemplate.convertAndSend(
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE,
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY,
|
||||
message,
|
||||
correlationData -> {
|
||||
correlationData.getMessageProperties().setMessageId(messageId);
|
||||
correlationData.getMessageProperties().setDelayLong(Long.valueOf(delay));
|
||||
return correlationData;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return messageId;
|
||||
}
|
||||
}
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
package com.cf.imes.module.system.service.funds.advertisement;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementTaskDO;
|
||||
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapper;
|
||||
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementTaskMapper;
|
||||
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
|
||||
import com.cf.imes.module.system.enums.advertisement.MessageStatusEnum;
|
||||
import com.cf.imes.module.system.mq.message.advertisement.AdvertisementSendMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE;
|
||||
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY;
|
||||
|
||||
/**
|
||||
* 广告状态修改 Service 实现类
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class AdvertisementCompensateTask {
|
||||
|
||||
@Resource
|
||||
private AdvertisementMapper advertisementMapper;
|
||||
|
||||
@Resource
|
||||
private AdvertisementTaskMapper advertisementTaskMapper;
|
||||
|
||||
@Resource
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
|
||||
//=== 补偿任务 ===//
|
||||
// @Scheduled(cron = "0 0/30 * * * ?")
|
||||
public void checkAdStatusConsistency() {
|
||||
// 1. 检查应发布但未发布的广告
|
||||
List<AdvertisementDO> unpublishedAds = advertisementMapper.selectList(LocalDate.now().atStartOfDay(), AdvertisementStatusEnum.UNPUBLISHED.getStatus());
|
||||
unpublishedAds.forEach(ad -> {
|
||||
updateAdStatus(ad, AdvertisementStatusEnum.PUBLISHED.getStatus());
|
||||
rescheduleExpireMessage(ad);
|
||||
});
|
||||
|
||||
// 2. 检查应结束但未结束的广告
|
||||
List<AdvertisementDO> publishedAds = advertisementMapper.selectList(
|
||||
new QueryWrapper<AdvertisementDO>()
|
||||
.le("end_time", LocalDateTime.now())
|
||||
.eq("status", AdvertisementStatusEnum.PUBLISHED.getStatus())
|
||||
);
|
||||
publishedAds.forEach(ad -> updateAdStatus(ad, AdvertisementStatusEnum.ENDED.getStatus()));
|
||||
}
|
||||
|
||||
private void rescheduleExpireMessage(AdvertisementDO ad) {
|
||||
if (ad.getEndTime().isAfter(LocalDate.now())) {
|
||||
String newMsgId = sendSingleMessage(ad.getId(), "expire", ad.getEndTime().atStartOfDay());
|
||||
trackMessage(ad.getId(), newMsgId, AdvertisementStatusEnum.PUBLISHED.getStatus(), MessageStatusEnum.CANCELLED.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAdStatus(AdvertisementDO ad, Integer newStatus) {
|
||||
advertisementMapper.updateAdStatus(ad.getId(), newStatus);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送单个延迟消息
|
||||
*/
|
||||
private String sendSingleMessage(Long adId, String action, LocalDateTime triggerTime) {
|
||||
String messageId = UUID.randomUUID().toString();
|
||||
long delay = Duration.between(LocalDateTime.now(), triggerTime).toMillis();
|
||||
|
||||
|
||||
if (delay > 0) {
|
||||
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
|
||||
|
||||
rabbitTemplate.convertAndSend(
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE,
|
||||
SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY,
|
||||
new AdvertisementSendMessage(adId, messageId, action),
|
||||
correlationData -> {
|
||||
correlationData.getMessageProperties().setMessageId(messageId);
|
||||
correlationData.getMessageProperties().setDelayLong(Long.valueOf(delay));
|
||||
return correlationData;
|
||||
}
|
||||
);
|
||||
}
|
||||
return messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录消息追踪
|
||||
*/
|
||||
private void trackMessage(Long adId, String messageId, Integer advertisementStatus, Integer messageStatus) {
|
||||
if (StringUtils.isNotBlank(messageId)) {
|
||||
advertisementTaskMapper.insert(new AdvertisementTaskDO()
|
||||
.setAdvertisementId(adId)
|
||||
.setMessageId(messageId)
|
||||
.setMessageStatus(messageStatus)
|
||||
.setAdvertisementStatus(advertisementStatus)
|
||||
);
|
||||
log.info("[trackMessage][adId({}) messageId({}) 记录消息追踪成功]", adId, messageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-14
@@ -14,7 +14,6 @@ import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapp
|
||||
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -38,9 +37,6 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
|
||||
@Slf4j
|
||||
public class AdvertisementServiceImpl implements AdvertisementService{
|
||||
|
||||
@Value("${chenfeng.info.name}")
|
||||
private String SOFT_WARE_ID; // 获取软件标识-可修改
|
||||
|
||||
@Resource
|
||||
private AdvertisementMapper advertisementMapper;
|
||||
|
||||
@@ -49,7 +45,6 @@ public class AdvertisementServiceImpl implements AdvertisementService{
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long create(AdvertisementSaveReqVO createReqVO) {
|
||||
|
||||
if (createReqVO.getStartTime().isAfter(createReqVO.getEndTime())) {
|
||||
@@ -64,8 +59,7 @@ public class AdvertisementServiceImpl implements AdvertisementService{
|
||||
// 插入广告
|
||||
AdvertisementDO advertisementDO = BeanUtils.toBean(createReqVO, AdvertisementDO.class)
|
||||
.setAdPosition(createReqVO.getAdPosition().stream().sorted().distinct().toList())
|
||||
.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus())
|
||||
.setSoftwareId(SOFT_WARE_ID);
|
||||
.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus());
|
||||
|
||||
advertisementMapper.insert(advertisementDO);
|
||||
|
||||
@@ -78,8 +72,11 @@ public class AdvertisementServiceImpl implements AdvertisementService{
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(AdvertisementSaveReqVO reqVO) {
|
||||
if (reqVO.getStartTime().isAfter(reqVO.getEndTime())) {
|
||||
throw exception(ADVERTISEMENT_TIME_ERROR);
|
||||
}
|
||||
|
||||
Long id = reqVO.getId();
|
||||
// 确认广告是否存在
|
||||
AdvertisementDO advertisementDO = validateAdvertisementExists(id);
|
||||
@@ -94,18 +91,14 @@ public class AdvertisementServiceImpl implements AdvertisementService{
|
||||
|
||||
AssertUtils.empty(aDo, ADVERTISEMENT_NAME_IS_EXIST);
|
||||
|
||||
if (reqVO.getStartTime().isAfter(reqVO.getEndTime())) {
|
||||
throw exception(ADVERTISEMENT_TIME_ERROR);
|
||||
}
|
||||
|
||||
// 更新内容
|
||||
advertisementDO.setAdName(reqVO.getAdName())
|
||||
.setAdImagePath(reqVO.getAdImagePath())
|
||||
.setStartTime(reqVO.getStartTime())
|
||||
.setEndTime(reqVO.getEndTime())
|
||||
.setAdPosition(reqVO.getAdPosition().stream().sorted().distinct().toList())
|
||||
.setSort(ObjectUtil.isNull(reqVO.getSort()) ? advertisementDO.getSort() : reqVO.getSort())
|
||||
.setAdRedirectUrl(StringUtils.isEmpty(reqVO.getAdRedirectUrl()) ? advertisementDO.getAdRedirectUrl() : reqVO.getAdRedirectUrl());
|
||||
.setSort(ObjectUtil.defaultIfNull(reqVO.getSort(), advertisementDO.getSort()))
|
||||
.setAdRedirectUrl(StringUtils.defaultIfEmpty(reqVO.getAdRedirectUrl(), advertisementDO.getAdRedirectUrl()));
|
||||
advertisementMapper.updateById(advertisementDO);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -35,10 +35,10 @@
|
||||
ad_redirect_url
|
||||
from advertisement
|
||||
where deleted = false
|
||||
and find_in_set (#{adPosition}, ad_position)
|
||||
and status = #{status}
|
||||
and start_time <= #{now}
|
||||
and end_time >= #{now}
|
||||
and CONCAT(',', ad_position, ',') like concat('%,', #{adPosition}, ',%')
|
||||
and status = #{status}
|
||||
and start_time <= #{now}
|
||||
and end_time >= #{now}
|
||||
order by sort desc
|
||||
</select>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user