feat: redis点赞数据同步数据库
This commit is contained in:
@@ -62,5 +62,15 @@
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>2.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>5.3.27</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@@ -0,0 +1,78 @@
|
||||
package com.landaiqing.subject.domain.config;
|
||||
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* xxl-job config
|
||||
*
|
||||
* @author landaiqing
|
||||
*/
|
||||
@Configuration
|
||||
public class XxlJobConfig {
|
||||
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
|
||||
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
|
||||
@Value("${xxl.job.accessToken}")
|
||||
private String accessToken;
|
||||
|
||||
@Value("${xxl.job.executor.appname}")
|
||||
private String appname;
|
||||
|
||||
@Value("${xxl.job.executor.address}")
|
||||
private String address;
|
||||
|
||||
@Value("${xxl.job.executor.ip}")
|
||||
private String ip;
|
||||
|
||||
@Value("${xxl.job.executor.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${xxl.job.executor.logpath}")
|
||||
private String logPath;
|
||||
|
||||
@Value("${xxl.job.executor.logretentiondays}")
|
||||
private int logRetentionDays;
|
||||
|
||||
|
||||
@Bean
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
logger.info(">>>>>>>>>>> xxl-job config init.");
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
xxlJobSpringExecutor.setAppname(appname);
|
||||
xxlJobSpringExecutor.setAddress(address);
|
||||
xxlJobSpringExecutor.setIp(ip);
|
||||
xxlJobSpringExecutor.setPort(port);
|
||||
xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
xxlJobSpringExecutor.setLogPath(logPath);
|
||||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
|
||||
*
|
||||
* 1、引入依赖:
|
||||
* <dependency>
|
||||
* <groupId>org.springframework.cloud</groupId>
|
||||
* <artifactId>spring-cloud-commons</artifactId>
|
||||
* <version>${version}</version>
|
||||
* </dependency>
|
||||
*
|
||||
* 2、配置文件,或者容器启动变量
|
||||
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
|
||||
*
|
||||
* 3、获取IP
|
||||
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
|
||||
*/
|
||||
|
||||
|
||||
}
|
@@ -5,6 +5,8 @@ import com.landaiqing.subject.infra.basic.entity.SubjectLiked;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 题目点赞表 bo转换器
|
||||
*
|
||||
@@ -18,4 +20,7 @@ public interface SubjectLikedBOConverter {
|
||||
|
||||
SubjectLiked convertBOToEntity(SubjectLikedBO subjectLikedBO);
|
||||
|
||||
List<SubjectLikedBO> convertListInfoToBO(List<SubjectLiked> subjectLikedList);
|
||||
|
||||
|
||||
}
|
||||
|
@@ -88,6 +88,24 @@ public class SubjectInfoBO extends PageInfo implements Serializable {
|
||||
*/
|
||||
private Integer subjectCount;
|
||||
|
||||
/**
|
||||
* 是否被当前用户点赞
|
||||
*/
|
||||
private Boolean liked;
|
||||
|
||||
/**
|
||||
* 当前题目点赞的数量
|
||||
*/
|
||||
private Integer likedCount;
|
||||
|
||||
/**
|
||||
* 下一题
|
||||
*/
|
||||
private Long nextSubjectId;
|
||||
/**
|
||||
* 上一题
|
||||
*/
|
||||
private Long lastSubjectId;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.landaiqing.subject.domain.entity;
|
||||
|
||||
import com.landaiqing.subject.common.entity.PageInfo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -12,7 +13,7 @@ import java.util.Date;
|
||||
* @since 2024-03-08 13:44:59
|
||||
*/
|
||||
@Data
|
||||
public class SubjectLikedBO implements Serializable {
|
||||
public class SubjectLikedBO extends PageInfo implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package com.landaiqing.subject.domain.job;
|
||||
|
||||
import com.landaiqing.subject.domain.service.SubjectLikedDomainService;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 同步点赞数据
|
||||
*
|
||||
* @author landaiqing
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SyncLikedJob {
|
||||
@Resource
|
||||
private SubjectLikedDomainService subjectLikedDomainService;
|
||||
|
||||
|
||||
/**
|
||||
* 同步点赞任务
|
||||
*/
|
||||
@XxlJob("syncLikedJobHandler")
|
||||
public void syncLikedJobHandler() throws Exception {
|
||||
XxlJobHelper.log("syncLikedJobHandler.starter");
|
||||
try {
|
||||
subjectLikedDomainService.syncLiked();
|
||||
} catch (Exception e) {
|
||||
XxlJobHelper.log("syncLikedJobHandler.error", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,11 +1,15 @@
|
||||
package com.landaiqing.subject.domain.redis;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.ZSetOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -105,10 +109,33 @@ public class RedisUtil {
|
||||
}
|
||||
|
||||
|
||||
public Set rankWithScore(String key,long start,long end){
|
||||
public Set rankWithScore(String key, long start, long end) {
|
||||
Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
public void putHash(String key, String hashKey, Object hashVal) {
|
||||
redisTemplate.opsForHash().put(key, hashKey, hashVal);
|
||||
}
|
||||
|
||||
public Integer getInt(String key) {
|
||||
return (Integer) redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
public void increment(String key, Integer count) {
|
||||
redisTemplate.opsForValue().increment(key,count);
|
||||
}
|
||||
public Map<Object, Object> getHashAndDelete(String key) {
|
||||
Map<Object, Object> map = new HashMap<>();
|
||||
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, ScanOptions.NONE);
|
||||
while (cursor.hasNext()) {
|
||||
Map.Entry<Object, Object> entry = cursor.next();
|
||||
Object hashKey = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
map.put(hashKey, value);
|
||||
redisTemplate.opsForHash().delete(key, hashKey);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.landaiqing.subject.domain.service;
|
||||
|
||||
import com.landaiqing.subject.common.entity.PageResult;
|
||||
import com.landaiqing.subject.domain.entity.SubjectLikedBO;
|
||||
|
||||
|
||||
@@ -14,7 +15,17 @@ public interface SubjectLikedDomainService {
|
||||
/**
|
||||
* 添加 题目点赞表 信息
|
||||
*/
|
||||
Boolean add(SubjectLikedBO subjectLikedBO);
|
||||
void add(SubjectLikedBO subjectLikedBO);
|
||||
|
||||
/**
|
||||
* 获取当前是否被点赞过
|
||||
*/
|
||||
Boolean isLiked(String subjectId, String userId);
|
||||
|
||||
/**
|
||||
* 获取点赞数量
|
||||
*/
|
||||
Integer getLikedCount(String subjectId);
|
||||
|
||||
/**
|
||||
* 更新 题目点赞表 信息
|
||||
@@ -25,5 +36,10 @@ public interface SubjectLikedDomainService {
|
||||
* 删除 题目点赞表 信息
|
||||
*/
|
||||
Boolean delete(SubjectLikedBO subjectLikedBO);
|
||||
/**
|
||||
* 同步点赞数据
|
||||
*/
|
||||
void syncLiked();
|
||||
|
||||
PageResult<SubjectLikedBO> getSubjectLikedPage(SubjectLikedBO subjectLikedBO);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import com.landaiqing.subject.domain.handler.subject.SubjectTypeHandler;
|
||||
import com.landaiqing.subject.domain.handler.subject.SubjectTypeHandlerFactory;
|
||||
import com.landaiqing.subject.domain.redis.RedisUtil;
|
||||
import com.landaiqing.subject.domain.service.SubjectInfoDomainService;
|
||||
import com.landaiqing.subject.domain.service.SubjectLikedDomainService;
|
||||
import com.landaiqing.subject.infra.basic.entity.SubjectInfo;
|
||||
import com.landaiqing.subject.infra.basic.entity.SubjectInfoEs;
|
||||
import com.landaiqing.subject.infra.basic.entity.SubjectLabel;
|
||||
@@ -54,6 +55,9 @@ public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Resource
|
||||
private SubjectLikedDomainService subjectLikedDomainService;
|
||||
|
||||
private static final String RANK_KEY = "subject_rank";
|
||||
|
||||
|
||||
@@ -148,6 +152,8 @@ public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {
|
||||
List<SubjectLabel> labelList = subjectLabelService.batchQueryById(labelIdList);
|
||||
List<String> labelNameList = labelList.stream().map(SubjectLabel::getLabelName).collect(Collectors.toList());
|
||||
bo.setLabelName(labelNameList);
|
||||
bo.setLiked(subjectLikedDomainService.isLiked(subjectInfoBO.getId().toString(), LoginUtil.getLoginId()));
|
||||
bo.setLikedCount(subjectLikedDomainService.getLikedCount(subjectInfoBO.getId().toString()));
|
||||
return bo;
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,25 @@
|
||||
package com.landaiqing.subject.domain.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.landaiqing.subject.common.entity.PageResult;
|
||||
import com.landaiqing.subject.common.enums.IsDeletedFlagEnum;
|
||||
import com.landaiqing.subject.common.enums.SubjectLikedStatusEnum;
|
||||
import com.landaiqing.subject.common.util.LoginUtil;
|
||||
import com.landaiqing.subject.domain.convert.SubjectLikedBOConverter;
|
||||
import com.landaiqing.subject.domain.entity.SubjectLikedBO;
|
||||
import com.landaiqing.subject.domain.redis.RedisUtil;
|
||||
import com.landaiqing.subject.domain.service.SubjectLikedDomainService;
|
||||
import com.landaiqing.subject.infra.basic.entity.SubjectLiked;
|
||||
import com.landaiqing.subject.infra.basic.service.SubjectLikedService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 题目点赞表 领域service实现了
|
||||
@@ -23,12 +33,53 @@ public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService
|
||||
|
||||
@Resource
|
||||
private SubjectLikedService subjectLikedService;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private static final String SUBJECT_LIKED_KEY = "subject.liked";
|
||||
private static final String SUBJECT_LIKED_COUNT_KEY = "subject.liked.count";
|
||||
private static final String SUBJECT_LIKED_DETAIL_KEY = "subject.liked.detail";
|
||||
|
||||
@Override
|
||||
public Boolean add(SubjectLikedBO subjectLikedBO) {
|
||||
SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
|
||||
subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
||||
return subjectLikedService.insert(subjectLiked) > 0;
|
||||
public void add(SubjectLikedBO subjectLikedBO) {
|
||||
Long subjectId = subjectLikedBO.getSubjectId();
|
||||
String likeUserId = subjectLikedBO.getLikeUserId();
|
||||
Integer status = subjectLikedBO.getStatus();
|
||||
String hashKey = buildSubjectLikedKey(subjectId.toString(), likeUserId);
|
||||
redisUtil.putHash(SUBJECT_LIKED_KEY, hashKey, status);
|
||||
String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;
|
||||
String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + likeUserId;
|
||||
if (SubjectLikedStatusEnum.LIKED.getCode() == status) {
|
||||
redisUtil.increment(countKey, 1);
|
||||
redisUtil.set(detailKey, "1");
|
||||
} else {
|
||||
Integer count = redisUtil.getInt(countKey);
|
||||
if (Objects.isNull(count) || count <= 0) {
|
||||
return;
|
||||
}
|
||||
redisUtil.increment(countKey, -1);
|
||||
redisUtil.del(detailKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isLiked(String subjectId, String userId) {
|
||||
String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;
|
||||
return redisUtil.exist(detailKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getLikedCount(String subjectId) {
|
||||
String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;
|
||||
Integer count = redisUtil.getInt(countKey);
|
||||
if (Objects.isNull(count) || count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return redisUtil.getInt(countKey);
|
||||
}
|
||||
|
||||
private String buildSubjectLikedKey(String subjectId, String userId) {
|
||||
return subjectId + ":" + userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,4 +96,52 @@ public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService
|
||||
return subjectLikedService.update(subjectLiked) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncLiked() {
|
||||
Map<Object, Object> subjectLikedMap = redisUtil.getHashAndDelete(SUBJECT_LIKED_KEY);
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("syncLiked.subjectLikedMap:{}", JSON.toJSONString(subjectLikedMap));
|
||||
}
|
||||
if (MapUtils.isEmpty(subjectLikedMap)) {
|
||||
return;
|
||||
}
|
||||
//批量同步到数据库
|
||||
List<SubjectLiked> subjectLikedList = new LinkedList<>();
|
||||
subjectLikedMap.forEach((key, val) -> {
|
||||
SubjectLiked subjectLiked = new SubjectLiked();
|
||||
String[] keyArr = key.toString().split(":");
|
||||
String subjectId = keyArr[0];
|
||||
String likedUser = keyArr[1];
|
||||
subjectLiked.setSubjectId(Long.valueOf(subjectId));
|
||||
subjectLiked.setLikeUserId(likedUser);
|
||||
subjectLiked.setStatus(Integer.valueOf(val.toString()));
|
||||
subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
||||
subjectLikedList.add(subjectLiked);
|
||||
});
|
||||
subjectLikedService.batchInsert(subjectLikedList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<SubjectLikedBO> getSubjectLikedPage(SubjectLikedBO subjectLikedBO) {
|
||||
PageResult<SubjectLikedBO> pageResult = new PageResult<>();
|
||||
pageResult.setPageNo(subjectLikedBO.getPageNo());
|
||||
pageResult.setPageSize(subjectLikedBO.getPageSize());
|
||||
int start = (subjectLikedBO.getPageNo() - 1) * subjectLikedBO.getPageSize();
|
||||
SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
|
||||
subjectLiked.setLikeUserId(LoginUtil.getLoginId());
|
||||
int count = subjectLikedService.countByCondition(subjectLiked);
|
||||
if (count == 0) {
|
||||
return pageResult;
|
||||
}
|
||||
List<SubjectLiked> subjectLikedList = subjectLikedService.queryPage(subjectLiked, start,
|
||||
subjectLikedBO.getPageSize());
|
||||
List<SubjectLikedBO> subjectInfoBOS = SubjectLikedBOConverter.INSTANCE.convertListInfoToBO(subjectLikedList);
|
||||
|
||||
|
||||
|
||||
pageResult.setRecords(subjectInfoBOS);
|
||||
pageResult.setTotal(count);
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user