fix (farm): 首页,基地/地块 (补充提交)
- 优先从缓存中获取地块信息 - 项目启动,预加载地块
This commit is contained in:
@@ -218,34 +218,11 @@ public class HomeServiceImpl implements HomeService {
|
||||
|
||||
List<PlotInfoDO> plotList = plotInfoService.getPlotInfos(baseObj.getId(), baseObj.getName());
|
||||
List<PlotInfo> targetList = BeanUtils.toBean(plotList, PlotInfo.class);
|
||||
targetList.stream().forEach(e -> {
|
||||
targetList.forEach(e -> {
|
||||
List<PlotPopupFrame> plotPopupFrame = this.getPlotPopupFrame(e.getPlotId(), e.getManager());
|
||||
e.setPlotPopupFrames(plotPopupFrame.get(0));
|
||||
});
|
||||
|
||||
// for (PlotInfoDO e : plotList) {
|
||||
// String employeeName = personnelManagementService.getEmployeeNameMap(employeeNameMap, e.getEmployeeId());
|
||||
// 地块详情 (包含计划信息)
|
||||
// PlotOrCropInfo plotOrCropInfo = this.getPlotOrCropInfoList(e,"地块详情",employeeName);
|
||||
// 地块浮框信息
|
||||
// List<PlotPopupFrame> plotPopupFrame = this.getPlotPopupFrame(e.getId(), employeeNameMap);
|
||||
// 户主流转信息
|
||||
// List<PlotLesseeDetailsRespVO> lesseeList = plotInfoService.getPlotLesseeList(e.getId());
|
||||
|
||||
// PlotInfo t = new PlotInfo();
|
||||
// t.setBaseId(e.getBaseId());
|
||||
// t.setBaseName(baseObj.getName());
|
||||
// t.setPlotId(e.getPlotId());
|
||||
// t.setPlotName(e.getPlotName());
|
||||
// t.setPlotArea(BigDecimalUtil.roundedViaMath(e.getPlotArea()));
|
||||
// t.setManager(employeeName);
|
||||
// t.setPoint(e.getPoint());
|
||||
// t.setPlotColor(e.getPlotColor());
|
||||
// t.setPlotPopupFrames(plotPopupFrame.get(0));
|
||||
// t.setPlotOrCropInfo(plotOrCropInfo);
|
||||
// t.setLesseeList(lesseeList);
|
||||
// targetList.add(t);
|
||||
// }
|
||||
return targetList;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,20 +90,31 @@ public class PlotInfoCacheService {
|
||||
}
|
||||
|
||||
try {
|
||||
// 添加调试日志
|
||||
log.debug("开始批量缓存地块信息,数量: {}", plotInfoList.size());
|
||||
for (PlotInfoDO plotInfo : plotInfoList) {
|
||||
if (plotInfo != null) {
|
||||
log.debug("处理地块: id={}, tenantId={}, baseId={}, plotId={}",
|
||||
plotInfo.getId(), plotInfo.getTenantId(), plotInfo.getBaseId(), plotInfo.getPlotId());
|
||||
}
|
||||
}
|
||||
|
||||
// 使用管道批量操作
|
||||
stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
List<Object> results = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
for (PlotInfoDO plotInfo : plotInfoList) {
|
||||
if (plotInfo != null) {
|
||||
String plotKey = buildPlotKey(plotInfo.getId());
|
||||
Map<String, String> hashData = toHashData(plotInfo);
|
||||
|
||||
log.debug("设置Hash键: {}", plotKey);
|
||||
|
||||
// 批量设置 Hash 字段
|
||||
connection.hashCommands().hMSet(
|
||||
plotKey.getBytes(StandardCharsets.UTF_8),
|
||||
hashData.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
e -> e.getKey().getBytes(StandardCharsets.UTF_8),
|
||||
e -> e.getValue().getBytes(StandardCharsets.UTF_8)
|
||||
e -> e.getValue() != null ? e.getValue().getBytes(StandardCharsets.UTF_8) : "".getBytes()
|
||||
))
|
||||
);
|
||||
|
||||
@@ -113,14 +124,16 @@ public class PlotInfoCacheService {
|
||||
CACHE_TTL.getSeconds()
|
||||
);
|
||||
|
||||
// 更新索引
|
||||
updateIndexInPipeline(connection, plotInfo);
|
||||
// 更新所有索引
|
||||
updateAllIndexesInPipeline(connection, plotInfo);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
log.debug("批量缓存完成,管道操作结果数量: {}", results.size());
|
||||
log.debug("批量缓存地块信息(Hash)成功,数量: {}", plotInfoList.size());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("批量缓存地块信息失败", e);
|
||||
}
|
||||
@@ -456,19 +469,27 @@ public class PlotInfoCacheService {
|
||||
|
||||
// ==================== 管道操作辅助方法 ====================
|
||||
|
||||
/**
|
||||
* 更新索引(确保包含集合索引)
|
||||
*/
|
||||
private void updateIndexInPipeline(RedisConnection connection, PlotInfoDO plotInfo) {
|
||||
// 租户索引集合
|
||||
if (StringUtils.hasText(plotInfo.getTenantId())) {
|
||||
String tenantKey = buildTenantPlotsKey(plotInfo.getTenantId());
|
||||
connection.setCommands().sAdd(tenantKey.getBytes(StandardCharsets.UTF_8),
|
||||
plotInfo.getId().getBytes(StandardCharsets.UTF_8));
|
||||
connection.keyCommands().expire(tenantKey.getBytes(StandardCharsets.UTF_8), CACHE_TTL.getSeconds());
|
||||
}
|
||||
|
||||
// 基地索引集合
|
||||
if (StringUtils.hasText(plotInfo.getBaseId())) {
|
||||
String baseKey = buildBasePlotsKey(plotInfo.getBaseId());
|
||||
connection.setCommands().sAdd(baseKey.getBytes(StandardCharsets.UTF_8),
|
||||
plotInfo.getId().getBytes(StandardCharsets.UTF_8));
|
||||
connection.keyCommands().expire(baseKey.getBytes(StandardCharsets.UTF_8), CACHE_TTL.getSeconds());
|
||||
}
|
||||
|
||||
// plotId 索引
|
||||
if (StringUtils.hasText(plotInfo.getPlotId())) {
|
||||
String plotIdIndexKey = buildPlotIdIndexKey(plotInfo.getPlotId());
|
||||
connection.stringCommands().set(
|
||||
@@ -480,6 +501,62 @@ public class PlotInfoCacheService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在管道中更新所有索引 - 修复版本
|
||||
*/
|
||||
private void updateAllIndexesInPipeline(RedisConnection connection, PlotInfoDO plotInfo) {
|
||||
// 1. 更新租户索引集合 - 确保这里正确执行
|
||||
if (StringUtils.hasText(plotInfo.getTenantId())) {
|
||||
String tenantKey = buildTenantPlotsKey(plotInfo.getTenantId());
|
||||
log.debug("添加租户索引: {} -> {}", tenantKey, plotInfo.getId());
|
||||
|
||||
connection.setCommands().sAdd(
|
||||
tenantKey.getBytes(StandardCharsets.UTF_8),
|
||||
plotInfo.getId().getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
// 设置集合的过期时间
|
||||
connection.keyCommands().expire(
|
||||
tenantKey.getBytes(StandardCharsets.UTF_8),
|
||||
CACHE_TTL.getSeconds()
|
||||
);
|
||||
} else {
|
||||
log.debug("地块 {} 没有tenantId,跳过租户索引", plotInfo.getId());
|
||||
}
|
||||
|
||||
// 2. 更新基地索引集合
|
||||
if (StringUtils.hasText(plotInfo.getBaseId())) {
|
||||
String baseKey = buildBasePlotsKey(plotInfo.getBaseId());
|
||||
log.debug("添加基地索引: {} -> {}", baseKey, plotInfo.getId());
|
||||
|
||||
connection.setCommands().sAdd(
|
||||
baseKey.getBytes(StandardCharsets.UTF_8),
|
||||
plotInfo.getId().getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
// 设置集合的过期时间
|
||||
connection.keyCommands().expire(
|
||||
baseKey.getBytes(StandardCharsets.UTF_8),
|
||||
CACHE_TTL.getSeconds()
|
||||
);
|
||||
} else {
|
||||
log.debug("地块 {} 没有baseId,跳过基地索引", plotInfo.getId());
|
||||
}
|
||||
|
||||
// 3. 更新 plotId 到主键的映射索引
|
||||
if (StringUtils.hasText(plotInfo.getPlotId())) {
|
||||
String plotIdIndexKey = buildPlotIdIndexKey(plotInfo.getPlotId());
|
||||
log.debug("添加plotId索引: {} -> {}", plotIdIndexKey, plotInfo.getId());
|
||||
|
||||
connection.stringCommands().set(
|
||||
plotIdIndexKey.getBytes(StandardCharsets.UTF_8),
|
||||
plotInfo.getId().getBytes(StandardCharsets.UTF_8),
|
||||
Expiration.from(CACHE_TTL),
|
||||
RedisStringCommands.SetOption.UPSERT
|
||||
);
|
||||
} else {
|
||||
log.debug("地块 {} 没有plotId,跳过plotId索引", plotInfo.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupIndexesInPipeline(RedisConnection connection, PlotInfoDO plotInfo) {
|
||||
if (StringUtils.hasText(plotInfo.getTenantId())) {
|
||||
String tenantKey = buildTenantPlotsKey(plotInfo.getTenantId());
|
||||
@@ -519,18 +596,18 @@ public class PlotInfoCacheService {
|
||||
// ==================== 键构建方法 ====================
|
||||
|
||||
private String buildPlotKey(String id) {
|
||||
return CACHE_PREFIX + "info:" + id;
|
||||
return CACHE_PREFIX + "info:" + id; // plots:info:{id}
|
||||
}
|
||||
|
||||
private String buildTenantPlotsKey(String tenantId) {
|
||||
return CACHE_PREFIX + "tenant:" + tenantId;
|
||||
return CACHE_PREFIX + "tenant:" + tenantId; // plots:tenant:{tenantId}
|
||||
}
|
||||
|
||||
private String buildBasePlotsKey(String baseId) {
|
||||
return CACHE_PREFIX + "base:" + baseId;
|
||||
return CACHE_PREFIX + "base:" + baseId; // plots:base:{baseId}
|
||||
}
|
||||
|
||||
private String buildPlotIdIndexKey(String plotId) {
|
||||
return CACHE_PREFIX + "index:plotId:" + plotId;
|
||||
return CACHE_PREFIX + "index:plotId:" + plotId; // plots:index:plotId:{plotId}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ public interface PlotInfoService {
|
||||
*/
|
||||
List<PlotInfoDO> getPlotInfos(String baseId);
|
||||
List<PlotInfoDO> getPlotInfos(String baseId,String baseName);
|
||||
/**
|
||||
* 通过基地ID获取地块信息(缓存优先)
|
||||
*/
|
||||
List<PlotInfoDO> getPlotInfosByCatch(String baseId);
|
||||
|
||||
/**
|
||||
* 地块集合
|
||||
* @param baseId
|
||||
|
||||
@@ -9,26 +9,22 @@ import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.baseinfo.v
|
||||
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.baseinfo.vo.wx.RegularPlotInfoRespVO;
|
||||
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
|
||||
import cn.iocoder.yudao.module.farm.dal.dataobject.plotinfo.PlotInfoDO;
|
||||
import cn.iocoder.yudao.module.farm.dal.dataobject.plotinfo.PlotLesseeDO;
|
||||
import cn.iocoder.yudao.module.farm.dal.mysql.baseinfo.BaseInfoMapper;
|
||||
import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper;
|
||||
import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotLesseeMapper;
|
||||
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
|
||||
import cn.iocoder.yudao.module.farm.service.personnelmanagement.PersonnelManagementService;
|
||||
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
|
||||
import cn.iocoder.yudao.module.farm.utils.BigDecimalUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
||||
@@ -40,6 +36,7 @@ import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.*;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Validated
|
||||
public class PlotInfoServiceImpl implements PlotInfoService {
|
||||
@@ -152,12 +149,14 @@ public class PlotInfoServiceImpl implements PlotInfoService {
|
||||
|
||||
@Override
|
||||
public List<PlotInfoDO> getPlotInfos(String baseId) {
|
||||
List<PlotInfoDO> list = this.getPlotInfosByCatch(baseId);
|
||||
|
||||
// 员工集合 <id,name>
|
||||
Map<String, String> employeeNameMap = personnelManagementService.getEmployeeNameMap();
|
||||
|
||||
List<PlotInfoDO> list = plotInfoMapper.selectList("base_id", baseId);
|
||||
list.forEach(e -> {
|
||||
e.setEmployeeName(employeeNameMap.get(e.getEmployeeId()));
|
||||
e.setManager(employeeNameMap.get(e.getEmployeeId()));
|
||||
e.setPlotArea(BigDecimalUtil.roundedViaMath(e.getPlotArea()));
|
||||
});
|
||||
|
||||
return list;
|
||||
@@ -165,10 +164,10 @@ public class PlotInfoServiceImpl implements PlotInfoService {
|
||||
|
||||
@Override
|
||||
public List<PlotInfoDO> getPlotInfos(String baseId, String baseName) {
|
||||
List<PlotInfoDO> list = this.getPlotInfosByCatch(baseId);
|
||||
|
||||
// 员工集合 <id,name>
|
||||
Map<String, String> employeeNameMap = personnelManagementService.getEmployeeNameMap();
|
||||
|
||||
List<PlotInfoDO> list = plotInfoMapper.selectList("base_id", baseId);
|
||||
list.forEach(e -> {
|
||||
e.setEmployeeName(employeeNameMap.get(e.getEmployeeId()));
|
||||
e.setManager(employeeNameMap.get(e.getEmployeeId()));
|
||||
@@ -179,6 +178,66 @@ public class PlotInfoServiceImpl implements PlotInfoService {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlotInfoDO> getPlotInfosByCatch(String baseId) {
|
||||
// 参数校验
|
||||
if (!StringUtils.hasText(baseId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<PlotInfoDO> result = null;
|
||||
|
||||
try {
|
||||
// 1. 首先尝试从缓存获取
|
||||
result = pCatchService.getPlotsByBaseId(baseId);
|
||||
|
||||
// 2. 如果缓存中存在数据,直接返回
|
||||
if (!CollectionUtils.isEmpty(result)) {
|
||||
log.debug("从缓存获取地块信息成功,基地ID: {},数量: {}", baseId, result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
log.debug("缓存未命中,从数据库查询地块信息,基地ID: {}", baseId);
|
||||
|
||||
// 3. 缓存中没有,从数据库查询
|
||||
result = plotInfoMapper.selectList("base_id", baseId);
|
||||
|
||||
if (CollectionUtils.isEmpty(result)) {
|
||||
log.debug("数据库中也未查询到地块信息,基地ID: {}", baseId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 4. 将数据库查询结果写入缓存
|
||||
try {
|
||||
pCatchService.batchCreateOrUpdatePlotInfo(result);
|
||||
log.debug("成功将地块信息写入缓存,基地ID: {},数量: {}", baseId, result.size());
|
||||
} catch (Exception cacheException) {
|
||||
// 缓存写入失败不应该影响主流程,只记录日志
|
||||
log.warn("写入缓存失败,但不影响数据返回,基地ID: {}", baseId, cacheException);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取地块信息异常,基地ID: {}", baseId, e);
|
||||
// 发生异常时,尝试从数据库直接查询作为降级方案
|
||||
return fallbackToDatabase(baseId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 降级方案:直接从数据库查询
|
||||
*/
|
||||
private List<PlotInfoDO> fallbackToDatabase(String baseId) {
|
||||
try {
|
||||
List<PlotInfoDO> result = plotInfoMapper.selectList("base_id", baseId);
|
||||
return result != null ? result : Collections.emptyList();
|
||||
} catch (Exception e) {
|
||||
log.error("降级查询数据库也失败,基地ID: {}", baseId, e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlotInfoDO> getPlotInfos() {
|
||||
LambdaQueryWrapper<PlotInfoDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
Reference in New Issue
Block a user