From 103e3e6404ee29904f34063d6e5e8f47e21217f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=9D=B0?= Date: Sat, 6 Oct 2018 14:13:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=EF=BC=8C=E8=B0=83=E5=BA=A6=E6=97=A5=E5=BF=97=EF=BC=8C?= =?UTF-8?q?Aurora=20v1.1=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- LICENSE | 2 +- README.MD | 10 +- mvnw | 2 - mvnw.cmd | 1 - pom.xml | 6 + .../me/aurora/app/rest/job/JobController.java | 141 ++++++++ .../aurora/app/rest/job/JobLogController.java | 51 +++ .../me/aurora/config/AuroraProperties.java | 3 - .../me/aurora/config/job/MyJobRunner.java | 41 +++ .../me/aurora/config/job/ScheduleConfig.java | 58 ++++ .../config/scheduled/db/DBProperties.java | 23 -- .../aurora/config/scheduled/db/DBRecover.java | 66 ---- .../config/scheduled/task/MyTaskTest.java | 21 ++ src/main/java/me/aurora/domain/Dict.java | 8 +- src/main/java/me/aurora/domain/job/Job.java | 115 +++++++ .../java/me/aurora/domain/job/JobLog.java | 90 ++++++ .../java/me/aurora/repository/JobLogRepo.java | 13 + .../java/me/aurora/repository/JobRepo.java | 20 ++ .../me/aurora/repository/spec/JobLogSpce.java | 65 ++++ .../me/aurora/repository/spec/JobSpce.java | 68 ++++ .../java/me/aurora/service/JobLogService.java | 28 ++ .../java/me/aurora/service/JobService.java | 63 ++++ .../service/impl/JobLogServiceImpl.java | 35 ++ .../aurora/service/impl/JobServiceImpl.java | 84 +++++ .../service/impl/PermissionServiceImpl.java | 28 +- .../aurora/service/impl/RoleServiceImpl.java | 4 +- .../aurora/service/impl/UserServiceImpl.java | 4 +- .../java/me/aurora/util/job/ScheduleJob.java | 73 +++++ .../me/aurora/util/job/ScheduleRunnable.java | 49 +++ .../me/aurora/util/job/ScheduleUtils.java | 175 ++++++++++ src/main/resources/application.yml | 11 +- src/main/resources/sql/aurora.sql | 80 ++++- src/main/resources/templates/common/app.html | 21 +- src/main/resources/templates/index.html | 4 +- src/main/resources/templates/job/add.html | 48 +++ src/main/resources/templates/job/index.html | 300 ++++++++++++++++++ src/main/resources/templates/job/log.html | 137 ++++++++ src/main/resources/templates/job/update.html | 49 +++ .../templates/utils/email/index.html | 9 +- 40 files changed, 1848 insertions(+), 160 deletions(-) create mode 100644 src/main/java/me/aurora/app/rest/job/JobController.java create mode 100644 src/main/java/me/aurora/app/rest/job/JobLogController.java create mode 100644 src/main/java/me/aurora/config/job/MyJobRunner.java create mode 100644 src/main/java/me/aurora/config/job/ScheduleConfig.java delete mode 100644 src/main/java/me/aurora/config/scheduled/db/DBProperties.java delete mode 100644 src/main/java/me/aurora/config/scheduled/db/DBRecover.java create mode 100644 src/main/java/me/aurora/config/scheduled/task/MyTaskTest.java create mode 100644 src/main/java/me/aurora/domain/job/Job.java create mode 100644 src/main/java/me/aurora/domain/job/JobLog.java create mode 100644 src/main/java/me/aurora/repository/JobLogRepo.java create mode 100644 src/main/java/me/aurora/repository/JobRepo.java create mode 100644 src/main/java/me/aurora/repository/spec/JobLogSpce.java create mode 100644 src/main/java/me/aurora/repository/spec/JobSpce.java create mode 100644 src/main/java/me/aurora/service/JobLogService.java create mode 100644 src/main/java/me/aurora/service/JobService.java create mode 100644 src/main/java/me/aurora/service/impl/JobLogServiceImpl.java create mode 100644 src/main/java/me/aurora/service/impl/JobServiceImpl.java create mode 100644 src/main/java/me/aurora/util/job/ScheduleJob.java create mode 100644 src/main/java/me/aurora/util/job/ScheduleRunnable.java create mode 100644 src/main/java/me/aurora/util/job/ScheduleUtils.java create mode 100644 src/main/resources/templates/job/add.html create mode 100644 src/main/resources/templates/job/index.html create mode 100644 src/main/resources/templates/job/log.html create mode 100644 src/main/resources/templates/job/update.html diff --git a/Dockerfile b/Dockerfile index fdb1143..6d46b35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,6 @@ ADD *.war app.war RUN bash -c 'touch /app.jar' #指定映射端口 -EXPOSE 8080 +EXPOSE 80 CMD ["java","-jar","app.war"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index fb09df2..558e4bd 100644 --- a/LICENSE +++ b/LICENSE @@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 郑杰 + Copyright 2018 ZhengJie Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.MD b/README.MD index 803f782..71606b3 100644 --- a/README.MD +++ b/README.MD @@ -1,4 +1,4 @@ -### Aurora 1.0 +### Aurora ![https://img.shields.io/badge/build-success-brightgreen.svg?longCache=true&style=flat-square](https://img.shields.io/badge/build-success-brightgreen.svg?longCache=true&style=flat-square) ![https://img.shields.io/badge/license-Apache%202-blue.svg?longCache=true&style=flat-square](https://img.shields.io/badge/license-Apache%202-blue.svg?longCache=true&style=flat-square) ![https://img.shields.io/badge/springboot-2.0.4-yellow.svg?longCache=true&style=popout-square](https://img.shields.io/badge/springboot-2.0.4-yellow.svg?longCache=true&style=popout-square) @@ -40,10 +40,8 @@ Aurora是一个简单高效的后台管理系统。项目基础框架采用全 │ │-支付宝支付 │ │-七牛云储存 │ │-SM.MS图床 -│ │-百度富文本编辑器 -│ │-微信支付(开发中) -│ └─阿里大鱼(开发中) -└─任务调度(开发中) +│ └─百度富文本编辑器 +└─任务调度 ├─定时任务 └─调度日志 ``` @@ -72,6 +70,8 @@ Aurora是一个简单高效的后台管理系统。项目基础框架采用全 - 工具包:hutool-all +- 任务调度:quartz + - 其他:fastjson,aop,MapStruct等。 #### 前端 diff --git a/mvnw b/mvnw index 95626b7..b3665fa 100644 --- a/mvnw +++ b/mvnw @@ -7,9 +7,7 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# # http://www.apache.org/licenses/LICENSE-2.0 -# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY diff --git a/mvnw.cmd b/mvnw.cmd index 9329ac6..4f6af6d 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -56,7 +56,6 @@ set ERROR_CODE=0 @REM ==== START VALIDATION ==== if not "%JAVA_HOME%" == "" goto OkJHome - echo. echo Error: JAVA_HOME not found in your environment. >&2 echo Please set the JAVA_HOME variable in your environment to match the >&2 diff --git a/pom.xml b/pom.xml index 2b67c27..b296988 100644 --- a/pom.xml +++ b/pom.xml @@ -159,6 +159,12 @@ 4.1.8 + + + org.quartz-scheduler + quartz + + com.qiniu diff --git a/src/main/java/me/aurora/app/rest/job/JobController.java b/src/main/java/me/aurora/app/rest/job/JobController.java new file mode 100644 index 0000000..0eb7f71 --- /dev/null +++ b/src/main/java/me/aurora/app/rest/job/JobController.java @@ -0,0 +1,141 @@ +package me.aurora.app.rest.job; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpStatus; +import lombok.extern.slf4j.Slf4j; +import me.aurora.annotation.Log; +import me.aurora.domain.ResponseEntity; +import me.aurora.domain.job.Job; +import me.aurora.repository.spec.JobSpce; +import me.aurora.service.JobService; +import me.aurora.util.HttpContextUtils; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * @author 郑杰 + * @date 2018/10/05 19:12:24 + */ +@Slf4j +@RestController +@RequestMapping("job") +public class JobController { + + @Autowired + private JobService jobService; + + /** + * 跳转到列表页面 + * @return + */ + @GetMapping(value = "/index") + public ModelAndView index(){ + return new ModelAndView("/job/index"); + } + + @Log("查询所有任务") + @RequiresPermissions(value={"admin", "job:all","job:select"}, logical= Logical.OR) + @GetMapping(value = "/getJobsInfo") + public Map getJobsInfo(@RequestParam(value = "beanName",required = false) String beanName, + @RequestParam(value = "methodName",required = false) String methodName, + @RequestParam(value = "remark",required = false) String remark, + @RequestParam(value = "status",required = false) String status, + @RequestParam(value = "page",defaultValue = "1")Integer page, + @RequestParam(value = "limit",defaultValue = "10")Integer limit){ + Sort sort = new Sort(Sort.Direction.ASC,"id"); + Pageable pageable = PageRequest.of(page-1,limit,sort); + return jobService.getJobsInfo(new JobSpce(beanName,methodName,remark,status),pageable); + } + + /** + * 去新增页面 + * @return + */ + @RequiresPermissions (value={"admin", "job:all","job:add"}, logical= Logical.OR) + @GetMapping(value = "/toAddPage") + public ModelAndView toAddPage(){ + return new ModelAndView("/job/add"); + } + + /** + * 新增 + * @param job + * @return + */ + @Log("新增任务") + @RequiresPermissions (value={"admin", "job:all","job:add"}, logical= Logical.OR) + @PostMapping(value = "/insert") + public ResponseEntity insert(@Validated(Job.New.class) @RequestBody Job job){ + log.warn("REST request to insert Job : {}"+job); + jobService.insert(job); + return ResponseEntity.ok(); + } + + /** + * 更新状态 + * @param id + * @return + */ + @Log("更新任务状态") + @RequiresPermissions (value={"admin", "job:all","job:status"}, logical= Logical.OR) + @PutMapping(value = "/updateStatus") + public ResponseEntity updateStatus(@RequestParam Long id){ + log.warn("REST request to updateStatus Job : {}" +id); + jobService.updateStatus(jobService.findById(id)); + return ResponseEntity.ok(); + } + + + /** + * 去编辑页面 + * @return + */ + @RequiresPermissions (value={"admin", "job:all","job:update"}, logical= Logical.OR) + @GetMapping(value = "/toUpdatePage") + public ModelAndView toUpdatePage(@RequestParam Long id){ + Job job = jobService.findById(id); + // 获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + request.setAttribute("job", job); + return new ModelAndView("/job/update"); + } + + /** + * 更新任务 + * @param job + * @return + */ + @Log("更新任务") + @RequiresPermissions (value={"admin", "job:all","job:update"}, logical= Logical.OR) + @PutMapping(value = "/update") + public ResponseEntity update(@Validated(Job.Update.class) @RequestBody Job job) { + log.warn("REST request to update Job : {}" +job); + jobService.update(jobService.findById(job.getId()),job); + return ResponseEntity.ok(); + } + + /** + * 删除任务 + * @param id + * @return + */ + @Log("删除任务") + @RequiresPermissions (value={"admin", "job:all","job:delete"}, logical= Logical.OR) + @DeleteMapping(value = "/delete") + public ResponseEntity delete(@RequestParam Long id) { + log.warn("REST request to delete Job : {}" +id); + jobService.delete(jobService.findById(id)); + return ResponseEntity.ok(); + } + +} diff --git a/src/main/java/me/aurora/app/rest/job/JobLogController.java b/src/main/java/me/aurora/app/rest/job/JobLogController.java new file mode 100644 index 0000000..2847f33 --- /dev/null +++ b/src/main/java/me/aurora/app/rest/job/JobLogController.java @@ -0,0 +1,51 @@ +package me.aurora.app.rest.job; + +import lombok.extern.slf4j.Slf4j; +import me.aurora.annotation.Log; +import me.aurora.repository.spec.JobLogSpce; +import me.aurora.service.JobLogService; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import java.util.Map; + +/** + * @author 郑杰 + * @date 2018/10/06 11:40:21 + */ +@Slf4j +@RestController +@RequestMapping("jobLog") +public class JobLogController { + + @Autowired + private JobLogService jobLogService; + + /** + * 跳转到列表页面 + * @return + */ + @GetMapping(value = "/index") + public ModelAndView index(){ + return new ModelAndView("/job/log"); + } + + @Log("查询所有任务日志") + @RequiresPermissions(value={"admin", "job:all","job:log"}, logical= Logical.OR) + @GetMapping(value = "/getJobLogsInfo") + public Map getJobLogsInfo(@RequestParam(value = "beanName",required = false) String beanName, + @RequestParam(value = "methodName",required = false) String methodName, + @RequestParam(value = "remark",required = false) String remark, + @RequestParam(value = "status",required = false) String status, + @RequestParam(value = "page",defaultValue = "1")Integer page, + @RequestParam(value = "limit",defaultValue = "10")Integer limit){ + Sort sort = new Sort(Sort.Direction.DESC,"id"); + Pageable pageable = PageRequest.of(page-1,limit,sort); + return jobLogService.getJobLogsInfo(new JobLogSpce(beanName,methodName,remark,status),pageable); + } +} diff --git a/src/main/java/me/aurora/config/AuroraProperties.java b/src/main/java/me/aurora/config/AuroraProperties.java index 85e6868..5821f5f 100644 --- a/src/main/java/me/aurora/config/AuroraProperties.java +++ b/src/main/java/me/aurora/config/AuroraProperties.java @@ -1,7 +1,6 @@ package me.aurora.config; import lombok.Data; -import me.aurora.config.scheduled.db.DBProperties; import me.aurora.config.shiro.ShiroProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -18,8 +17,6 @@ public class AuroraProperties { private ShiroProperties shiro = new ShiroProperties(); - private DBProperties db = new DBProperties(); - private Boolean openAopLog; private String userAvatar; diff --git a/src/main/java/me/aurora/config/job/MyJobRunner.java b/src/main/java/me/aurora/config/job/MyJobRunner.java new file mode 100644 index 0000000..f3c48a6 --- /dev/null +++ b/src/main/java/me/aurora/config/job/MyJobRunner.java @@ -0,0 +1,41 @@ +package me.aurora.config.job; + +import lombok.extern.slf4j.Slf4j; +import me.aurora.domain.job.Job; +import me.aurora.repository.JobRepo; +import me.aurora.util.job.ScheduleUtils; +import org.quartz.Scheduler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; +import java.util.List; + +/** + * @author 郑杰 + * @date 2018/10/06 11:09:35 + */ +@Component +@Slf4j +public class MyJobRunner implements ApplicationRunner { + + @Autowired + private JobRepo jobRepo; + + @Resource(name = "scheduler") + private Scheduler scheduler; + + /** + * 项目启动时重新激活启用的定时任务 + * @param applicationArguments + * @throws Exception + */ + @Override + public void run(ApplicationArguments applicationArguments){ + List jobs = jobRepo.findAll(); + jobs.forEach(scheduleJob -> { + ScheduleUtils.createScheduleJob(scheduler, scheduleJob); + }); + } +} diff --git a/src/main/java/me/aurora/config/job/ScheduleConfig.java b/src/main/java/me/aurora/config/job/ScheduleConfig.java new file mode 100644 index 0000000..cf7d189 --- /dev/null +++ b/src/main/java/me/aurora/config/job/ScheduleConfig.java @@ -0,0 +1,58 @@ +package me.aurora.config.job; + +import org.quartz.Scheduler; +import org.quartz.spi.TriggerFiredBundle; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.AdaptableJobFactory; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.stereotype.Component; + +/** + * 定时任务配置 + * @author 郑杰 + */ +@Configuration +public class ScheduleConfig { + + /** + * 解决Job中注入Spring Bean为null的问题 + */ + @Component("quartzJobFactory") + public class QuartzJobFactory extends AdaptableJobFactory { + + /** + * 这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴. + */ + @Autowired + private AutowireCapableBeanFactory capableBeanFactory; + + @Override + protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { + //调用父类的方法 + Object jobInstance = super.createJobInstance(bundle); + //进行注入,这属于Spring的技术,不清楚的可以查看Spring的API. + capableBeanFactory.autowireBean(jobInstance); + return jobInstance; + } + } + + /** + * 注入scheduler到spring,在下面quartzManege会用到 + * @param quartzJobFactory + * @return + * @throws Exception + */ + @Bean(name = "scheduler") + public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception { + + SchedulerFactoryBean factoryBean=new SchedulerFactoryBean(); + factoryBean.setJobFactory(quartzJobFactory); + factoryBean.afterPropertiesSet(); + Scheduler scheduler=factoryBean.getScheduler(); + scheduler.start(); + return scheduler; + } +} diff --git a/src/main/java/me/aurora/config/scheduled/db/DBProperties.java b/src/main/java/me/aurora/config/scheduled/db/DBProperties.java deleted file mode 100644 index afca287..0000000 --- a/src/main/java/me/aurora/config/scheduled/db/DBProperties.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.aurora.config.scheduled.db; - -import lombok.Data; - -/** - * @author 郑杰 - * @date 2018/09/16 13:59:01 - */ -@Data -public class DBProperties { - - private String username; - - private String password; - - private String dbName; - - private String path; - - private String linuxDbPath; - - private String pathName; -} diff --git a/src/main/java/me/aurora/config/scheduled/db/DBRecover.java b/src/main/java/me/aurora/config/scheduled/db/DBRecover.java deleted file mode 100644 index f72b7fc..0000000 --- a/src/main/java/me/aurora/config/scheduled/db/DBRecover.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.aurora.config.scheduled.db; - -import lombok.extern.slf4j.Slf4j; -import me.aurora.config.AuroraProperties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.ClassPathResource; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -/** - * @author 郑杰 - * @date 2018/09/18 11:28:39 - * 还原数据库 - */ -@Slf4j -@Component -public class DBRecover { - - @Autowired - private AuroraProperties auroraProperties; - - /** - * 还原数据库 - * @Scheduled(cron = "0 0 1 * * ?") - * @Scheduled(cron = "0/5 * * * * ?") - */ - public void recover(){ - log.warn("=====>>>>>定时恢复数据库"); - String path = ""; - String userName = auroraProperties.getDb().getUsername(); - String password = auroraProperties.getDb().getPassword(); - String database = auroraProperties.getDb().getDbName(); - try { - InputStream file = new ClassPathResource(auroraProperties.getDb().getPath()).getInputStream(); - path = auroraProperties.getDb().getLinuxDbPath()+auroraProperties.getDb().getPathName(); - Path dBPaht = Paths.get(path); - /** - * 将本地的sql复制到linux - */ - Files.copy(file, dBPaht, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - } - String[] cmd=new String[]{"/bin/sh ","-c ","/usr/bin/mysqldump -u"+userName+" -p"+password+" "+database+ " < " + path}; - try { - Process p = Runtime.getRuntime().exec(cmd); - BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); - // 0 表示线程正常终止。 - if (p.waitFor() == 0) { - System.out.println("数据库恢复成功!"); - } else { - System.out.println("数据库恢复失败!"); - } - } catch (Exception e){ - e.printStackTrace(); - } - } -} diff --git a/src/main/java/me/aurora/config/scheduled/task/MyTaskTest.java b/src/main/java/me/aurora/config/scheduled/task/MyTaskTest.java new file mode 100644 index 0000000..1ed338c --- /dev/null +++ b/src/main/java/me/aurora/config/scheduled/task/MyTaskTest.java @@ -0,0 +1,21 @@ +package me.aurora.config.scheduled.task; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author 郑杰 + * @date 2018/10/06 10:03:43 + */ +@Slf4j +@Component +public class MyTaskTest { + + public void test(String params) { + log.info("我是带参数的test方法,正在被执行,参数为:{}" , params); + } + + public void test1() { + log.info("我是不带参数的test1方法,正在被执行"); + } +} diff --git a/src/main/java/me/aurora/domain/Dict.java b/src/main/java/me/aurora/domain/Dict.java index b58f3a1..7b4f4a5 100644 --- a/src/main/java/me/aurora/domain/Dict.java +++ b/src/main/java/me/aurora/domain/Dict.java @@ -22,20 +22,20 @@ public class Dict implements Serializable { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @NotBlank(groups = {Menu.New.class, Menu.Update.class}) + @NotBlank(groups = {New.class, Update.class}) @Column(name = "table_name",nullable = false) private String tableName; - @NotBlank(groups = {Menu.New.class, Menu.Update.class}) + @NotBlank(groups = {New.class, Update.class}) @Column(name = "fteld_name",nullable = false) private String fieldName; - @NotBlank(groups = {Menu.New.class, Menu.Update.class}) + @NotBlank(groups = {New.class, Update.class}) @Column(name = "field_value",nullable = false) private String fieldValue; @Column(name = "field_detail",nullable = false) - @NotBlank(groups = {Menu.New.class, Menu.Update.class}) + @NotBlank(groups = {New.class, Update.class}) private String fieldDetail; @CreationTimestamp diff --git a/src/main/java/me/aurora/domain/job/Job.java b/src/main/java/me/aurora/domain/job/Job.java new file mode 100644 index 0000000..90d4a3b --- /dev/null +++ b/src/main/java/me/aurora/domain/job/Job.java @@ -0,0 +1,115 @@ +package me.aurora.domain.job; + +import com.google.common.base.MoreObjects; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * @author 郑杰 + * @date 2018/10/05 19:06:42 + */ +@Data +@Entity +@Table(name = "zj_job") +public class Job implements Serializable { + + /** + * 任务调度参数key + */ + public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; + + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL("0"), + /** + * 暂停 + */ + PAUSE("1"); + + private String value; + + private ScheduleStatus(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * Bean名称 + */ + @Column(name = "baen_name") + @NotBlank(groups = {New.class,Update.class}) + private String beanName; + + /** + * 方法名称 + */ + @Column(name = "method_name") + @NotBlank(groups = {New.class,Update.class}) + private String methodName; + + /** + * 参数 + */ + @Column(name = "params") + private String params; + + /** + * cron表达式 + */ + @Column(name = "cron_expression") + @NotBlank(groups = {New.class,Update.class}) + private String cronExpression; + + /** + * 状态 0=正常,1=暂停 + */ + @Column(name = "status") + @NotBlank(groups = {New.class,Update.class}) + private String status = "0"; + + /** + * 备注 + */ + @Column(name = "remark") + @NotBlank(groups = {New.class,Update.class}) + private String remark; + + /** + * 创建日期 + */ + @UpdateTimestamp + private Timestamp updateTime; + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .add("beanName", beanName) + .add("methodName", methodName) + .add("params", params) + .add("cronExpression", cronExpression) + .add("status", status) + .add("remark", remark) + .add("updateTime", updateTime) + .toString(); + } + + public interface New{}; + public interface Update{}; +} \ No newline at end of file diff --git a/src/main/java/me/aurora/domain/job/JobLog.java b/src/main/java/me/aurora/domain/job/JobLog.java new file mode 100644 index 0000000..265f3fe --- /dev/null +++ b/src/main/java/me/aurora/domain/job/JobLog.java @@ -0,0 +1,90 @@ +package me.aurora.domain.job; + +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * @author 郑杰 + * @date 2018/10/05 19:47:38 + */ +@Entity +@Data +@Table(name = "zj_job_log") +public class JobLog implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 任务id + */ + @Column(name = "job_id") + private Long jobId; + + /** + * Bean名称 + */ + @Column(name = "baen_name") + private String beanName; + + /** + * 方法名称 + */ + @Column(name = "method_name") + private String methodName; + + /** + * 参数 + */ + @Column(name = "params") + private String params; + + /** + * cron表达式 + */ + @Column(name = "cron_expression") + private String cronExpression; + + /** + * 0=成功,1=失败 + */ + @Column(name = "status") + private String status; + + /** + * 错误信息 + */ + @Column(name = "error_msg") + private String error; + + /** + * 耗时(毫秒) + */ + private Long times; + + /** + * 创建日期 + */ + @CreationTimestamp + private Timestamp createTime; + + @Override + public String toString() { + return "JobLog{" + + "id=" + id + + ", jobId=" + jobId + + ", beanName='" + beanName + '\'' + + ", methodName='" + methodName + '\'' + + ", params='" + params + '\'' + + ", cronExpression='" + cronExpression + '\'' + + ", status='" + status + '\'' + + ", error='" + error + '\'' + + ", times=" + times + + ", createTime=" + createTime + + '}'; + } +} diff --git a/src/main/java/me/aurora/repository/JobLogRepo.java b/src/main/java/me/aurora/repository/JobLogRepo.java new file mode 100644 index 0000000..28e1cca --- /dev/null +++ b/src/main/java/me/aurora/repository/JobLogRepo.java @@ -0,0 +1,13 @@ +package me.aurora.repository; + +import me.aurora.domain.job.JobLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * @author 郑杰 + * @date 2018/10/05 19:52:11 + */ +public interface JobLogRepo extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/src/main/java/me/aurora/repository/JobRepo.java b/src/main/java/me/aurora/repository/JobRepo.java new file mode 100644 index 0000000..04d37a4 --- /dev/null +++ b/src/main/java/me/aurora/repository/JobRepo.java @@ -0,0 +1,20 @@ +package me.aurora.repository; + +import me.aurora.domain.job.Job; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * @author 郑杰 + * @date 2018/10/05 19:18:54 + */ +public interface JobRepo extends JpaRepository, JpaSpecificationExecutor { + + /** + * 查找启用的任务 + * @return + */ + List findByStatusIsTrue(); +} diff --git a/src/main/java/me/aurora/repository/spec/JobLogSpce.java b/src/main/java/me/aurora/repository/spec/JobLogSpce.java new file mode 100644 index 0000000..9a1d937 --- /dev/null +++ b/src/main/java/me/aurora/repository/spec/JobLogSpce.java @@ -0,0 +1,65 @@ +package me.aurora.repository.spec; + +import cn.hutool.core.util.StrUtil; +import me.aurora.domain.job.JobLog; +import org.springframework.data.jpa.domain.Specification; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; + + +/** + * @author 郑杰 + * @date 2018/10/06 11:43:38 + */ +public class JobLogSpce implements Specification { + + private String beanName; + private String remark; + private String methodName; + private String status; + + public JobLogSpce(String beanName, String methodName, String remark, String status) { + this.beanName = beanName; + this.remark = remark; + this.methodName = methodName; + this.status = status; + } + + @Override + public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder cb) { + List list = new ArrayList(); + + if (!StrUtil.isEmpty(status)) { + list.add(cb.equal(root.get("status").as(String.class), status)); + } + + if (!StrUtil.isEmpty(beanName)) { + list.add(cb.equal(root.get("beanName").as(String.class), "%"+beanName+"%")); + } + + if (!StrUtil.isEmpty(remark)) { + list.add(cb.like(root.get("remark").as(String.class), "%"+remark+"%")); + } + + if (!StrUtil.isEmpty(methodName)) { + list.add(cb.equal(root.get("methodName").as(String.class), "%"+methodName+"%")); + } + + Predicate[] p = new Predicate[list.size()]; + return cb.and(list.toArray(p)); + } + + @Override + public String toString() { + return "JobSpce{" + + "beanName='" + beanName + '\'' + + ", remark='" + remark + '\'' + + ", methodName='" + methodName + '\'' + + ", status='" + status + '\'' + + '}'; + } +} diff --git a/src/main/java/me/aurora/repository/spec/JobSpce.java b/src/main/java/me/aurora/repository/spec/JobSpce.java new file mode 100644 index 0000000..b97e788 --- /dev/null +++ b/src/main/java/me/aurora/repository/spec/JobSpce.java @@ -0,0 +1,68 @@ +package me.aurora.repository.spec; + +import cn.hutool.core.util.StrUtil; +import me.aurora.domain.Dict; +import me.aurora.domain.job.Job; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; + + +/** + * @author 郑杰 + * @date 2018/10/05 19:20:51 + */ +public class JobSpce implements Specification { + + private String beanName; + private String remark; + private String methodName; + private String status; + + public JobSpce(String beanName, String methodName, String remark, String status) { + this.beanName = beanName; + this.remark = remark; + this.methodName = methodName; + this.status = status; + } + + @Override + public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder cb) { + List list = new ArrayList(); + + + if (!StrUtil.isEmpty(status)) { + list.add(cb.equal(root.get("status").as(String.class), status)); + } + + if (!StrUtil.isEmpty(beanName)) { + list.add(cb.equal(root.get("beanName").as(String.class), "%"+beanName+"%")); + } + + if (!StrUtil.isEmpty(methodName)) { + list.add(cb.equal(root.get("methodName").as(String.class), "%"+methodName+"%")); + } + + if (!StrUtil.isEmpty(remark)) { + list.add(cb.like(root.get("remark").as(String.class), "%"+remark+"%")); + } + + Predicate[] p = new Predicate[list.size()]; + return cb.and(list.toArray(p)); + } + + @Override + public String toString() { + return "JobSpce{" + + "beanName='" + beanName + '\'' + + ", remark='" + remark + '\'' + + ", methodName='" + methodName + '\'' + + ", status='" + status + '\'' + + '}'; + } +} diff --git a/src/main/java/me/aurora/service/JobLogService.java b/src/main/java/me/aurora/service/JobLogService.java new file mode 100644 index 0000000..cbf3341 --- /dev/null +++ b/src/main/java/me/aurora/service/JobLogService.java @@ -0,0 +1,28 @@ +package me.aurora.service; + +import me.aurora.domain.job.JobLog; +import me.aurora.repository.spec.JobLogSpce; +import org.springframework.data.domain.Pageable; + +import java.util.Map; + +/** + * @author 郑杰 + * @date 2018/10/05 19:50:21 + */ +public interface JobLogService { + + /** + * 保存日志 + * @param log + */ + void insert(JobLog log); + + /** + * 查询全部日志 + * @param jobLogSpce + * @param pageable + * @return + */ + Map getJobLogsInfo(JobLogSpce jobLogSpce, Pageable pageable); +} diff --git a/src/main/java/me/aurora/service/JobService.java b/src/main/java/me/aurora/service/JobService.java new file mode 100644 index 0000000..2b576a7 --- /dev/null +++ b/src/main/java/me/aurora/service/JobService.java @@ -0,0 +1,63 @@ +package me.aurora.service; + +import me.aurora.domain.job.Job; +import me.aurora.repository.spec.JobSpce; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Pageable; +import java.util.Map; + +/** + * @author 郑杰 + * @date 2018/10/05 19:17:38 + */ +@CacheConfig(cacheNames = "job") +public interface JobService { + + /** + * 查询全部任务 + * @param jobSpce + * @param pageable + * @return + */ + @Cacheable(keyGenerator = "keyGenerator") + Map getJobsInfo(JobSpce jobSpce, Pageable pageable); + + /** + * 新增任务 + * @param job + */ + @CacheEvict(allEntries = true) + void insert(Job job); + + /** + * 根据ID查询 + * @param id + * @return + */ + @Cacheable(key = "#p0") + Job findById(Long id); + + /** + * 更新任务状态 + * @param byId + */ + @CacheEvict(allEntries = true) + void updateStatus(Job byId); + + /** + * 更新任务 + * @param old + * @param job + */ + @CacheEvict(allEntries = true) + void update(Job old, Job job); + + /** + * 删除任务 + * @param byId + */ + @CacheEvict(allEntries = true) + void delete(Job byId); +} diff --git a/src/main/java/me/aurora/service/impl/JobLogServiceImpl.java b/src/main/java/me/aurora/service/impl/JobLogServiceImpl.java new file mode 100644 index 0000000..b1239cd --- /dev/null +++ b/src/main/java/me/aurora/service/impl/JobLogServiceImpl.java @@ -0,0 +1,35 @@ +package me.aurora.service.impl; + +import me.aurora.domain.job.JobLog; +import me.aurora.repository.JobLogRepo; +import me.aurora.repository.spec.JobLogSpce; +import me.aurora.service.JobLogService; +import me.aurora.util.PageUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * @author 郑杰 + * @date 2018/10/05 19:51:22 + */ +@Service(value = "jobLogService") +public class JobLogServiceImpl implements JobLogService { + + @Autowired + private JobLogRepo jobLogRepo; + + @Override + public void insert(JobLog log) { + jobLogRepo.save(log); + } + + @Override + public Map getJobLogsInfo(JobLogSpce jobLogSpce, Pageable pageable) { + Page jobLogs = jobLogRepo.findAll(jobLogSpce,pageable); + return PageUtil.buildPage(jobLogs.getContent(),jobLogs.getTotalElements()); + } +} diff --git a/src/main/java/me/aurora/service/impl/JobServiceImpl.java b/src/main/java/me/aurora/service/impl/JobServiceImpl.java new file mode 100644 index 0000000..e187005 --- /dev/null +++ b/src/main/java/me/aurora/service/impl/JobServiceImpl.java @@ -0,0 +1,84 @@ +package me.aurora.service.impl; + +import cn.hutool.http.HttpStatus; +import me.aurora.config.exception.AuroraException; +import me.aurora.domain.job.Job; +import me.aurora.repository.JobRepo; +import me.aurora.repository.spec.JobSpce; +import me.aurora.service.JobService; +import me.aurora.util.PageUtil; +import me.aurora.util.ValidationUtil; +import me.aurora.util.job.ScheduleUtils; +import org.quartz.CronExpression; +import org.quartz.Scheduler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.util.Map; +import java.util.Optional; + +/** + * @author 郑杰 + * @date 2018/10/05 19:18:05 + */ +@Service(value = "jobService") +public class JobServiceImpl implements JobService { + + @Autowired + private JobRepo jobRepo; + + @Resource(name = "scheduler") + private Scheduler scheduler; + + @Override + public Map getJobsInfo(JobSpce jobSpce, Pageable pageable) { + Page jobs = jobRepo.findAll(jobSpce,pageable); + return PageUtil.buildPage(jobs.getContent(),jobs.getTotalElements()); + } + + @Override + public void insert(Job job) { + if (!CronExpression.isValidExpression(job.getCronExpression())){ + throw new AuroraException(HttpStatus.HTTP_BAD_REQUEST,"cron表达式格式错误"); + } + jobRepo.save(job); + ScheduleUtils.createScheduleJob(scheduler, job); + } + + @Override + public Job findById(Long id) { + Optional job = jobRepo.findById(id); + ValidationUtil.isNull(job,"id :" +id +" is not find"); + return job.get(); + } + + @Override + public void updateStatus(Job job) { + if (job.getStatus().equals(Job.ScheduleStatus.PAUSE.getValue())) { + ScheduleUtils.resumeJob(scheduler, job.getId()); + job.setStatus("0"); + } else { + ScheduleUtils.pauseJob(scheduler,job.getId()); + job.setStatus("1"); + } + jobRepo.save(job); + } + + @Override + public void update(Job old, Job job) { + if (!CronExpression.isValidExpression(job.getCronExpression())){ + throw new AuroraException(HttpStatus.HTTP_BAD_REQUEST,"cron表达式格式错误"); + } + job.setStatus(old.getStatus()); + jobRepo.save(job); + ScheduleUtils.updateScheduleJob(scheduler,job); + } + + @Override + public void delete(Job job) { + ScheduleUtils.deleteScheduleJob(scheduler,job.getId()); + jobRepo.delete(job); + } +} diff --git a/src/main/java/me/aurora/service/impl/PermissionServiceImpl.java b/src/main/java/me/aurora/service/impl/PermissionServiceImpl.java index 8673af7..4a7acf7 100644 --- a/src/main/java/me/aurora/service/impl/PermissionServiceImpl.java +++ b/src/main/java/me/aurora/service/impl/PermissionServiceImpl.java @@ -12,6 +12,7 @@ import me.aurora.service.mapper.PerMissionMapper; import me.aurora.util.PageUtil; import me.aurora.config.exception.AuroraException; import me.aurora.util.ValidationUtil; +import me.aurora.util.job.ScheduleUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -88,21 +89,22 @@ public class PermissionServiceImpl implements PermissionService { @Override public List> buildPermissionTree(List permissions) { List> maps = new LinkedList<>(); - for (Permission permission:permissions) { - if (permission!=null){ - List permissionList = permissionRepo.findByPid(Integer.parseInt(permission.getId()+"")); - Map map = new HashMap<>(16); - map.put("id",permission.getId()); - String name = !StrUtil.isEmpty(permission.getRemark())?permission.getRemark():permission.getPerms(); - map.put("name",name); - if(permissionList!=null && permissionList.size()!=0){ - map.put("open",true); - map.put("isParent",true); - map.put("children",buildPermissionTree(permissionList)); + permissions.forEach(permission -> { + if (permission!=null){ + List permissionList = permissionRepo.findByPid(Integer.parseInt(permission.getId()+"")); + Map map = new HashMap<>(16); + map.put("id",permission.getId()); + String name = !StrUtil.isEmpty(permission.getRemark())?permission.getRemark():permission.getPerms(); + map.put("name",name); + if(permissionList!=null && permissionList.size()!=0){ + map.put("open",true); + map.put("isParent",true); + map.put("children",buildPermissionTree(permissionList)); + } + maps.add(map); } - maps.add(map); } - } + ); return maps; } diff --git a/src/main/java/me/aurora/service/impl/RoleServiceImpl.java b/src/main/java/me/aurora/service/impl/RoleServiceImpl.java index e4a2599..8ae6a65 100644 --- a/src/main/java/me/aurora/service/impl/RoleServiceImpl.java +++ b/src/main/java/me/aurora/service/impl/RoleServiceImpl.java @@ -36,14 +36,14 @@ public class RoleServiceImpl implements RoleService { @Override public List> buildRoleTree(List roles) { List> maps = new LinkedList<>(); - for (Role role:roles) { + roles.forEach(role -> { if (role!=null){ Map map = new HashMap<>(16); map.put("id",role.getId()); map.put("name",role.getName()); maps.add(map); } - } + }); return maps; } diff --git a/src/main/java/me/aurora/service/impl/UserServiceImpl.java b/src/main/java/me/aurora/service/impl/UserServiceImpl.java index 1c0a49e..9d014aa 100644 --- a/src/main/java/me/aurora/service/impl/UserServiceImpl.java +++ b/src/main/java/me/aurora/service/impl/UserServiceImpl.java @@ -70,10 +70,10 @@ public class UserServiceImpl implements UserService { public Map getUsersInfo(UserSpec userSpec, Pageable pageable) { Page users = userRepo.findAll(userSpec,pageable); List userDTOS = new ArrayList<>(); - for(User user:users.getContent()){ + users.getContent().forEach(user -> { UserDTO userDTO = userMapper.toDto(user,roleService.getRoles(user.getRoles())); userDTOS.add(userDTO); - } + }); return PageUtil.buildPage(userDTOS,users.getTotalElements()); } diff --git a/src/main/java/me/aurora/util/job/ScheduleJob.java b/src/main/java/me/aurora/util/job/ScheduleJob.java new file mode 100644 index 0000000..8b22669 --- /dev/null +++ b/src/main/java/me/aurora/util/job/ScheduleJob.java @@ -0,0 +1,73 @@ +package me.aurora.util.job; + +import me.aurora.domain.job.Job; +import me.aurora.domain.job.JobLog; +import me.aurora.service.JobLogService; +import me.aurora.service.JobService; +import me.aurora.util.SpringContextUtils; +import org.apache.commons.lang3.StringUtils; +import org.quartz.JobExecutionContext; +import org.quartz.Scheduler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.quartz.QuartzJobBean; +import javax.annotation.Resource; +import java.util.concurrent.*; + +/** + * 用于记录日志 + * 定时任务 + * @author 郑杰 + */ +public class ScheduleJob extends QuartzJobBean { + + @Resource(name = "scheduler") + private Scheduler scheduler; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ExecutorService service = Executors.newSingleThreadExecutor(); + + @Override + protected void executeInternal(JobExecutionContext context) { + Job scheduleJob = (Job) context.getMergedJobDataMap().get(Job.JOB_PARAM_KEY); + + // 获取spring bean + JobLogService logService = (JobLogService) SpringContextUtils.getBean("jobLogService"); + JobService jobService = (JobService) SpringContextUtils.getBean("jobService"); + + JobLog log = new JobLog(); + log.setJobId(scheduleJob.getId()); + log.setBeanName(scheduleJob.getBeanName()); + log.setMethodName(scheduleJob.getMethodName()); + log.setParams(scheduleJob.getParams()); + long startTime = System.currentTimeMillis(); + log.setCronExpression(scheduleJob.getCronExpression()); + try { + // 执行任务 + logger.info("任务准备执行,任务ID:{}", scheduleJob.getId()); + ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(), scheduleJob.getMethodName(), + scheduleJob.getParams()); + Future future = service.submit(task); + future.get(); + long times = System.currentTimeMillis() - startTime; + log.setTimes(times); + // 任务状态 0:成功 1:失败 + log.setStatus("0"); + logger.info("任务执行完毕,任务ID:{} 总共耗时:{} 毫秒", scheduleJob.getId(), times); + } catch (Exception e) { + logger.error("任务执行失败,任务ID:" + scheduleJob.getId(), e); + long times = System.currentTimeMillis() - startTime; + log.setTimes(times); + // 任务状态 0:成功 1:失败 + log.setStatus("1"); + log.setError(StringUtils.substring(e.toString(), 0, 2000)); + //出错就暂停任务 + ScheduleUtils.pauseJob(scheduler,scheduleJob.getId()); + //更新状态 + jobService.updateStatus(scheduleJob); + } finally { + logService.insert(log); + } + } +} diff --git a/src/main/java/me/aurora/util/job/ScheduleRunnable.java b/src/main/java/me/aurora/util/job/ScheduleRunnable.java new file mode 100644 index 0000000..2eb5722 --- /dev/null +++ b/src/main/java/me/aurora/util/job/ScheduleRunnable.java @@ -0,0 +1,49 @@ +package me.aurora.util.job; + +import me.aurora.util.SpringContextUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; + +/** + * 执行定时任务 + * @author 郑杰 + * + */ +public class ScheduleRunnable implements Runnable { + + private Logger log = LoggerFactory.getLogger(this.getClass()); + + private Object target; + private Method method; + private String params; + + ScheduleRunnable(String beanName, String methodName, String params) + throws NoSuchMethodException, SecurityException { + this.target = SpringContextUtils.getBean(beanName); + this.params = params; + + if (StringUtils.isNotBlank(params)) { + this.method = target.getClass().getDeclaredMethod(methodName, String.class); + } else { + this.method = target.getClass().getDeclaredMethod(methodName); + } + } + + @Override + public void run() { + try { + ReflectionUtils.makeAccessible(method); + if (StringUtils.isNotBlank(params)) { + method.invoke(target, params); + } else { + method.invoke(target); + } + } catch (Exception e) { + log.error("执行定时任务失败",e); + } + } + +} diff --git a/src/main/java/me/aurora/util/job/ScheduleUtils.java b/src/main/java/me/aurora/util/job/ScheduleUtils.java new file mode 100644 index 0000000..1f99d38 --- /dev/null +++ b/src/main/java/me/aurora/util/job/ScheduleUtils.java @@ -0,0 +1,175 @@ +package me.aurora.util.job; + +import cn.hutool.http.HttpStatus; +import lombok.extern.slf4j.Slf4j; +import me.aurora.config.exception.AuroraException; +import me.aurora.domain.job.Job; +import org.quartz.*; +import org.quartz.impl.triggers.CronTriggerImpl; +import java.util.Date; + +/** + * 定时任务工具类 + * @author 郑杰 + */ +@Slf4j +public class ScheduleUtils { + + protected ScheduleUtils() { + } + + private static final String JOB_NAME = "TASK_"; + + /** + * 获取触发器key + */ + private static TriggerKey getTriggerKey(Long id) { + return TriggerKey.triggerKey(JOB_NAME + id); + } + + /** + * 获取jobKey + */ + private static JobKey getJobKey(Long id) { + return JobKey.jobKey(JOB_NAME + id); + } + + /** + * 获取表达式触发器 + */ + public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) { + try { + return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId)); + } catch (SchedulerException e) { + log.error("获取Cron表达式失败", e); + } + return null; + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, Job scheduleJob) { + try { + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getId())) + .build(); + + // 表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) + .withMisfireHandlingInstructionDoNothing(); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getId())) + .withSchedule(scheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(Job.JOB_PARAM_KEY, scheduleJob); + + //重置启动时间 + ((CronTriggerImpl)trigger).setStartTime(new Date()); + + //执行定时任务 + scheduler.scheduleJob(jobDetail, trigger); + + // 暂停任务 + if (scheduleJob.getStatus().equals(Job.ScheduleStatus.PAUSE.getValue())) { + pauseJob(scheduler, scheduleJob.getId()); + } + } catch (SchedulerException e) { + log.error("创建定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"创建定时任务失败"); + } + } + + /** + * 更新定时任务 + */ + public static void updateScheduleJob(Scheduler scheduler, Job scheduleJob) { + try { + TriggerKey triggerKey = getTriggerKey(scheduleJob.getId()); + + // 表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) + .withMisfireHandlingInstructionDoNothing(); + + CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getId()); + + if (trigger == null) { + throw new SchedulerException("获取Cron表达式失败"); + } else { + // 按新的cronExpression表达式重新构建trigger + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + // 参数 + trigger.getJobDataMap().put(Job.JOB_PARAM_KEY, scheduleJob); + } + + //重置启动时间 + ((CronTriggerImpl)trigger).setStartTime(new Date()); + + //重置表达式 + scheduler.rescheduleJob(triggerKey, trigger); + + // 暂停任务 + if (scheduleJob.getStatus().equals(Job.ScheduleStatus.PAUSE.getValue())) { + pauseJob(scheduler, scheduleJob.getId()); + } + + } catch (SchedulerException e) { + log.error("更新定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"更新定时任务失败"); + } + } + + /** + * 立即执行任务 + */ + public static void run(Scheduler scheduler, Job scheduleJob) { + try { + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(Job.JOB_PARAM_KEY, scheduleJob); + + scheduler.triggerJob(getJobKey(scheduleJob.getId()), dataMap); + } catch (SchedulerException e) { + log.error("执行定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"执行定时任务失败"); + } + } + + /** + * 暂停任务 + */ + public static void pauseJob(Scheduler scheduler, Long jobId) { + try { + scheduler.pauseJob(getJobKey(jobId)); + } catch (SchedulerException e) { + log.error("暂停定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"暂停定时任务失败"); + } + } + + /** + * 恢复任务 + */ + public static void resumeJob(Scheduler scheduler, Long jobId) { + try { + scheduler.resumeJob(getJobKey(jobId)); + } catch (SchedulerException e) { + log.error("恢复定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"恢复定时任务失败"); + } + } + + /** + * 删除定时任务 + */ + public static void deleteScheduleJob(Scheduler scheduler, Long jobId) { + try { + scheduler.deleteJob(getJobKey(jobId)); + } catch (SchedulerException e) { + log.error("删除定时任务失败", e); + throw new AuroraException(HttpStatus.HTTP_INTERNAL_ERROR,"删除定时任务失败"); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 38e62b4..9475760 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -134,13 +134,4 @@ aurora: unauthorizedUrl: /exception/403 # 是否开启 AOP 日志,默认开启 openAopLog: true - userAvatar: https://i.loli.net/2018/08/16/5b75166b3157a.jpg - - db: - username: root - password: dqjdda@1996. - dbName: aurora - # 将resources下的sql文件,复制到Windows或者linux系统下,用于还原操作 - path: sql/aurora.sql - pathName: aurora.sql - linuxDbPath: /data/db \ No newline at end of file + userAvatar: https://i.loli.net/2018/08/16/5b75166b3157a.jpg \ No newline at end of file diff --git a/src/main/resources/sql/aurora.sql b/src/main/resources/sql/aurora.sql index 99b431c..2eceac5 100644 --- a/src/main/resources/sql/aurora.sql +++ b/src/main/resources/sql/aurora.sql @@ -11,7 +11,7 @@ Target Server Version : 50559 File Encoding : 65001 - Date: 05/10/2018 15:02:12 + Date: 06/10/2018 14:05:55 */ SET NAMES utf8mb4; @@ -54,7 +54,7 @@ CREATE TABLE `zj_dict` ( `table_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `updateTime` datetime NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of zj_dict @@ -68,6 +68,10 @@ INSERT INTO `zj_dict` VALUES (6, '2018-10-05 14:15:18', '内链菜单', 'iframe' INSERT INTO `zj_dict` VALUES (7, '2018-10-05 14:15:39', '外链菜单', 'iframe', '1', 'zj_menu', '2018-10-05 14:15:39'); INSERT INTO `zj_dict` VALUES (8, '2018-10-05 14:16:36', '系统菜单', 'sys', '1', 'zj_menu', '2018-10-05 14:16:36'); INSERT INTO `zj_dict` VALUES (9, '2018-10-05 14:16:55', '普通菜单', 'sys', '0', 'zj_menu', '2018-10-05 14:16:55'); +INSERT INTO `zj_dict` VALUES (11, '2018-10-06 12:31:03', '启动', 'status', '0', 'zj_job', '2018-10-06 12:31:03'); +INSERT INTO `zj_dict` VALUES (12, '2018-10-06 12:31:19', '暂停', 'status', '1', 'zj_job', '2018-10-06 12:31:19'); +INSERT INTO `zj_dict` VALUES (13, '2018-10-06 12:31:36', '成功', 'status', '0', 'zj_job_log', '2018-10-06 12:31:36'); +INSERT INTO `zj_dict` VALUES (14, '2018-10-06 12:31:49', '失败', 'status', '1', 'zj_job_log', '2018-10-06 12:31:49'); -- ---------------------------- -- Table structure for zj_email_config @@ -89,6 +93,46 @@ CREATE TABLE `zj_email_config` ( -- ---------------------------- INSERT INTO `zj_email_config` VALUES (1, 'auaur@sina.com', 'smtp.sina.com', '21BC734311FFD2BA881D34A08DAB61AE', '465', 'auaur', b'1'); +-- ---------------------------- +-- Table structure for zj_job +-- ---------------------------- +DROP TABLE IF EXISTS `zj_job`; +CREATE TABLE `zj_job` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `baen_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `params` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `updateTime` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Records of zj_job +-- ---------------------------- +INSERT INTO `zj_job` VALUES (1, 'myTaskTest', '0/5 * * * * ?', 'test', '测试', '带参数测试', '1', '2018-10-06 12:45:19'); +INSERT INTO `zj_job` VALUES (2, 'myTaskTest', '0/6 * * * * ?', 'test1', '', '不带参数测试', '1', '2018-10-06 12:46:13'); + +-- ---------------------------- +-- Table structure for zj_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `zj_job_log`; +CREATE TABLE `zj_job_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `baen_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `createTime` datetime NULL DEFAULT NULL, + `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `error_msg` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `job_id` bigint(20) NULL DEFAULT NULL, + `method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `params` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `times` bigint(20) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + -- ---------------------------- -- Table structure for zj_menu -- ---------------------------- @@ -108,7 +152,7 @@ CREATE TABLE `zj_menu` ( `sys` bit(1) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `UK_cbhg0bi3f1emxkhqqtvca9btx`(`soft`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of zj_menu @@ -131,6 +175,9 @@ INSERT INTO `zj_menu` VALUES (22, 'layui-icon-edit', 18, 2, '邮件工具', 41, INSERT INTO `zj_menu` VALUES (24, 'layui-icon-dollar', 18, 2, '支付宝工具', 42, '/aliPay/index', '2018-09-30 15:16:43', '2018-10-02 16:27:09', 0, b'0', b'1'); INSERT INTO `zj_menu` VALUES (25, 'layui-icon-upload', 18, 2, '七牛云存储', 43, '/qiNiu/index', '2018-10-02 11:03:27', '2018-10-02 16:26:42', 0, b'0', b'1'); INSERT INTO `zj_menu` VALUES (27, 'layui-icon-read', 7, 2, '字典管理', 6, '/dict/index', '2018-10-05 14:03:40', '2018-10-05 14:03:40', 0, b'0', b'0'); +INSERT INTO `zj_menu` VALUES (28, 'layui-icon-log', 0, 1, '任务调度', 20, '', '2018-10-06 10:37:11', '2018-10-06 11:55:59', 2, b'0', b'0'); +INSERT INTO `zj_menu` VALUES (29, 'layui-icon-radio', 28, 2, '定时任务', 21, '/job/index', '2018-10-06 10:38:06', '2018-10-06 10:38:06', 0, b'0', b'0'); +INSERT INTO `zj_menu` VALUES (30, 'layui-icon-survey', 28, 2, '调度日志', 22, '/jobLog/index', '2018-10-06 11:55:59', '2018-10-06 11:55:59', 0, b'0', b'0'); -- ---------------------------- -- Table structure for zj_menus_roles @@ -166,6 +213,9 @@ INSERT INTO `zj_menus_roles` VALUES (22, 1); INSERT INTO `zj_menus_roles` VALUES (24, 1); INSERT INTO `zj_menus_roles` VALUES (25, 1); INSERT INTO `zj_menus_roles` VALUES (27, 1); +INSERT INTO `zj_menus_roles` VALUES (28, 1); +INSERT INTO `zj_menus_roles` VALUES (29, 1); +INSERT INTO `zj_menus_roles` VALUES (30, 1); INSERT INTO `zj_menus_roles` VALUES (5, 3); INSERT INTO `zj_menus_roles` VALUES (6, 3); INSERT INTO `zj_menus_roles` VALUES (7, 3); @@ -194,7 +244,7 @@ CREATE TABLE `zj_permission` ( `pid` int(11) NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `UK_djtxn2vldlgrkfk21d155b48i`(`perms`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of zj_permission @@ -232,6 +282,13 @@ INSERT INTO `zj_permission` VALUES (33, 'dict:select', '字典查询', '2018-10- INSERT INTO `zj_permission` VALUES (34, 'dict:add', '新增字典', '2018-10-05 14:01:19', '2018-10-05 14:01:19', 32); INSERT INTO `zj_permission` VALUES (35, 'dict:update', '更新字典', '2018-10-05 14:01:33', '2018-10-05 14:01:33', 32); INSERT INTO `zj_permission` VALUES (36, 'dict:delete', '删除字典', '2018-10-05 14:01:46', '2018-10-05 14:01:46', 32); +INSERT INTO `zj_permission` VALUES (37, 'job:all', '任务调度', '2018-10-06 12:28:06', '2018-10-06 12:28:06', 0); +INSERT INTO `zj_permission` VALUES (38, 'job:select', '任务查询', '2018-10-06 12:28:39', '2018-10-06 12:28:39', 37); +INSERT INTO `zj_permission` VALUES (39, 'job:log', '任务日志查询', '2018-10-06 12:28:59', '2018-10-06 12:29:06', 37); +INSERT INTO `zj_permission` VALUES (40, 'job:add', '新增任务', '2018-10-06 12:29:28', '2018-10-06 12:29:28', 37); +INSERT INTO `zj_permission` VALUES (41, 'job:status', '任务状态修改', '2018-10-06 12:29:45', '2018-10-06 12:29:45', 37); +INSERT INTO `zj_permission` VALUES (42, 'job:update', '更新任务', '2018-10-06 12:30:00', '2018-10-06 12:30:00', 37); +INSERT INTO `zj_permission` VALUES (43, 'job:delete', '删除任务', '2018-10-06 12:30:16', '2018-10-06 12:30:16', 37); -- ---------------------------- -- Table structure for zj_permissions_roles @@ -275,7 +332,7 @@ CREATE TABLE `zj_picture` ( PRIMARY KEY (`id`) USING BTREE, INDEX `FK5qtt7wql9517j0e2read2pdus`(`user_id`) USING BTREE, CONSTRAINT `FK5qtt7wql9517j0e2read2pdus` FOREIGN KEY (`user_id`) REFERENCES `zj_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of zj_picture @@ -315,12 +372,7 @@ CREATE TABLE `zj_qiniu_content` ( `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `updateTime` datetime NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; - --- ---------------------------- --- Records of zj_qiniu_content --- ---------------------------- -INSERT INTO `zj_qiniu_content` VALUES (1, 'aurora', '8.49KB ', '5ba46d305018d20181003145806.jpg', '公开', 'http://pfywktugt.bkt.clouddn.com/5ba46d305018d20181003145806.jpg', '2018-10-05 11:50:30'); +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Table structure for zj_role @@ -356,7 +408,7 @@ CREATE TABLE `zj_syslog` ( `time` int(11) NULL DEFAULT NULL, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 369 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Table structure for zj_user @@ -373,12 +425,12 @@ CREATE TABLE `zj_user` ( `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `UK_kpubos9gc2cvtkb0thktkbkes`(`email`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of zj_user -- ---------------------------- -INSERT INTO `zj_user` VALUES (1, 'https://www.zhengjie.me/images/avatar.jpg', '2018-08-23 09:11:56', 'zhengjie@tom.com', 1, '2018-10-05 14:58:50', '65a674ce6632479005ea7a9071234cfb', 'aurora'); +INSERT INTO `zj_user` VALUES (1, 'https://www.zhengjie.me/images/avatar.jpg', '2018-08-23 09:11:56', 'zhengjie@tom.com', 1, '2018-10-06 14:01:49', '65a674ce6632479005ea7a9071234cfb', 'aurora'); INSERT INTO `zj_user` VALUES (2, 'https://i.loli.net/2018/08/16/5b75166b3157a.jpg', '2018-10-03 09:16:20', 'everyone@aurora.xyz', 1, '2018-10-05 11:29:44', '36318d4cc46eb68050b8b81ebc620f05', 'everyone'); -- ---------------------------- diff --git a/src/main/resources/templates/common/app.html b/src/main/resources/templates/common/app.html index b2ac5f5..723fdfd 100644 --- a/src/main/resources/templates/common/app.html +++ b/src/main/resources/templates/common/app.html @@ -114,7 +114,7 @@ 版本号 - v1.0 + v1.1 前端框架 @@ -135,7 +135,7 @@
-
关于Aurora 1.0
+
关于Aurora
    @@ -190,7 +190,7 @@
  • -

    2018年9月28日 - 至今 (v1.0.1)

    +

    2018年9月28日 (v1.0.1)

    #集成了第三方工具

      @@ -198,8 +198,19 @@
    • 邮件发送工具
    • 支付宝支付
    • 七牛云储存
    • -
    • 微信支付(开发中)
    • -
    • 阿里大鱼(开发中)
    • +
    +

    +
    +
  • +
  • + +
    +

    2018年10月6日 (v1.1)

    +

    + #v1.1发布,集成任务调度 +

      +
    • 任务调度
    • +
    • 调度日志

    diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index ff69668..0b37853 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -3,7 +3,7 @@ - Aurora 1.0 后台管理 + Aurora 后台管理 @@ -19,7 +19,7 @@
