feat(REQ-2106): 接口实现完成
This commit is contained in:
parent
c2ba6dde14
commit
e04a66daca
@ -54,7 +54,7 @@ public enum MaterialTargetUserTypeEnum {
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 是否需要投放
|
||||
* 根据目标人权类型确认是否需要投放
|
||||
*
|
||||
* @param workspaceIds 配置的投放项目部
|
||||
* @param ouIds 配置的投放单位
|
||||
|
||||
@ -4,7 +4,6 @@ import cn.axzo.nanopart.api.dto.AspectRatioDto;
|
||||
import cn.axzo.nanopart.api.enums.CarouselStatusEnum;
|
||||
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
|
||||
import cn.axzo.nanopart.api.enums.StatusEnum;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -17,6 +16,7 @@ import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
@ -33,6 +33,8 @@ public class CreateBannerReq {
|
||||
/**
|
||||
* 广告位名称
|
||||
*/
|
||||
@Length(max = 20)
|
||||
@NotBlank(message = "广告位名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
@ -52,7 +54,7 @@ public class CreateBannerReq {
|
||||
/**
|
||||
* 标签,内置标签:“弹窗”,“banner”
|
||||
*/
|
||||
private JSONArray tag;
|
||||
private List<String> tag;
|
||||
|
||||
/**
|
||||
* 轮播状态,取值:OPENED, CLOSED,默认为ClOSED
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.nanopart.api.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/4/11 10:38
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateMaterialPutLogReq {
|
||||
|
||||
/**
|
||||
* 请求id
|
||||
*/
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 用户personId
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 广告位编码
|
||||
*/
|
||||
private String bannerCode;
|
||||
|
||||
/**
|
||||
* 投放的素材id列表
|
||||
*/
|
||||
private List<Long> materialIds;
|
||||
}
|
||||
@ -6,7 +6,9 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -30,7 +32,8 @@ public class ListMaterialByBannerCodeReq {
|
||||
/**
|
||||
* 当前登录人的personId
|
||||
*/
|
||||
// @NotNull(message = "personId不能为空")
|
||||
@NotNull(message = "personId不能为空")
|
||||
@Min(value = 1, message = "请传入正确的personId")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
|
||||
@ -17,6 +17,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -31,6 +32,8 @@ public class MaterialController implements MaterialApi {
|
||||
|
||||
private final MaterialService materialService;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public ApiPageResult<PageMaterialResp> page(PageMaterialReq req) {
|
||||
Page<PageMaterialResp> pageData = materialService.page(req);
|
||||
@ -61,6 +64,7 @@ public class MaterialController implements MaterialApi {
|
||||
|
||||
@Override
|
||||
public ApiResult<List<MaterialResp>> listMaterialByBannerCode(ListMaterialByBannerCodeReq req) {
|
||||
return ApiResult.ok(materialService.listMaterialByBannerCode(req));
|
||||
String traceId = request.getHeader("traceId");
|
||||
return ApiResult.ok(materialService.listMaterialByBannerCode(req,traceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package cn.axzo.nanopart.server.domain;
|
||||
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.type.LongListTypeHandler;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 素材投放日志记录
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/4/10 18:36
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName(value = "material_put_log", autoResultMap = true)
|
||||
public class MaterialPutLog extends BaseEntity<MaterialPutLog> {
|
||||
|
||||
/**
|
||||
* 请求id
|
||||
*/
|
||||
@TableField(value = "request_id")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 用户personId
|
||||
*/
|
||||
@TableField(value = "person_id")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 广告位编码
|
||||
*/
|
||||
@TableField(value = "banner_code")
|
||||
private String bannerCode;
|
||||
|
||||
/**
|
||||
* 投放的素材id列表
|
||||
*/
|
||||
@TableField(value = "material_ids", typeHandler = LongListTypeHandler.class)
|
||||
private List<Long> materialIds;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.axzo.nanopart.server.mapper;
|
||||
|
||||
import cn.axzo.nanopart.server.domain.MaterialPutLog;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/4/10 18:40
|
||||
*/
|
||||
@Mapper
|
||||
public interface MaterialPutLogDao extends BaseMapper<MaterialPutLog> {
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.axzo.nanopart.server.service;
|
||||
|
||||
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/4/10 18:41
|
||||
*/
|
||||
public interface MaterialPutLogService {
|
||||
|
||||
Long create(CreateMaterialPutLogReq req);
|
||||
}
|
||||
@ -28,7 +28,7 @@ public interface MaterialService {
|
||||
* @param req {@link ListMaterialByBannerCodeReq}
|
||||
* @return 根据优先级(priority)升序,创建时间(createAt)降序排序后的列表
|
||||
*/
|
||||
List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req);
|
||||
List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req,String traceId);
|
||||
|
||||
Page<PageMaterialResp> page(PageMaterialReq req);
|
||||
|
||||
|
||||
@ -10,14 +10,14 @@ import cn.axzo.nanopart.api.request.UpdateBannerReq;
|
||||
import cn.axzo.nanopart.api.request.UpdateStatusReq;
|
||||
import cn.axzo.nanopart.api.response.DetailBannerResp;
|
||||
import cn.axzo.nanopart.api.response.PageBannerResp;
|
||||
import cn.axzo.nanopart.server.mapper.BannerDao;
|
||||
import cn.axzo.nanopart.server.domain.Banner;
|
||||
import cn.axzo.nanopart.server.mapper.BannerDao;
|
||||
import cn.axzo.nanopart.server.service.BannerOperationLogService;
|
||||
import cn.axzo.nanopart.server.service.BannerService;
|
||||
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@ -49,10 +49,10 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
|
||||
*/
|
||||
@Override
|
||||
public Page<PageBannerResp> page(PageBannerReq req) {
|
||||
LambdaQueryChainWrapper<Banner> pageLambdaQueryChain = buildPageLambdaQueryChain(req);
|
||||
LambdaQueryWrapper<Banner> pageLambdaQueryWrapper = buildPageLambdaQueryWrapper(req);
|
||||
|
||||
Page<Banner> bannerPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryChain);
|
||||
if (bannerPage.getTotal() == 0) {
|
||||
Page<Banner> bannerPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryWrapper);
|
||||
if (Objects.isNull(bannerPage) || bannerPage.getTotal() == 0) {
|
||||
return new Page<>();
|
||||
}
|
||||
return PageConverter.convert(bannerPage, record -> BeanUtil.toBean(record, PageBannerResp.class));
|
||||
@ -217,10 +217,11 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
|
||||
* 构建分页查询条件
|
||||
*
|
||||
* @param req {@link PageBannerReq}
|
||||
* @return {@link LambdaQueryChainWrapper}
|
||||
* @return {@link LambdaQueryWrapper}
|
||||
*/
|
||||
private LambdaQueryChainWrapper<Banner> buildPageLambdaQueryChain(PageBannerReq req) {
|
||||
return lambdaQuery()
|
||||
private LambdaQueryWrapper<Banner> buildPageLambdaQueryWrapper(PageBannerReq req) {
|
||||
LambdaQueryWrapper<Banner> lambdaQueryWrapper = new LambdaQueryWrapper<Banner>();
|
||||
return lambdaQueryWrapper
|
||||
.like(StringUtils.isNotEmpty(req.getName()), Banner::getName, req.getName())
|
||||
.eq(Objects.nonNull(req.getTerminal()), Banner::getTerminal, req.getTerminal())
|
||||
.eq(Objects.nonNull(req.getStatus()), Banner::getStatus, req.getStatus())
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.axzo.nanopart.server.service.impl;
|
||||
|
||||
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
|
||||
import cn.axzo.nanopart.server.domain.MaterialPutLog;
|
||||
import cn.axzo.nanopart.server.mapper.MaterialPutLogDao;
|
||||
import cn.axzo.nanopart.server.service.MaterialPutLogService;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/4/10 18:41
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MaterialPutLogServiceImpl extends ServiceImpl<MaterialPutLogDao, MaterialPutLog> implements MaterialPutLogService {
|
||||
|
||||
/**
|
||||
* 创建
|
||||
*
|
||||
* @param req {@link CreateMaterialPutLogReq}
|
||||
* @return {@link Long}
|
||||
*/
|
||||
@Override
|
||||
public Long create(CreateMaterialPutLogReq req) {
|
||||
MaterialPutLog materialPutLog = BeanUtil.copyProperties(req, MaterialPutLog.class);
|
||||
save(materialPutLog);
|
||||
return materialPutLog.getId();
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ import cn.axzo.nanopart.api.enums.MaterialDisplayFrequencyTypeEnum;
|
||||
import cn.axzo.nanopart.api.enums.RecodeTypeEnum;
|
||||
import cn.axzo.nanopart.api.enums.StatusEnum;
|
||||
import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
|
||||
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
|
||||
import cn.axzo.nanopart.api.request.CreateMaterialReq;
|
||||
import cn.axzo.nanopart.api.request.DetailMaterialReq;
|
||||
import cn.axzo.nanopart.api.request.ListMaterialByBannerCodeReq;
|
||||
@ -27,27 +28,37 @@ import cn.axzo.nanopart.server.rpc.OrganizationalJobGateway;
|
||||
import cn.axzo.nanopart.server.rpc.OrganizationalNodeUserGateway;
|
||||
import cn.axzo.nanopart.server.service.BannerOperationLogService;
|
||||
import cn.axzo.nanopart.server.service.BannerService;
|
||||
import cn.axzo.nanopart.server.service.MaterialPutLogService;
|
||||
import cn.axzo.nanopart.server.service.MaterialService;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -57,6 +68,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RefreshScope
|
||||
@RequiredArgsConstructor
|
||||
public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> implements MaterialService {
|
||||
|
||||
@ -64,13 +76,20 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
|
||||
private final BannerOperationLogService bannerOperationLogService;
|
||||
|
||||
private final MaterialPutLogService materialPutLogService;
|
||||
|
||||
private final OrganizationalNodeUserGateway organizationalNodeUserGateway;
|
||||
|
||||
private final OrganizationalJobGateway organizationalJobGateway;
|
||||
|
||||
private final CooperateShipGateway cooperateShipGateway;
|
||||
|
||||
// private final
|
||||
/**
|
||||
* 素材投放频次缓存key有效期,
|
||||
* 单位:天,默认为90天
|
||||
*/
|
||||
@Value("${materialDisplayFrequencyKeyTtl: 90}")
|
||||
private Long materialDisplayFrequencyKeyTtl;
|
||||
|
||||
/**
|
||||
* 根据广告位编码(bannerCode)查询素材
|
||||
@ -81,15 +100,12 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
* @param req {@link ListMaterialByBannerCodeReq}
|
||||
* @return 根据优先级(priority)升序,创建时间(createAt)降序排序后的列表
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req) {
|
||||
public List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req, String traceId) {
|
||||
// 获取广告位并校验
|
||||
Banner banner = bannerService.selectByCode(req.getBannerCode());
|
||||
if (Objects.isNull(banner)) {
|
||||
throw new ServiceException("广告位不存在");
|
||||
}
|
||||
if (banner.getStatus() != StatusEnum.ONLINE) {
|
||||
throw new ServiceException("广告位已停用");
|
||||
if (Objects.isNull(validateBanner(req.getBannerCode()))) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 获取该广告位下已上架且在有效期内的所有素材
|
||||
@ -105,44 +121,30 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
throw new ServiceException("数据异常");
|
||||
}
|
||||
|
||||
// 根据素材投放人群和投放规则频次进行过滤
|
||||
// 根据素材投放规则进行过滤
|
||||
List<Material> list = materialList.stream()
|
||||
.filter(m -> {
|
||||
m.getTargetUserType().isDeliverRequired(m.getWorkspaceIds(), m.getOuIds(), m.getJobCodes(), personJoinedWorkspaceOuJob);
|
||||
|
||||
// 频次过滤,这个人
|
||||
// RedisClient.KeyOps.hasKey();
|
||||
return false;
|
||||
// 投放人群过滤
|
||||
return m.getTargetUserType().isDeliverRequired(m.getWorkspaceIds(), m.getOuIds(), m.getJobCodes(), personJoinedWorkspaceOuJob)
|
||||
&&
|
||||
filterByDisplayFrequency(req, m);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 记录素材投放日志
|
||||
CreateMaterialPutLogReq materialPutLogReq = new CreateMaterialPutLogReq();
|
||||
materialPutLogReq.setRequestId(traceId)
|
||||
.setPersonId(req.getPersonId())
|
||||
.setBannerCode(req.getBannerCode())
|
||||
.setMaterialIds(list.stream().map(Material::getId).collect(Collectors.toList()));
|
||||
materialPutLogService.create(materialPutLogReq);
|
||||
|
||||
return BeanUtil.copyToList(list, MaterialResp.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建素材投放频次记录缓存key
|
||||
*
|
||||
* <p>
|
||||
* 1.含义:指定素材给指定人按照投放频次类型投放次数
|
||||
* 2.组成:namespace:bannerCode:materialId:personId:频次类型转换后的值
|
||||
* 3.频次类型转换规则示例:投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum}
|
||||
* 有效期内:VALIDITY_PERIOD -> 有效期
|
||||
* 每天:EVERY_DAY -> 当天
|
||||
* 每周:EVERY_WEEK -> 当周第一天
|
||||
* 每月:EVERY_MONTH -> 当月第一天
|
||||
* </p>
|
||||
*
|
||||
* @param material 素材信息
|
||||
* @param personId 投放人Id
|
||||
* @return key
|
||||
*/
|
||||
public static String buildMaterialDisplayFrequencyKey(Material material, Long personId) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
// return String.format("nanopart:%s:%s", materialId, bannerId);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
@ -151,7 +153,7 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
*/
|
||||
@Override
|
||||
public Page<PageMaterialResp> page(PageMaterialReq req) {
|
||||
LambdaQueryChainWrapper<Material> pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req);
|
||||
LambdaQueryWrapper<Material> pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req);
|
||||
|
||||
Page<Material> materialPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageQueryLambdaWrapper);
|
||||
if (materialPage.getTotal() == 0) {
|
||||
@ -266,14 +268,68 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
return BeanUtil.copyProperties(getById(req.getId()), MaterialResp.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于给定bannerCode校验其存在性和状态有效性
|
||||
*
|
||||
* @param bannerCode 广告位code
|
||||
* @return 若存在且有效返回广告位对象,否则否则返回null
|
||||
*/
|
||||
private Banner validateBanner(String bannerCode) {
|
||||
if (StringUtils.isEmpty(bannerCode)) {
|
||||
return null;
|
||||
}
|
||||
Banner banner = bannerService.selectByCode(bannerCode);
|
||||
if (Objects.isNull(banner)) {
|
||||
log.warn("广告位不存在,广告位code:{}", bannerCode);
|
||||
return null;
|
||||
}
|
||||
if (banner.getStatus() != StatusEnum.ONLINE) {
|
||||
log.warn("广告位已停用,广告位code:{}", bannerCode);
|
||||
return null;
|
||||
}
|
||||
LocalTime now = LocalTime.now();
|
||||
// 当前不在广告位配置的展示时间范围内
|
||||
if (now.isBefore(banner.getStartTime()) || now.isAfter(banner.getEndTime())) {
|
||||
log.warn("当前时间不在广告位配置的展示时间范围内,广告位code:{},当前时间:{},广告位开始时间:{},广告位结束时间:{}", bannerCode, now, banner.getStartTime(), banner.getEndTime());
|
||||
return null;
|
||||
}
|
||||
return banner;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据素材投放频次规则进行过滤
|
||||
*
|
||||
* @param req {@link ListMaterialByBannerCodeReq}
|
||||
* @param m {@link Material}
|
||||
* @return true:符合投放规则;false:不符合投放规则
|
||||
*/
|
||||
private boolean filterByDisplayFrequency(ListMaterialByBannerCodeReq req, Material m) {
|
||||
boolean displayFrequencyFilter;
|
||||
String key = buildMaterialDisplayFrequencyKey(m, req.getPersonId());
|
||||
if (RedisClient.KeyOps.hasKey(key)) {
|
||||
int frequency = Integer.parseInt(RedisClient.StringOps.get(key));
|
||||
displayFrequencyFilter = frequency < m.getMaxDisplayFrequency();
|
||||
if (displayFrequencyFilter) {
|
||||
// 本次需要投放
|
||||
RedisClient.StringOps.incrBy(key, 1L);
|
||||
}
|
||||
} else {
|
||||
displayFrequencyFilter = true;
|
||||
RedisClient.StringOps.set(key, String.valueOf(1));
|
||||
RedisClient.KeyOps.expire(key, materialDisplayFrequencyKeyTtl, TimeUnit.DAYS);
|
||||
}
|
||||
return displayFrequencyFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建分页查询条件
|
||||
*
|
||||
* @param req {@link PageMaterialReq}
|
||||
* @return {@link LambdaQueryChainWrapper}
|
||||
* @return {@link LambdaQueryWrapper}
|
||||
*/
|
||||
private LambdaQueryChainWrapper<Material> buildPageQueryLambdaWrapper(PageMaterialReq req) {
|
||||
return lambdaQuery()
|
||||
private LambdaQueryWrapper<Material> buildPageQueryLambdaWrapper(PageMaterialReq req) {
|
||||
LambdaQueryWrapper<Material> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
return lambdaQueryWrapper
|
||||
.eq(Material::getIsDelete, 0)
|
||||
.eq(StringUtils.isNotEmpty(req.getBannerCode()), Material::getBannerCode, req.getBannerCode())
|
||||
.like(StringUtils.isNotEmpty(req.getName()), Material::getName, req.getName())
|
||||
@ -289,16 +345,17 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
* 构建通过BannerCode查询素材的wrapper
|
||||
*
|
||||
* @param req {@link ListMaterialByBannerCodeReq}
|
||||
* @return {@link LambdaQueryChainWrapper}
|
||||
* @return {@link LambdaQueryWrapper}
|
||||
*/
|
||||
private LambdaQueryChainWrapper<Material> buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) {
|
||||
private LambdaQueryWrapper<Material> buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) {
|
||||
Date now = new Date(System.currentTimeMillis());
|
||||
return lambdaQuery()
|
||||
LambdaQueryWrapper<Material> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
return lambdaQueryWrapper
|
||||
.eq(Material::getIsDelete, 0)
|
||||
.eq(Material::getBannerCode, req.getBannerCode())
|
||||
.eq(Material::getStatus, StatusEnum.ONLINE)
|
||||
.ge(Material::getStartTime, now)
|
||||
.le(Material::getEndTime, now)
|
||||
.le(Material::getStartTime, now)
|
||||
.ge(Material::getEndTime, now)
|
||||
.orderByAsc(Material::getPriority)
|
||||
.orderByDesc(Material::getCreateAt);
|
||||
}
|
||||
@ -384,4 +441,43 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
|
||||
return new JoinedWorkspaceOuJob(workspaceToJobCodeMap, ouIdToJobCodeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建素材投放频次记录缓存key
|
||||
*
|
||||
* <p>
|
||||
* 1.含义:指定素材给指定人按照投放频次类型投放次数
|
||||
* 2.组成:namespace:bannerCode:materialId:personId:频次类型转换后的值
|
||||
* 3.频次类型转换规则示例:投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum}
|
||||
* 有效期内:VALIDITY_PERIOD -> 有效期
|
||||
* 每天:EVERY_DAY -> 当天
|
||||
* 每周:EVERY_WEEK -> 当周第一天
|
||||
* 每月:EVERY_MONTH -> 当月第一天
|
||||
* </p>
|
||||
*
|
||||
* @param material 素材信息
|
||||
* @param personId 投放人Id
|
||||
* @return key
|
||||
*/
|
||||
public static String buildMaterialDisplayFrequencyKey(Material material, Long personId) {
|
||||
String prefix = String.format("nanopart:%s:%s:%s:", material.getBannerCode(), material.getId(), personId);
|
||||
String datePattern = "yyyy_MM_dd";
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
|
||||
LocalDate now = LocalDate.now();
|
||||
String suffix = "";
|
||||
switch (material.getDisplayFrequencyType()) {
|
||||
case VALIDITY_PERIOD:
|
||||
suffix = String.join("_", "P", DateUtil.format(material.getStartTime(), datePattern), DateUtil.format(material.getEndTime(), datePattern));
|
||||
break;
|
||||
case EVERY_DAY:
|
||||
suffix = String.join("_", "D", now.format(formatter));
|
||||
break;
|
||||
case EVERY_WEEK:
|
||||
suffix = String.join("_", "W", now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).format(formatter));
|
||||
break;
|
||||
case EVERY_MONTH:
|
||||
suffix = String.join("_", "M", now.with(TemporalAdjusters.firstDayOfMonth()).format(formatter));
|
||||
}
|
||||
return prefix + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,37 +6,19 @@ import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
@Slf4j
|
||||
@MapperScan(value = {"cn.axzo.**.mapper"})
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients(basePackages = {
|
||||
"cn.axzo.nanopart.api"
|
||||
"cn.axzo"
|
||||
})
|
||||
@EnableAspectJAutoProxy()
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class NanopartApplication {
|
||||
public static void main(String[] args) {
|
||||
ConfigurableApplicationContext run = SpringApplication.run(NanopartApplication.class, args);
|
||||
Environment env = run.getEnvironment();
|
||||
log.info(
|
||||
"--------------------------------------------------------------------------------------------------------------------\n" +
|
||||
"Application 【{}】 is running on 【{}】 environment!\n" +
|
||||
"Api Local: \thttp://127.0.0.1:{}\n" +
|
||||
"Mysql: \t{}\t username:{}\n" +
|
||||
"Redis: \t{}:{}\t database:{}\n",
|
||||
env.getProperty("spring.application.name"),
|
||||
env.getProperty("spring.profiles.active"),
|
||||
env.getProperty("server.port"),
|
||||
env.getProperty("spring.datasource.url"),
|
||||
env.getProperty("spring.datasource.username"),
|
||||
env.getProperty("spring.redis.host"),
|
||||
env.getProperty("spring.redis.port"),
|
||||
env.getProperty("spring.redis.database") +
|
||||
"\n----------------------------------------------------------");
|
||||
SpringApplication.run(NanopartApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ mybatis-plus:
|
||||
logic-delete-value: id #逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: 0 #逻辑未删除值(默认为 0)
|
||||
logic-delete-field: isDelete #逻辑删除字段
|
||||
type-enums-package: cn.axzo.nanopart.api.constant.enums,cn.axzo.nanopart.api.enums
|
||||
type-enums-package: cn.axzo.nanopart.api.constant.enums;cn.axzo.nanopart.api.enums
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user