增加定时任务删除不存在的图标
This commit is contained in:
@@ -3,9 +3,11 @@ package com.onekeycall.videotablet;
|
|||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@EnableAsync // 启用异步支持
|
||||||
@MapperScan({"com.onekeycall.videotablet.mapper",})
|
@MapperScan({"com.onekeycall.videotablet.mapper",})
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class VideoTabletApplication {
|
public class VideoTabletApplication {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.onekeycall.videotablet.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
public class AsyncConfig implements AsyncConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Executor getAsyncExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(10); // 核心线程数
|
||||||
|
executor.setMaxPoolSize(20); // 最大线程数
|
||||||
|
executor.setQueueCapacity(100); // 队列容量
|
||||||
|
executor.setThreadNamePrefix("async-task-");
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.onekeycall.videotablet.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SchedulerConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
// taskRegistrar.setScheduler(taskExecutor());
|
||||||
|
|
||||||
|
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||||
|
scheduler.setPoolSize(10); // 核心线程数
|
||||||
|
scheduler.setThreadNamePrefix("scheduled-task-"); // 线程名前缀
|
||||||
|
scheduler.setAwaitTerminationSeconds(60); // 等待终止时间
|
||||||
|
scheduler.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成
|
||||||
|
scheduler.initialize(); // 初始化调度器
|
||||||
|
taskRegistrar.setTaskScheduler(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Executor taskExecutor() {
|
||||||
|
// 创建包含10个线程的线程池
|
||||||
|
return Executors.newScheduledThreadPool(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,16 +3,10 @@ package com.onekeycall.videotablet.controller.user;
|
|||||||
import com.onekeycall.videotablet.config.PushIdConfig;
|
import com.onekeycall.videotablet.config.PushIdConfig;
|
||||||
import com.onekeycall.videotablet.controller.pub.LoginController;
|
import com.onekeycall.videotablet.controller.pub.LoginController;
|
||||||
import com.onekeycall.videotablet.dto.TokenPair;
|
import com.onekeycall.videotablet.dto.TokenPair;
|
||||||
import com.onekeycall.videotablet.entity.DeviceApkInfo;
|
import com.onekeycall.videotablet.entity.*;
|
||||||
import com.onekeycall.videotablet.entity.DeviceInfo;
|
|
||||||
import com.onekeycall.videotablet.entity.DeviceLocation;
|
|
||||||
import com.onekeycall.videotablet.entity.User;
|
|
||||||
import com.onekeycall.videotablet.gson.GsonUtils;
|
import com.onekeycall.videotablet.gson.GsonUtils;
|
||||||
import com.onekeycall.videotablet.result.Result;
|
import com.onekeycall.videotablet.result.Result;
|
||||||
import com.onekeycall.videotablet.service.DeviceApkInfoService;
|
import com.onekeycall.videotablet.service.*;
|
||||||
import com.onekeycall.videotablet.service.DeviceLocationService;
|
|
||||||
import com.onekeycall.videotablet.service.DeviceSnService;
|
|
||||||
import com.onekeycall.videotablet.service.UserService;
|
|
||||||
import com.onekeycall.videotablet.utils.DevicePushUtils;
|
import com.onekeycall.videotablet.utils.DevicePushUtils;
|
||||||
import com.onekeycall.videotablet.utils.JwtUtil;
|
import com.onekeycall.videotablet.utils.JwtUtil;
|
||||||
import com.onekeycall.videotablet.utils.TextUtils;
|
import com.onekeycall.videotablet.utils.TextUtils;
|
||||||
@@ -26,7 +20,9 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
@@ -45,6 +41,8 @@ public class UserController {
|
|||||||
private DeviceLocationService deviceLocationService;
|
private DeviceLocationService deviceLocationService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeviceApkInfoService deviceApkInfoService;
|
private DeviceApkInfoService deviceApkInfoService;
|
||||||
|
@Autowired
|
||||||
|
private ApkIconService apkIconService;
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger(LoginController.class);
|
Logger logger = LoggerFactory.getLogger(LoginController.class);
|
||||||
|
|
||||||
@@ -190,6 +188,14 @@ public class UserController {
|
|||||||
if (deviceApkInfo == null || deviceApkInfo.getApkList() == null) {
|
if (deviceApkInfo == null || deviceApkInfo.getApkList() == null) {
|
||||||
return Result.notFound().message("未找到设备APK信息");
|
return Result.notFound().message("未找到设备APK信息");
|
||||||
}
|
}
|
||||||
|
List<ApkInfo> apkList = deviceApkInfo.getApkList();
|
||||||
|
apkList.stream().forEach(new Consumer<ApkInfo>() {
|
||||||
|
@Override
|
||||||
|
public void accept(ApkInfo apkInfo) {
|
||||||
|
Optional<ApkIconFileInfo> apkIconFileInfo = apkIconService.findMaxVersionCodeByPackageName(apkInfo.getPackageName());
|
||||||
|
apkIconFileInfo.ifPresent(iconFileInfo -> apkInfo.setIconUrl(iconFileInfo.getFileName()));
|
||||||
|
}
|
||||||
|
});
|
||||||
return Result.ok().data(deviceApkInfo.getApkList());
|
return Result.ok().data(deviceApkInfo.getApkList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
package com.onekeycall.videotablet.repository;
|
package com.onekeycall.videotablet.repository;
|
||||||
|
|
||||||
import com.onekeycall.videotablet.entity.ApkIconFileInfo;
|
import com.onekeycall.videotablet.entity.ApkIconFileInfo;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface ApkIconRepository extends JpaRepository<ApkIconFileInfo, Long> {
|
public interface ApkIconRepository extends JpaRepository<ApkIconFileInfo, Long> {
|
||||||
|
|
||||||
@@ -15,4 +21,23 @@ public interface ApkIconRepository extends JpaRepository<ApkIconFileInfo, Long>
|
|||||||
|
|
||||||
List<ApkIconFileInfo> findByPackageName(String packageName);
|
List<ApkIconFileInfo> findByPackageName(String packageName);
|
||||||
|
|
||||||
|
List<ApkIconFileInfo> findAll();
|
||||||
|
|
||||||
|
Integer deleteApkIconFileInfosById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过packageName查找version_code最大的一条记录
|
||||||
|
* 使用 JPQL 并限制结果数量,但JPQL不支持LIMIT,故用Pageable
|
||||||
|
*/
|
||||||
|
@Query("SELECT e FROM ApkIconFileInfo e WHERE e.packageName = :pkgName ORDER BY e.versionCode DESC")
|
||||||
|
Page<ApkIconFileInfo> findTopByPackageNameOrderByVersionCodeDesc(@Param("pkgName") String packageName, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在Service中调用该方法,获取第一条记录
|
||||||
|
*/
|
||||||
|
default Optional<ApkIconFileInfo> findMaxVersionCodeByPackageName(String packageName) {
|
||||||
|
PageRequest pageRequest = PageRequest.of(0, 1); // 获取第一页的第一条记录
|
||||||
|
Page<ApkIconFileInfo> page = findTopByPackageNameOrderByVersionCodeDesc(packageName, pageRequest);
|
||||||
|
return page.getContent().stream().findFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import com.onekeycall.videotablet.entity.ApkIconFileInfo;
|
|||||||
import com.onekeycall.videotablet.repository.ApkIconRepository;
|
import com.onekeycall.videotablet.repository.ApkIconRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ApkIconService {
|
public class ApkIconService {
|
||||||
@@ -27,4 +29,17 @@ public class ApkIconService {
|
|||||||
public List<ApkIconFileInfo> findByPackageName(String packageName) {
|
public List<ApkIconFileInfo> findByPackageName(String packageName) {
|
||||||
return apkIconRepository.findByPackageName(packageName);
|
return apkIconRepository.findByPackageName(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<ApkIconFileInfo> findMaxVersionCodeByPackageName(String packageName) {
|
||||||
|
return apkIconRepository.findMaxVersionCodeByPackageName(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ApkIconFileInfo> findAll() {
|
||||||
|
return apkIconRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Integer deleteApkIconFileInfosById(Long id) {
|
||||||
|
return apkIconRepository.deleteApkIconFileInfosById(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.onekeycall.videotablet.task;
|
||||||
|
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AsyncScheduledTasks {
|
||||||
|
|
||||||
|
// @Async // 异步执行
|
||||||
|
// @Scheduled(fixedRate = 5000)
|
||||||
|
// public void asyncTask() {
|
||||||
|
// try {
|
||||||
|
// Thread.sleep(3000); // 模拟耗时操作
|
||||||
|
// System.out.println("异步任务执行: " + Thread.currentThread().getName());
|
||||||
|
// } catch (InterruptedException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.onekeycall.videotablet.task;
|
||||||
|
|
||||||
|
import com.onekeycall.videotablet.config.FilePath;
|
||||||
|
import com.onekeycall.videotablet.entity.ApkIconFileInfo;
|
||||||
|
import com.onekeycall.videotablet.repository.ApkIconRepository;
|
||||||
|
import com.onekeycall.videotablet.service.ApkIconService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ScheduledTasks {
|
||||||
|
@Autowired
|
||||||
|
private ApkIconService apkIconService;
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);
|
||||||
|
|
||||||
|
// // 固定速率:每隔5秒执行一次(从上一次任务开始时间计算)
|
||||||
|
// @Scheduled(fixedRate = 5000)
|
||||||
|
// public void taskWithFixedRate() {
|
||||||
|
// System.out.println("固定速率任务执行: " + new Date());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 固定延迟:上一次任务结束后延迟3秒执行
|
||||||
|
// @Scheduled(fixedDelay = 3000)
|
||||||
|
// public void taskWithFixedDelay() {
|
||||||
|
// System.out.println("固定延迟任务执行: " + new Date());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 初始延迟:应用启动后延迟10秒开始,然后每隔5秒执行一次
|
||||||
|
// @Scheduled(initialDelay = 10000, fixedRate = 5000)
|
||||||
|
// public void taskWithInitialDelay() {
|
||||||
|
// System.out.println("带初始延迟的任务执行: " + new Date());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 使用Cron表达式:每天中午12点执行
|
||||||
|
@Scheduled(cron = "0 0 0 * * ?")
|
||||||
|
// @Scheduled(initialDelay = 10000)
|
||||||
|
@Async
|
||||||
|
public void taskWithCron() {
|
||||||
|
logger.info("Cron表达式任务执行: " + new Date());
|
||||||
|
List<ApkIconFileInfo> apkIconFileInfoList = apkIconService.findAll();
|
||||||
|
for (ApkIconFileInfo apkIconFileInfo : apkIconFileInfoList) {
|
||||||
|
logger.info("检查图标文件是否存在: " + apkIconFileInfo);
|
||||||
|
File file = new File(FilePath.getApkIconPath() + apkIconFileInfo.getFileName());
|
||||||
|
if (!file.exists()) {
|
||||||
|
Integer i = apkIconService.deleteApkIconFileInfosById(apkIconFileInfo.getId());
|
||||||
|
logger.info("删除图标数据: id = " + apkIconFileInfo.getId() + " Successful =" + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user