From 5d1b983c71b83a66eb1d125375a3125199c1891a Mon Sep 17 00:00:00 2001 From: Bunny <1319900154@qq.com> Date: Sun, 20 Oct 2024 21:43:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9A=E6=97=B6=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E4=BB=BB=E5=8A=A1=E6=9C=89bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/entity/log/ScheduleExecuteLog.java | 2 +- .../entity/log/ScheduleExecuteLogJson.java | 4 +- .../pojo/constant/LocalDateTimeConstant.java | 1 + .../bunny/dao/vo/log/QuartzExecuteLogVo.java | 3 +- service/Dockerfile | 5 +- .../cn/bunny/services/aop/JobExecuteAop.java | 107 ++++++++++++++++++ .../aop/annotation/QuartzSchedulers.java | 4 + .../bunny/services/factory/FileFactory.java | 6 +- .../services/quartz/DatabaseBackupJob.java | 63 +++++++++++ .../cn/bunny/services/quartz/JobHello.java | 9 +- .../cn/bunny/services/quartz/JobHello2.java | 9 +- .../cn/bunny/services/quartz/MailingJob.java | 2 + .../service/impl/SchedulersServiceImpl.java | 24 +++- .../src/main/resources/application-dev.yml | 5 +- .../src/main/resources/application-prod.yml | 11 +- service/src/main/resources/application.yml | 6 +- .../services/backup/MysqlBackupTest.java | 21 ++++ 17 files changed, 246 insertions(+), 36 deletions(-) create mode 100644 service/src/main/java/cn/bunny/services/aop/JobExecuteAop.java create mode 100644 service/src/main/java/cn/bunny/services/quartz/DatabaseBackupJob.java create mode 100644 service/src/test/java/cn/bunny/services/backup/MysqlBackupTest.java diff --git a/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLog.java b/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLog.java index ef3ab3e..2ae287e 100644 --- a/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLog.java +++ b/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLog.java @@ -43,7 +43,7 @@ public class ScheduleExecuteLog extends BaseEntity { private String executeResult; @Schema(name = "duration", title = "执行时间") - private Integer duration; + private Long duration; @Schema(name = "endTime", title = "结束时间") private LocalDateTime endTime; diff --git a/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLogJson.java b/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLogJson.java index db9479c..d521931 100644 --- a/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLogJson.java +++ b/dao/src/main/java/cn/bunny/dao/entity/log/ScheduleExecuteLogJson.java @@ -6,6 +6,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.Map; + @Data @AllArgsConstructor @NoArgsConstructor @@ -26,5 +28,5 @@ public class ScheduleExecuteLogJson { private String operationTime; @Schema(name = "executeParams", title = "执行任务参数") - private String executeParams; + private Map executeParams; } diff --git a/dao/src/main/java/cn/bunny/dao/pojo/constant/LocalDateTimeConstant.java b/dao/src/main/java/cn/bunny/dao/pojo/constant/LocalDateTimeConstant.java index 01bff35..6ef9f39 100644 --- a/dao/src/main/java/cn/bunny/dao/pojo/constant/LocalDateTimeConstant.java +++ b/dao/src/main/java/cn/bunny/dao/pojo/constant/LocalDateTimeConstant.java @@ -7,4 +7,5 @@ public class LocalDateTimeConstant { public static final String YYYY_MM_DD = "yyyy-MM-dd"; public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; public static final String YYYY_MM_DD_HH_MM_SS_SLASH = "yyyy/MM/dd HH:mm:ss"; + public static final String YYYY_MM_DD_HH_MM_SS_UNDERLINE = "yyyy-MM-dd HH_mm_ss_SSS"; } diff --git a/dao/src/main/java/cn/bunny/dao/vo/log/QuartzExecuteLogVo.java b/dao/src/main/java/cn/bunny/dao/vo/log/QuartzExecuteLogVo.java index 56875bb..4cb80ee 100644 --- a/dao/src/main/java/cn/bunny/dao/vo/log/QuartzExecuteLogVo.java +++ b/dao/src/main/java/cn/bunny/dao/vo/log/QuartzExecuteLogVo.java @@ -1,6 +1,5 @@ package cn.bunny.dao.vo.log; -import cn.bunny.dao.entity.log.ScheduleExecuteLogJson; import cn.bunny.dao.vo.common.BaseVo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -31,7 +30,7 @@ public class QuartzExecuteLogVo extends BaseVo { private String triggerName; @Schema(name = "executeResult", title = "执行结果") - private ScheduleExecuteLogJson executeResult; + private String executeResult; @Schema(name = "duration", title = "执行时间") private Integer duration; diff --git a/service/Dockerfile b/service/Dockerfile index 4a52015..e6081a7 100644 --- a/service/Dockerfile +++ b/service/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:17 +FROM openjdk:24-ea-17-jdk-oraclelinux9 MAINTAINER server #系统编码 @@ -18,6 +18,7 @@ COPY target/*.jar /home/server/app.jar VOLUME /usr/bin/docker VOLUME ["/var/run/docker.sock"] VOLUME /etc/docker/daemon.json +VOLUME ["/bunny/docker_data/mysql/slave_3304/backup"] # 启动容器时的进程 ENTRYPOINT ["java","-jar","/home/server/app.jar"] @@ -25,5 +26,5 @@ ENTRYPOINT ["java","-jar","/home/server/app.jar"] #暴露 8000 端口 EXPOSE 8000 -# mvn clean package -Pprod -DskipTests +# mvn clean package -Pprod -DskipTests diff --git a/service/src/main/java/cn/bunny/services/aop/JobExecuteAop.java b/service/src/main/java/cn/bunny/services/aop/JobExecuteAop.java new file mode 100644 index 0000000..414a4e4 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/aop/JobExecuteAop.java @@ -0,0 +1,107 @@ +package cn.bunny.services.aop; + +import cn.bunny.dao.entity.log.ScheduleExecuteLog; +import cn.bunny.dao.entity.log.ScheduleExecuteLogJson; +import cn.bunny.dao.pojo.constant.LocalDateTimeConstant; +import cn.bunny.services.mapper.ScheduleExecuteLogMapper; +import com.alibaba.fastjson2.JSON; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +@Aspect +@Component +public class JobExecuteAop { + + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS); + + @Autowired + private ScheduleExecuteLogMapper scheduleExecuteLogMapper; + + @Around(value = "pointCut()") + public Object aroundMethod(ProceedingJoinPoint joinPoint) { + Object result; + Object[] args = joinPoint.getArgs(); + JobExecutionContext context = (JobExecutionContext) args[0]; + + // 存储到任务调度日志中 + ScheduleExecuteLog executeLog = new ScheduleExecuteLog(); + ScheduleExecuteLogJson executeLogJson = new ScheduleExecuteLogJson(); + + // 格式化时间 + LocalDateTime startLocalDateTime = LocalDateTime.now(); + String startExecuteTIme = startLocalDateTime.format(dateTimeFormatter); + + // 获取上下文map集合 + Map jobDataMap = context.getJobDetail().getJobDataMap().getWrappedMap(); + String jobName = String.valueOf(jobDataMap.get("jobName")); + String jobGroup = String.valueOf(jobDataMap.get("jobGroup")); + String cronExpression = String.valueOf(jobDataMap.get("cronExpression")); + String triggerName = String.valueOf(jobDataMap.get("triggerName")); + Class jobClass = context.getJobDetail().getJobClass(); + + try { + // 开始执行 + executeLog.setJobName(jobName); + executeLog.setJobGroup(jobGroup); + executeLog.setJobClassName(jobClass.getName()); + executeLog.setCronExpression(cronExpression); + executeLog.setTriggerName(triggerName); + // 设置状态结果 + executeLogJson.setResult("unfinished"); + executeLogJson.setStatus("running"); + executeLogJson.setMessage("running..."); + executeLogJson.setOperationTime(startExecuteTIme); + executeLogJson.setExecuteParams(jobDataMap); + executeLog.setExecuteResult(JSON.toJSONString(executeLogJson)); + scheduleExecuteLogMapper.insert(executeLog); + + // 执行... + result = joinPoint.proceed(); + + // 设置执行结果-执行任务的日志 + executeLogJson.setResult("finish"); + executeLogJson.setStatus("finish"); + executeLogJson.setMessage("finish"); + setEndExecuteLog(executeLogJson, executeLog, startLocalDateTime); + } catch (Throwable e) { + // 设置执行结果-执行任务的日志 + executeLogJson.setResult("error"); + executeLogJson.setStatus("error"); + executeLogJson.setMessage(e.getMessage()); + setEndExecuteLog(executeLogJson, executeLog, startLocalDateTime); + throw new RuntimeException(e); + } + + return result; + } + + /** + * 设置结束日志存储 + */ + private void setEndExecuteLog(ScheduleExecuteLogJson executeLogJson, ScheduleExecuteLog executeLog, LocalDateTime startLocalDateTime) { + LocalDateTime endLocalDateTime = LocalDateTime.now(); + String endExecuteTime = endLocalDateTime.format(dateTimeFormatter); + executeLogJson.setOperationTime(endExecuteTime); + // 设置状态结果 + executeLog.setId(null); + executeLog.setExecuteResult(JSON.toJSONString(executeLogJson)); + executeLog.setDuration(Duration.between(startLocalDateTime, endLocalDateTime).toSeconds()); + scheduleExecuteLogMapper.insert(executeLog); + } + + @Pointcut("execution(* cn.bunny.services.quartz.*.execute(..))") + public void pointCut() { + } + +} diff --git a/service/src/main/java/cn/bunny/services/aop/annotation/QuartzSchedulers.java b/service/src/main/java/cn/bunny/services/aop/annotation/QuartzSchedulers.java index 7c6c745..42bbdab 100644 --- a/service/src/main/java/cn/bunny/services/aop/annotation/QuartzSchedulers.java +++ b/service/src/main/java/cn/bunny/services/aop/annotation/QuartzSchedulers.java @@ -10,5 +10,9 @@ import java.lang.annotation.Target; public @interface QuartzSchedulers { String value() default ""; + // 类型 + String type(); + + // 详情 String description(); } diff --git a/service/src/main/java/cn/bunny/services/factory/FileFactory.java b/service/src/main/java/cn/bunny/services/factory/FileFactory.java index cde1d44..203eb2e 100644 --- a/service/src/main/java/cn/bunny/services/factory/FileFactory.java +++ b/service/src/main/java/cn/bunny/services/factory/FileFactory.java @@ -17,10 +17,12 @@ import org.springframework.web.multipart.MultipartFile; @Component public class FileFactory { - @Autowired - private FilesMapper filesMapper; @Value("${spring.servlet.multipart.max-file-size}") private String maxFileSize; + + @Autowired + private FilesMapper filesMapper; + @Autowired private MinioUtil minioUtil; diff --git a/service/src/main/java/cn/bunny/services/quartz/DatabaseBackupJob.java b/service/src/main/java/cn/bunny/services/quartz/DatabaseBackupJob.java new file mode 100644 index 0000000..c8e37a0 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/quartz/DatabaseBackupJob.java @@ -0,0 +1,63 @@ +package cn.bunny.services.quartz; + +import cn.bunny.dao.pojo.constant.LocalDateTimeConstant; +import cn.bunny.services.aop.annotation.QuartzSchedulers; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + + +@Slf4j +@QuartzSchedulers(type = "backup", description = "数据库备份任务") +@Component +public class DatabaseBackupJob implements Job { + + @Value("${spring.datasource.dynamic.datasource.master.username}") + private String masterUsername; + + @Value("${spring.datasource.dynamic.datasource.master.password}") + private String masterPassword; + + @Value("${bunny.master.database}") + private String masterDatabase; + + @Value("${bunny.master.databaseBackupDir}") + private String databaseBackupDir; + + @Override + public void execute(JobExecutionContext context) { + // 格式化时间 + LocalDateTime localStartExecuteTime = LocalDateTime.now(); + DateTimeFormatter sqlTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_UNDERLINE); + String sqlTimeNow = localStartExecuteTime.format(sqlTimeFormatter); + + // 命令行参数 + String dockerCommand = "docker exec -it bunny_auth_server bash"; + String mysqldumpCommand = "mysqldump -u " + masterUsername + " -p" + masterPassword + " " + masterDatabase + " > " + databaseBackupDir + "backup_auth_admin_" + sqlTimeNow + ".sql"; + ProcessBuilder processBuilder = new ProcessBuilder(dockerCommand, mysqldumpCommand); + + try { + // 执行命令 + Process process = processBuilder.start(); + + // 执行后读取内容 + InputStream inputStream = process.getInputStream(); + StringBuilder output = new StringBuilder(); + byte[] bytes = new byte[1024]; + int bytesRead; + + while ((bytesRead = inputStream.read(bytes)) != -1) { + output.append(new String(bytes, 0, bytesRead)); + } + System.out.println(output); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } +} diff --git a/service/src/main/java/cn/bunny/services/quartz/JobHello.java b/service/src/main/java/cn/bunny/services/quartz/JobHello.java index c00e35d..6d008d1 100644 --- a/service/src/main/java/cn/bunny/services/quartz/JobHello.java +++ b/service/src/main/java/cn/bunny/services/quartz/JobHello.java @@ -7,15 +7,10 @@ import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @Slf4j -@QuartzSchedulers(description = "JobHello任务内容") +@QuartzSchedulers(type = "test", description = "JobHello任务内容") public class JobHello implements Job { - public void start() { - log.error("执行任务--JobHello。。。。。。。。。"); - System.out.print("执行任务--JobHello。。。。。。。。。"); - } - @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - start(); + System.out.print("执行任务--JobHello。。。。。。。。。"); } } diff --git a/service/src/main/java/cn/bunny/services/quartz/JobHello2.java b/service/src/main/java/cn/bunny/services/quartz/JobHello2.java index 5585015..521a264 100644 --- a/service/src/main/java/cn/bunny/services/quartz/JobHello2.java +++ b/service/src/main/java/cn/bunny/services/quartz/JobHello2.java @@ -7,15 +7,10 @@ import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @Slf4j -@QuartzSchedulers(description = "Demo的类JobHello2") +@QuartzSchedulers(type = "test", description = "Demo的类JobHello2") public class JobHello2 implements Job { - public void start() { - log.error("执行任务---JobHello2。。。。。。。。。"); - System.out.print("执行任务--JobHello2。。。。。。。。。"); - } - @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - start(); + System.out.print("执行任务--JobHello2。。。。。。。。。"); } } diff --git a/service/src/main/java/cn/bunny/services/quartz/MailingJob.java b/service/src/main/java/cn/bunny/services/quartz/MailingJob.java index f83dbc3..d316a26 100644 --- a/service/src/main/java/cn/bunny/services/quartz/MailingJob.java +++ b/service/src/main/java/cn/bunny/services/quartz/MailingJob.java @@ -1,10 +1,12 @@ package cn.bunny.services.quartz; +import cn.bunny.services.aop.annotation.QuartzSchedulers; import cn.bunny.services.factory.EmailFactory; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +@QuartzSchedulers(type = "email", description = "定时邮件任务") public class MailingJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { diff --git a/service/src/main/java/cn/bunny/services/service/impl/SchedulersServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/SchedulersServiceImpl.java index 2095425..210e156 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/SchedulersServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/SchedulersServiceImpl.java @@ -86,9 +86,12 @@ public class SchedulersServiceImpl extends ServiceImpl className = Class.forName(dto.getJobClassName()); @@ -111,18 +118,25 @@ public class SchedulersServiceImpl extends ServiceImpl) className) - .withIdentity(dto.getJobName(), dto.getJobGroup()) + .withIdentity(jobName, jobGroup) .withDescription(dto.getDescription()) .build(); - jobDetail.getJobDataMap().put("jobMethodName", "execute"); // 执行任务 CronTrigger trigger = TriggerBuilder.newTrigger() - .withIdentity(dto.getJobName(), dto.getJobGroup()) + .withIdentity(jobName, jobGroup) .withDescription(dto.getDescription()) .startNow() - .withSchedule(CronScheduleBuilder.cronSchedule(dto.getCronExpression())) + .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); + + // 设置任务map值 + JobDataMap jobDataMap = jobDetail.getJobDataMap(); + jobDataMap.put("jobName", jobName); + jobDataMap.put("jobGroup", jobGroup); + jobDataMap.put("cronExpression", cronExpression); + jobDataMap.put("triggerName", trigger.getKey().getName()); + scheduler.scheduleJob(jobDetail, trigger); } catch (Exception exception) { throw new BunnyException(exception.getMessage()); diff --git a/service/src/main/resources/application-dev.yml b/service/src/main/resources/application-dev.yml index 93c1bca..cb5148c 100644 --- a/service/src/main/resources/application-dev.yml +++ b/service/src/main/resources/application-dev.yml @@ -40,12 +40,13 @@ mybatis-plus: # max-attempts: 3 # 最大重试次数 bunny: - datasource1: + master: host: 192.168.3.98 port: 3304 - sqlData: auth_admin + database: auth_admin username: root password: "02120212" + databaseBackupDir: "/home/backup/" redis: host: 192.168.3.98 diff --git a/service/src/main/resources/application-prod.yml b/service/src/main/resources/application-prod.yml index 4bb97b5..301ef5b 100644 --- a/service/src/main/resources/application-prod.yml +++ b/service/src/main/resources/application-prod.yml @@ -24,12 +24,15 @@ knife4j: production: true bunny: - datasource1: - host: 106.15.251.123 - port: 3306 - sqlData: auth_admin + master: + # host: 106.15.251.123 + # port: 3306 + host: 192.168.3.98 + port: 3304 + database: auth_admin username: root password: "02120212" + databaseBackupDir: "/home/backup/" redis: host: 47.120.65.66 diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml index e37cc67..29a2a46 100644 --- a/service/src/main/resources/application.yml +++ b/service/src/main/resources/application.yml @@ -21,9 +21,9 @@ spring: master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${bunny.datasource1.host}:${bunny.datasource1.port}/${bunny.datasource1.sqlData}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true - username: ${bunny.datasource1.username} - password: ${bunny.datasource1.password} + url: jdbc:mysql://${bunny.master.host}:${bunny.master.port}/${bunny.master.database}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: ${bunny.master.username} + password: ${bunny.master.password} aop: enabled: true diff --git a/service/src/test/java/cn/bunny/services/backup/MysqlBackupTest.java b/service/src/test/java/cn/bunny/services/backup/MysqlBackupTest.java new file mode 100644 index 0000000..ae9e758 --- /dev/null +++ b/service/src/test/java/cn/bunny/services/backup/MysqlBackupTest.java @@ -0,0 +1,21 @@ +package cn.bunny.services.backup; + +import cn.bunny.dao.pojo.constant.LocalDateTimeConstant; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class MysqlBackupTest { + @SneakyThrows + @Test + void testMysqlBackup() { + LocalDateTime localDateTime = LocalDateTime.now(); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_UNDERLINE); + String timeNow = localDateTime.format(timeFormatter); + + System.out.println(timeNow); + + } +}