添加获取项目生产天数接口;添加定时任务,每天自动删除项目缓存

This commit is contained in:
lcj
2025-05-14 18:20:54 +08:00
parent dfcece5841
commit 4c238435d8
10 changed files with 169 additions and 31 deletions

View File

@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/** /**
* 启动程序 * 启动程序
@ -14,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication @SpringBootApplication
@EnableAsync @EnableAsync
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableScheduling
public class DromaraApplication { public class DromaraApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -263,6 +263,7 @@ justauth:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab redirect-uri: ${justauth.address}/social-callback?source=gitlab
# 和风天气 https://dev.qweather.com/
weather: weather:
key-id: T65EAABUXC key-id: T65EAABUXC
project-id: 2JTHPUQ5YY project-id: 2JTHPUQ5YY

View File

@ -0,0 +1,43 @@
package org.dromara.job.cycle;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.project.constant.BusProjectConstant;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
@Slf4j
@Component
public class IncSyncDeleteProjectCache {
@Resource
private StringRedisTemplate stringRedisTemplate;
// 每天凌晨 12 点执行
@Scheduled(cron = "0 0 0 * * ?")
public void run() {
log.info("执行定时任务:清理项目缓存");
// 构建扫描选项
ScanOptions scanOptions = ScanOptions.scanOptions()
.match(BusProjectConstant.PROJECT_CACHE_REDIS_KEY_PREFIX + "*")
.count(1000) // 每次 scan 的数量
.build();
Set<String> keysToDelete = new HashSet<>();
Cursor<byte[]> cursor = stringRedisTemplate.getConnectionFactory()
.getConnection()
.scan(scanOptions);
while (cursor.hasNext()) {
keysToDelete.add(new String(cursor.next()));
}
// 批量删除
if (!keysToDelete.isEmpty()) {
stringRedisTemplate.delete(keysToDelete);
}
}
}

View File

@ -3,6 +3,7 @@ package org.dromara.manager.weathermanager;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpResponse;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -21,6 +22,7 @@ import java.util.Base64;
* @author lcj * @author lcj
* @date 2025/5/12 17:33 * @date 2025/5/12 17:33
*/ */
@Slf4j
@Component @Component
public class WeatherManager { public class WeatherManager {
@ -48,6 +50,7 @@ public class WeatherManager {
.execute()) { .execute()) {
int status = result.getStatus(); int status = result.getStatus();
if (status != HttpStatus.SUCCESS) { if (status != HttpStatus.SUCCESS) {
log.error("获取天气失败,状态码:{}body{}", status, result.body());
throw new ServiceException("获取天气失败,状态码:" + status, HttpStatus.ERROR); throw new ServiceException("获取天气失败,状态码:" + status, HttpStatus.ERROR);
} }
body = result.body(); body = result.body();

View File

@ -11,4 +11,14 @@ public interface BusProjectConstant {
*/ */
String PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX = "project:weather:list"; String PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX = "project:weather:list";
/**
* 项目安全生产天数缓存的 Redis Key 前缀
*/
String PROJECT_SAFETY_DAYS_REDIS_KEY_PREFIX = "project:safetyDays";
/**
* 项目缓存的 Redis Key 前缀
*/
String PROJECT_CACHE_REDIS_KEY_PREFIX = "project";
} }

View File

@ -21,6 +21,7 @@ import org.dromara.project.domain.req.project.BusProjectCreateReq;
import org.dromara.project.domain.req.project.BusProjectQueryReq; import org.dromara.project.domain.req.project.BusProjectQueryReq;
import org.dromara.project.domain.req.project.BusProjectUpdateReq; import org.dromara.project.domain.req.project.BusProjectUpdateReq;
import org.dromara.project.domain.vo.project.BusProjectContractorListVo; import org.dromara.project.domain.vo.project.BusProjectContractorListVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectVo; import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo; import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
@ -131,4 +132,13 @@ public class BusProjectController extends BaseController {
return R.ok(projectService.getWeather(id)); return R.ok(projectService.getWeather(id));
} }
/**
* 查询项目安全天数
*/
@GetMapping("/safetyDay/{id}")
public R<BusProjectSafetyDayVo> getSafetyDay(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(projectService.getSafetyDay(id));
}
} }

View File

@ -0,0 +1,23 @@
package org.dromara.project.domain.vo.project;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/5/14 9:34
*/
@Data
public class BusProjectSafetyDayVo implements Serializable {
@Serial
private static final long serialVersionUID = -1479490255029878315L;
/**
* 安全生产天数
*/
private Integer safetyDay;
}

View File