diff --git a/src/main/resources/templates/job/add.html b/src/main/resources/templates/job/add.html new file mode 100644 index 0000000..8fa4f19 --- /dev/null +++ b/src/main/resources/templates/job/add.html @@ -0,0 +1,48 @@ + + + + + + Aurora- 新增任务 + + + + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/job/index.html b/src/main/resources/templates/job/index.html new file mode 100644 index 0000000..a258a05 --- /dev/null +++ b/src/main/resources/templates/job/index.html @@ -0,0 +1,300 @@ +
+
+
+
+
定时任务管理
+
+ +
+ + +
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/job/log.html b/src/main/resources/templates/job/log.html new file mode 100644 index 0000000..1b35aa8 --- /dev/null +++ b/src/main/resources/templates/job/log.html @@ -0,0 +1,137 @@ +
+
+
+
+
调度日志
+
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/job/update.html b/src/main/resources/templates/job/update.html new file mode 100644 index 0000000..2093a6d --- /dev/null +++ b/src/main/resources/templates/job/update.html @@ -0,0 +1,49 @@ + + + + + + Aurora- 新增任务 + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/utils/email/index.html b/src/main/resources/templates/utils/email/index.html index 008213f..a1096d3 100644 --- a/src/main/resources/templates/utils/email/index.html +++ b/src/main/resources/templates/utils/email/index.html @@ -7,9 +7,6 @@ -
@@ -44,7 +41,7 @@
注意,某些邮箱需要为SMTP服务单独设置密码
- +
@@ -52,9 +49,9 @@
- +
- +
邮件服务器SMTP端口