初始化项目
This commit is contained in:
76
xtools-app-sys/xtools-app-sys-scheduled/pom.xml
Normal file
76
xtools-app-sys/xtools-app-sys-scheduled/pom.xml
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-app-sys-scheduled</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools begin -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-web</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-extend begin -->
|
||||
<!-- excel 表格工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.fesod</groupId>
|
||||
<artifactId>fesod-sheet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-extend</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-extend end -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot-db-mybatis-plus -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-db-mybatis-plus</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools end -->
|
||||
|
||||
<!-- 项目模块 begin -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-common-log-bus</artifactId>
|
||||
</dependency>
|
||||
<!-- 项目模块 end -->
|
||||
|
||||
<!-- SpringBoot begin -->
|
||||
<!-- SpringBoot-Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- SpringBoot end -->
|
||||
|
||||
<!-- mapstruct begin -->
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
</dependency>
|
||||
<!-- mapstruct end -->
|
||||
|
||||
<!-- fastjson2 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,171 @@
|
||||
package xtools.app.sys.scheduled.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import xtools.app.sys.scheduled.model.dto.excel.SysScheduledExcel;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledAddReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledPageReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledUpdateReq;
|
||||
import xtools.app.sys.scheduled.model.dto.resp.SysScheduledResp;
|
||||
import xtools.app.sys.scheduled.service.SysScheduledService;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.api.exection.BizWarning;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
import xtools.boot.api.model.dto.req.IdListReq;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.extend.office.FesodUtils;
|
||||
import xtools.web.HttpServletUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledController</p>
|
||||
* <p>Description : 定时任务 Controller</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:27:18
|
||||
*/
|
||||
@Tag(name = "定时任务")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/sys/scheduled")
|
||||
public class SysScheduledController {
|
||||
|
||||
private final SysScheduledService sysScheduledService;
|
||||
|
||||
@Operation(summary = "分页请求")
|
||||
@PostMapping("page")
|
||||
public Result<PageResp<SysScheduledResp>> page(@RequestBody @Valid PageReq<SysScheduledPageReq> pageReq) {
|
||||
return sysScheduledService.page(pageReq);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取数据")
|
||||
@GetMapping("base/{id}")
|
||||
public Result<SysScheduledResp> getById(
|
||||
@Schema(description = "ID", example = "1")
|
||||
@Min(value = 1L, message = "不能小于1")
|
||||
@NotNull(message = "不能为空")
|
||||
@PathVariable Long id
|
||||
) {
|
||||
return sysScheduledService.getById(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "添加数据")
|
||||
@PostMapping("base")
|
||||
public Result<Boolean> add(@RequestBody @Valid SysScheduledAddReq req) {
|
||||
return sysScheduledService.add(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新数据")
|
||||
@PutMapping("base")
|
||||
public Result<Boolean> update(@RequestBody @Valid SysScheduledUpdateReq req) {
|
||||
return sysScheduledService.update(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除数据")
|
||||
@DeleteMapping("base")
|
||||
public Result<Boolean> delById(@RequestBody @Valid IdListReq req) {
|
||||
return sysScheduledService.delById(req.getIdList());
|
||||
}
|
||||
|
||||
@Operation(summary = "导出Excel")
|
||||
@PostMapping("export")
|
||||
public void exportExcel(@RequestBody @Valid SysScheduledPageReq req, HttpServletResponse response) {
|
||||
String sheetName = "定时任务";
|
||||
String filename = sheetName + ".xlsx";
|
||||
List<SysScheduledExcel> dataList = sysScheduledService.exportExcel(req);
|
||||
try {
|
||||
FesodUtils.write(response.getOutputStream(), SysScheduledExcel.class, sheetName, dataList);
|
||||
} catch (IOException e) {
|
||||
throw new BizError("导出Excel失败");
|
||||
}
|
||||
// 设置 header 和 contentType.写在最后的原因是,避免报错时,响应 contentType 已经被修改
|
||||
HttpServletUtils.addDownloadHeader(response, filename);
|
||||
}
|
||||
|
||||
@Operation(summary = "导入Excel")
|
||||
@PostMapping("import")
|
||||
public Result<Boolean> importExcel(@RequestParam("file") MultipartFile file) {
|
||||
List<SysScheduledExcel> dataList;
|
||||
try {
|
||||
dataList = FesodUtils.read(file.getInputStream(), SysScheduledExcel.class);
|
||||
} catch (IOException e) {
|
||||
throw new BizError("导入Excel失败");
|
||||
}
|
||||
if (CollectionUtils.isEmpty(dataList)) {
|
||||
throw new BizWarning("导入Excel没有包含有效数据");
|
||||
}
|
||||
sysScheduledService.importExcel(dataList);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "运行定时任务")
|
||||
@PostMapping("run/{id}")
|
||||
public Result<Boolean> run(
|
||||
@Schema(description = "ID", example = "1")
|
||||
@Min(value = 1L, message = "不能小于1")
|
||||
@NotNull(message = "不能为空")
|
||||
@PathVariable Long id
|
||||
) {
|
||||
sysScheduledService.run(id);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "启动定时任务")
|
||||
@PostMapping("start/{id}")
|
||||
public Result<Boolean> start(
|
||||
@Schema(description = "ID", example = "1")
|
||||
@Min(value = 1L, message = "不能小于1")
|
||||
@NotNull(message = "不能为空")
|
||||
@PathVariable Long id
|
||||
) {
|
||||
sysScheduledService.start(id);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "停止定时任务")
|
||||
@PostMapping("stop/{id}")
|
||||
public Result<Boolean> stop(
|
||||
@Schema(description = "ID", example = "1")
|
||||
@Min(value = 1L, message = "不能小于1")
|
||||
@NotNull(message = "不能为空")
|
||||
@PathVariable Long id
|
||||
) {
|
||||
sysScheduledService.stop(id);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "重启定时任务")
|
||||
@PostMapping("restart/{id}")
|
||||
public Result<Boolean> restart(
|
||||
@Schema(description = "ID", example = "1")
|
||||
@Min(value = 1L, message = "不能小于1")
|
||||
@NotNull(message = "不能为空")
|
||||
@PathVariable Long id
|
||||
) {
|
||||
sysScheduledService.restart(id);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package xtools.app.sys.scheduled.convert;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import xtools.app.sys.scheduled.model.dto.excel.SysScheduledExcel;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledAddReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledUpdateReq;
|
||||
import xtools.app.sys.scheduled.model.dto.resp.SysScheduledResp;
|
||||
import xtools.app.sys.scheduled.model.entity.SysScheduled;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledConvert</p>
|
||||
* <p>Description : 定时任务 Convert</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface SysScheduledConvert {
|
||||
|
||||
/**
|
||||
* 添加请求转实体
|
||||
*
|
||||
* @param req 添加请求
|
||||
* @return 实体
|
||||
*/
|
||||
SysScheduled addReqToEntity(SysScheduledAddReq req);
|
||||
|
||||
/**
|
||||
* 修改请求转实体
|
||||
*
|
||||
* @param req 修改请求
|
||||
* @return 实体
|
||||
*/
|
||||
SysScheduled updateReqToEntity(SysScheduledUpdateReq req);
|
||||
|
||||
/**
|
||||
* 实体转响应
|
||||
*
|
||||
* @param data 实体
|
||||
* @return 响应
|
||||
*/
|
||||
SysScheduledResp entityToResp(SysScheduled data);
|
||||
|
||||
/**
|
||||
* 批量实体转响应
|
||||
*
|
||||
* @param dataList 批量实体
|
||||
* @return 响应
|
||||
*/
|
||||
List<SysScheduledResp> entityToRespList(List<SysScheduled> dataList);
|
||||
|
||||
/**
|
||||
* 实体转Excel
|
||||
*
|
||||
* @param data 实体
|
||||
* @return Excel
|
||||
*/
|
||||
SysScheduledExcel entityToExcel(SysScheduled data);
|
||||
|
||||
/**
|
||||
* Excel转实体
|
||||
*
|
||||
* @param data Excel
|
||||
* @return 实体
|
||||
*/
|
||||
@Mapping(target = "status", ignore = true)
|
||||
SysScheduled excelToEntity(SysScheduledExcel data);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package xtools.app.sys.scheduled.init;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.app.sys.scheduled.service.SysScheduledService;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.log.LogBus;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.boot.log.holder.LogTrackHolder;
|
||||
import xtools.core.enums.LogLevel;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Title : InitSysScheduled</p>
|
||||
* <p>Description : InitSysScheduled</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/2/2 14:13
|
||||
*/
|
||||
@Component
|
||||
@Order(BaseParams.CP_NUM200)
|
||||
@RequiredArgsConstructor
|
||||
public class InitSysScheduled implements ApplicationRunner {
|
||||
|
||||
private final SysScheduledService sysScheduledService;
|
||||
|
||||
@Override
|
||||
public void run(@NonNull ApplicationArguments args) {
|
||||
ScopedValue.where(LogTrackHolder.getScoped(), LogTrackHolder.newMain()).run(() -> {
|
||||
try {
|
||||
init();
|
||||
} catch (Exception e) {
|
||||
LogBus.init(LogLevel.ERROR, LogBusBaseType.OTHER).title("初始化异常").error(e).save();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private void init() {
|
||||
sysScheduledService.init();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package xtools.app.sys.scheduled.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import xtools.app.sys.scheduled.model.entity.SysScheduled;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledMapper</p>
|
||||
* <p>Description : 定时任务 Mapper 接口</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysScheduledMapper extends BaseMapper<SysScheduled> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package xtools.app.sys.scheduled.model.dto.excel;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.fesod.sheet.annotation.ExcelProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledExcel</p>
|
||||
* <p>Description : 定时任务Excel对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysScheduledExcel implements Serializable {
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@ExcelProperty("任务描述")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@ExcelProperty("Bean名称")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@ExcelProperty("执行参数")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@ExcelProperty("表达式")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@ExcelProperty("任务状态")
|
||||
private String status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package xtools.app.sys.scheduled.model.dto.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledAddReq</p>
|
||||
* <p>Description : 定时任务添加请求对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysScheduledAddReq implements Serializable {
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@Schema(description = "需要执行的SpringBean的名称")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@Schema(description = "执行参数")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@Schema(description = "表达式")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@Schema(description = "状态(默认1)")
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package xtools.app.sys.scheduled.model.dto.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledPageReq</p>
|
||||
* <p>Description : 定时任务分页请求对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysScheduledPageReq implements Serializable {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@Schema(description = "主键 ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@Schema(description = "需要执行的SpringBean的名称")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@Schema(description = "执行参数")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@Schema(description = "表达式")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@Schema(description = "状态(默认1)")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间(范围)
|
||||
*/
|
||||
@Schema(description = "创建时间(范围)", example = "['2026-01-01 00:00:00', '2026-01-01 12:00:00']")
|
||||
private Instant[] gmtCreateRange;
|
||||
|
||||
/**
|
||||
* 更新时间(范围)
|
||||
*/
|
||||
@Schema(description = "更新时间(范围)", example = "['2026-01-01 00:00:00', '2026-01-01 12:00:00']")
|
||||
private Instant[] gmtModifiedRange;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package xtools.app.sys.scheduled.model.dto.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledUpdateReq</p>
|
||||
* <p>Description : 定时任务更新请求对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysScheduledUpdateReq implements Serializable {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@Schema(description = "主键 ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@Schema(description = "需要执行的SpringBean的名称")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@Schema(description = "执行参数")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@Schema(description = "表达式")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@Schema(description = "状态(默认1)")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package xtools.app.sys.scheduled.model.dto.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import xtools.boot.api.model.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledResp</p>
|
||||
* <p>Description : 定时任务响应对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysScheduledResp extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@Schema(description = "主键 ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@Schema(description = "需要执行的SpringBean的名称")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@Schema(description = "执行参数")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@Schema(description = "表达式")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 运行状态
|
||||
*/
|
||||
@Schema(description = "运行状态")
|
||||
private Integer run;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package xtools.app.sys.scheduled.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import xtools.boot.api.model.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduled</p>
|
||||
* <p>Description : 定时任务实体对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_scheduled")
|
||||
public class SysScheduled extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@Schema(description = "主键 ID")
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述")
|
||||
@TableField(value = "title")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 需要执行的SpringBean的名称
|
||||
*/
|
||||
@Schema(description = "需要执行的SpringBean的名称")
|
||||
@TableField(value = "bean_name")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 执行参数
|
||||
*/
|
||||
@Schema(description = "执行参数")
|
||||
@TableField(value = "params")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
@Schema(description = "表达式")
|
||||
@TableField(value = "cron")
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 状态(默认1)
|
||||
*/
|
||||
@Schema(description = "状态(默认1)")
|
||||
@TableField(value = "status")
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package xtools.app.sys.scheduled.service;
|
||||
|
||||
import xtools.app.sys.scheduled.model.dto.excel.SysScheduledExcel;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledAddReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledPageReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledUpdateReq;
|
||||
import xtools.app.sys.scheduled.model.dto.resp.SysScheduledResp;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledService</p>
|
||||
* <p>Description : 定时任务 Service</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
public interface SysScheduledService {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param pageReq 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
Result<PageResp<SysScheduledResp>> page(PageReq<SysScheduledPageReq> pageReq);
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*
|
||||
* @param id ID
|
||||
* @return 结果
|
||||
*/
|
||||
Result<SysScheduledResp> getById(Long id);
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param req 添加请求
|
||||
* @return 添加结果
|
||||
*/
|
||||
Result<Boolean> add(SysScheduledAddReq req);
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*
|
||||
* @param req 修改请求
|
||||
* @return 修改结果
|
||||
*/
|
||||
Result<Boolean> update(SysScheduledUpdateReq req);
|
||||
|
||||
/**
|
||||
* 根据 ID 删除
|
||||
*
|
||||
* @param idList ID 集合
|
||||
* @return 删除结果
|
||||
*/
|
||||
Result<Boolean> delById(List<Long> idList);
|
||||
|
||||
/**
|
||||
* 导出 Excel
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return Excel 数据
|
||||
*/
|
||||
List<SysScheduledExcel> exportExcel(SysScheduledPageReq req);
|
||||
|
||||
/**
|
||||
* 导入 Excel
|
||||
*
|
||||
* @param dataList Excel 数据
|
||||
*/
|
||||
void importExcel(List<SysScheduledExcel> dataList);
|
||||
|
||||
/**
|
||||
* 初始化定时任务
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* 运行定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
void run(Long id);
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
void start(Long id);
|
||||
|
||||
/**
|
||||
* 停止定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
void stop(Long id);
|
||||
|
||||
/**
|
||||
* 重启定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
void restart(Long id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package xtools.app.sys.scheduled.service.base;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.app.sys.scheduled.mapper.SysScheduledMapper;
|
||||
import xtools.app.sys.scheduled.model.entity.SysScheduled;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledBaseService</p>
|
||||
* <p>Description : 定时任务 BaseService</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Component
|
||||
public class SysScheduledBaseService extends ServiceImpl<SysScheduledMapper, SysScheduled> {
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
package xtools.app.sys.scheduled.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import xtools.app.sys.scheduled.convert.SysScheduledConvert;
|
||||
import xtools.app.sys.scheduled.model.dto.excel.SysScheduledExcel;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledAddReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledPageReq;
|
||||
import xtools.app.sys.scheduled.model.dto.req.SysScheduledUpdateReq;
|
||||
import xtools.app.sys.scheduled.model.dto.resp.SysScheduledResp;
|
||||
import xtools.app.sys.scheduled.model.entity.SysScheduled;
|
||||
import xtools.app.sys.scheduled.service.SysScheduledService;
|
||||
import xtools.app.sys.scheduled.service.base.SysScheduledBaseService;
|
||||
import xtools.app.sys.scheduled.utils.ScheduledUtils;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.enums.StatusEnum;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.api.exection.BizWarning;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
import xtools.boot.db.mybatisplus.utils.QueryUtils;
|
||||
import xtools.boot.log.LogBus;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.enums.LogLevel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : SysScheduledServiceImpl</p>
|
||||
* <p>Description : 定时任务 ServiceImpl</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-02-23 10:15:23
|
||||
*/
|
||||
@Slf4j
|
||||
@Primary
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysScheduledServiceImpl implements SysScheduledService, BaseParams {
|
||||
|
||||
private final SysScheduledBaseService sysScheduledBaseService;
|
||||
|
||||
private final SysScheduledConvert sysScheduledConvert;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param pageReq 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
@Override
|
||||
public Result<PageResp<SysScheduledResp>> page(PageReq<SysScheduledPageReq> pageReq) {
|
||||
// 分页查询
|
||||
Page<SysScheduled> page = getPageData(pageReq.getCurrentPage(), pageReq.getPageSize(), pageReq.getQuery());
|
||||
List<SysScheduledResp> dataList = sysScheduledConvert.entityToRespList(page.getRecords());
|
||||
if (CollectionUtils.isNotEmpty(dataList)) {
|
||||
dataList.forEach(item -> item.setRun(ScheduledUtils.isRun(item.getId()) ? CP_NUM1 : CP_NUM0));
|
||||
}
|
||||
// 分装结果
|
||||
PageResp<SysScheduledResp> pageResp = new PageResp<>(pageReq, page.getTotal(), dataList);
|
||||
return Result.ok(pageResp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*
|
||||
* @param id ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Result<SysScheduledResp> getById(Long id) {
|
||||
SysScheduled data = sysScheduledBaseService.getById(id);
|
||||
return Result.ok(sysScheduledConvert.entityToResp(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param req 添加请求
|
||||
* @return 添加结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Boolean> add(SysScheduledAddReq req) {
|
||||
SysScheduled entity = sysScheduledConvert.addReqToEntity(req);
|
||||
if (Objects.nonNull(existsEntity(entity))) {
|
||||
throw new BizWarning("数据已存在");
|
||||
}
|
||||
return Result.ok(sysScheduledBaseService.save(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*
|
||||
* @param req 修改请求
|
||||
* @return 修改结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Boolean> update(SysScheduledUpdateReq req) {
|
||||
SysScheduled entity = sysScheduledConvert.updateReqToEntity(req);
|
||||
if (ScheduledUtils.isRun(entity.getId())) {
|
||||
throw new BizWarning("任务正在运行中,请先停止任务");
|
||||
}
|
||||
if (Objects.nonNull(existsEntity(entity))) {
|
||||
throw new BizWarning("数据已存在");
|
||||
}
|
||||
return Result.ok(sysScheduledBaseService.updateById(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 删除
|
||||
*
|
||||
* @param idList ID 集合
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Boolean> delById(List<Long> idList) {
|
||||
idList.forEach(id -> {
|
||||
if (ScheduledUtils.isRun(id)) {
|
||||
throw new BizWarning("有任务正在运行中,请先停止任务");
|
||||
}
|
||||
});
|
||||
boolean removed = sysScheduledBaseService.removeByIds(idList);
|
||||
if (!removed) {
|
||||
throw new BizError("删除失败");
|
||||
}
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 Excel
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return Excel 数据
|
||||
*/
|
||||
@Override
|
||||
public List<SysScheduledExcel> exportExcel(SysScheduledPageReq req) {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysScheduled> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(
|
||||
SysScheduled::getTitle
|
||||
, SysScheduled::getBeanName
|
||||
, SysScheduled::getParams
|
||||
, SysScheduled::getCron
|
||||
, SysScheduled::getStatus
|
||||
);
|
||||
// 设置查询条件
|
||||
setQueryWrapper(query, req);
|
||||
// 排序
|
||||
query.orderByDesc(SysScheduled::getGmtCreate);
|
||||
List<SysScheduled> dataList = sysScheduledBaseService.list(query);
|
||||
return dataList.stream().map(item -> {
|
||||
StatusEnum status = StatusEnum.valueOf(item.getStatus());
|
||||
SysScheduledExcel excel = sysScheduledConvert.entityToExcel(item);
|
||||
excel.setStatus(status.desc());
|
||||
return excel;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入 Excel
|
||||
*
|
||||
* @param dataList Excel 数据
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void importExcel(List<SysScheduledExcel> dataList) {
|
||||
for (SysScheduledExcel excel : dataList) {
|
||||
StatusEnum status = StatusEnum.valueOfDesc(excel.getStatus());
|
||||
|
||||
SysScheduled item = sysScheduledConvert.excelToEntity(excel);
|
||||
item.setStatus(status.code());
|
||||
|
||||
SysScheduled dbItem = existsEntity(item);
|
||||
if (Objects.isNull(dbItem)) {
|
||||
// 新增
|
||||
sysScheduledBaseService.save(item);
|
||||
} else {
|
||||
// 修改
|
||||
item.setId(dbItem.getId());
|
||||
sysScheduledBaseService.updateById(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页数据
|
||||
*
|
||||
* @param currentPage 当前页
|
||||
* @param pageSize 每页数量
|
||||
* @param req 请求参数
|
||||
* @return 分页数据
|
||||
*/
|
||||
private Page<SysScheduled> getPageData(Integer currentPage, Integer pageSize, SysScheduledPageReq req) {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysScheduled> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(
|
||||
SysScheduled::getId
|
||||
, SysScheduled::getTitle
|
||||
, SysScheduled::getBeanName
|
||||
, SysScheduled::getParams
|
||||
, SysScheduled::getCron
|
||||
, SysScheduled::getStatus
|
||||
, SysScheduled::getGmtCreate
|
||||
, SysScheduled::getGmtModified
|
||||
);
|
||||
// 设置查询条件
|
||||
setQueryWrapper(query, req);
|
||||
// 排序
|
||||
query.orderByDesc(SysScheduled::getGmtCreate);
|
||||
return sysScheduledBaseService.page(QueryUtils.getPage(currentPage, pageSize), query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置查询条件
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param req 请求参数
|
||||
*/
|
||||
private void setQueryWrapper(LambdaQueryWrapper<SysScheduled> query, SysScheduledPageReq req) {
|
||||
if (Objects.isNull(req)) {
|
||||
return;
|
||||
}
|
||||
// 查询条件
|
||||
query.eq(Objects.nonNull(req.getId()), SysScheduled::getId, req.getId());
|
||||
query.like(StringUtils.isNotBlank(req.getTitle()), SysScheduled::getTitle, req.getTitle());
|
||||
query.like(StringUtils.isNotBlank(req.getBeanName()), SysScheduled::getBeanName, req.getBeanName());
|
||||
query.like(StringUtils.isNotBlank(req.getParams()), SysScheduled::getParams, req.getParams());
|
||||
query.like(StringUtils.isNotBlank(req.getCron()), SysScheduled::getCron, req.getCron());
|
||||
query.eq(Objects.nonNull(req.getStatus()), SysScheduled::getStatus, req.getStatus());
|
||||
QueryUtils.addTimeRange(query, req.getGmtCreateRange(), SysScheduled::getGmtCreate);
|
||||
QueryUtils.addTimeRange(query, req.getGmtModifiedRange(), SysScheduled::getGmtModified);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断实体是否存在
|
||||
*
|
||||
* @param entity 实体
|
||||
* @return 是否存在
|
||||
*/
|
||||
private SysScheduled existsEntity(SysScheduled entity) {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysScheduled> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(SysScheduled::getId);
|
||||
// 排除当前数据
|
||||
query.ne(Objects.nonNull(entity.getId()), SysScheduled::getId, entity.getId());
|
||||
// 校验数据时候存在的条件
|
||||
query.eq(StringUtils.isNotBlank(entity.getBeanName()), SysScheduled::getBeanName, entity.getBeanName());
|
||||
return sysScheduledBaseService.getOne(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化定时任务
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysScheduled> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(
|
||||
SysScheduled::getId
|
||||
, SysScheduled::getTitle
|
||||
, SysScheduled::getBeanName
|
||||
, SysScheduled::getParams
|
||||
, SysScheduled::getCron
|
||||
);
|
||||
query.eq(SysScheduled::getStatus, StatusEnum.NORMAL.code());
|
||||
List<SysScheduled> dataList = sysScheduledBaseService.list(query);
|
||||
if (CollectionUtils.isEmpty(dataList)) {
|
||||
log.info("初始化定时任务成功,无定时任务");
|
||||
return;
|
||||
}
|
||||
for (SysScheduled item : dataList) {
|
||||
String beanName = item.getBeanName();
|
||||
Runnable task = getTask(beanName);
|
||||
if (Objects.isNull(task)) {
|
||||
LogBus.init(LogLevel.ERROR, LogBusBaseType.JOB).title("定时任务不存在").data(item).save();
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ScheduledUtils.add(item.getId(), task, item.getCron());
|
||||
log.info("定时任务添加成功,任务名称:{}", item.getTitle());
|
||||
} catch (Exception e) {
|
||||
LogBus.init(LogLevel.ERROR, LogBusBaseType.JOB).title("定时任务添加异常").error(e).data(item).save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
@Override
|
||||
public void run(Long id) {
|
||||
SysScheduled item = sysScheduledBaseService.getById(id);
|
||||
if (Objects.isNull(item)) {
|
||||
throw new BizError("定时任务不存在");
|
||||
}
|
||||
boolean run = ScheduledUtils.isRun(id);
|
||||
if (run) {
|
||||
throw new BizError("定时任务已启动");
|
||||
}
|
||||
Runnable task = getTask(item.getBeanName());
|
||||
if (Objects.isNull(task)) {
|
||||
throw new BizError("定时任务bean不存在");
|
||||
}
|
||||
task.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
@Override
|
||||
public void start(Long id) {
|
||||
SysScheduled item = sysScheduledBaseService.getById(id);
|
||||
if (Objects.isNull(item)) {
|
||||
throw new BizError("定时任务不存在");
|
||||
}
|
||||
boolean run = ScheduledUtils.isRun(id);
|
||||
if (run) {
|
||||
throw new BizError("定时任务已启动");
|
||||
}
|
||||
ScheduledUtils.add(id, getTask(item.getBeanName()), item.getCron());
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
@Override
|
||||
public void stop(Long id) {
|
||||
SysScheduled item = sysScheduledBaseService.getById(id);
|
||||
if (Objects.isNull(item)) {
|
||||
throw new BizError("定时任务不存在");
|
||||
}
|
||||
boolean run = ScheduledUtils.isRun(id);
|
||||
if (!run) {
|
||||
throw new BizError("定时任务未启动");
|
||||
}
|
||||
ScheduledUtils.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启定时任务
|
||||
*
|
||||
* @param id 定时任务ID
|
||||
*/
|
||||
@Override
|
||||
public void restart(Long id) {
|
||||
stop(id);
|
||||
start(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务
|
||||
*
|
||||
* @param beanName 任务bean名称
|
||||
* @return 任务
|
||||
*/
|
||||
private Runnable getTask(String beanName) {
|
||||
Object obj = SpringContextUtils.getBeanDefNull(beanName);
|
||||
if (obj instanceof Runnable task) {
|
||||
return task;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package xtools.app.sys.scheduled.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.extend.CheckUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* <p>Title : ScheduledUtils</p>
|
||||
* <p>Description : ScheduledUtils</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/2/23 09:46
|
||||
*/
|
||||
@Slf4j
|
||||
public class ScheduledUtils implements BaseParams {
|
||||
|
||||
/**
|
||||
* 任务线程池
|
||||
*/
|
||||
private final static TaskScheduler TASK_SCHEDULER;
|
||||
|
||||
/**
|
||||
* 任务列表
|
||||
*/
|
||||
private static final ConcurrentHashMap<Long, ScheduledFuture<?>> TASKS = new ConcurrentHashMap<>();
|
||||
|
||||
// 初始化
|
||||
static {
|
||||
// 创建任务虚拟线程池
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.setVirtualThreads(true);
|
||||
scheduler.initialize();
|
||||
TASK_SCHEDULER = scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任务
|
||||
*
|
||||
* @param id 任务ID
|
||||
* @param task 任务执行线程
|
||||
* @param cron 执行时间表达式
|
||||
*/
|
||||
public static void add(Long id, Runnable task, String cron) {
|
||||
// 参数校验
|
||||
if (!CheckUtils.id(id) || Objects.isNull(task) || StringUtils.isBlank(cron)) {
|
||||
throw new BizError("参数错误");
|
||||
}
|
||||
// 如果任务已存在,先取消
|
||||
if (TASKS.containsKey(id)) {
|
||||
remove(id);
|
||||
}
|
||||
CronTrigger trigger;
|
||||
try {
|
||||
trigger = new CronTrigger(cron);
|
||||
} catch (Exception e) {
|
||||
throw new BizError("时间表达式错误");
|
||||
}
|
||||
|
||||
// 用虚拟线程包装任务
|
||||
Runnable virtualTask = () -> Thread.startVirtualThread(task);
|
||||
ScheduledFuture<?> future = TASK_SCHEDULER.schedule(virtualTask, trigger);
|
||||
if (Objects.isNull(future)) {
|
||||
throw new BizError("定时任务添加失败");
|
||||
}
|
||||
TASKS.put(id, future);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*
|
||||
* @param id 任务ID
|
||||
*/
|
||||
public static void remove(Long id) {
|
||||
ScheduledFuture<?> future = TASKS.remove(id);
|
||||
if (Objects.isNull(future)) {
|
||||
return;
|
||||
}
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在运行
|
||||
*
|
||||
* @param id 任务ID
|
||||
* @return true or false
|
||||
*/
|
||||
public static boolean isRun(Long id) {
|
||||
if (!CheckUtils.id(id)) {
|
||||
return false;
|
||||
}
|
||||
// 获取任务实例
|
||||
ScheduledFuture<?> task = TASKS.get(id);
|
||||
if (Objects.isNull(task)) {
|
||||
return false;
|
||||
}
|
||||
return !task.isCancelled();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user