@ -3,7 +3,6 @@ package org.dromara.project.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
@ -11,6 +10,7 @@ import org.dromara.project.domain.req.project.BusProjectCreateReq;
import org.dromara.project.domain.req.project.BusProjectQueryReq; import org.dromara.project.domain.req.project.BusProjectQueryReq;
import org.dromara.project.domain.req.project.BusProjectUpdateReq; import org.dromara.project.domain.req.project.BusProjectUpdateReq;
import org.dromara.project.domain.vo.project.BusProjectContractorListVo; import org.dromara.project.domain.vo.project.BusProjectContractorListVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectVo; import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo; import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
@ -130,4 +130,12 @@ public interface IBusProjectService extends IService<BusProject> {
*/ */
List<BusProjectWeatherVo> getWeather(Long id); List<BusProjectWeatherVo> getWeather(Long id);
/**
* 获取项目安全天数
*
* @param id 项目id
* @return 安全天数
*/
BusProjectSafetyDayVo getSafetyDay(Long id);
} }

View File

@ -20,6 +20,7 @@ import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.vo.IdAndNameVO; import org.dromara.common.core.domain.vo.IdAndNameVO;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
@ -36,6 +37,7 @@ import org.dromara.project.domain.req.project.BusProjectCreateReq;
import org.dromara.project.domain.req.project.BusProjectQueryReq; import org.dromara.project.domain.req.project.BusProjectQueryReq;
import org.dromara.project.domain.req.project.BusProjectUpdateReq; import org.dromara.project.domain.req.project.BusProjectUpdateReq;
import org.dromara.project.domain.vo.project.BusProjectContractorListVo; import org.dromara.project.domain.vo.project.BusProjectContractorListVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectVo; import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo; import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.mapper.BusProjectMapper; import org.dromara.project.mapper.BusProjectMapper;
@ -85,8 +87,8 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
private final Cache<String, String> WEATHER_CACHE = private final Cache<String, String> WEATHER_CACHE =
Caffeine.newBuilder().initialCapacity(1024) Caffeine.newBuilder().initialCapacity(1024)
.maximumSize(10000L) .maximumSize(10000L)
// 缓存 30 分钟移除 // 缓存 60 分钟移除
.expireAfterWrite(30L, TimeUnit.MINUTES) .expireAfterWrite(60L, TimeUnit.MINUTES)
.build(); .build();
/** /**
@ -532,12 +534,45 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
// 更新本地缓存 // 更新本地缓存
WEATHER_CACHE.put(cacheKey, cacheValue); WEATHER_CACHE.put(cacheKey, cacheValue);
// 更新 Redis 缓存,设置 5 - 10 分钟随机过期,防止雪崩 // 更新 Redis 缓存,设置 5 - 10 分钟随机过期,防止雪崩
int cacheExpireTime = 30 * 60 + RandomUtil.randomInt(0, 300); int cacheExpireTime = 60 * 60 + RandomUtil.randomInt(0, 300);
valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS); valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS);
// 返回结果 // 返回结果
return weatherList; return weatherList;
} }
/**
* 获取项目安全天数
*
* @param id 项目id
* @return 安全天数
*/
@Override
public BusProjectSafetyDayVo getSafetyDay(Long id) {
// 构建缓存 key
String cacheKey = String.format("%s:%s", BusProjectConstant.PROJECT_SAFETY_DAYS_REDIS_KEY_PREFIX, id);
// 查询分布式缓存Redis
ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
String cachedValue = valueOps.get(cacheKey);
if (cachedValue != null) {
// 如果命中Redis返回结果
return JSONUtil.toBean(cachedValue, BusProjectSafetyDayVo.class);
}
BusProject project = this.getById(id);
if (project == null) {
throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND);
}
int days = DateUtils.differentDaysByMillisecond(project.getCreateTime(), new Date());
BusProjectSafetyDayVo safetyDayVo = new BusProjectSafetyDayVo();
safetyDayVo.setSafetyDay(days);
// 更新缓存
String cacheValue = JSONUtil.toJsonStr(safetyDayVo);
// 更新 Redis 缓存
int cacheExpireTime = 12;
valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.HOURS);
// 返回结果
return safetyDayVo;
}
/** /**
* 根据天气图标获取天气类别 * 根据天气图标获取天气类别
* *

View File

@ -150,6 +150,9 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect
List<HseTeamMeeting> teamMeetings = teamMeetingService.lambdaQuery() List<HseTeamMeeting> teamMeetings = teamMeetingService.lambdaQuery()
.eq(HseTeamMeeting::getProjectId, projectId) .eq(HseTeamMeeting::getProjectId, projectId)
.list(); .list();
if (CollUtil.isEmpty(teamMeetings)){
return gisVo;
}
// 获取最新的班组列表 // 获取最新的班组列表
List<HseTeamMeeting> topList = teamMeetings.stream() List<HseTeamMeeting> topList = teamMeetings.stream()
.sorted(Comparator.comparing(HseTeamMeeting::getCreateTime).reversed()) .sorted(Comparator.comparing(HseTeamMeeting::getCreateTime).reversed())