初始代码

This commit is contained in:
wangmingwei
2026-04-21 17:18:06 +08:00
parent ac9e431f80
commit aa74bd741e
259 changed files with 45901 additions and 0 deletions

22
xxl-job-admin/Dockerfile Normal file
View File

@@ -0,0 +1,22 @@
# 基础镜像
FROM bellsoft/liberica-openjre-rocky:21
# FROM bellsoft/liberica-openjre-rocky:17
# FROM bellsoft/liberica-openjre-rocky:11
# FROM bellsoft/liberica-openjre-rocky:8
LABEL maintainer=yunzhupaas-team
# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 指定运行时的工作目录
WORKDIR /data/yunzhupaassoft/scheduletaskApi
# 将构建产物jar包拷贝到运行时目录中
COPY target/*.jar ./yunzhupaas-scheduletask-server.jar
# 指定容器内运行端口
EXPOSE 30020
# 指定容器启动时要运行的命令
ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -Djava.security.egd=file:/dev/./urandom -jar yunzhupaas-scheduletask-server.jar"]

185
xxl-job-admin/pom.xml Normal file
View File

@@ -0,0 +1,185 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>
<artifactId>yunzhupaas-dependencies</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
<relativePath/>
</parent>
<groupId>com.yunzhupaas</groupId>
<artifactId>xxl-job-admin</artifactId>
<packaging>jar</packaging>
<version>5.2.0-RELEASE</version>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencyManagement>
</dependencyManagement>
<dependencies>
<!-- starter-webspring-webmvc + autoconfigure + logback + yaml + tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- starter-testjunit + spring-test + mockito -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- freemarker-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- mail-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-scheduletask-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!--sqlserver-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!-- oracle -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.nls</groupId>
<artifactId>orai18n</artifactId>
</dependency>
<!-- dm -->
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
</dependency>
<!-- 金仓 -->
<dependency>
<groupId>cn.com.kingbase</groupId>
<artifactId>kingbase8</artifactId>
</dependency>
<!--PostGre-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!--GaussDB-->
<!--<dependency>
<groupId>org.opengauss</groupId>
<artifactId>opengauss-jdbc</artifactId>
</dependency>-->
<!--HighgoDB-->
<!--<dependency>
<groupId>com.highgo</groupId>
<artifactId>hgdb-pgjdbc</artifactId>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- docker -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version>
<configuration>
<!-- made of '[a-z0-9-_.]' -->
<imageName>${project.artifactId}:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>boot3</id>
<activation>
<jdk>[17,)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.vesion}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>boot2</id>
<activation>
<jdk>(,17)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.vesion}</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,20 @@
package com.xxl.job.admin;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author xuxueli 2018-10-28 00:38:13
*/
@EnableAsync
@SpringBootApplication(scanBasePackages = { "com.xxl.job", "com.yunzhupaas" })
@MapperScan(basePackages = { "com.xxl.job.admin.dao", "com.xxl.job.admin.mapper" })
public class XxlJobAdminApplication {
public static void main(String[] args) {
SpringApplication.run(XxlJobAdminApplication.class, args);
}
}

View File

@@ -0,0 +1,35 @@
package com.xxl.job.admin.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.xxl.job.admin.service.HandlerNameService;
import com.yunzhupaas.util.context.SpringContext;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 8:49
*/
@Component
public class XxlJobListener implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
HandlerNameService handlerNameService = SpringContext.getBean(HandlerNameService.class);
handlerNameService.removeAll();
}
@Bean
public MybatisPlusInterceptor pageHelper() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

View File

@@ -0,0 +1,97 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.impl.XxlJobLoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* index controller
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
public class IndexController {
@Resource
private XxlJobService xxlJobService;
@Resource
private XxlJobLoginService loginService;
@RequestMapping("/")
public String index(Model model) {
Map<String, Object> dashboardMap = xxlJobService.dashboardInfo();
model.addAllAttributes(dashboardMap);
return "index";
}
@RequestMapping("/chartInfo")
@ResponseBody
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
return chartInfo;
}
@RequestMapping("/toLogin")
@PermissionLimit(limit=false)
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response,ModelAndView modelAndView) {
if (loginService.ifLogin(request, response) != null) {
modelAndView.setView(new RedirectView("/",true,false));
return modelAndView;
}
return new ModelAndView("login");
}
@RequestMapping(value="login", method=RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit=false)
public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
return loginService.login(request, response, userName, password, ifRem);
}
@RequestMapping(value="logout", method=RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit=false)
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
return loginService.logout(request, response);
}
@RequestMapping("/help")
public String help() {
/*if (!PermissionInterceptor.ifLogin(request)) {
return "redirect:/toLogin";
}*/
return "help";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
}

View File

@@ -0,0 +1,109 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.service.HandlerNameService;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.GsonTool;
import com.xxl.job.core.util.XxlJobRemotingUtil;
import com.yunzhupaas.scheduletask.entity.HandlerNameEntity;
import com.yunzhupaas.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xxl.job.core.biz.model.RegistryHandlerName;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Created by xuxueli on 17/5/10.
*/
@Controller
@RequestMapping("/api")
public class JobApiController {
@Resource
private AdminBiz adminBiz;
@Autowired
private HandlerNameService handlerNameService;
/**
* api
*
* @param uri
* @param data
* @return
*/
@RequestMapping("/{uri}")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri,
@RequestBody(required = false) String data) {
// valid
if (!"POST".equalsIgnoreCase(request.getMethod())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
}
if (uri == null || uri.trim().length() == 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
}
if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null
&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0
&& !XxlJobAdminConfig.getAdminConfig().getAccessToken()
.equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
}
// services mapping
if ("callback".equals(uri)) {
List<HandleCallbackParam> callbackParamList = GsonTool.fromJsonList(data, HandleCallbackParam.class);
return adminBiz.callback(callbackParamList);
} else if ("registry".equals(uri)) {
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
return adminBiz.registry(registryParam);
} else if ("registryRemove".equals(uri)) {
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
return adminBiz.registryRemove(registryParam);
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
}
}
/**
* api
*
* @param data
* @return
*/
@RequestMapping("/{uri}/handlerName")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> registryHandler(@PathVariable("uri") String uri,
@RequestBody(required = false) String data) {
RegistryHandlerName handlerName = JsonUtil.getJsonToBean(data, RegistryHandlerName.class);
if (handlerName != null) {
for (String hand : handlerName.getHandlerList()) {
HandlerNameEntity entity = new HandlerNameEntity();
entity.setExecutor(handlerName.getExecutorName());
entity.setHandlerName(hand);
// 注册前先删除
handlerNameService.delete(entity);
if (!"remove".equals(uri)) {
handlerNameService.create(entity);
}
}
}
return new ReturnT<>(ReturnT.SUCCESS_CODE, "处理成功");
}
}

View File

@@ -0,0 +1,103 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.service.XxlJobInfoService;
import com.xxl.job.admin.service.XxlJobLogGlueService;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
/**
* job code controller
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/jobcode")
public class JobCodeController {
@Autowired
private XxlJobInfoService xxlJobInfoService;
@Resource
private XxlJobLogGlueService xxlJobLogGlueService;
@RequestMapping
public String index(HttpServletRequest request, Model model, String jobId) {
XxlJobInfo jobInfo = xxlJobInfoService.loadById(jobId);
List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueService.findByJobId(jobId);
if (jobInfo == null) {
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
}
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
// Glue类型-字典
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
model.addAttribute("jobInfo", jobInfo);
model.addAttribute("jobLogGlues", jobLogGlues);
return "jobcode/jobcode.index";
}
@RequestMapping("/save")
@ResponseBody
public ReturnT<String> save(HttpServletRequest request, String id, String glueSource, String glueRemark) {
// valid
if (glueRemark==null) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
}
if (glueRemark.length()<4 || glueRemark.length()>100) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
}
XxlJobInfo existsJobInfo = xxlJobInfoService.loadById(id);
if (existsJobInfo == null) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
// valid permission
PermissionInterceptor.validJobGroupPermission(request, existsJobInfo.getJobGroup());
// update new code
existsJobInfo.setGlueSource(glueSource);
existsJobInfo.setGlueRemark(glueRemark);
existsJobInfo.setGlueUpdatetime(new Date());
existsJobInfo.setUpdateTime(new Date());
xxlJobInfoService.update(existsJobInfo);
// log old code
XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();
xxlJobLogGlue.setJobId(existsJobInfo.getId());
xxlJobLogGlue.setGlueType(existsJobInfo.getGlueType());
xxlJobLogGlue.setGlueSource(glueSource);
xxlJobLogGlue.setGlueRemark(glueRemark);
xxlJobLogGlue.setAddTime(new Date());
xxlJobLogGlue.setUpdateTime(new Date());
xxlJobLogGlueService.save(xxlJobLogGlue);
// remove code backup more than 30
xxlJobLogGlueService.removeOld(existsJobInfo.getId(), 30);
return ReturnT.SUCCESS;
}
}

View File

@@ -0,0 +1,205 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.XxlJobGroupService;
import com.xxl.job.admin.service.XxlJobInfoService;
import com.xxl.job.admin.service.XxlJobRegistryService;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
/**
* job group controller
* @author xuxueli 2016-10-02 20:52:56
*/
@Controller
@RequestMapping("/jobgroup")
public class JobGroupController {
@Autowired
public XxlJobInfoService xxlJobInfoService;
@Autowired
public XxlJobGroupService xxlJobGroupService;
@Autowired
private XxlJobRegistryService xxlJobRegistryService;
@RequestMapping
@PermissionLimit(adminuser = true)
public String index(Model model) {
return "jobgroup/jobgroup.index";
}
@RequestMapping("/pageList")
@ResponseBody
@PermissionLimit(adminuser = true)
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String appname, String title) {
// page query
List<XxlJobGroup> list = xxlJobGroupService.pageList(start, length, appname, title);
long list_count = xxlJobGroupService.pageListCount(start, length, appname, title);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/save")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> save(XxlJobGroup xxlJobGroup){
// valid
if (xxlJobGroup.getAppname()==null || xxlJobGroup.getAppname().trim().length()==0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
}
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length") );
}
if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) {
return new ReturnT<String>(500, "AppName"+I18nUtil.getString("system_unvalid") );
}
if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
}
if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_title")+I18nUtil.getString("system_unvalid") );
}
if (xxlJobGroup.getAddressType()!=0) {
if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
}
if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList")+I18nUtil.getString("system_unvalid") );
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) {
if (item==null || item.trim().length()==0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
}
}
}
// process
xxlJobGroup.setUpdateTime(new Date());
int ret = xxlJobGroupService.create(xxlJobGroup);
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
}
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> update(XxlJobGroup xxlJobGroup){
// valid
if (xxlJobGroup.getAppname()==null || xxlJobGroup.getAppname().trim().length()==0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
}
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length") );
}
if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
}
if (xxlJobGroup.getAddressType() == 0) {
// 0=自动注册
List<String> registryList = findRegistryByAppName(xxlJobGroup.getAppname());
String addressListStr = null;
if (registryList!=null && !registryList.isEmpty()) {
Collections.sort(registryList);
addressListStr = "";
for (String item:registryList) {
addressListStr += item + ",";
}
addressListStr = addressListStr.substring(0, addressListStr.length()-1);
}
xxlJobGroup.setAddressList(addressListStr);
} else {
// 1=手动录入
if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) {
if (item==null || item.trim().length()==0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
}
}
}
// process
xxlJobGroup.setUpdateTime(new Date());
int ret = xxlJobGroupService.update(xxlJobGroup);
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
}
private List<String> findRegistryByAppName(String appnameParam){
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
List<XxlJobRegistry> list = xxlJobRegistryService.findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
if (list != null) {
for (XxlJobRegistry item: list) {
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
String appname = item.getRegistryKey();
List<String> registryList = appAddressMap.get(appname);
if (registryList == null) {
registryList = new ArrayList<String>();
}
if (!registryList.contains(item.getRegistryValue())) {
registryList.add(item.getRegistryValue());
}
appAddressMap.put(appname, registryList);
}
}
}
return appAddressMap.get(appnameParam);
}
@RequestMapping("/remove")
@ResponseBody
public ReturnT<String> remove(String id){
// valid
long count = xxlJobInfoService.pageListCount(0, 10, id, -1, null, null, null);
if (count > 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_0") );
}
List<XxlJobGroup> allList = xxlJobGroupService.findAll();
if (allList.size() == 1) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_1") );
}
int ret = xxlJobGroupService.remove(id);
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
}
@RequestMapping("/loadById")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<XxlJobGroup> loadById(String id){
XxlJobGroup jobGroup = xxlJobGroupService.load(id);
return jobGroup!=null?new ReturnT<XxlJobGroup>(jobGroup):new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);
}
}

View File

@@ -0,0 +1,156 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.service.XxlJobGroupService;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.DateUtil;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
/**
* index controller
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/jobinfo")
public class JobInfoController {
private static Logger logger = LoggerFactory.getLogger(JobInfoController.class);
@Autowired
private XxlJobGroupService xxlJobGroupService;
@Autowired
private XxlJobService xxlJobService;
@RequestMapping
public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") String jobGroup) {
// 枚举-字典
model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典
model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典
model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型
model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略
// 执行器列表
List<XxlJobGroup> jobGroupList_all = xxlJobGroupService.findAll();
// filter group
List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList==null || jobGroupList.size()==0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("jobGroup", jobGroup);
return "jobinfo/jobinfo.index";
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
}
@RequestMapping("/add")
@ResponseBody
public ReturnT<String> add(HttpServletRequest request, XxlJobInfo jobInfo) {
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
// opt
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
return xxlJobService.add(jobInfo, loginUser);
}
@RequestMapping("/update")
@ResponseBody
public ReturnT<String> update(HttpServletRequest request, XxlJobInfo jobInfo) {
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
// opt
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
return xxlJobService.update(jobInfo, loginUser);
}
@RequestMapping("/remove")
@ResponseBody
public ReturnT<String> remove(String id) {
return xxlJobService.remove(id);
}
@RequestMapping("/stop")
@ResponseBody
public ReturnT<String> pause(String id) {
return xxlJobService.stop(id);
}
@RequestMapping("/start")
@ResponseBody
public ReturnT<String> start(String id) {
return xxlJobService.start(id);
}
@RequestMapping("/trigger")
@ResponseBody
public ReturnT<String> triggerJob(HttpServletRequest request, String id, String executorParam, String addressList) {
// login user
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
// trigger
return xxlJobService.trigger(loginUser, id, executorParam, addressList);
}
@RequestMapping("/nextTriggerTime")
@ResponseBody
public ReturnT<List<String>> nextTriggerTime(String scheduleType, String scheduleConf) {
XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
paramXxlJobInfo.setScheduleType(scheduleType);
paramXxlJobInfo.setScheduleConf(scheduleConf);
List<String> result = new ArrayList<>();
try {
Date lastTime = new Date();
for (int i = 0; i < 5; i++) {
lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
if (lastTime != null) {
result.add(DateUtil.formatDateTime(lastTime));
} else {
break;
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<List<String>>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) + e.getMessage());
}
return new ReturnT<List<String>>(result);
}
}

View File

@@ -0,0 +1,259 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.service.XxlJobLogService;
import com.xxl.job.admin.service.XxlJobGroupService;
import com.xxl.job.admin.service.XxlJobInfoService;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.KillParam;
import com.xxl.job.core.biz.model.LogParam;
import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.DateUtil;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.HtmlUtils;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/joblog")
public class JobLogController {
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
@Autowired
private XxlJobGroupService xxlJobGroupService;
@Autowired
public XxlJobInfoService xxlJobInfoDao;
@Autowired
public XxlJobLogService xxlJobLogService;
@RequestMapping
public String index(HttpServletRequest request, Model model,
@RequestParam(required = false, defaultValue = "0") String jobId) {
// 执行器列表
List<XxlJobGroup> jobGroupList_all = xxlJobGroupService.findAll();
// filter group
List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList == null || jobGroupList.size() == 0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
model.addAttribute("JobGroupList", jobGroupList);
// 任务
if (!jobId.equals("0")) {
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
if (jobInfo == null) {
throw new RuntimeException(
I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
}
model.addAttribute("jobInfo", jobInfo);
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
}
return "joblog/joblog.index";
}
@RequestMapping("/getJobsByGroup")
@ResponseBody
public ReturnT<List<XxlJobInfo>> getJobsByGroup(String jobGroup) {
List<XxlJobInfo> list = xxlJobInfoDao.getJobsByGroup(jobGroup);
return new ReturnT<List<XxlJobInfo>>(list);
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
@RequestParam(required = false, defaultValue = "0") String jobGroup,
@RequestParam(required = false, defaultValue = "0") String jobId, int logStatus, String filterTime) {
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
// parse param
Date triggerTimeStart = null;
Date triggerTimeEnd = null;
if (filterTime != null && filterTime.trim().length() > 0) {
String[] temp = filterTime.split(" - ");
if (temp.length == 2) {
triggerTimeStart = DateUtil.parseDateTime(temp[0]);
triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
}
}
// page query
List<XxlJobLog> list = xxlJobLogService.pageList(start, length, jobGroup, jobId, triggerTimeStart,
triggerTimeEnd, logStatus);
int list_count = xxlJobLogService.pageListCount(start, length, jobGroup, jobId, triggerTimeStart,
triggerTimeEnd, logStatus);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/logDetailPage")
public String logDetailPage(String id, Model model) {
// base check
XxlJobLog jobLog = xxlJobLogService.load(id);
if (jobLog == null) {
throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
}
model.addAttribute("triggerCode", jobLog.getTriggerCode());
model.addAttribute("handleCode", jobLog.getHandleCode());
model.addAttribute("logId", jobLog.getId());
return "joblog/joblog.detail";
}
@RequestMapping("/logDetailCat")
@ResponseBody
public ReturnT<LogResult> logDetailCat(String logId, int fromLineNum) {
try {
// valid
XxlJobLog jobLog = xxlJobLogService.load(logId); // todo, need to improve performance
if (jobLog == null) {
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
}
// log cat
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
ReturnT<LogResult> logResult = executorBiz
.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
// is end
if (logResult.getContent() != null
&& logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
if (jobLog.getHandleCode() > 0) {
logResult.getContent().setEnd(true);
}
}
// fix xss
if (logResult.getContent() != null && StringUtils.hasText(logResult.getContent().getLogContent())) {
String newLogContent = logResult.getContent().getLogContent();
newLogContent = HtmlUtils.htmlEscape(newLogContent, "UTF-8");
logResult.getContent().setLogContent(newLogContent);
}
return logResult;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
}
}
@RequestMapping("/logKill")
@ResponseBody
public ReturnT<String> logKill(String id) {
// base check
XxlJobLog log = xxlJobLogService.load(id);
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
if (jobInfo == null) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
return new ReturnT<String>(500, I18nUtil.getString("joblog_kill_log_limit"));
}
// request of kill
ReturnT<String> runResult = null;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
runResult = new ReturnT<String>(500, e.getMessage());
}
if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
log.setHandleCode(ReturnT.FAIL_CODE);
log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":"
+ (runResult.getMsg() != null ? runResult.getMsg() : ""));
log.setHandleTime(new Date());
XxlJobCompleter.updateHandleInfoAndFinish(log);
return new ReturnT<String>(runResult.getMsg());
} else {
return new ReturnT<String>(500, runResult.getMsg());
}
}
@RequestMapping("/clearLog")
@ResponseBody
public ReturnT<String> clearLog(HttpServletRequest request, String jobGroup, String jobId, int type) {
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobGroup);
// opt
Date clearBeforeTime = null;
int clearBeforeNum = 0;
if (type == 1) {
clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据
} else if (type == 2) {
clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据
} else if (type == 3) {
clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据
} else if (type == 4) {
clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据
} else if (type == 5) {
clearBeforeNum = 1000; // 清理一千条以前日志数据
} else if (type == 6) {
clearBeforeNum = 10000; // 清理一万条以前日志数据
} else if (type == 7) {
clearBeforeNum = 30000; // 清理三万条以前日志数据
} else if (type == 8) {
clearBeforeNum = 100000; // 清理十万条以前日志数据
} else if (type == 9) {
clearBeforeNum = 0; // 清理所有日志数据
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
}
List<String> logIds = null;
do {
logIds = xxlJobLogService.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
if (logIds != null && logIds.size() > 0) {
xxlJobLogService.clearLog(logIds);
}
} while (logIds != null && logIds.size() > 0);
return ReturnT.SUCCESS;
}
}

View File

@@ -0,0 +1,188 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.service.XxlJobGroupService;
import com.xxl.job.admin.service.XxlJobUserService;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xuxueli 2019-05-04 16:39:50
*/
@Controller
@RequestMapping("/user")
public class JobUserController {
@Resource
private XxlJobUserService xxlJobUserService;
@Resource
private XxlJobGroupService xxlJobGroupService;
@RequestMapping
@PermissionLimit(adminuser = true)
public String index(Model model) {
// 执行器列表
List<XxlJobGroup> groupList = xxlJobGroupService.findAll();
model.addAttribute("groupList", groupList);
return "user/user.index";
}
@RequestMapping("/pageList")
@ResponseBody
@PermissionLimit(adminuser = true)
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String username, int role) {
// page list
List<XxlJobUser> list = xxlJobUserService.pageList(start, length, username, role);
int list_count = xxlJobUserService.pageListCount(start, length, username, role);
// filter
if (list!=null && list.size()>0) {
for (XxlJobUser item: list) {
item.setPassword(null);
}
}
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/add")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> add(XxlJobUser xxlJobUser) {
// valid username
if (!StringUtils.hasText(xxlJobUser.getUsername())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_username") );
}
xxlJobUser.setUsername(xxlJobUser.getUsername().trim());
if (!(xxlJobUser.getUsername().length()>=4 && xxlJobUser.getUsername().length()<=20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
}
// valid password
if (!StringUtils.hasText(xxlJobUser.getPassword())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_password") );
}
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
}
// md5 password
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
// check repeat
XxlJobUser existUser = xxlJobUserService.loadByUserName(xxlJobUser.getUsername());
if (existUser != null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat") );
}
// write
xxlJobUserService.create(xxlJobUser);
return ReturnT.SUCCESS;
}
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
// avoid opt login seft
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
// valid password
if (StringUtils.hasText(xxlJobUser.getPassword())) {
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
}
// md5 password
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
} else {
xxlJobUser.setPassword(null);
}
// write
xxlJobUserService.update(xxlJobUser);
return ReturnT.SUCCESS;
}
@RequestMapping("/remove")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> remove(HttpServletRequest request, String id) {
// avoid opt login seft
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getId().equals(id)) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
xxlJobUserService.delete(id);
return ReturnT.SUCCESS;
}
@RequestMapping("/updatePwd")
@ResponseBody
public ReturnT<String> updatePwd(HttpServletRequest request, String password, String oldPassword){
// valid
if (oldPassword==null || oldPassword.trim().isEmpty()){
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd"));
}
if (password==null || password.trim().isEmpty()){
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd"));
}
password = password.trim();
if (!(password.length()>=4 && password.length()<=20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
}
// md5 password
String md5OldPassword = DigestUtils.md5DigestAsHex(oldPassword.getBytes());
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
// valid old pwd
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
XxlJobUser existUser = xxlJobUserService.loadByUserName(loginUser.getUsername());
if (!md5OldPassword.equals(existUser.getPassword())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("change_pwd_field_oldpwd") + I18nUtil.getString("system_unvalid"));
}
// write new
existUser.setPassword(md5Password);
xxlJobUserService.update(existUser);
return ReturnT.SUCCESS;
}
}

View File

@@ -0,0 +1,30 @@
package com.xxl.job.admin.controller.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 权限限制
* @author xuxueli 2015-12-12 18:29:02
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionLimit {
/**
* 登录拦截 (默认拦截)
*/
boolean limit() default true;
/**
* 要求管理员权限
*
* @return
*/
boolean adminuser() default false;
}

View File

@@ -0,0 +1,41 @@
package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.core.util.FtlUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.HashMap;
/**
* push cookies to model as cookieMap
*
* @author xuxueli 2015-12-12 18:09:04
*/
@Component
public class CookieInterceptor implements AsyncHandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// cookie
if (modelAndView!=null && request.getCookies()!=null && request.getCookies().length>0) {
HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
for (Cookie ck : request.getCookies()) {
cookieMap.put(ck.getName(), ck);
}
modelAndView.addObject("cookieMap", cookieMap);
}
// static method
if (modelAndView != null) {
modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
}
}
}

View File

@@ -0,0 +1,121 @@
package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.impl.XxlJobLoginService;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 权限拦截
*
* @author xuxueli 2015-12-12 18:09:04
*/
@Component
public class PermissionInterceptor implements AsyncHandlerInterceptor {
@Autowired
private XxlJobLoginService loginService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true; // proceed with the next interceptor
}
// if need login
boolean needLogin = true;
boolean needAdminuser = false;
HandlerMethod method = (HandlerMethod)handler;
PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
if (permission!=null) {
needLogin = permission.limit();
needAdminuser = permission.adminuser();
}
if (needLogin) {
XxlJobUser loginUser = loginService.ifLogin(request, response);
if (loginUser == null) {
response.setStatus(302);
response.setHeader("location", request.getContextPath()+"/toLogin");
return false;
}
if (needAdminuser && loginUser.getRole()!=1) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
}
request.setAttribute(XxlJobLoginService.LOGIN_IDENTITY_KEY, loginUser); // set loginUser, with request
}
return true; // proceed with the next interceptor
}
// -------------------- permission tool --------------------
/**
* get loginUser
*
* @param request
* @return
*/
public static XxlJobUser getLoginUser(HttpServletRequest request){
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(XxlJobLoginService.LOGIN_IDENTITY_KEY); // get loginUser, with request
return loginUser;
}
/**
* valid permission by JobGroup
*
* @param request
* @param jobGroup
*/
public static void validJobGroupPermission(HttpServletRequest request, String jobGroup) {
XxlJobUser loginUser = getLoginUser(request);
if (!loginUser.validPermission(jobGroup)) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
}
}
/**
* filter XxlJobGroup by role
*
* @param request
* @param jobGroupList_all
* @return
*/
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
List<XxlJobGroup> jobGroupList = new ArrayList<>();
if (jobGroupList_all!=null && !jobGroupList_all.isEmpty()) {
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getRole() == 1) {
jobGroupList = jobGroupList_all;
} else {
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission()!=null && !loginUser.getPermission().trim().isEmpty()) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
for (XxlJobGroup groupItem:jobGroupList_all) {
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
jobGroupList.add(groupItem);
}
}
}
}
return jobGroupList;
}
}

View File

@@ -0,0 +1,29 @@
package com.xxl.job.admin.controller.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import jakarta.annotation.Resource;
/**
* web mvc config
*
* @author xuxueli 2018-04-02 20:48:20
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private PermissionInterceptor permissionInterceptor;
@Resource
private CookieInterceptor cookieInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
}
}

View File

@@ -0,0 +1,67 @@
package com.xxl.job.admin.controller.resolver;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.admin.core.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* common exception resolver
*
* @author xuxueli 2016-1-6 19:22:18
*/
@Component
public class WebExceptionResolver implements HandlerExceptionResolver {
private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
if (!(ex instanceof XxlJobException)) {
logger.error("WebExceptionResolver:{}", ex);
}
// if json
boolean isJson = false;
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod)handler;
ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
if (responseBody != null) {
isJson = true;
}
}
// error result
ReturnT<String> errorResult = new ReturnT<String>(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "<br/>"));
// response
ModelAndView mv = new ModelAndView();
if (isJson) {
try {
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return mv;
} else {
mv.addObject("exceptionMsg", errorResult.getMsg());
mv.setViewName("/common/common.exception");
return mv;
}
}
}

View File

@@ -0,0 +1,34 @@
package com.xxl.job.admin.controller.rest;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.HandlerNameService;
import com.yunzhupaas.scheduletask.entity.HandlerNameEntity;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "执行器", description = "Handler")
@RestController
@RequestMapping("/api/handler")
public class HandlerController {
@Autowired
private HandlerNameService handlerNameService;
@Operation(summary = "获取执行器列表")
@GetMapping("/queryList")
@PermissionLimit(limit=false)
public List<HandlerNameEntity> queryList() {
List<HandlerNameEntity> queryList = handlerNameService.queryList();
return queryList;
}
}

View File

@@ -0,0 +1,55 @@
package com.xxl.job.admin.controller.rest;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.xxl.job.admin.service.XxlJobLogService;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.base.vo.PageListVO;
import com.yunzhupaas.base.vo.PaginationVO;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import com.yunzhupaas.scheduletask.model.TaskLogVO;
import com.yunzhupaas.scheduletask.model.TaskPage;
import com.yunzhupaas.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Tag(name = "任务调度日志", description = "Log")
@RestController
@RequestMapping("/api/log")
public class LogController {
@Autowired
private XxlJobLogService xxlJobLogService;
@Operation(summary = "通过任务id获取日志列表")
@PostMapping("/{taskId}")
@PermissionLimit(limit=false)
public ActionResult<PageListVO<TaskLogVO>> getList(@PathVariable("taskId") String taskId, @RequestBody UserInfo userInfo, TaskPage taskPage) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().queryByTaskId(taskId);
List<TaskLogVO> voList = new ArrayList<>(16);
if (xxlJobInfo != null) {
List<XxlJobLog> list = xxlJobLogService.getList(xxlJobInfo.getId(), taskPage);
for (XxlJobLog xxlJobLog : list) {
TaskLogVO taskLogVO = new TaskLogVO();
taskLogVO.setId(String.valueOf(xxlJobLog.getId()));
taskLogVO.setRunTime(xxlJobLog.getTriggerTime().getTime());
taskLogVO.setDescription(xxlJobLog.getTriggerMsg());
taskLogVO.setRunResult(xxlJobLog.getHandleCode() == 200 ? 0 : 1);
voList.add(taskLogVO);
}
}
PaginationVO pageModel = JsonUtil.getJsonToBean(taskPage, PaginationVO.class);
return ActionResult.page(voList, pageModel);
}
}

View File

@@ -0,0 +1,132 @@
package com.xxl.job.admin.controller.rest;
import cn.hutool.core.util.ObjectUtil;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.TimetaskService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.Pagination;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.base.vo.PageListVO;
import com.yunzhupaas.base.vo.PaginationVO;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.scheduletask.entity.TimeTaskEntity;
import com.yunzhupaas.scheduletask.model.*;
import com.yunzhupaas.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "任务调度", description = "ScheduleTask")
@RestController
@RequestMapping("/api/ScheduleTask")
public class ScheduleTaskController {
@Autowired
private TimetaskService timetaskService;
@Operation(summary = "通过任务id获取任务详情")
@PostMapping("/List")
@PermissionLimit(limit = false)
public ActionResult<PageListVO<TaskVO>> getList(Pagination pagination, @RequestBody UserInfo userInfo) {
List<TimeTaskEntity> data = timetaskService.getList(pagination, userInfo);
List<TaskVO> list = JsonUtil.getJsonToList(data, TaskVO.class);
for (int i = 0; i < list.size(); i++) {
TimeTaskEntity timeTaskEntity = data.get(i);
TaskVO taskVO = list.get(i);
if (timeTaskEntity == null || taskVO == null) {
continue;
}
ContentNewModel contentNewModel = JsonUtil.getJsonToBean(timeTaskEntity.getExecuteContent(),
ContentNewModel.class);
if (contentNewModel == null) {
continue;
}
taskVO.setStartTime(contentNewModel.getStartTime());
taskVO.setEndTime(contentNewModel.getEndTime());
taskVO.setNextRunTime(ObjectUtil.equal(taskVO.getNextRunTime(), 0L) ? null : taskVO.getNextRunTime());
}
PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
return ActionResult.page(list, paginationVO);
}
@Operation(summary = "通过任务id获取任务详情")
@PostMapping("/getInfo")
@PermissionLimit(limit = false)
public TimeTaskEntity queryByTaskId(@RequestParam(value = "taskId", required = false) String taskId,
@RequestBody UserInfo userInfo) {
TimeTaskEntity entity = timetaskService.getInfo(taskId, userInfo);
return entity;
}
@Operation(summary = "日程任务调度")
@PostMapping("/schedule")
@PermissionLimit(limit = false)
public ActionResult<String> schedule(@RequestBody TaskCrForm taskCrForm) {
TimeTaskEntity entity = JsonUtil.getJsonToBean(taskCrForm, TimeTaskEntity.class);
timetaskService.schedule(entity);
return ActionResult.success(MsgCode.SU001.get());
}
@Operation(summary = "保存任务调度")
@PostMapping
@PermissionLimit(limit = false)
public ActionResult<String> save(@RequestBody TaskCrForm taskCrForm) {
UserInfo userInfo = taskCrForm.getUserInfo();
TimeTaskEntity entity = JsonUtil.getJsonToBean(taskCrForm, TimeTaskEntity.class);
if (timetaskService.isExistByFullName(entity.getFullName(), entity.getId())) {
return ActionResult.fail("任务名称不能重复");
}
timetaskService.create(entity, userInfo);
return ActionResult.success(MsgCode.SU001.get());
}
@Operation(summary = "修改任务调度")
@PutMapping("/{id}")
@PermissionLimit(limit = false)
public ActionResult<String> update(@PathVariable("id") String id, @RequestBody TaskUpForm taskUpForm) {
UserInfo userInfo = taskUpForm.getUserInfo();
TimeTaskEntity entity = JsonUtil.getJsonToBean(taskUpForm, TimeTaskEntity.class);
TimeTaskEntity taskEntity = timetaskService.getInfo(id, userInfo);
if (taskEntity == null) {
return ActionResult.fail(MsgCode.FA002.get());
}
if (timetaskService.isExistByFullName(entity.getFullName(), id)) {
return ActionResult.fail("任务名称不能重复");
}
entity.setRunCount(taskEntity.getRunCount());
boolean update = timetaskService.update(id, entity, userInfo);
if (!update) {
return ActionResult.fail(MsgCode.FA002.get());
}
return ActionResult.success(MsgCode.SU004.get());
}
@Operation(summary = "删除任务调度")
@PostMapping("/remove/{id}")
@PermissionLimit(limit = false)
public ActionResult<String> remove(@PathVariable("id") String id, @RequestBody UserInfo userInfo) {
TimeTaskEntity entity = timetaskService.getInfo(id, userInfo);
if (entity != null) {
timetaskService.delete(entity);
return ActionResult.success(MsgCode.SU003.get());
}
return ActionResult.fail(MsgCode.FA003.get());
}
@Operation(summary = "修改任务调度")
@PostMapping("/updateTask")
@PermissionLimit(limit = false)
public ActionResult<String> update(@RequestBody UpdateTaskModel model) {
boolean flag = timetaskService.update(model.getEntity().getId(), model.getEntity(), model.getUserInfo());
if (flag) {
return ActionResult.fail(MsgCode.FA002.get());
}
return ActionResult.success(MsgCode.SU004.get());
}
}

View File

@@ -0,0 +1,24 @@
package com.xxl.job.admin.controller.rest;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/jobinfo")
public class XxlJobInfoController {
@GetMapping
@PermissionLimit(limit=false)
public XxlJobInfo getInfoByTaskId(@RequestParam(value = "taskId", required = false) String taskId) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().queryByTaskId(taskId);
return xxlJobInfo;
}
}

View File

@@ -0,0 +1,21 @@
package com.xxl.job.admin.core.alarm;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
/**
* @author xuxueli 2020-01-19
*/
public interface JobAlarm {
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);
}

View File

@@ -0,0 +1,67 @@
package com.xxl.job.admin.core.alarm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class JobAlarmer implements ApplicationContextAware, InitializingBean {
private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);
private ApplicationContext applicationContext;
private List<JobAlarm> jobAlarmList;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());
}
}
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
boolean result = false;
if (jobAlarmList!=null && jobAlarmList.size()>0) {
result = true; // success means all-success
for (JobAlarm alarm: jobAlarmList) {
boolean resultItem = false;
try {
resultItem = alarm.doAlarm(info, jobLog);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
if (!resultItem) {
result = false;
}
}
}
return result;
}
}

View File

@@ -0,0 +1,120 @@
package com.xxl.job.admin.core.alarm.impl;
import com.xxl.job.admin.core.alarm.JobAlarm;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import jakarta.mail.internet.MimeMessage;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* job alarm by email
*
* @author xuxueli 2020-01-19
*/
@Component
public class EmailJobAlarm implements JobAlarm {
private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);
/**
* fail alarm
*
* @param jobLog
*/
@Override
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){
boolean alarmResult = true;
// send monitor email
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
// alarmContent
String alarmContent = "Alarm Job LogId=" + jobLog.getId();
if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();
}
if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();
}
// email info
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().load(info.getJobGroup());
String personal = I18nUtil.getString("admin_name_full");
String title = I18nUtil.getString("jobconf_monitor");
String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
group!=null?group.getTitle():"null",
info.getId(),
info.getJobDesc(),
alarmContent);
Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));
for (String email: emailSet) {
// make mail
try {
MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal);
helper.setTo(email);
helper.setSubject(title);
helper.setText(content, true);
XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
alarmResult = false;
}
}
}
return alarmResult;
}
/**
* load email job alarm template
*
* @return
*/
private static final String loadEmailJobAlarmTemplate(){
String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + "</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
" <td width=\"40%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_content") +"</td>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td>{0}</td>\n" +
" <td>{1}</td>\n" +
" <td>{2}</td>\n" +
" <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
" <td>{3}</td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>";
return mailBodyTemplate;
}
}

View File

@@ -0,0 +1,107 @@
package com.xxl.job.admin.core.complete;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
/**
* @author xuxueli 2020-10-30 20:43:10
*/
public class XxlJobCompleter {
private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class);
/**
* common fresh handle entrance (limit only once)
*
* @param xxlJobLog
* @return
*/
public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) {
// finish
finishJob(xxlJobLog);
// text最大64kb 避免长度过长
if (xxlJobLog.getHandleMsg().length() > 15000) {
xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000));
}
// fresh handle
return XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().updateHandleInfo(xxlJobLog);
}
/**
* do somethind to finish job
*/
private static void finishJob(XxlJobLog xxlJobLog) {
// 1、handle success, to trigger child job
String triggerChildMsg = null;
if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService()
.loadById(xxlJobLog.getJobId());
if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null
&& xxlJobInfo.getChildJobId().trim().length() > 0) {
logger.info(">>>>>>>>> Job[{}] handle success, start to trigger child jobs.", xxlJobLog.getJobId());
triggerChildMsg = "" + I18nUtil.getString("jobconf_trigger_child_run") + "";
String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
for (int i = 0; i < childJobIds.length; i++) {
int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0
&& isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1;
if (childJobId > 0) {
JobTriggerPoolHelper.trigger(childJobIds[childJobId], TriggerTypeEnum.PARENT, -1, null, null,
null);
ReturnT<String> triggerChildResult = ReturnT.SUCCESS;
// add msg
triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
(i + 1),
childJobIds.length,
childJobIds[i],
(triggerChildResult.getCode() == ReturnT.SUCCESS_CODE
? I18nUtil.getString("system_success")
: I18nUtil.getString("system_fail")),
triggerChildResult.getMsg());
} else {
triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
(i + 1),
childJobIds.length,
childJobIds[i]);
}
}
}
}
if (triggerChildMsg != null) {
xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg);
logger.info(">>>>>>>>> Job[{}] finished with child job trigger message.", xxlJobLog.getJobId());
}
// 2、fix_delay trigger next
// on the way
}
private static boolean isNumeric(String str) {
try {
Integer.valueOf(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}

View File

@@ -0,0 +1,172 @@
package com.xxl.job.admin.core.conf;
import com.xxl.job.admin.core.alarm.JobAlarmer;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.service.*;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}
// ---------------------- XxlJobScheduler ----------------------
private XxlJobScheduler xxlJobScheduler;
@Override
public void afterPropertiesSet() throws Exception {
adminConfig = this;
xxlJobScheduler = new XxlJobScheduler();
xxlJobScheduler.init();
}
@Override
public void destroy() throws Exception {
xxlJobScheduler.destroy();
}
// ---------------------- XxlJobScheduler ----------------------
// conf
@Value("${xxl.job.i18n}")
private String i18n;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${spring.mail.from}")
private String emailFrom;
@Value("${xxl.job.triggerpool.fast.max}")
private int triggerPoolFastMax;
@Value("${xxl.job.triggerpool.slow.max}")
private int triggerPoolSlowMax;
@Value("${xxl.job.logretentiondays}")
private int logretentiondays;
// dao, service
@Resource
private XxlJobInfoService xxlJobInfoService;
@Resource
private XxlJobRegistryService xxlJobRegistryService;
@Resource
private XxlJobGroupService xxlJobGroupService;
@Resource
private XxlJobLogReportService xxlJobLogReportService;
@Resource
private JavaMailSender mailSender;
@Resource
private DataSource dataSource;
@Resource
private JobAlarmer jobAlarmer;
@Resource
private XxlJobLogService xxlJobLogService;
@Resource
private TimetaskService timetaskService;
public String getI18n() {
if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) {
return "zh_CN";
}
return i18n;
}
public String getAccessToken() {
return accessToken;
}
public String getEmailFrom() {
return emailFrom;
}
public int getTriggerPoolFastMax() {
if (triggerPoolFastMax < 200) {
return 200;
}
return triggerPoolFastMax;
}
public int getTriggerPoolSlowMax() {
if (triggerPoolSlowMax < 100) {
return 100;
}
return triggerPoolSlowMax;
}
public int getLogretentiondays() {
if (logretentiondays < 7) {
return -1; // Limit greater than or equal to 7, otherwise close
}
return logretentiondays;
}
public XxlJobInfoService getXxlJobInfoService() {
return xxlJobInfoService;
}
public XxlJobRegistryService getXxlJobRegistryService() {
return xxlJobRegistryService;
}
public XxlJobGroupService getXxlJobGroupService() {
return xxlJobGroupService;
}
public XxlJobLogReportService getXxlJobLogReportService() {
return xxlJobLogReportService;
}
public JavaMailSender getMailSender() {
return mailSender;
}
public DataSource getDataSource() {
return dataSource;
}
public JobAlarmer getJobAlarmer() {
return jobAlarmer;
}
public XxlJobLogService getXxlJobLogService() {
return xxlJobLogService;
}
public void setXxlJobLogService(XxlJobLogService xxlJobLogService) {
this.xxlJobLogService = xxlJobLogService;
}
public TimetaskService getTimetaskService() {
return timetaskService;
}
public void setTimetaskService(TimetaskService timetaskService) {
this.timetaskService = timetaskService;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
package com.xxl.job.admin.core.exception;
/**
* @author xuxueli 2019-05-04 23:19:29
*/
public class XxlJobException extends RuntimeException {
public XxlJobException() {
}
public XxlJobException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,34 @@
package com.xxl.job.admin.core.model;
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 lombok.Data;
import java.util.Date;
/**
* xxl-job log for glue, used to track job code process
* @author xuxueli 2016-5-19 17:57:46
*/
@Data
@TableName("xxl_job_logglue")
public class XxlJobLogGlue {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField("JOB_ID")
private String jobId; // 任务主键ID
@TableField("GLUE_TYPE")
private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
@TableField("GLUE_SOURCE")
private String glueSource;
@TableField("GLUE_REMARK")
private String glueRemark;
@TableField("ADD_TIME")
private Date addTime;
@TableField("UPDATE_TIME")
private Date updateTime;
}

View File

@@ -0,0 +1,35 @@
package com.xxl.job.admin.core.model;
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 lombok.Data;
import java.util.Date;
@Data
@TableName("xxl_job_log_report")
public class XxlJobLogReport {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField(value = "TRIGGER_DAY")
private Date triggerDay;
@TableField(value = "RUNNING_COUNT")
private int runningCount;
@TableField(value = "SUC_COUNT")
private int sucCount;
@TableField(value = "FAIL_COUNT")
private int failCount;
@TableField(value = "UPDATE_TIME")
private Date updateTime;
}

View File

@@ -0,0 +1,30 @@
package com.xxl.job.admin.core.model;
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 lombok.Data;
import java.util.Date;
/**
* Created by xuxueli on 16/9/30.
*/
@Data
@TableName("xxl_job_registry")
public class XxlJobRegistry {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField("REGISTRY_GROUP")
private String registryGroup;
@TableField("REGISTRY_KEY")
private String registryKey;
@TableField("REGISTRY_VALUE")
private String registryValue;
@TableField("UPDATE_TIME")
private Date updateTime;
}

View File

@@ -0,0 +1,46 @@
package com.xxl.job.admin.core.model;
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 lombok.Data;
import org.springframework.util.StringUtils;
/**
* @author xuxueli 2019-05-04 16:43:12
*/
@Data
@TableName("xxl_job_user")
public class XxlJobUser {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField("USERNAME")
private String username; // 账号
@TableField("PASSWORD")
private String password; // 密码
@TableField("ROLE")
private int role; // 角色0-普通用户、1-管理员
@TableField("PERMISSION")
private String permission; // 权限执行器ID列表多个逗号分割
// plugin
public boolean validPermission(String jobGroup){
if (this.role == 1) {
return true;
} else {
if (StringUtils.hasText(this.permission)) {
for (String permissionItem : this.permission.split(",")) {
if (jobGroup.equals(permissionItem)) {
return true;
}
}
}
return false;
}
}
}

View File

@@ -0,0 +1,49 @@
package com.xxl.job.admin.core.route;
import com.xxl.job.admin.core.route.strategy.*;
import com.xxl.job.admin.core.util.I18nUtil;
/**
* Created by xuxueli on 17/3/10.
*/
public enum ExecutorRouteStrategyEnum {
FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
this.title = title;
this.router = router;
}
private String title;
private ExecutorRouter router;
public String getTitle() {
return title;
}
public ExecutorRouter getRouter() {
return router;
}
public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem){
if (name != null) {
for (ExecutorRouteStrategyEnum item: ExecutorRouteStrategyEnum.values()) {
if (item.name().equals(name)) {
return item;
}
}
}
return defaultItem;
}
}

View File

@@ -0,0 +1,25 @@
package com.xxl.job.admin.core.route;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by xuxueli on 17/3/10.
*/
public abstract class ExecutorRouter {
protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class);
/**
* route address
*
* @param addressList
* @return ReturnT.content=address
*/
public abstract ReturnT<String> route(TriggerParam triggerParam, List<String> addressList);
}

View File

@@ -0,0 +1,49 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.IdleBeatParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteBusyover extends ExecutorRouter {
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
StringBuffer idleBeatResultSB = new StringBuffer();
for (String address : addressList) {
// beat
ReturnT<String> idleBeatResult = null;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
}
idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"<br><br>":"")
.append(I18nUtil.getString("jobconf_idleBeat") + "")
.append("<br>address").append(address)
.append("<br>code").append(idleBeatResult.getCode())
.append("<br>msg").append(idleBeatResult.getMsg());
// beat success
if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
idleBeatResult.setMsg(idleBeatResultSB.toString());
idleBeatResult.setContent(address);
return idleBeatResult;
}
}
return new ReturnT<String>(ReturnT.FAIL_CODE, idleBeatResultSB.toString());
}
}

View File

@@ -0,0 +1,86 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* 分组下机器地址相同不同JOB均匀散列在不同机器上保证分组下机器分配JOB平均且每个JOB固定调度其中一台机器
* a、virtual node解决不均衡问题
* b、hash method replace hashCodeString的hashCode可能重复需要进一步扩大hashCode的取值范围
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteConsistentHash extends ExecutorRouter {
private static int VIRTUAL_NODE_NUM = 100;
/**
* get hash code on 2^32 ring (md5散列的方式计算hash值)
* @param key
* @return
*/
private static long hash(String key) {
// md5 byte
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 not supported", e);
}
md5.reset();
byte[] keyBytes = null;
try {
keyBytes = key.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unknown string :" + key, e);
}
md5.update(keyBytes);
byte[] digest = md5.digest();
// hash code, Truncate to 32-bits
long hashCode = ((long) (digest[3] & 0xFF) << 24)
| ((long) (digest[2] & 0xFF) << 16)
| ((long) (digest[1] & 0xFF) << 8)
| (digest[0] & 0xFF);
long truncateHashCode = hashCode & 0xffffffffL;
return truncateHashCode;
}
public String hashJob(String jobId, List<String> addressList) {
// ------A1------A2-------A3------
// -----------J1------------------
TreeMap<Long, String> addressRing = new TreeMap<Long, String>();
for (String address: addressList) {
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
long addressHash = hash("SHARD-" + address + "-NODE-" + i);
addressRing.put(addressHash, address);
}
}
long jobHash = hash(String.valueOf(jobId));
SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);
if (!lastRing.isEmpty()) {
return lastRing.get(lastRing.firstKey());
}
return addressRing.firstEntry().getValue();
}
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
String address = hashJob(triggerParam.getJobId(), addressList);
return new ReturnT<String>(address);
}
}

View File

@@ -0,0 +1,49 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteFailover extends ExecutorRouter {
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
StringBuffer beatResultSB = new StringBuffer();
for (String address : addressList) {
// beat
ReturnT<String> beatResult = null;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
beatResult = executorBiz.beat();
} catch (Exception e) {
logger.error(e.getMessage(), e);
beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
}
beatResultSB.append( (beatResultSB.length()>0)?"<br><br>":"")
.append(I18nUtil.getString("jobconf_beat") + "")
.append("<br>address").append(address)
.append("<br>code").append(beatResult.getCode())
.append("<br>msg").append(beatResult.getMsg());
// beat success
if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
beatResult.setMsg(beatResultSB.toString());
beatResult.setContent(address);
return beatResult;
}
}
return new ReturnT<String>(ReturnT.FAIL_CODE, beatResultSB.toString());
}
}

View File

@@ -0,0 +1,20 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteFirst extends ExecutorRouter {
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList){
return new ReturnT<String>(addressList.get(0));
}
}

View File

@@ -0,0 +1,78 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 单个JOB对应的每个执行器使用频率最低的优先被选举
* a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数
* b、LRU(Least Recently Used):最近最久未使用,时间
*
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteLFU extends ExecutorRouter {
private static ConcurrentMap<String, HashMap<String, Integer>> jobLfuMap = new ConcurrentHashMap<>();
private static long CACHE_VALID_TIME = 0;
public String route(String jobId, List<String> addressList) {
// cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
jobLfuMap.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24;
}
// lfu item init
HashMap<String, Integer> lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参CompareValue排序暂时只能通过ArrayList
if (lfuItemMap == null) {
lfuItemMap = new HashMap<String, Integer>();
jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖
}
// put new
for (String address : addressList) {
if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) > 1000000) {
lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次缓解首次压力
}
}
// remove old
List<String> delKeys = new ArrayList<>();
for (String existKey : lfuItemMap.keySet()) {
if (!addressList.contains(existKey)) {
delKeys.add(existKey);
}
}
if (delKeys.size() > 0) {
for (String delKey : delKeys) {
lfuItemMap.remove(delKey);
}
}
// load least userd count address
List<Map.Entry<String, Integer>> lfuItemList = new ArrayList<Map.Entry<String, Integer>>(lfuItemMap.entrySet());
Collections.sort(lfuItemList, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
Map.Entry<String, Integer> addressItem = lfuItemList.get(0);
addressItem.setValue(addressItem.getValue() + 1);
return addressItem.getKey();
}
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
String address = route(triggerParam.getJobId(), addressList);
return new ReturnT<String>(address);
}
}

View File

@@ -0,0 +1,77 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 单个JOB对应的每个执行器最久为使用的优先被选举
* a、LFU(Least Frequently Used):最不经常使用,频率/次数
* b(*)、LRU(Least Recently Used):最近最久未使用,时间
*
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteLRU extends ExecutorRouter {
private static ConcurrentMap<String, LinkedHashMap<String, String>> jobLRUMap = new ConcurrentHashMap<>();
private static long CACHE_VALID_TIME = 0;
public String route(String jobId, List<String> addressList) {
// cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
jobLRUMap.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
}
// init lru
LinkedHashMap<String, String> lruItem = jobLRUMap.get(jobId);
if (lruItem == null) {
/**
* LinkedHashMap
* a、accessOrdertrue=访问顺序排序get/put时排序false=插入顺序排期;
* b、removeEldestEntry新增元素时将会调用返回true时会删除最老元素可封装LinkedHashMap并重写该方法比如定义最大容量超出是返回true即可实现固定长度的LRU算法
*/
lruItem = new LinkedHashMap<String, String>(16, 0.75f, true);
jobLRUMap.putIfAbsent(jobId, lruItem);
}
// put new
for (String address: addressList) {
if (!lruItem.containsKey(address)) {
lruItem.put(address, address);
}
}
// remove old
List<String> delKeys = new ArrayList<>();
for (String existKey: lruItem.keySet()) {
if (!addressList.contains(existKey)) {
delKeys.add(existKey);
}
}
if (delKeys.size() > 0) {
for (String delKey: delKeys) {
lruItem.remove(delKey);
}
}
// load
String eldestKey = lruItem.entrySet().iterator().next().getKey();
String eldestValue = lruItem.get(eldestKey);
return eldestValue;
}
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
String address = route(triggerParam.getJobId(), addressList);
return new ReturnT<String>(address);
}
}

View File

@@ -0,0 +1,20 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteLast extends ExecutorRouter {
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
return new ReturnT<String>(addressList.get(addressList.size()-1));
}
}

View File

@@ -0,0 +1,24 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
import java.util.Random;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteRandom extends ExecutorRouter {
private static Random localRandom = new Random();
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
String address = addressList.get(localRandom.nextInt(addressList.size()));
return new ReturnT<String>(address);
}
}

View File

@@ -0,0 +1,47 @@
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteRound extends ExecutorRouter {
private static ConcurrentMap<String, AtomicInteger> routeCountEachJob = new ConcurrentHashMap<>();
private static long CACHE_VALID_TIME = 0;
private static int count(String jobId) {
// cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
routeCountEachJob.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
}
AtomicInteger count = routeCountEachJob.get(jobId);
if (count == null || count.get() > 1000000) {
// 初始化时主动Random一次缓解首次压力
count = new AtomicInteger(new Random().nextInt(100));
} else {
// count++
count.addAndGet(1);
}
routeCountEachJob.put(jobId, count);
return count.get();
}
@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
String address = addressList.get(count(triggerParam.getJobId())%addressList.size());
return new ReturnT<String>(address);
}
}

View File

@@ -0,0 +1,40 @@
package com.xxl.job.admin.core.scheduler;
import com.xxl.job.admin.core.util.I18nUtil;
/**
* @author xuxueli 2020-10-29 21:11:23
*/
public enum MisfireStrategyEnum {
/**
* do nothing
*/
DO_NOTHING(I18nUtil.getString("misfire_strategy_do_nothing")),
/**
* fire once now
*/
FIRE_ONCE_NOW(I18nUtil.getString("misfire_strategy_fire_once_now"));
private String title;
MisfireStrategyEnum(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem){
for (MisfireStrategyEnum item: MisfireStrategyEnum.values()) {
if (item.name().equals(name)) {
return item;
}
}
return defaultItem;
}
}

View File

@@ -0,0 +1,47 @@
package com.xxl.job.admin.core.scheduler;
import com.xxl.job.admin.core.util.I18nUtil;
/**
* @author xuxueli 2020-10-29 21:11:23
*/
public enum ScheduleTypeEnum {
NONE(I18nUtil.getString("schedule_type_none")),
/**
* schedule by cron
*/
CRON(I18nUtil.getString("schedule_type_cron")),
/**
* schedule by fixed rate (in seconds)
*/
FIX_RATE(I18nUtil.getString("schedule_type_fix_rate")),
/**
* schedule by fix delay (in seconds) after the last time
*/
/*FIX_DELAY(I18nUtil.getString("schedule_type_fix_delay"))*/;
private String title;
ScheduleTypeEnum(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem){
for (ScheduleTypeEnum item: ScheduleTypeEnum.values()) {
if (item.name().equals(name)) {
return item;
}
}
return defaultItem;
}
}

View File

@@ -0,0 +1,102 @@
package com.xxl.job.admin.core.scheduler;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.thread.*;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.client.ExecutorBizClient;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author xuxueli 2018-10-28 00:18:17
*/
public class XxlJobScheduler {
private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);
public void init() throws Exception {
// init i18n
initI18n();
// admin trigger pool start
JobTriggerPoolHelper.toStart();
// admin registry monitor run
JobRegistryHelper.getInstance().start();
// admin fail-monitor run
JobFailMonitorHelper.getInstance().start();
// admin lose-monitor run ( depend on JobTriggerPoolHelper )
JobCompleteHelper.getInstance().start();
// admin log report start
JobLogReportHelper.getInstance().start();
// start-schedule ( depend on JobTriggerPoolHelper )
JobScheduleHelper.getInstance().start();
logger.info(">>>>>>>>> init xxl-job admin success.");
}
public void destroy() throws Exception {
// stop-schedule
JobScheduleHelper.getInstance().toStop();
// admin log report stop
JobLogReportHelper.getInstance().toStop();
// admin lose-monitor stop
JobCompleteHelper.getInstance().toStop();
// admin fail-monitor stop
JobFailMonitorHelper.getInstance().toStop();
// admin registry stop
JobRegistryHelper.getInstance().toStop();
// admin trigger pool stop
JobTriggerPoolHelper.toStop();
}
// ---------------------- I18n ----------------------
private void initI18n(){
for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
}
}
// ---------------------- executor-client ----------------------
private static ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
public static ExecutorBiz getExecutorBiz(String address) throws Exception {
// valid
if (address==null || address.trim().length()==0) {
return null;
}
// load-cache
address = address.trim();
ExecutorBiz executorBiz = executorBizRepository.get(address);
if (executorBiz != null) {
return executorBiz;
}
// set-cache
executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken());
executorBizRepository.put(address, executorBiz);
return executorBiz;
}
}

View File

@@ -0,0 +1,186 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.DateUtil;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
/**
* job lose-monitor instance
*
* @author xuxueli 2015-9-1 18:05:56
*/
public class JobCompleteHelper {
private static Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class);
private static JobCompleteHelper instance = new JobCompleteHelper();
public static JobCompleteHelper getInstance(){
return instance;
}
// ---------------------- monitor ----------------------
private ThreadPoolExecutor callbackThreadPool = null;
private Thread monitorThread;
private volatile boolean toStop = false;
public void start(){
// for callback
callbackThreadPool = new ThreadPoolExecutor(
2,
20,
30L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-" + r.hashCode());
}
},
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
logger.warn(">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now).");
}
});
// for monitor
monitorThread = new Thread(new Runnable() {
@Override
public void run() {
// wait for JobTriggerPoolHelper-init
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
// monitor
while (!toStop) {
try {
// 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min且对应执行器心跳注册失败不在线则将本地调度主动标记失败
Date losedTime = DateUtil.addMinutes(new Date(), -10);
List<String> losedJobIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().findLostJobIds(losedTime);
if (losedJobIds!=null && losedJobIds.size()>0) {
for (String logId: losedJobIds) {
XxlJobLog jobLog = new XxlJobLog();
jobLog.setId(logId);
jobLog.setHandleTime(new Date());
jobLog.setHandleCode(ReturnT.FAIL_CODE);
jobLog.setHandleMsg( I18nUtil.getString("joblog_lost_fail") );
XxlJobCompleter.updateHandleInfoAndFinish(jobLog);
}
}
} catch (Exception e) {
if (!toStop) {
logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
}
}
try {
TimeUnit.SECONDS.sleep(60);
} catch (Exception e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop");
}
});
monitorThread.setDaemon(true);
monitorThread.setName("xxl-job, admin JobLosedMonitorHelper");
monitorThread.start();
}
public void toStop(){
toStop = true;
// stop registryOrRemoveThreadPool
callbackThreadPool.shutdownNow();
// stop monitorThread (interrupt and wait)
monitorThread.interrupt();
try {
monitorThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
// ---------------------- helper ----------------------
public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
callbackThreadPool.execute(new Runnable() {
@Override
public void run() {
for (HandleCallbackParam handleCallbackParam: callbackParamList) {
ReturnT<String> callbackResult = callback(handleCallbackParam);
logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
(callbackResult.getCode()== ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult);
}
}
});
return ReturnT.SUCCESS;
}
private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
// valid log item
XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().load(handleCallbackParam.getLogId());
if (log == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
}
if (log.getHandleCode() > 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback."); // avoid repeat callback, trigger child job etc
}
// handle msg
StringBuffer handleMsg = new StringBuffer();
if (log.getHandleMsg()!=null) {
handleMsg.append(log.getHandleMsg()).append("<br>");
}
if (handleCallbackParam.getHandleMsg() != null) {
handleMsg.append(handleCallbackParam.getHandleMsg());
}
// success, save log
log.setHandleTime(new Date());
log.setHandleCode(handleCallbackParam.getHandleCode());
log.setHandleMsg(handleMsg.toString());
XxlJobCompleter.updateHandleInfoAndFinish(log);
return ReturnT.SUCCESS;
}
}

View File

@@ -0,0 +1,112 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* job monitor instance
*
* @author xuxueli 2015-9-1 18:05:56
*/
public class JobFailMonitorHelper {
private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class);
private static JobFailMonitorHelper instance = new JobFailMonitorHelper();
public static JobFailMonitorHelper getInstance(){
return instance;
}
// ---------------------- monitor ----------------------
private Thread monitorThread;
private volatile boolean toStop = false;
public void start(){
monitorThread = new Thread(new Runnable() {
@Override
public void run() {
// monitor
while (!toStop) {
try {
List<String> failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().findFailJobLogIds(1000);
if (failLogIds!=null && !failLogIds.isEmpty()) {
for (String failLogId: failLogIds) {
// lock log
int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().updateAlarmStatus(failLogId, 0, -1);
if (lockRet < 1) {
continue;
}
XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().load(failLogId);
XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().loadById(log.getJobId());
// 1、fail retry monitor
if (log.getExecutorFailRetryCount() > 0) {
JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount()-1), log.getExecutorShardingParam(), log.getExecutorParam(), null);
String retryMsg = ""+ I18nUtil.getString("jobconf_trigger_type_retry") +"";
log.setTriggerMsg(log.getTriggerMsg() + retryMsg);
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().updateTriggerInfo(log);
}
// 2、fail alarm monitor
int newAlarmStatus = 0; // 告警状态0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
if (info != null) {
boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
newAlarmStatus = alarmResult?2:3;
} else {
newAlarmStatus = 1;
}
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().updateAlarmStatus(failLogId, -1, newAlarmStatus);
}
}
} catch (Exception e) {
if (!toStop) {
logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
}
}
try {
TimeUnit.SECONDS.sleep(10);
} catch (Exception e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop");
}
});
monitorThread.setDaemon(true);
monitorThread.setName("xxl-job, admin JobFailMonitorHelper");
monitorThread.start();
}
public void toStop(){
toStop = true;
// interrupt and wait
monitorThread.interrupt();
try {
monitorThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,153 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* job log report helper
*
* @author xuxueli 2019-11-22
*/
public class JobLogReportHelper {
private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);
private static JobLogReportHelper instance = new JobLogReportHelper();
public static JobLogReportHelper getInstance(){
return instance;
}
private Thread logrThread;
private volatile boolean toStop = false;
public void start(){
logrThread = new Thread(new Runnable() {
@Override
public void run() {
// last clean log time
long lastCleanLogTime = 0;
while (!toStop) {
// 1、log-report refresh: refresh log report in 3 days
try {
for (int i = 0; i < 3; i++) {
// today
Calendar itemDay = Calendar.getInstance();
itemDay.add(Calendar.DAY_OF_MONTH, -i);
itemDay.set(Calendar.HOUR_OF_DAY, 0);
itemDay.set(Calendar.MINUTE, 0);
itemDay.set(Calendar.SECOND, 0);
itemDay.set(Calendar.MILLISECOND, 0);
Date todayFrom = itemDay.getTime();
itemDay.set(Calendar.HOUR_OF_DAY, 23);
itemDay.set(Calendar.MINUTE, 59);
itemDay.set(Calendar.SECOND, 59);
itemDay.set(Calendar.MILLISECOND, 999);
Date todayTo = itemDay.getTime();
// refresh log-report every minute
XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();
xxlJobLogReport.setTriggerDay(todayFrom);
xxlJobLogReport.setRunningCount(0);
xxlJobLogReport.setSucCount(0);
xxlJobLogReport.setFailCount(0);
Map<String, Object> triggerCountMap = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().findLogReport(todayFrom, todayTo);
if (triggerCountMap!=null && triggerCountMap.size()>0) {
int triggerDayCount = triggerCountMap.containsKey("triggerDayCount")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))):0;
int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))):0;
int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))):0;
int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
xxlJobLogReport.setRunningCount(triggerDayCountRunning);
xxlJobLogReport.setSucCount(triggerDayCountSuc);
xxlJobLogReport.setFailCount(triggerDayCountFail);
}
// do refresh
int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportService().update(xxlJobLogReport);
if (ret < 1) {
XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportService().create(xxlJobLogReport);
}
}
} catch (Exception e) {
if (!toStop) {
logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e);
}
}
// 2、log-clean: switch open & once each day
if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays()>0
&& System.currentTimeMillis() - lastCleanLogTime > 24*60*60*1000) {
// expire-time
Calendar expiredDay = Calendar.getInstance();
expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays());
expiredDay.set(Calendar.HOUR_OF_DAY, 0);
expiredDay.set(Calendar.MINUTE, 0);
expiredDay.set(Calendar.SECOND, 0);
expiredDay.set(Calendar.MILLISECOND, 0);
Date clearBeforeTime = expiredDay.getTime();
// clean expired log
List<String> logIds = null;
do {
logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().findClearLogIds("0", "0", clearBeforeTime, 0, 1000);
if (logIds!=null && logIds.size()>0) {
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().clearLog(logIds);
}
} while (logIds!=null && logIds.size()>0);
// update clean time
lastCleanLogTime = System.currentTimeMillis();
}
try {
TimeUnit.MINUTES.sleep(1);
} catch (Exception e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, job log report thread stop");
}
});
logrThread.setDaemon(true);
logrThread.setName("xxl-job, admin JobLogReportHelper");
logrThread.start();
}
public void toStop(){
toStop = true;
// interrupt and wait
logrThread.interrupt();
try {
logrThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,242 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.concurrent.*;
/**
* job registry instance
* @author xuxueli 2016-10-02 19:10:24
*/
public class JobRegistryHelper {
private static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class);
private static JobRegistryHelper instance = new JobRegistryHelper();
public static JobRegistryHelper getInstance(){
return instance;
}
private ThreadPoolExecutor registryOrRemoveThreadPool = null;
private Thread registryMonitorThread;
private volatile boolean toStop = false;
public void start(){
// for registry or remove
registryOrRemoveThreadPool = new ThreadPoolExecutor(
2,
10,
30L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(2000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode());
}
},
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now).");
}
});
// for monitor
registryMonitorThread = new Thread(new Runnable() {
@Override
public void run() {
while (!toStop) {
try {
// auto registry group
List<XxlJobGroup> groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().findByAddressType(0);
if (groupList!=null && !groupList.isEmpty()) {
// remove dead address (admin/executor)
List<String> ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().findDead(RegistryConfig.DEAD_TIMEOUT, new Date());
if (ids!=null && ids.size()>0) {
XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().removeDead(ids);
}
// fresh online address (admin/executor)
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
List<XxlJobRegistry> list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
if (list != null) {
for (XxlJobRegistry item: list) {
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
String appname = item.getRegistryKey();
List<String> registryList = appAddressMap.get(appname);
if (registryList == null) {
registryList = new ArrayList<String>();
}
if (!registryList.contains(item.getRegistryValue())) {
registryList.add(item.getRegistryValue());
}
appAddressMap.put(appname, registryList);
}
}
}
// fresh group address
for (XxlJobGroup group: groupList) {
List<String> registryList = appAddressMap.get(group.getAppname());
String addressListStr = null;
if (registryList!=null && !registryList.isEmpty()) {
Collections.sort(registryList);
StringBuilder addressListSB = new StringBuilder();
for (String item:registryList) {
addressListSB.append(item).append(",");
}
addressListStr = addressListSB.toString();
addressListStr = addressListStr.substring(0, addressListStr.length()-1);
}
group.setAddressList(addressListStr);
group.setUpdateTime(new Date());
XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().update(group);
}
}
} catch (Exception e) {
if (!toStop) {
logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
}
}
try {
TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
} catch (InterruptedException e) {
if (!toStop) {
logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop");
}
});
registryMonitorThread.setDaemon(true);
registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread");
registryMonitorThread.start();
}
public void toStop(){
toStop = true;
// stop registryOrRemoveThreadPool
registryOrRemoveThreadPool.shutdownNow();
// stop monitir (interrupt and wait)
registryMonitorThread.interrupt();
try {
registryMonitorThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
// ---------------------- helper ----------------------
public ReturnT<String> registry(RegistryParam registryParam) {
// valid
if (!StringUtils.hasText(registryParam.getRegistryGroup())
|| !StringUtils.hasText(registryParam.getRegistryKey())
|| !StringUtils.hasText(registryParam.getRegistryValue())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
}
// async execute
registryOrRemoveThreadPool.execute(new Runnable() {
@Override
public void run() {
int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
if (ret < 1) {
XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
// fresh
freshGroupRegistryInfo(registryParam);
}
}
});
return ReturnT.SUCCESS;
}
public ReturnT<String> registryRemove(RegistryParam registryParam) {
// valid
if (!StringUtils.hasText(registryParam.getRegistryGroup())
|| !StringUtils.hasText(registryParam.getRegistryKey())
|| !StringUtils.hasText(registryParam.getRegistryValue())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
}
// async execute
registryOrRemoveThreadPool.execute(new Runnable() {
@Override
public void run() {
int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryService().registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
if (ret > 0) {
// fresh
freshGroupRegistryInfo(registryParam);
}
}
});
return ReturnT.SUCCESS;
}
private void freshGroupRegistryInfo(RegistryParam registryParam){
// Under consideration, prevent affecting core tables
// 通过appname查询是否有重名的appname
List<XxlJobGroup> groupByAppname = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().findByAppname(registryParam.getRegistryKey());
// 如果appname有重复的则直接替换内容,且等于1则直接替换内容如果大于1则抛出异常
if (groupByAppname.size() == 1) {
XxlJobGroup xxlJobGroup = new XxlJobGroup();
// 设置Appname
xxlJobGroup.setAppname(registryParam.getRegistryKey());
// 设置title
xxlJobGroup.setTitle(registryParam.getRegistryKey());
// 默认都是自动注册
xxlJobGroup.setAddressType(0);
// 设置修改时间
xxlJobGroup.setUpdateTime(new Date());
// 设置ip
if (groupByAppname.get(0).getAddressList().contains(registryParam.getRegistryValue())) {
xxlJobGroup.setAddressList(groupByAppname.get(0).getAddressList() + "," + registryParam.getRegistryValue());
} else {
xxlJobGroup.setAddressList(registryParam.getRegistryValue());
}
XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().updateByAppname(xxlJobGroup);
} else if (groupByAppname.size() == 0) {
XxlJobGroup xxlJobGroup = new XxlJobGroup();
// 设置Appname
xxlJobGroup.setAppname(registryParam.getRegistryKey());
// 设置title
xxlJobGroup.setTitle(registryParam.getRegistryKey());
// 默认都是自动注册
xxlJobGroup.setAddressType(0);
// 设置修改时间
xxlJobGroup.setUpdateTime(new Date());
// 设置ip
xxlJobGroup.setAddressList(registryParam.getRegistryValue());
XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().create(xxlJobGroup);
} else {
logger.error(registryParam.getRegistryKey() + "已重复请检查appname属性");
}
}
}

View File

@@ -0,0 +1,426 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @author xuxueli 2019-05-21
*/
public class JobScheduleHelper {
private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class);
private static JobScheduleHelper instance = new JobScheduleHelper();
public static JobScheduleHelper getInstance() {
return instance;
}
public static final long PRE_READ_MS = 5000; // pre read
private Thread scheduleThread;
private Thread ringThread;
private volatile boolean scheduleThreadToStop = false;
private volatile boolean ringThreadToStop = false;
private volatile static Map<Integer, List<String>> ringData = new ConcurrentHashMap<>();
public void start() {
// schedule thread
scheduleThread = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis() % 1000);
} catch (InterruptedException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
logger.info(">>>>>>>>> init xxl-job admin scheduler success.");
// pre-read count: treadpool-size * trigger-qps (each trigger cost 50ms, qps =
// 1000/50 = 20)
int preReadCount = (XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax()
+ XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax()) * 20;
while (!scheduleThreadToStop) {
// Scan Job
long start = System.currentTimeMillis();
Connection conn = null;
boolean connAutoCommit = true; // 默认为 true在获取连接后更新
PreparedStatement preparedStatement = null;
boolean preReadSuc = true;
boolean autoCommitSet = false; // 标记是否已设置 AutoCommit
try {
conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
connAutoCommit = conn.getAutoCommit();
// 获取查询语句
String selectSQL = getSelectSQL(conn.getMetaData().getDriverName());
preparedStatement = conn.prepareStatement(selectSQL);
preparedStatement.execute();
// 设置事务手动提交(在 execute 之后)
conn.setAutoCommit(false);
autoCommitSet = true;
// tx start
// 1、pre read
long nowTime = System.currentTimeMillis();
List<XxlJobInfo> scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService()
.scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);
if (scheduleList != null && scheduleList.size() > 0) {
// 2、push time-ring
for (XxlJobInfo jobInfo : scheduleList) {
// time-ring jump
if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) {
// 2.1、trigger-expire > 5spass && make next-trigger-time
logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId());
// 1、misfire match
MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum
.match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING);
if (MisfireStrategyEnum.FIRE_ONCE_NOW == misfireStrategyEnum) {
// FIRE_ONCE_NOW 》 trigger
JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MISFIRE, -1, null,
null, null);
logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = "
+ jobInfo.getId());
}
// 2、fresh next
refreshNextValidTime(jobInfo, new Date());
} else if (nowTime > jobInfo.getTriggerNextTime()) {
// 2.2、trigger-expire < 5sdirect-trigger && make next-trigger-time
// 1、trigger
JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null,
null);
logger.debug(
">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId());
// 2、fresh next
refreshNextValidTime(jobInfo, new Date());
// next-trigger-time in 5s, pre-read again
if (jobInfo.getTriggerStatus() == 1
&& nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) {
// 1、make ring second
int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60);
// 2、push time ring
pushTimeRing(ringSecond, jobInfo.getId());
// 3、fresh next
refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
}
} else {
// 2.3、trigger-pre-readtime-ring trigger && make next-trigger-time
// 1、make ring second
int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60);
// 2、push time ring
pushTimeRing(ringSecond, jobInfo.getId());
// 3、fresh next
refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
}
}
// 3、update trigger info
for (XxlJobInfo jobInfo : scheduleList) {
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().scheduleUpdate(jobInfo);
}
} else {
preReadSuc = false;
}
// tx stop
} catch (Exception e) {
if (!scheduleThreadToStop) {
logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e);
}
} finally {
// commit
if (conn != null) {
try {
conn.commit();
} catch (SQLException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
try {
if (autoCommitSet) {
conn.setAutoCommit(connAutoCommit);
}
} catch (SQLException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
try {
conn.close();
} catch (SQLException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
}
// close PreparedStatement
if (null != preparedStatement) {
try {
preparedStatement.close();
} catch (SQLException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
}
}
long cost = System.currentTimeMillis() - start;
// Wait seconds, align second
if (cost < 1000) { // scan-overtime, not wait
try {
// pre-read period: success > scan each second; fail > skip this period;
TimeUnit.MILLISECONDS
.sleep((preReadSuc ? 1000 : PRE_READ_MS) - System.currentTimeMillis() % 1000);
} catch (InterruptedException e) {
if (!scheduleThreadToStop) {
logger.error(e.getMessage(), e);
}
}
}
}
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop");
}
});
scheduleThread.setDaemon(true);
scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread");
scheduleThread.start();
// ring thread
ringThread = new Thread(new Runnable() {
@Override
public void run() {
while (!ringThreadToStop) {
// align second
try {
TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000);
} catch (InterruptedException e) {
if (!ringThreadToStop) {
logger.error(e.getMessage(), e);
}
}
try {
// second data
List<String> ringItemData = new ArrayList<>();
int nowSecond = Calendar.getInstance().get(Calendar.SECOND); // 避免处理耗时太长,跨过刻度,向前校验一个刻度;
for (int i = 0; i < 2; i++) {
List<String> tmpData = ringData.remove((nowSecond + 60 - i) % 60);
if (tmpData != null) {
ringItemData.addAll(tmpData);
}
}
// ring trigger
logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = "
+ Arrays.asList(ringItemData));
if (ringItemData.size() > 0) {
// do trigger
for (String jobId : ringItemData) {
// do trigger
JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);
}
// clear
ringItemData.clear();
}
} catch (Exception e) {
if (!ringThreadToStop) {
logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop");
}
});
ringThread.setDaemon(true);
ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread");
ringThread.start();
}
private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {
try {
Date nextValidTime = generateNextValidTime(jobInfo, fromTime);
if (nextValidTime != null) {
jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
jobInfo.setTriggerNextTime(nextValidTime.getTime());
} else {
// generateNextValidTime fail, stop job
jobInfo.setTriggerStatus(0);
jobInfo.setTriggerLastTime(0L);
jobInfo.setTriggerNextTime(0L);
logger.error(
">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}",
jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf());
}
} catch (Exception e) {
// generateNextValidTime error, stop job
jobInfo.setTriggerStatus(0);
jobInfo.setTriggerLastTime(0L);
jobInfo.setTriggerNextTime(0L);
logger.error(
">>>>>>>>>>> xxl-job, refreshNextValidTime error for job: jobId={}, scheduleType={}, scheduleConf={}",
jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf(), e);
}
}
private void pushTimeRing(Integer ringSecond, String jobId) {
// push async ring
List<String> ringItemData = ringData.get(ringSecond);
if (ringItemData == null) {
ringItemData = new ArrayList<>();
ringData.put(ringSecond, ringItemData);
}
ringItemData.add(jobId);
logger.debug(
">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData));
}
public void toStop() {
// 1、stop schedule
scheduleThreadToStop = true;
try {
TimeUnit.SECONDS.sleep(1); // wait
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
if (scheduleThread.getState() != Thread.State.TERMINATED) {
// interrupt and wait
scheduleThread.interrupt();
try {
scheduleThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
// if has ring data
boolean hasRingData = false;
if (!ringData.isEmpty()) {
for (Integer second : ringData.keySet()) {
List<String> tmpData = ringData.get(second);
if (tmpData != null && tmpData.size() > 0) {
hasRingData = true;
break;
}
}
}
if (hasRingData) {
try {
TimeUnit.SECONDS.sleep(8);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
// stop ring (wait job-in-memory stop)
ringThreadToStop = true;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
if (ringThread.getState() != Thread.State.TERMINATED) {
// interrupt and wait
ringThread.interrupt();
try {
ringThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop");
}
// ---------------------- tools ----------------------
public static Date generateNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {
try {
ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
if (ScheduleTypeEnum.CRON == scheduleTypeEnum) {
Date nextValidTime = new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime);
return nextValidTime;
} else if (ScheduleTypeEnum.FIX_RATE == scheduleTypeEnum /*
* || ScheduleTypeEnum.FIX_DELAY ==
* scheduleTypeEnum
*/) {
return new Date(fromTime.getTime() + Integer.valueOf(jobInfo.getScheduleConf()) * 1000);
}
} catch (Exception e) {
logger.warn(
">>>>>>>>>>> xxl-job, scheduleConf is invalid for job: jobId={}, scheduleType={}, scheduleConf={}, msg={}",
jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf(), e.getMessage());
}
return null;
}
/**
* 得到当前库类型
*
* @param driverClassName
* @return
*/
private static String getSelectSQL(String driverClassName) {
if (driverClassName.contains("sqlserver")) {
return "select * from xxl_job_lock with(UPDLOCK) where lock_name = 'schedule_lock'";
} else if (driverClassName.contains("oracle")) {
return "select * from xxl_job_lock where lock_name = 'schedule_lock' for update";
}
// else if (driverClassName.contains("kingbase8")) {
// return "KingbaseES";
// }
return "select * from xxl_job_lock where lock_name = 'schedule_lock' for update";
}
}

View File

@@ -0,0 +1,151 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* job trigger thread pool helper
*
* @author xuxueli 2018-07-03 21:08:07
*/
public class JobTriggerPoolHelper {
private static Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class);
// ---------------------- trigger pool ----------------------
// fast/slow thread pool
private ThreadPoolExecutor fastTriggerPool = null;
private ThreadPoolExecutor slowTriggerPool = null;
public void start(){
fastTriggerPool = new ThreadPoolExecutor(
10,
XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(),
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode());
}
});
slowTriggerPool = new ThreadPoolExecutor(
10,
XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(),
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(2000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode());
}
});
}
public void stop() {
//triggerPool.shutdown();
fastTriggerPool.shutdownNow();
slowTriggerPool.shutdownNow();
logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success.");
}
// job timeout count
private volatile long minTim = System.currentTimeMillis()/60000; // ms > min
private volatile ConcurrentMap<String, AtomicInteger> jobTimeoutCountMap = new ConcurrentHashMap<>();
/**
* add trigger
*/
public void addTrigger(final String jobId,
final TriggerTypeEnum triggerType,
final int failRetryCount,
final String executorShardingParam,
final String executorParam,
final String addressList) {
// choose thread pool
ThreadPoolExecutor triggerPool_ = fastTriggerPool;
AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId);
if (jobTimeoutCount!=null && jobTimeoutCount.get() > 10) { // job-timeout 10 times in 1 min
triggerPool_ = slowTriggerPool;
}
// trigger
triggerPool_.execute(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
// do trigger
XxlJobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
// check timeout-count-map
long minTim_now = System.currentTimeMillis()/60000;
if (minTim != minTim_now) {
minTim = minTim_now;
jobTimeoutCountMap.clear();
}
// incr timeout-count-map
long cost = System.currentTimeMillis()-start;
if (cost > 500) { // ob-timeout threshold 500ms
AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1));
if (timeoutCount != null) {
timeoutCount.incrementAndGet();
}
}
}
}
});
}
// ---------------------- helper ----------------------
private static JobTriggerPoolHelper helper = new JobTriggerPoolHelper();
public static void toStart() {
helper.start();
}
public static void toStop() {
helper.stop();
}
/**
* @param jobId
* @param triggerType
* @param failRetryCount
* >=0: use this param
* <0: use param from job info config
* @param executorShardingParam
* @param executorParam
* null: use job param
* not null: cover job param
*/
public static void trigger(String jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) {
helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
}
}

View File

@@ -0,0 +1,28 @@
package com.xxl.job.admin.core.trigger;
import com.xxl.job.admin.core.util.I18nUtil;
/**
* trigger type enum
*
* @author xuxueli 2018-09-16 04:56:41
*/
public enum TriggerTypeEnum {
MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")),
CRON(I18nUtil.getString("jobconf_trigger_type_cron")),
RETRY(I18nUtil.getString("jobconf_trigger_type_retry")),
PARENT(I18nUtil.getString("jobconf_trigger_type_parent")),
API(I18nUtil.getString("jobconf_trigger_type_api")),
MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire"));
private TriggerTypeEnum(String title){
this.title = title;
}
private String title;
public String getTitle() {
return title;
}
}

View File

@@ -0,0 +1,284 @@
package com.xxl.job.admin.core.trigger;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.XxlJobLogService;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.util.IpUtil;
import com.xxl.job.core.util.ThrowableUtil;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.scheduletask.entity.TimeTaskEntity;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import com.yunzhupaas.scheduletask.model.ContentNewModel;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.StringUtil;
import com.xxl.job.admin.service.TimetaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
/**
* xxl-job trigger
* Created by xuxueli on 17/7/13.
*/
public class XxlJobTrigger {
private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);
/**
* trigger job
*
* @param jobId
* @param triggerType
* @param failRetryCount
* >=0: use this param
* <0: use param from job info config
* @param executorShardingParam
* @param executorParam
* null: use job param
* not null: cover job param
* @param addressList
* null: use executor addressList
* not null: cover
*/
public static void trigger(String jobId,
TriggerTypeEnum triggerType,
int failRetryCount,
String executorShardingParam,
String executorParam,
String addressList) {
// load data
XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().loadById(jobId);
if (jobInfo == null) {
logger.warn(">>>>>>>>>>>> trigger fail, jobId invalidjobId={}", jobId);
return;
}
TimeTaskEntity timeTaskEntity = JsonUtil.getJsonToBean(jobInfo.getExecutorParam(), TimeTaskEntity.class);
if (timeTaskEntity != null) {
ContentNewModel contentNewModel = JsonUtil.getJsonToBean(jobInfo.getExecutorParam(), ContentNewModel.class);
if (contentNewModel != null && contentNewModel.getStartTime() != null
&& contentNewModel.getStartTime() > System.currentTimeMillis()) {
logger.debug("任务未到开始时间jobId={}", jobId);
return;
}
if (contentNewModel != null && contentNewModel.getEndTime() != null
&& contentNewModel.getEndTime() < System.currentTimeMillis()) {
logger.debug("任务到结束时间jobId={}", jobId);
jobInfo.setTriggerStatus(0);
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().update(jobInfo);
return;
}
}
logger.debug("当前正在执行id" + jobId);
if (executorParam != null) {
jobInfo.setExecutorParam(executorParam);
}
int finalFailRetryCount = failRetryCount >= 0 ? failRetryCount : jobInfo.getExecutorFailRetryCount();
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService().load(jobInfo.getJobGroup());
// cover addressList
if (addressList != null && addressList.trim().length() > 0) {
group.setAddressType(1);
group.setAddressList(addressList.trim());
}
// sharding param
int[] shardingParam = null;
if (executorShardingParam != null) {
String[] shardingArr = executorShardingParam.split("/");
if (shardingArr.length == 2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) {
shardingParam = new int[2];
shardingParam[0] = Integer.valueOf(shardingArr[0]);
shardingParam[1] = Integer.valueOf(shardingArr[1]);
}
}
if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == ExecutorRouteStrategyEnum
.match(jobInfo.getExecutorRouteStrategy(), null)
&& group.getRegistryList() != null && !group.getRegistryList().isEmpty()
&& shardingParam == null) {
for (int i = 0; i < group.getRegistryList().size(); i++) {
processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size());
}
} else {
if (shardingParam == null) {
shardingParam = new int[] { 0, 1 };
}
processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]);
}
}
private static boolean isNumeric(String str) {
try {
Integer.valueOf(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
* @param group job group, registry list may be empty
* @param jobInfo
* @param finalFailRetryCount
* @param triggerType
* @param index sharding index
* @param total sharding index
*/
private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount,
TriggerTypeEnum triggerType, int index, int total) {
// 修改调用次数和最后执行时间
TimetaskService timetaskService = XxlJobAdminConfig.getAdminConfig().getTimetaskService();
XxlJobLogService xxlJobLogService = XxlJobAdminConfig.getAdminConfig().getXxlJobLogService();
// 得到日志数量,并修改执行次数
long count = xxlJobLogService.queryCountByJobId(jobInfo.getId());
UserInfo userInfo = new UserInfo();
if (StringUtil.isNotEmpty(jobInfo.getTenantId())) {
userInfo.setTenantId(jobInfo.getTenantId());
}
TimeTaskEntity entity = timetaskService.getInfo(jobInfo.getTaskId(), userInfo);
entity.setRunCount((int) count + 1);
entity.setNextRunTime(new Date(jobInfo.getTriggerNextTime()));
entity.setLastRunTime(new Date());
timetaskService.updateTask(jobInfo.getTaskId(), entity);
// param
ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(),
ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy
ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum
.match(jobInfo.getExecutorRouteStrategy(), null); // route strategy
String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum)
? String.valueOf(index).concat("/").concat(String.valueOf(total))
: null;
// 1、save log-id
XxlJobLog jobLog = new XxlJobLog();
jobLog.setJobGroup(jobInfo.getJobGroup());
jobLog.setJobId(jobInfo.getId());
jobLog.setTriggerTime(new Date());
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().create(jobLog);
logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
// 2、init trigger-param
TriggerParam triggerParam = new TriggerParam();
triggerParam.setJobId(jobInfo.getId());
triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
triggerParam.setExecutorParams(jobInfo.getExecutorParam());
triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
triggerParam.setLogId(jobLog.getId());
triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime());
triggerParam.setGlueType(jobInfo.getGlueType());
triggerParam.setGlueSource(jobInfo.getGlueSource());
triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
triggerParam.setBroadcastIndex(index);
triggerParam.setBroadcastTotal(total);
// 3、init address
String address = null;
ReturnT<String> routeAddressResult = null;
if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) {
if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) {
if (index < group.getRegistryList().size()) {
address = group.getRegistryList().get(index);
} else {
address = group.getRegistryList().get(0);
}
} else {
routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList());
if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) {
address = routeAddressResult.getContent();
}
}
} else {
routeAddressResult = new ReturnT<String>(ReturnT.FAIL_CODE,
I18nUtil.getString("jobconf_trigger_address_empty"));
}
// 4、trigger remote executor
ReturnT<String> triggerResult = null;
if (address != null) {
triggerResult = runExecutor(triggerParam, address);
} else {
triggerResult = new ReturnT<String>(ReturnT.FAIL_CODE, null);
}
// 5、collection trigger info
StringBuffer triggerMsgSb = new StringBuffer();
triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append("").append(triggerType.getTitle());
triggerMsgSb.append("").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append("")
.append(IpUtil.getIp());
triggerMsgSb.append("").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append("")
.append((group.getAddressType() == 0) ? I18nUtil.getString("jobgroup_field_addressType_0")
: I18nUtil.getString("jobgroup_field_addressType_1"));
triggerMsgSb.append("").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append("")
.append(group.getRegistryList());
triggerMsgSb.append("").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append("")
.append(executorRouteStrategyEnum.getTitle());
if (shardingParam != null) {
triggerMsgSb.append("(" + shardingParam + ")");
}
triggerMsgSb.append("").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append("")
.append(blockStrategy.getTitle());
triggerMsgSb.append("").append(I18nUtil.getString("jobinfo_field_timeout")).append("")
.append(jobInfo.getExecutorTimeout());
triggerMsgSb.append("").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append("")
.append(finalFailRetryCount);
triggerMsgSb.append("" + I18nUtil.getString("jobconf_trigger_run") + "")
.append((routeAddressResult != null && routeAddressResult.getMsg() != null)
? routeAddressResult.getMsg() + ""
: "")
.append(triggerResult.getMsg() != null ? triggerResult.getMsg() : "");
// 6、save log trigger-info
jobLog.setExecutorAddress(address);
jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
jobLog.setExecutorParam(jobInfo.getExecutorParam());
jobLog.setExecutorShardingParam(shardingParam);
jobLog.setExecutorFailRetryCount(finalFailRetryCount);
// jobLog.setTriggerTime();
jobLog.setTriggerCode(triggerResult.getCode());
jobLog.setTriggerMsg(triggerMsgSb.toString());
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().updateTriggerInfo(jobLog);
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
}
/**
* run executor
*
* @param triggerParam
* @param address
* @return
*/
public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address) {
ReturnT<String> runResult = null;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
runResult = executorBiz.run(triggerParam);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
}
StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + "");
runResultSB.append("address").append(address);
runResultSB.append("code").append(runResult.getCode());
runResultSB.append("msg").append(runResult.getMsg());
runResult.setMsg(runResultSB.toString());
return runResult;
}
}

View File

@@ -0,0 +1,99 @@
package com.xxl.job.admin.core.util;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* Cookie.Util
*
* @author xuxueli 2015-12-12 18:01:06
*/
public class CookieUtil {
// 默认缓存时间,单位/秒, 2H
private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE;
// 保存路径,根路径
private static final String COOKIE_PATH = "/";
/**
* 保存
*
* @param response
* @param key
* @param value
* @param ifRemember
*/
public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) {
int age = ifRemember?COOKIE_MAX_AGE:-1;
set(response, key, value, null, COOKIE_PATH, age, true);
}
/**
* 保存
*
* @param response
* @param key
* @param value
* @param maxAge
*/
private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
Cookie cookie = new Cookie(key, value);
if (domain != null) {
cookie.setDomain(domain);
}
cookie.setPath(path);
cookie.setMaxAge(maxAge);
cookie.setHttpOnly(isHttpOnly);
response.addCookie(cookie);
}
/**
* 查询value
*
* @param request
* @param key
* @return
*/
public static String getValue(HttpServletRequest request, String key) {
Cookie cookie = get(request, key);
if (cookie != null) {
return cookie.getValue();
}
return null;
}
/**
* 查询Cookie
*
* @param request
* @param key
*/
private static Cookie get(HttpServletRequest request, String key) {
Cookie[] arr_cookie = request.getCookies();
if (arr_cookie != null && arr_cookie.length > 0) {
for (Cookie cookie : arr_cookie) {
if (cookie.getName().equals(key)) {
return cookie;
}
}
}
return null;
}
/**
* 删除Cookie
*
* @param request
* @param response
* @param key
*/
public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
Cookie cookie = get(request, key);
if (cookie != null) {
set(response, key, "", null, COOKIE_PATH, 0, true);
}
}
}

View File

@@ -0,0 +1,32 @@
package com.xxl.job.admin.core.util;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.Configuration;
import freemarker.template.TemplateHashModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* ftl util
*
* @author xuxueli 2018-01-17 20:37:48
*/
public class FtlUtil {
private static Logger logger = LoggerFactory.getLogger(FtlUtil.class);
private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build(); //BeansWrapper.getDefaultInstance();
public static TemplateHashModel generateStaticModel(String packageName) {
try {
TemplateHashModel staticModels = wrapper.getStaticModels();
TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);
return fileStatics;
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return null;
}
}

View File

@@ -0,0 +1,80 @@
package com.xxl.job.admin.core.util;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* i18n util
*
* @author xuxueli 2018-01-17 20:39:06
*/
public class I18nUtil {
private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
private static Properties prop = null;
public static Properties loadI18nProp(){
if (prop != null) {
return prop;
}
try {
// build i18n prop
String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n);
// load prop
Resource resource = new ClassPathResource(i18nFile);
EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
prop = PropertiesLoaderUtils.loadProperties(encodedResource);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return prop;
}
/**
* get val of i18n key
*
* @param key
* @return
*/
public static String getString(String key) {
return loadI18nProp().getProperty(key);
}
/**
* get mult val of i18n mult key, as json
*
* @param keys
* @return
*/
public static String getMultString(String... keys) {
Map<String, String> map = new HashMap<String, String>();
Properties prop = loadI18nProp();
if (keys!=null && keys.length>0) {
for (String key: keys) {
map.put(key, prop.getProperty(key));
}
} else {
for (String key: prop.stringPropertyNames()) {
map.put(key, prop.getProperty(key));
}
}
String json = JacksonUtil.writeValueAsString(map);
return json;
}
}

View File

@@ -0,0 +1,93 @@
package com.xxl.job.admin.core.util;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* Jackson util
*
* 1、obj need private and set/get
* 2、do not support inner class
*
* @author xuxueli 2015-9-25 18:02:56
*/
public class JacksonUtil {
private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);
private final static ObjectMapper objectMapper = new ObjectMapper();
public static ObjectMapper getInstance() {
return objectMapper;
}
/**
* bean、array、List、Map --> json
*
* @param obj
* @return json string
* @throws Exception
*/
public static String writeValueAsString(Object obj) {
try {
return getInstance().writeValueAsString(obj);
} catch (JsonGenerationException e) {
logger.error(e.getMessage(), e);
} catch (JsonMappingException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* string --> bean、Map、List(array)
*
* @param jsonStr
* @param clazz
* @return obj
* @throws Exception
*/
public static <T> T readValue(String jsonStr, Class<T> clazz) {
try {
return getInstance().readValue(jsonStr, clazz);
} catch (JsonParseException e) {
logger.error(e.getMessage(), e);
} catch (JsonMappingException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* string --> List<Bean>...
*
* @param jsonStr
* @param parametrized
* @param parameterClasses
* @param <T>
* @return
*/
public static <T> T readValue(String jsonStr, Class<?> parametrized, Class<?>... parameterClasses) {
try {
JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
return getInstance().readValue(jsonStr, javaType);
} catch (JsonParseException e) {
logger.error(e.getMessage(), e);
} catch (JsonMappingException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return null;
}
}

View File

@@ -0,0 +1,118 @@
package com.xxl.job.admin.core.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* local cache tool
*
* @author xuxueli 2018-01-22 21:37:34
*/
public class LocalCacheUtil {
private static ConcurrentMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<String, LocalCacheData>(); // 类型建议用抽象父类,兼容性更好;
private static class LocalCacheData {
private String key;
private Object val;
private long timeoutTime;
public LocalCacheData(String key, Object val, long timeoutTime) {
this.key = key;
this.val = val;
this.timeoutTime = timeoutTime;
}
public String getKey() {
return key;
}
public Object getVal() {
return val;
}
public long getTimeoutTime() {
return timeoutTime;
}
}
/**
* set cache
*
* @param key
* @param val
* @param cacheTime
* @return
*/
public static boolean set(String key, Object val, long cacheTime) {
// clean timeout cache, before set new cache (avoid cache too much)
cleanTimeoutCache();
// set new cache
if (key == null || key.trim().length() == 0) {
return false;
}
if (val == null) {
remove(key);
}
if (cacheTime <= 0) {
remove(key);
}
long timeoutTime = System.currentTimeMillis() + cacheTime;
LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);
cacheRepository.put(localCacheData.getKey(), localCacheData);
return true;
}
/**
* remove cache
*
* @param key
* @return
*/
public static boolean remove(String key) {
if (key == null || key.trim().length() == 0) {
return false;
}
cacheRepository.remove(key);
return true;
}
/**
* get cache
*
* @param key
* @return
*/
public static Object get(String key) {
if (key == null || key.trim().length() == 0) {
return null;
}
LocalCacheData localCacheData = cacheRepository.get(key);
if (localCacheData != null && System.currentTimeMillis() < localCacheData.getTimeoutTime()) {
return localCacheData.getVal();
} else {
remove(key);
return null;
}
}
/**
* clean timeout cache
*
* @return
*/
public static boolean cleanTimeoutCache() {
if (!cacheRepository.keySet().isEmpty()) {
for (String key : cacheRepository.keySet()) {
LocalCacheData localCacheData = cacheRepository.get(key);
if (localCacheData != null && System.currentTimeMillis() >= localCacheData.getTimeoutTime()) {
cacheRepository.remove(key);
}
}
}
return true;
}
}

View File

@@ -0,0 +1,11 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
/**
* Created by xuxueli on 16/9/30.
*/
public interface XxlJobGroupDao extends BaseMapper<XxlJobGroup> {
}

View File

@@ -0,0 +1,13 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
/**
* job info
* @author xuxueli 2016-1-12 18:03:45
*/
public interface XxlJobInfoDao extends BaseMapper<XxlJobInfo> {
}

View File

@@ -0,0 +1,29 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* job log
* @author xuxueli 2016-1-12 18:03:06
*/
public interface XxlJobLogDao extends BaseMapper<XxlJobLog> {
Map<String, Object> findLogReport(@Param("from") Date from,
@Param("to") Date to, @Param("dbType") String dbType);
Map<String, Object> oracleFindLogReport(@Param("from") String from,
@Param("to") String to, @Param("dbType") String dbType);
List<String> findLostJobIds(@Param("losedTime") String losedTime, @Param("dbType") String dbType);
}

View File

@@ -0,0 +1,13 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
/**
* job log for glue
* @author xuxueli 2016-5-19 18:04:56
*/
public interface XxlJobLogGlueDao extends BaseMapper<XxlJobLogGlue> {
}

View File

@@ -0,0 +1,15 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxl.job.admin.core.model.XxlJobLogReport;
/**
* job log
* @author xuxueli 2019-11-22
*/
public interface XxlJobLogReportDao extends BaseMapper<XxlJobLogReport> {
XxlJobLogReport queryLogReportTotal();
}

View File

@@ -0,0 +1,12 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxl.job.admin.core.model.XxlJobRegistry;
/**
* Created by xuxueli on 16/9/30.
*/
public interface XxlJobRegistryDao extends BaseMapper<XxlJobRegistry> {
}

View File

@@ -0,0 +1,12 @@
package com.xxl.job.admin.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxl.job.admin.core.model.XxlJobUser;
/**
* @author xuxueli 2019-05-04 16:44:59
*/
public interface XxlJobUserDao extends BaseMapper<XxlJobUser> {
}

View File

@@ -0,0 +1,16 @@
package com.xxl.job.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.scheduletask.entity.HandlerNameEntity;
/**
* 任务名称表
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/29 11:08
*/
public interface HandlerNameMapper extends BaseMapper<HandlerNameEntity> {
}

View File

@@ -0,0 +1,17 @@
package com.xxl.job.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.scheduletask.entity.TimeTaskEntity;
/**
* 定时任务
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
public interface TimeTaskMapper extends BaseMapper<TimeTaskEntity> {
}

View File

@@ -0,0 +1,56 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yunzhupaas.scheduletask.entity.HandlerNameEntity;
import java.util.List;
/**
* 任务名称业务类
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/29 11:10
*/
public interface HandlerNameService extends IService<HandlerNameEntity> {
/**
* 创建任务名称
*
* @param entity
* @return
*/
boolean create(HandlerNameEntity entity);
/**
* 创建任务名称
*
* @param entity
* @return
*/
boolean delete(HandlerNameEntity entity);
/**
* 获取本地方法
*
* @return
*/
List<HandlerNameEntity> queryList();
/**
* 删除所有数据
*
* @return
*/
boolean removeAll();
/**
* 获取本地方法
*
* @param localHostTaskId
* @return
*/
HandlerNameEntity getInfo(String localHostTaskId);
}

View File

@@ -0,0 +1,90 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yunzhupaas.base.Pagination;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.scheduletask.entity.TimeTaskEntity;
import java.util.List;
/**
* 定时任务
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
public interface TimetaskService extends IService<TimeTaskEntity> {
/**
* 列表
*
* @param pagination 分页
* @return
*/
List<TimeTaskEntity> getList(Pagination pagination, UserInfo userInfo);
/**
* 信息
*
* @param id 主键值
* @return
*/
TimeTaskEntity getInfo(String id, UserInfo userInfo);
/**
* 验证名称
*
* @param fullName 名称
* @param id 主键值
* @return
*/
boolean isExistByFullName(String fullName, String id);
/**
* 验证编码
*
* @param enCode 编码
* @param id 主键值
* @return
*/
boolean isExistByEnCode(String enCode, String id);
/**
* 创建
*
* @param entity 实体对象
*/
boolean create(TimeTaskEntity entity, UserInfo userInfo);
/**
* 日程调度
*
* @param entity 实体对象
*/
boolean schedule(TimeTaskEntity entity);
/**
* 更新
*
* @param id 主键值
* @param entity 实体对象
*/
boolean update(String id, TimeTaskEntity entity, UserInfo userInfo);
/**
* 删除
*
* @param entity 实体对象
*/
void delete(TimeTaskEntity entity);
/**
* 修改执行次数
* @param taskId
* @param entity
*/
void updateTask(String taskId, TimeTaskEntity entity);
}

View File

@@ -0,0 +1,49 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import java.util.List;
public interface XxlJobGroupService extends IService<XxlJobGroup> {
List<XxlJobGroup> findAll();
List<XxlJobGroup> findByAddressType(int addressType);
int create(XxlJobGroup xxlJobGroup);
int update(XxlJobGroup xxlJobGroup);
int remove(String id);
XxlJobGroup load(String id);
List<XxlJobGroup> pageList(int offset,
int pagesize,
String appname,
String title);
long pageListCount(int offset,
int pagesize,
String appname,
String title);
/**
* 通过Appname查询分组
*
* @param appname
* @return
*/
List<XxlJobGroup> findByAppname(String appname);
/**
* 通过appname修改数据
*
* @param xxlJobGroup
* @return
*/
int updateByAppname(XxlJobGroup xxlJobGroup);
}

View File

@@ -0,0 +1,59 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import java.util.List;
public interface XxlJobInfoService extends IService<XxlJobInfo> {
List<XxlJobInfo> pageList(int offset,
int pagesize,
String jobGroup,
int triggerStatus,
String jobDesc,
String executorHandler,
String author);
long pageListCount(int offset,
int pagesize,
String jobGroup,
int triggerStatus,
String jobDesc,
String executorHandler,
String author);
int create(XxlJobInfo info);
XxlJobInfo loadById(String id);
int update(XxlJobInfo xxlJobInfo);
int delete(String id);
List<XxlJobInfo> getJobsByGroup(String jobGroup);
int findAllCount();
List<XxlJobInfo> scheduleJobQuery(long maxNextTime, int pagesize );
int scheduleUpdate(XxlJobInfo xxlJobInfo);
/**
* 通过taskId获取任务信息
*
* @param taskId
* @return
*/
XxlJobInfo queryByTaskId(String taskId);
/**
* 通过taskId删除任务
*
* @param taskId
* @return
*/
boolean deleteByTaskId(String taskId);
}

View File

@@ -0,0 +1,18 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
import java.util.List;
public interface XxlJobLogGlueService extends IService<XxlJobLogGlue> {
int create(XxlJobLogGlue xxlJobLogGlue);
List<XxlJobLogGlue> findByJobId(String jobId);
int removeOld(String jobId, int limit);
int deleteByJobId(String jobId);
}

View File

@@ -0,0 +1,20 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import java.util.Date;
import java.util.List;
public interface XxlJobLogReportService extends IService<XxlJobLogReport> {
int create(XxlJobLogReport xxlJobLogReport);
int update(XxlJobLogReport xxlJobLogReport);
List<XxlJobLogReport> queryLogReport(Date triggerDayFrom,
Date triggerDayTo);
XxlJobLogReport queryLogReportTotal();
}

View File

@@ -0,0 +1,88 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import com.yunzhupaas.scheduletask.model.TaskPage;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* xxljoblog
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/29 15:05
*/
public interface XxlJobLogService extends IService<XxlJobLog> {
/**
* 分页获取调用日志
*
* @param taskId 任务id
* @param taskPage
* @return
*/
List<XxlJobLog> getList(String taskId, TaskPage taskPage);
/**
* 通过jobid获取日志总数
*
* @param jobId 任务id
* @return
*/
Long queryCountByJobId(String jobId);
// exist jobId not use jobGroup, not exist use jobGroup
List<XxlJobLog> pageList(int offset,
int pagesize,
String jobGroup,
String jobId,
Date triggerTimeStart,
Date triggerTimeEnd,
int logStatus);
int pageListCount(int offset,
int pagesize,
String jobGroup,
String jobId,
Date triggerTimeStart,
Date triggerTimeEnd,
int logStatus);
XxlJobLog load(String id);
long create(XxlJobLog xxlJobLog);
int updateTriggerInfo(XxlJobLog xxlJobLog);
int updateHandleInfo(XxlJobLog xxlJobLog);
int delete(String jobId);
Map<String, Object> findLogReport(Date from,
Date to);
List<String> findClearLogIds(String jobGroup,
String jobId,
Date clearBeforeTime,
int clearBeforeNum,
int pagesize);
int clearLog(List<String> logIds);
List<String> findFailJobLogIds(int pagesize);
int updateAlarmStatus(String logId,
int oldAlarmStatus,
int newAlarmStatus);
List<String> findLostJobIds(Date losedTime);
boolean deleteByTaskId(String taskId);
}

View File

@@ -0,0 +1,33 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import java.util.Date;
import java.util.List;
public interface XxlJobRegistryService extends IService<XxlJobRegistry> {
List<String> findDead(int timeout,
Date nowTime);
int removeDead(List<String> ids);
List<XxlJobRegistry> findAll(int timeout,
Date nowTime);
int registryUpdate(String registryGroup,
String registryKey,
String registryValue,
Date updateTime);
int registrySave(String registryGroup,
String registryKey,
String registryValue,
Date updateTime);
int registryDelete(String registryGroup,
String registryKey,
String registryValue);
}

View File

@@ -0,0 +1,99 @@
package com.xxl.job.admin.service;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.core.biz.model.ReturnT;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import java.util.Date;
import java.util.Map;
/**
* core job action for xxl-job
*
* @author xuxueli 2016-5-28 15:30:33
*/
public interface XxlJobService {
/**
* page list
*
* @param start
* @param length
* @param jobGroup
* @param jobDesc
* @param executorHandler
* @param author
* @return
*/
public Map<String, Object> pageList(int start, int length, String jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author);
/**
* add job
*
* @param jobInfo
* @return
*/
public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser);
/**
* update job
*
* @param jobInfo
* @return
*/
public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser);
/**
* remove job
* *
* @param id
* @return
*/
public ReturnT<String> remove(String id);
/**
* start job
*
* @param id
* @return
*/
public ReturnT<String> start(String id);
/**
* stop job
*
* @param id
* @return
*/
public ReturnT<String> stop(String id);
/**
* trigger
*
* @param loginUser
* @param jobId
* @param executorParam
* @param addressList
* @return
*/
public ReturnT<String> trigger(XxlJobUser loginUser, String jobId, String executorParam, String addressList);
/**
* dashboard info
*
* @return
*/
public Map<String,Object> dashboardInfo();
/**
* chart info
*
* @param startDate
* @param endDate
* @return
*/
public ReturnT<Map<String,Object>> chartInfo(Date startDate, Date endDate);
}

View File

@@ -0,0 +1,29 @@
package com.xxl.job.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.job.admin.core.model.XxlJobUser;
import java.util.List;
public interface XxlJobUserService extends IService<XxlJobUser> {
List<XxlJobUser> pageList(int offset,
int pagesize,
String username,
int role);
int pageListCount(int offset,
int pagesize,
String username,
int role);
XxlJobUser loadByUserName(String username);
int create(XxlJobUser xxlJobUser);
int update(XxlJobUser xxlJobUser);
int delete(String id);
}

View File

@@ -0,0 +1,42 @@
package com.xxl.job.admin.service.impl;
import com.xxl.job.admin.core.thread.JobCompleteHelper;
import com.xxl.job.admin.core.thread.JobRegistryHelper;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryHandlerName;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author xuxueli 2017-07-27 21:54:20
*/
@Service
public class AdminBizImpl implements AdminBiz {
@Override
public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
return JobCompleteHelper.getInstance().callback(callbackParamList);
}
@Override
public ReturnT<String> registry(RegistryParam registryParam) {
return JobRegistryHelper.getInstance().registry(registryParam);
}
@Override
public ReturnT<String> registryRemove(RegistryParam registryParam) {
return JobRegistryHelper.getInstance().registryRemove(registryParam);
}
@Override
public ReturnT<String> registryHandlerName(RegistryHandlerName registryHandlerName) {
return null;
}
}

View File

@@ -0,0 +1,56 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.mapper.HandlerNameMapper;
import com.xxl.job.admin.service.HandlerNameService;
import com.yunzhupaas.scheduletask.entity.HandlerNameEntity;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 任务名称业务实现类
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/29 11:10
*/
@Service
public class HandlerNameServiceImpl extends ServiceImpl<HandlerNameMapper, HandlerNameEntity> implements HandlerNameService {
@Override
public boolean create(HandlerNameEntity entity) {
entity.setId(entity.getHandlerName());
return this.save(entity);
}
@Override
public boolean delete(HandlerNameEntity entity) {
QueryWrapper<HandlerNameEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(HandlerNameEntity::getExecutor, entity.getExecutor()).eq(HandlerNameEntity::getHandlerName, entity.getHandlerName());
return this.remove(queryWrapper);
}
@Override
public List<HandlerNameEntity> queryList() {
QueryWrapper<HandlerNameEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().groupBy(HandlerNameEntity::getHandlerName);
return this.list();
}
@Override
public boolean removeAll() {
return this.remove(new QueryWrapper<HandlerNameEntity>());
}
@Override
public HandlerNameEntity getInfo(String localHostTaskId) {
QueryWrapper<HandlerNameEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(HandlerNameEntity::getId, localHostTaskId);
return this.getOne(queryWrapper);
}
}

View File

@@ -0,0 +1,276 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.mapper.TimeTaskMapper;
import com.xxl.job.admin.service.HandlerNameService;
import com.xxl.job.admin.service.TimetaskService;
import com.xxl.job.admin.service.XxlJobService;
import com.yunzhupaas.base.Pagination;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.scheduletask.entity.*;
import com.yunzhupaas.scheduletask.model.ContentNewModel;
import com.yunzhupaas.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
/**
* 定时任务
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
@Service
public class TimetaskServiceImpl extends ServiceImpl<TimeTaskMapper, TimeTaskEntity> implements TimetaskService {
@Autowired
private HandlerNameService handlerNameService;
@Autowired
private XxlJobService xxlJobService;
@Override
public List<TimeTaskEntity> getList(Pagination pagination, UserInfo userInfo) {
QueryWrapper<TimeTaskEntity> queryWrapper = new QueryWrapper<>();
if (pagination.getKeyword() != null) {
queryWrapper.lambda().and(
t -> t.like(TimeTaskEntity::getEnCode, pagination.getKeyword())
.or().like(TimeTaskEntity::getFullName, pagination.getKeyword()));
}
// 验证是否为多租户
if (StringUtil.isNotEmpty(userInfo.getTenantId())) {
queryWrapper.lambda().eq(TimeTaskEntity::getTenantId, userInfo.getTenantId());
}
// 排序
queryWrapper.lambda().orderByAsc(TimeTaskEntity::getSortCode).orderByDesc(TimeTaskEntity::getCreatorTime);
Page<TimeTaskEntity> page = new Page<>(pagination.getCurrentPage(), pagination.getPageSize());
IPage<TimeTaskEntity> iPage = this.page(page, queryWrapper);
return pagination.setData(iPage.getRecords(), page.getTotal());
}
@Override
public TimeTaskEntity getInfo(String id, UserInfo userInfo) {
QueryWrapper<TimeTaskEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TimeTaskEntity::getId, id);
// 验证是否为多租户
if (StringUtil.isNotEmpty(userInfo.getTenantId())) {
queryWrapper.lambda().eq(TimeTaskEntity::getTenantId, userInfo.getTenantId());
}
return this.getOne(queryWrapper);
}
@Override
public boolean isExistByFullName(String fullName, String id) {
QueryWrapper<TimeTaskEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TimeTaskEntity::getFullName, fullName);
if (!StringUtil.isEmpty(id)) {
queryWrapper.lambda().ne(TimeTaskEntity::getId, id);
}
return this.count(queryWrapper) > 0 ? true : false;
}
@Override
public boolean isExistByEnCode(String enCode, String id) {
QueryWrapper<TimeTaskEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TimeTaskEntity::getEnCode, enCode);
if (!StringUtil.isEmpty(id)) {
queryWrapper.lambda().ne(TimeTaskEntity::getId, id);
}
return this.count(queryWrapper) > 0 ? true : false;
}
@Override
public boolean create(TimeTaskEntity entity, UserInfo userInfo) {
entity.setId(StringUtil.isNotEmpty(entity.getId()) ? entity.getId() : RandomUtil.uuId());
ContentNewModel model = JsonUtil.getJsonToBean(entity.getExecuteContent(), ContentNewModel.class);
model.setUserInfo(userInfo);
// 得到token
model.setToken(userInfo.getToken());
// 添加时间
Date date = new Date();
entity.setCreatorTime(date);
entity.setCreatorUserId(userInfo.getUserId());
entity.setTenantId(userInfo.getTenantId());
// 将任务添加到info表中
// 构造模型
XxlJobInfo xxlJobInfo = buildModel(entity, model, new XxlJobInfo(), date, userInfo);
// 如果是本地方法
boolean flag = true;
if ("3".equals(entity.getExecuteType())) {
// 获取本地方法对应的executor和handlerName
HandlerNameEntity handlerNameEntity = handlerNameService.getInfo(model.getLocalHostTaskId());
if (handlerNameEntity == null) {
flag = false;
} else {
// 获取执行器
List<XxlJobGroup> xxlJobGroup = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService()
.findByAppname(handlerNameEntity.getExecutor());
xxlJobInfo.setJobGroup(xxlJobGroup.size() == 1 ? xxlJobGroup.get(0).getId() : null);
xxlJobInfo.setScheduleConf(model.getCron());
xxlJobInfo.setExecutorHandler(handlerNameEntity.getHandlerName());
}
}
// 保存到yunzhupaas的表中
this.save(entity);
if (flag) {
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().create(xxlJobInfo);
// 开始调度
xxlJobService.start(xxlJobInfo.getId());
}
return flag;
}
@Override
public boolean schedule(TimeTaskEntity entity) {
String id = entity.getId();
boolean flag = true;
ContentNewModel model = JsonUtil.getJsonToBean(entity.getExecuteContent(), ContentNewModel.class);
UserInfo userInfo = model.getUserInfo();
TimeTaskEntity info = getInfo(id, userInfo);
if (info == null) {
create(entity, userInfo);
}
return flag;
}
@Override
public boolean update(String id, TimeTaskEntity entity, UserInfo userInfo) {
entity.setId(id);
entity.setLastModifyTime(DateUtil.getNowDate());
entity.setLastModifyUserId(userInfo.getUserId());
entity.setTenantId(userInfo.getTenantId());
ContentNewModel model = JsonUtil.getJsonToBean(entity.getExecuteContent(), ContentNewModel.class);
model.setUserInfo(userInfo);
// 得到token
model.setToken(userInfo.getToken());
// 获取当前时间
Date date = new Date();
entity.setLastModifyTime(date);
entity.setLastModifyUserId(userInfo.getUserId());
// 修改任务
// 通过任务id得到任务
XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().queryByTaskId(id);
if (jobInfo == null) {
jobInfo = new XxlJobInfo();
}
// 构造模型
XxlJobInfo xxlJobInfo = buildModel(entity, model, jobInfo, date, userInfo);
// 如果是本地方法
boolean flag = true;
if ("3".equals(entity.getExecuteType())) {
// 获取本地方法对应的executor和handlerName
HandlerNameEntity handlerNameEntity = handlerNameService.getInfo(model.getLocalHostTaskId());
if (handlerNameEntity == null) {
flag = false;
} else {
// 获取执行器
List<XxlJobGroup> xxlJobGroup = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupService()
.findByAppname(handlerNameEntity.getExecutor());
xxlJobInfo.setJobGroup(xxlJobGroup.size() == 1 ? xxlJobGroup.get(0).getId() : null);
xxlJobInfo.setScheduleConf(model.getCron());
xxlJobInfo.setExecutorHandler(handlerNameEntity.getHandlerName());
}
}
if (flag) {
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().update(xxlJobInfo);
}
// return修改结果
return this.updateById(entity);
}
@Override
public void delete(TimeTaskEntity entity) {
this.removeById(entity.getId());
// 删除任务
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoService().deleteByTaskId(entity.getId());
XxlJobAdminConfig.getAdminConfig().getXxlJobLogService().deleteByTaskId(entity.getId());
}
@Override
public void updateTask(String taskId, TimeTaskEntity entity) {
entity.setId(taskId);
this.updateById(entity);
}
/**
* 构造任务并启动
*
* @param entity
* @param date
* @param model
*/
private XxlJobInfo buildModel(TimeTaskEntity entity, ContentNewModel model, XxlJobInfo xxlJobInfo, Date date,
UserInfo userInfo) {
// 默认一个执行器主键ID
xxlJobInfo.setJobGroup("8");
// 默认一个执行器描述
xxlJobInfo.setJobDesc(entity.getFullName());
// 负责人
xxlJobInfo.setAuthor(userInfo.getUserId());
// 调度类型
xxlJobInfo.setScheduleType("CRON");
// 添加时间
xxlJobInfo.setAddTime(date);
// 调度配置,值含义取决于调度类型
xxlJobInfo.setScheduleConf(model.getCron());
// 调度过期策略(默认忽略)
xxlJobInfo.setMisfireStrategy("DO_NOTHING");
// 执行器路由策略(默认第一个)
xxlJobInfo.setExecutorRouteStrategy("FIRST");
// 执行器任务handler执行任务的handler
xxlJobInfo.setExecutorHandler("defaultHandler");
// 执行参数
// 将ContentNewModel当做参数传递给任务执行器
model.setExecuteType(entity.getExecuteType());
xxlJobInfo.setExecutorParam(JsonUtil.getObjectToString(model));
// 阻塞处理策略(默认单行串行)
xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
// 任务执行超时时间单位秒默认0秒
xxlJobInfo.setExecutorTimeout(0);
// 失败重试次数默认0
xxlJobInfo.setExecutorFailRetryCount(0);
// GLUE类型默认BEAN
xxlJobInfo.setGlueType("BEAN");
// GLUE源代码
xxlJobInfo.setGlueRemark("GLUE代码初始化");
// 调度状态0-停止1-运行(默认运行)
xxlJobInfo.setTriggerStatus(entity.getEnabledMark());
// 上次调度时间
xxlJobInfo.setTriggerLastTime(0L);
// 下次调度时间
xxlJobInfo.setTriggerNextTime(0L);
// 创建时间GLUE
xxlJobInfo.setGlueUpdatetime(date);
// GLUE源代码
xxlJobInfo.setGlueSource("");
// 子任务ID多个逗号分隔
xxlJobInfo.setChildJobId("");
// 租户id
xxlJobInfo.setTenantId(userInfo.getTenantId());
// 创建时增加任务id
xxlJobInfo.setTaskId(entity.getId());
// 修改时间
if (entity.getLastModifyTime() != null) {
xxlJobInfo.setUpdateTime(entity.getLastModifyTime());
}
return xxlJobInfo;
}
}

View File

@@ -0,0 +1,108 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.service.XxlJobGroupService;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.util.StringUtil;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class XxlJobGroupServiceImpl extends ServiceImpl<XxlJobGroupDao, XxlJobGroup> implements XxlJobGroupService {
@Override
public List<XxlJobGroup> findAll() {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().orderByAsc(XxlJobGroup::getAppname)
.orderByAsc(XxlJobGroup::getTitle)
.orderByAsc(XxlJobGroup::getId);
return this.list(queryWrapper);
}
@Override
public List<XxlJobGroup> findByAddressType(int addressType) {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobGroup::getAddressType, addressType);
queryWrapper.lambda().orderByAsc(XxlJobGroup::getAppname)
.orderByAsc(XxlJobGroup::getTitle)
.orderByAsc(XxlJobGroup::getId);
return this.list(queryWrapper);
}
@Override
public int create(XxlJobGroup xxlJobGroup) {
return this.save(xxlJobGroup) ? 1 : 0;
}
@Override
public int update(XxlJobGroup xxlJobGroup) {
return this.updateById(xxlJobGroup) ? 1 : 0;
}
@Override
public int remove(String id) {
return this.removeById(id) ? 1 : 0;
}
@Override
public XxlJobGroup load(String id) {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobGroup::getId, id);
return this.getOne(queryWrapper);
}
@Override
public List<XxlJobGroup> pageList(int offset, int pagesize, String appname, String title) {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(appname)) {
queryWrapper.lambda().like(XxlJobGroup::getAppname, appname);
}
if (StringUtil.isNotEmpty(title)) {
queryWrapper.lambda().like(XxlJobGroup::getTitle, title);
}
queryWrapper.lambda().orderByAsc(XxlJobGroup::getAppname)
.orderByAsc(XxlJobGroup::getTitle)
.orderByAsc(XxlJobGroup::getId);
Page<XxlJobGroup> page = new Page<>(offset/pagesize + 1, pagesize);
IPage<XxlJobGroup> iPage = this.page(page, queryWrapper);
return iPage.getRecords();
}
@Override
public long pageListCount(int offset, int pagesize, String appname, String title) {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(appname)) {
queryWrapper.lambda().like(XxlJobGroup::getAppname, appname);
}
if (StringUtil.isNotEmpty(title)) {
queryWrapper.lambda().like(XxlJobGroup::getTitle, title);
}
return this.count(queryWrapper);
}
@Override
public List<XxlJobGroup> findByAppname(String appname) {
QueryWrapper<XxlJobGroup> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobGroup::getAppname, appname);
return this.list(queryWrapper);
}
@Override
public int updateByAppname(XxlJobGroup xxlJobGroup) {
UpdateWrapper<XxlJobGroup> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobGroup::getAppname, xxlJobGroup.getAppname());
updateWrapper.lambda().set(XxlJobGroup::getTitle, xxlJobGroup.getTitle());
updateWrapper.lambda().set(XxlJobGroup::getAddressType, xxlJobGroup.getAddressType());
updateWrapper.lambda().set(XxlJobGroup::getAddressList, xxlJobGroup.getAddressList());
updateWrapper.lambda().set(XxlJobGroup::getUpdateTime, xxlJobGroup.getUpdateTime());
return this.update(updateWrapper) ? 1 : 0;
}
}

View File

@@ -0,0 +1,133 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.service.XxlJobInfoService;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.util.StringUtil;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class XxlJobInfoServiceImpl extends ServiceImpl<XxlJobInfoDao, XxlJobInfo> implements XxlJobInfoService {
@Override
public List<XxlJobInfo> pageList(int offset, int pagesize, String jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !"0".equals(jobGroup)) {
queryWrapper.lambda().eq(XxlJobInfo::getJobGroup, jobGroup);
}
if (triggerStatus >= 0) {
queryWrapper.lambda().eq(XxlJobInfo::getTriggerStatus, triggerStatus);
}
if (StringUtil.isNotEmpty(jobDesc)) {
queryWrapper.lambda().like(XxlJobInfo::getJobDesc, jobDesc);
}
if (StringUtil.isNotEmpty(executorHandler)) {
queryWrapper.lambda().like(XxlJobInfo::getExecutorHandler, executorHandler);
}
if (StringUtil.isNotEmpty(author)) {
queryWrapper.lambda().like(XxlJobInfo::getAuthor, author);
}
queryWrapper.lambda().orderByDesc(XxlJobInfo::getId);
Page<XxlJobInfo> page = new Page<>(offset/pagesize + 1, pagesize);
IPage<XxlJobInfo> iPage = this.page(page, queryWrapper);
return iPage.getRecords();
}
@Override
public long pageListCount(int offset, int pagesize, String jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !"0".equals(jobGroup)) {
queryWrapper.lambda().eq(XxlJobInfo::getJobGroup, jobGroup);
}
if (triggerStatus >= 0) {
queryWrapper.lambda().eq(XxlJobInfo::getTriggerStatus, triggerStatus);
}
if (StringUtil.isNotEmpty(jobDesc)) {
queryWrapper.lambda().like(XxlJobInfo::getJobDesc, jobDesc);
}
if (StringUtil.isNotEmpty(executorHandler)) {
queryWrapper.lambda().like(XxlJobInfo::getExecutorHandler, executorHandler);
}
if (StringUtil.isNotEmpty(author)) {
queryWrapper.lambda().like(XxlJobInfo::getAuthor, author);
}
return this.count(queryWrapper);
}
@Override
public int create(XxlJobInfo info) {
return this.save(info) ? 1 : 0;
}
@Override
public XxlJobInfo loadById(String id) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobInfo::getId, id);
return this.getOne(queryWrapper);
}
@Override
public int update(XxlJobInfo xxlJobInfo) {
return this.updateById(xxlJobInfo) ? 1 : 0;
}
@Override
public int delete(String id) {
return this.removeById(id) ? 1 : 0;
}
@Override
public List<XxlJobInfo> getJobsByGroup(String jobGroup) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobInfo::getJobGroup, jobGroup);
return this.list(queryWrapper);
}
@Override
public int findAllCount() {
return this.list().size();
}
@Override
public List<XxlJobInfo> scheduleJobQuery(long maxNextTime, int pagesize) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobInfo::getTriggerStatus, 1);
queryWrapper.lambda().le(XxlJobInfo::getTriggerNextTime, maxNextTime);
queryWrapper.lambda().orderByAsc(XxlJobInfo::getId);
return this.list(queryWrapper);
}
@Override
public int scheduleUpdate(XxlJobInfo xxlJobInfo) {
UpdateWrapper<XxlJobInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobInfo::getId, xxlJobInfo.getId());
updateWrapper.lambda().set(XxlJobInfo::getTriggerLastTime, xxlJobInfo.getTriggerLastTime());
updateWrapper.lambda().set(XxlJobInfo::getTriggerNextTime, xxlJobInfo.getTriggerNextTime());
updateWrapper.lambda().set(XxlJobInfo::getTriggerStatus, xxlJobInfo.getTriggerStatus());
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public XxlJobInfo queryByTaskId(String taskId) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobInfo::getTaskId, taskId);
return this.getOne(queryWrapper);
}
@Override
public boolean deleteByTaskId(String taskId) {
QueryWrapper<XxlJobInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobInfo::getTaskId, taskId);
return this.remove(queryWrapper);
}
}

View File

@@ -0,0 +1,53 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
import com.xxl.job.admin.dao.XxlJobLogGlueDao;
import com.xxl.job.admin.service.XxlJobLogGlueService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class XxlJobLogGlueServiceImpl extends ServiceImpl<XxlJobLogGlueDao, XxlJobLogGlue> implements XxlJobLogGlueService {
@Override
public int create(XxlJobLogGlue xxlJobLogGlue) {
return this.save(xxlJobLogGlue) ? 1 : 0;
}
@Override
public List<XxlJobLogGlue> findByJobId(String jobId) {
QueryWrapper<XxlJobLogGlue> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLogGlue::getJobId, jobId);
queryWrapper.lambda().orderByDesc(XxlJobLogGlue::getId);
return this.list(queryWrapper);
}
@Override
public int removeOld(String jobId, int limit) {
QueryWrapper<XxlJobLogGlue> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.lambda().eq(XxlJobLogGlue::getJobId, jobId);
queryWrapper1.lambda().orderByDesc(XxlJobLogGlue::getUpdateTime);
Page<XxlJobLogGlue> page = new Page<>(0, limit);
IPage<XxlJobLogGlue> iPage = this.page(page, queryWrapper1);
List<String> ids = iPage.getRecords().stream().map(XxlJobLogGlue::getId).collect(Collectors.toList());
QueryWrapper<XxlJobLogGlue> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().notIn(XxlJobLogGlue::getId, ids);
queryWrapper.lambda().eq(XxlJobLogGlue::getJobId, jobId);
return this.remove(queryWrapper) ? 1 : 0;
}
@Override
public int deleteByJobId(String jobId) {
QueryWrapper<XxlJobLogGlue> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLogGlue::getJobId, jobId);
return this.remove(queryWrapper) ? 1 : 0;
}
}

View File

@@ -0,0 +1,45 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import com.xxl.job.admin.dao.XxlJobLogReportDao;
import com.xxl.job.admin.service.XxlJobLogReportService;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
@Service
public class XxlJobLogReportServiceImpl extends ServiceImpl<XxlJobLogReportDao, XxlJobLogReport> implements XxlJobLogReportService {
@Override
public int create(XxlJobLogReport xxlJobLogReport) {
return this.save(xxlJobLogReport) ? 1 : 0;
}
@Override
public int update(XxlJobLogReport xxlJobLogReport) {
UpdateWrapper<XxlJobLogReport> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobLogReport::getTriggerDay, xxlJobLogReport.getTriggerDay());
updateWrapper.lambda().set(XxlJobLogReport::getRunningCount, xxlJobLogReport.getRunningCount());
updateWrapper.lambda().set(XxlJobLogReport::getSucCount, xxlJobLogReport.getSucCount());
updateWrapper.lambda().set(XxlJobLogReport::getFailCount, xxlJobLogReport.getFailCount());
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public List<XxlJobLogReport> queryLogReport(Date triggerDayFrom, Date triggerDayTo) {
QueryWrapper<XxlJobLogReport> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().between(XxlJobLogReport::getTriggerDay, triggerDayFrom, triggerDayTo);
queryWrapper.lambda().orderByAsc(XxlJobLogReport::getTriggerDay);
return this.list(queryWrapper);
}
@Override
public XxlJobLogReport queryLogReportTotal() {
return null;
}
}

View File

@@ -0,0 +1,287 @@
package com.xxl.job.admin.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaxxer.hikari.HikariDataSource;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.service.XxlJobLogService;
import com.yunzhupaas.scheduletask.entity.XxlJobLog;
import com.yunzhupaas.scheduletask.model.TaskPage;
import com.yunzhupaas.util.DateUtil;
import com.yunzhupaas.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* XxJobLogServiceImpl
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/29 15:06
*/
@Service
public class XxlJobLogServiceImpl extends ServiceImpl<XxlJobLogDao, XxlJobLog> implements XxlJobLogService {
@Autowired
private DataSource dataSource;
@Override
public List<XxlJobLog> getList(String taskId, TaskPage taskPage) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLog::getJobId, taskId);
// 日期范围
if (ObjectUtil.isNotEmpty(taskPage.getStartTime()) && ObjectUtil.isNotEmpty(taskPage.getEndTime())) {
queryWrapper.lambda().between(XxlJobLog::getTriggerTime, new Date(taskPage.getStartTime()),
new Date(taskPage.getEndTime()));
}
if (taskPage.getRunResult() != null) {
if (taskPage.getRunResult() == 1) {
queryWrapper.lambda().ne(XxlJobLog::getHandleCode, 200);
} else {
queryWrapper.lambda().eq(XxlJobLog::getHandleCode, 200);
}
}
queryWrapper.lambda().orderByDesc(XxlJobLog::getTriggerTime);
queryWrapper.select(XxlJobLog.class, t -> !"executor_param".equals(t.getColumn()));
Page<XxlJobLog> page = new Page<>(taskPage.getCurrentPage(), taskPage.getPageSize());
IPage<XxlJobLog> iPage = this.page(page, queryWrapper);
return taskPage.setData(iPage.getRecords(), page.getTotal());
}
@Override
public Long queryCountByJobId(String jobId) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLog::getJobId, jobId);
return this.count(queryWrapper);
}
@Override
public List<XxlJobLog> pageList(int offset, int pagesize, String jobGroup, String jobId, Date triggerTimeStart,
Date triggerTimeEnd, int logStatus) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !jobGroup.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getJobGroup, jobGroup);
}
if (StringUtil.isNotEmpty(jobGroup) && !jobId.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getId, jobId);
}
if (triggerTimeStart != null) {
queryWrapper.lambda().ge(XxlJobLog::getTriggerTime, triggerTimeStart);
}
if (triggerTimeEnd != null) {
queryWrapper.lambda().le(XxlJobLog::getTriggerTime, triggerTimeEnd);
}
if (logStatus == 1) {
queryWrapper.lambda().eq(XxlJobLog::getHandleCode, 200);
} else if (logStatus == 2) {
queryWrapper.lambda()
.and(t -> t.notIn(XxlJobLog::getTriggerCode, 0, 200).or().notIn(XxlJobLog::getHandleCode, 0, 200));
} else if (logStatus == 3) {
queryWrapper.lambda().eq(XxlJobLog::getTriggerCode, 200).eq(XxlJobLog::getHandleCode, 200);
}
queryWrapper.lambda().orderByDesc(XxlJobLog::getTriggerTime);
Page<XxlJobLog> page = new Page<>(offset / pagesize + 1, pagesize);
IPage<XxlJobLog> iPage = this.page(page, queryWrapper);
return iPage.getRecords();
}
@Override
public int pageListCount(int offset, int pagesize, String jobGroup, String jobId, Date triggerTimeStart,
Date triggerTimeEnd, int logStatus) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !jobGroup.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getJobGroup, jobGroup);
}
if (StringUtil.isNotEmpty(jobGroup) && !jobId.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getId, jobId);
}
if (triggerTimeStart != null) {
queryWrapper.lambda().ge(XxlJobLog::getTriggerTime, triggerTimeStart);
}
if (triggerTimeEnd != null) {
queryWrapper.lambda().le(XxlJobLog::getTriggerTime, triggerTimeEnd);
}
if (logStatus == 1) {
queryWrapper.lambda().eq(XxlJobLog::getHandleCode, 200);
} else if (logStatus == 2) {
queryWrapper.lambda()
.and(t -> t.notIn(XxlJobLog::getTriggerCode, 0, 200).or().notIn(XxlJobLog::getHandleCode, 0, 200));
} else if (logStatus == 3) {
queryWrapper.lambda().eq(XxlJobLog::getTriggerCode, 200).eq(XxlJobLog::getHandleCode, 200);
}
Page<XxlJobLog> page = new Page<>(offset / pagesize + 1, pagesize);
IPage<XxlJobLog> iPage = this.page(page, queryWrapper);
return (int) iPage.getTotal();
}
@Override
public XxlJobLog load(String id) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLog::getId, id);
return this.getOne(queryWrapper);
}
@Override
public long create(XxlJobLog xxlJobLog) {
return this.save(xxlJobLog) ? 1 : 0;
}
@Override
public int updateTriggerInfo(XxlJobLog xxlJobLog) {
return this.updateById(xxlJobLog) ? 1 : 0;
}
@Override
public int updateHandleInfo(XxlJobLog xxlJobLog) {
UpdateWrapper<XxlJobLog> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobLog::getId, xxlJobLog.getId());
updateWrapper.lambda().set(XxlJobLog::getHandleTime, xxlJobLog.getHandleTime());
updateWrapper.lambda().set(XxlJobLog::getHandleCode, xxlJobLog.getHandleCode());
updateWrapper.lambda().set(XxlJobLog::getHandleMsg, xxlJobLog.getHandleMsg());
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public int delete(String jobId) {
return this.removeById(jobId) ? 1 : 0;
}
@Override
public Map<String, Object> findLogReport(Date from, Date to) {
String url = null;
try {
url = ((HikariDataSource) dataSource).getJdbcUrl();
} catch (Exception e) {
log.error("获取连接连接失败:" + e.getMessage());
}
String dbType = getDbType(url);
if (dbType.equals("Oracle")) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return this.baseMapper.oracleFindLogReport(fmt.format(from), fmt.format(to), dbType);
}
return this.baseMapper.findLogReport(from, to, dbType);
}
/**
* 得到当前库类型
*
* @param url
* @return
*/
private static String getDbType(String url) {
if (url == null) {
return "";
}
if (url.contains("mysql")) {
return "MySQL";
} else if (url.contains("sqlserver")) {
return "SQLServer";
} else if (url.contains("oracle")) {
return "Oracle";
} else if (url.contains("dm")) {
return "DM8";
} else if (url.contains("kingbase8")) {
return "KingbaseES";
} else if (url.contains("postgresql")) {
return "PostgreSQL";
}
return "";
}
@Override
public List<String> findClearLogIds(String jobGroup, String jobId, Date clearBeforeTime, int clearBeforeNum,
int pagesize) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !jobGroup.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getJobGroup, jobGroup);
}
if (StringUtil.isNotEmpty(jobGroup) && !jobId.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getId, jobId);
}
if (clearBeforeTime != null) {
queryWrapper.lambda().le(XxlJobLog::getTriggerTime, clearBeforeTime);
}
if (clearBeforeNum > 0) {
// 子查询内容转换
QueryWrapper<XxlJobLog> queryWrapper1 = new QueryWrapper<>();
if (StringUtil.isNotEmpty(jobGroup) && !jobGroup.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getJobGroup, jobGroup);
}
if (StringUtil.isNotEmpty(jobGroup) && !jobId.equals("0")) {
queryWrapper.lambda().eq(XxlJobLog::getId, jobId);
}
queryWrapper1.lambda().orderByDesc(XxlJobLog::getTriggerTime);
Page<XxlJobLog> page = new Page<>(0, clearBeforeNum);
IPage<XxlJobLog> iPage = this.page(page, queryWrapper1);
List<String> collect = iPage.getRecords().stream().map(XxlJobLog::getId).collect(Collectors.toList());
queryWrapper.lambda().notIn(XxlJobLog::getJobId, collect);
}
Page<XxlJobLog> page = new Page<>(0, pagesize);
IPage<XxlJobLog> iPage = this.page(page, queryWrapper);
return iPage.getRecords().stream().map(XxlJobLog::getId).collect(Collectors.toList());
}
@Override
public int clearLog(List<String> logIds) {
if (logIds.size() > 0) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().in(XxlJobLog::getId, logIds);
return this.remove(queryWrapper) ? 1 : 0;
}
return 0;
}
@Override
public List<String> findFailJobLogIds(int pagesize) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLog::getAlarmStatus, 0);
queryWrapper.lambda().orderByDesc(XxlJobLog::getJobId);
queryWrapper.lambda()
.and(t -> t.in(XxlJobLog::getTriggerCode, 201, 50000).and(tt -> tt.ne(XxlJobLog::getHandleCode, 0))
.or().ne(XxlJobLog::getHandleCode, 200));
Page<XxlJobLog> page = new Page<>(0, pagesize);
IPage<XxlJobLog> iPage = this.page(page, queryWrapper);
return iPage.getRecords().stream().map(XxlJobLog::getId).collect(Collectors.toList());
}
@Override
public int updateAlarmStatus(String logId, int oldAlarmStatus, int newAlarmStatus) {
UpdateWrapper<XxlJobLog> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobLog::getId, logId).eq(XxlJobLog::getAlarmStatus, oldAlarmStatus);
updateWrapper.lambda().set(XxlJobLog::getAlarmStatus, newAlarmStatus);
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public List<String> findLostJobIds(Date losedTime) {
String url = null;
try {
url = ((HikariDataSource) dataSource).getJdbcUrl();
} catch (Exception e) {
log.error("获取连接连接失败:" + e.getMessage());
}
String dbType = getDbType(url);
return this.baseMapper.findLostJobIds(DateUtil.dateFormat(losedTime), dbType);
}
@Override
public boolean deleteByTaskId(String taskId) {
QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobLog::getId, taskId);
return this.remove(queryWrapper);
}
}

View File

@@ -0,0 +1,112 @@
package com.xxl.job.admin.service.impl;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.CookieUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.admin.service.XxlJobUserService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigInteger;
/**
* @author xuxueli 2019-05-04 22:13:264
*/
@Service
public class XxlJobLoginService {
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
@Autowired
private XxlJobUserService xxlJobUserService;
// ---------------------- token tool ----------------------
private String makeToken(XxlJobUser xxlJobUser){
String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
return tokenHex;
}
private XxlJobUser parseToken(String tokenHex){
XxlJobUser xxlJobUser = null;
if (tokenHex != null) {
String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5)
xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class);
}
return xxlJobUser;
}
// ---------------------- login tool, with cookie and db ----------------------
public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){
// param
if (username==null || username.trim().length()==0 || password==null || password.trim().length()==0){
return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
}
// valid passowrd
XxlJobUser xxlJobUser = xxlJobUserService.loadByUserName(username);
if (xxlJobUser == null) {
return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
}
String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
if (!passwordMd5.equals(xxlJobUser.getPassword())) {
return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
}
String loginToken = makeToken(xxlJobUser);
// do login
CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
return ReturnT.SUCCESS;
}
/**
* logout
*
* @param request
* @param response
*/
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
return ReturnT.SUCCESS;
}
/**
* logout
*
* @param request
* @return
*/
public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){
String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
if (cookieToken != null) {
XxlJobUser cookieUser = null;
try {
cookieUser = parseToken(cookieToken);
} catch (Exception e) {
logout(request, response);
}
if (cookieUser != null) {
XxlJobUser dbUser = xxlJobUserService.loadByUserName(cookieUser.getUsername());
if (dbUser != null) {
if (cookieUser.getPassword().equals(dbUser.getPassword())) {
return dbUser;
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,76 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.admin.dao.XxlJobRegistryDao;
import com.xxl.job.admin.service.XxlJobRegistryService;
import com.yunzhupaas.util.DateUtil;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class XxlJobRegistryServiceImpl extends ServiceImpl<XxlJobRegistryDao, XxlJobRegistry> implements XxlJobRegistryService {
@Override
public List<String> findDead(int timeout, Date nowTime) {
QueryWrapper<XxlJobRegistry> queryWrapper = new QueryWrapper<>();
// 计算时间
Date date = DateUtil.dateAddSeconds(nowTime, - timeout);
queryWrapper.lambda().lt(XxlJobRegistry::getUpdateTime, date);
return this.list(queryWrapper).stream().map(XxlJobRegistry::getId).collect(Collectors.toList());
}
@Override
public int removeDead(List<String> ids) {
if (ids.size() > 0) {
QueryWrapper<XxlJobRegistry> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().in(XxlJobRegistry::getId, ids);
return this.remove(queryWrapper) ? 1 : 0;
}
return 0;
}
@Override
public List<XxlJobRegistry> findAll(int timeout, Date nowTime) {
QueryWrapper<XxlJobRegistry> queryWrapper = new QueryWrapper<>();
// 计算时间
Date date = DateUtil.dateAddSeconds(nowTime, -timeout);
queryWrapper.lambda().gt(XxlJobRegistry::getUpdateTime, date);
return this.list(queryWrapper);
}
@Override
public int registryUpdate(String registryGroup, String registryKey, String registryValue, Date updateTime) {
UpdateWrapper<XxlJobRegistry> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobRegistry::getRegistryGroup, registryGroup);
updateWrapper.lambda().eq(XxlJobRegistry::getRegistryKey, registryKey);
updateWrapper.lambda().eq(XxlJobRegistry::getRegistryValue, registryValue);
updateWrapper.lambda().set(XxlJobRegistry::getUpdateTime, updateTime);
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public int registrySave(String registryGroup, String registryKey, String registryValue, Date updateTime) {
XxlJobRegistry xxlJobRegistry = new XxlJobRegistry();
xxlJobRegistry.setRegistryGroup(registryGroup);
xxlJobRegistry.setRegistryKey(registryKey);
xxlJobRegistry.setRegistryValue(registryValue);
xxlJobRegistry.setUpdateTime(updateTime);
return this.save(xxlJobRegistry) ? 1 : 0;
}
@Override
public int registryDelete(String registryGroup, String registryKey, String registryValue) {
QueryWrapper<XxlJobRegistry> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobRegistry::getRegistryGroup, registryGroup);
queryWrapper.lambda().eq(XxlJobRegistry::getRegistryKey, registryKey);
queryWrapper.lambda().eq(XxlJobRegistry::getRegistryValue, registryValue);
return this.remove(queryWrapper) ? 1 : 0;
}
}

View File

@@ -0,0 +1,481 @@
package com.xxl.job.admin.service.impl;
import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.service.*;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.DateUtil;
import com.yunzhupaas.scheduletask.entity.XxlJobGroup;
import com.yunzhupaas.scheduletask.entity.XxlJobInfo;
import com.yunzhupaas.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.MessageFormat;
import java.util.*;
/**
* core job action for xxl-job
* @author xuxueli 2016-5-28 15:30:33
*/
@Service
public class XxlJobServiceImpl implements XxlJobService {
private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
@Autowired
private XxlJobGroupService xxlJobGroupService;
@Autowired
private XxlJobInfoService xxlJobInfoService;
@Autowired
public XxlJobLogService xxlJobLogService;
@Autowired
private XxlJobLogGlueService xxlJobLogGlueService;
@Autowired
private XxlJobLogReportService xxlJobLogReportService;
@Override
public Map<String, Object> pageList(int start, int length, String jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
// page list
List<XxlJobInfo> list = xxlJobInfoService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
long list_count = xxlJobInfoService.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@Override
public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser) {
// valid base
XxlJobGroup group = xxlJobGroupService.load(jobInfo.getJobGroup());
if (group == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
}
if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
}
if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
}
// valid trigger
ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
if (scheduleTypeEnum == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron"+I18nUtil.getString("system_unvalid"));
}
} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
if (jobInfo.getScheduleConf() == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")) );
}
try {
int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
if (fixSecond < 1) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
} catch (Exception e) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
}
// valid job
if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
}
if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
}
// 》fix "\r" in shell
if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
}
// valid advanced
if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
}
if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy")+I18nUtil.getString("system_unvalid")) );
}
if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
}
// 》ChildJobId valid
if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
String[] childJobIds = jobInfo.getChildJobId().split(",");
for (String childJobIdItem: childJobIds) {
if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
XxlJobInfo childJobInfo = xxlJobInfoService.loadById(childJobIdItem);
if (childJobInfo==null) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
}
if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
}
}
// join , avoid "xxx,,"
String temp = "";
for (String item:childJobIds) {
temp += item + ",";
}
temp = temp.substring(0, temp.length()-1);
jobInfo.setChildJobId(temp);
}
// add in db
jobInfo.setAddTime(new Date());
jobInfo.setUpdateTime(new Date());
jobInfo.setGlueUpdatetime(new Date());
xxlJobInfoService.create(jobInfo);
if (StringUtil.isEmpty(jobInfo.getId()) || jobInfo.getId().equals("-1") || jobInfo.getId().equals("0")) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
}
return new ReturnT<String>(String.valueOf(jobInfo.getId()));
}
private boolean isNumeric(String str){
try {
Integer.valueOf(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser) {
// valid base
if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
}
if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
}
// valid trigger
ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
if (scheduleTypeEnum == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron"+I18nUtil.getString("system_unvalid") );
}
} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
if (jobInfo.getScheduleConf() == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
try {
int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
if (fixSecond < 1) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
} catch (Exception e) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
}
// valid advanced
if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
}
if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy")+I18nUtil.getString("system_unvalid")) );
}
if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
}
// 》ChildJobId valid
if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
String[] childJobIds = jobInfo.getChildJobId().split(",");
for (String childJobIdItem: childJobIds) {
if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
XxlJobInfo childJobInfo = xxlJobInfoService.loadById(childJobIdItem);
if (childJobInfo==null) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
}
if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
}
}
// join , avoid "xxx,,"
String temp = "";
for (String item:childJobIds) {
temp += item + ",";
}
temp = temp.substring(0, temp.length()-1);
jobInfo.setChildJobId(temp);
}
// group valid
XxlJobGroup jobGroup = xxlJobGroupService.load(jobInfo.getJobGroup());
if (jobGroup == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup")+I18nUtil.getString("system_unvalid")) );
}
// stage job info
XxlJobInfo exists_jobInfo = xxlJobInfoService.loadById(jobInfo.getId());
if (exists_jobInfo == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
}
// next trigger time (5s后生效避开预读周期)
long nextTriggerTime = exists_jobInfo.getTriggerNextTime();
boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());
if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) {
try {
Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
if (nextValidTime == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
nextTriggerTime = nextValidTime.getTime();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
}
exists_jobInfo.setJobGroup(jobInfo.getJobGroup());
exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
exists_jobInfo.setAuthor(jobInfo.getAuthor());
exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
exists_jobInfo.setScheduleType(jobInfo.getScheduleType());
exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());
exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());
exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
exists_jobInfo.setTriggerNextTime(nextTriggerTime);
exists_jobInfo.setUpdateTime(new Date());
xxlJobInfoService.update(exists_jobInfo);
return ReturnT.SUCCESS;
}
@Override
public ReturnT<String> remove(String id) {
XxlJobInfo xxlJobInfo = xxlJobInfoService.loadById(id);
if (xxlJobInfo == null) {
return ReturnT.SUCCESS;
}
xxlJobInfoService.delete(id);
xxlJobLogService.delete(id);
xxlJobLogGlueService.deleteByJobId(id);
return ReturnT.SUCCESS;
}
@Override
public ReturnT<String> start(String id) {
XxlJobInfo xxlJobInfo = xxlJobInfoService.loadById(id);
// valid
ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);
if (ScheduleTypeEnum.NONE == scheduleTypeEnum) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start")) );
}
// next trigger time (5s后生效避开预读周期)
long nextTriggerTime = 0;
try {
Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
if (nextValidTime == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
nextTriggerTime = nextValidTime.getTime();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
}
xxlJobInfo.setTriggerStatus(1);
xxlJobInfo.setTriggerLastTime(0L);
xxlJobInfo.setTriggerNextTime(nextTriggerTime);
xxlJobInfo.setUpdateTime(new Date());
xxlJobInfoService.update(xxlJobInfo);
return ReturnT.SUCCESS;
}
@Override
public ReturnT<String> stop(String id) {
XxlJobInfo xxlJobInfo = xxlJobInfoService.loadById(id);
xxlJobInfo.setTriggerStatus(0);
xxlJobInfo.setTriggerLastTime(0L);
xxlJobInfo.setTriggerNextTime(0L);
xxlJobInfo.setUpdateTime(new Date());
xxlJobInfoService.update(xxlJobInfo);
return ReturnT.SUCCESS;
}
@Override
public ReturnT<String> trigger(XxlJobUser loginUser, String jobId, String executorParam, String addressList) {
// permission
if (loginUser == null) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit"));
}
XxlJobInfo xxlJobInfo = xxlJobInfoService.loadById(jobId);
if (xxlJobInfo == null) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (!hasPermission(loginUser, xxlJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit"));
}
// force cover job param
if (executorParam == null) {
executorParam = "";
}
JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
return ReturnT.SUCCESS;
}
private boolean hasPermission(XxlJobUser loginUser, String jobGroup){
if (loginUser.getRole() == 1) {
return true;
}
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission()!=null && !loginUser.getPermission().trim().isEmpty()) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
return groupIdStrs.contains(jobGroup);
}
@Override
public Map<String, Object> dashboardInfo() {
int jobInfoCount = xxlJobInfoService.findAllCount();
int jobLogCount = 0;
int jobLogSuccessCount = 0;
XxlJobLogReport xxlJobLogReport = xxlJobLogReportService.queryLogReportTotal();
if (xxlJobLogReport != null) {
jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();
jobLogSuccessCount = xxlJobLogReport.getSucCount();
}
// executor count
Set<String> executorAddressSet = new HashSet<String>();
List<XxlJobGroup> groupList = xxlJobGroupService.findAll();
if (groupList!=null && !groupList.isEmpty()) {
for (XxlJobGroup group: groupList) {
if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
executorAddressSet.addAll(group.getRegistryList());
}
}
}
int executorCount = executorAddressSet.size();
Map<String, Object> dashboardMap = new HashMap<String, Object>();
dashboardMap.put("jobInfoCount", jobInfoCount);
dashboardMap.put("jobLogCount", jobLogCount);
dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
dashboardMap.put("executorCount", executorCount);
return dashboardMap;
}
@Override
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
// process
List<String> triggerDayList = new ArrayList<String>();
List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
int triggerCountRunningTotal = 0;
int triggerCountSucTotal = 0;
int triggerCountFailTotal = 0;
List<XxlJobLogReport> logReportList = xxlJobLogReportService.queryLogReport(startDate, endDate);
if (logReportList!=null && logReportList.size()>0) {
for (XxlJobLogReport item: logReportList) {
String day = DateUtil.formatDate(item.getTriggerDay());
int triggerDayCountRunning = item.getRunningCount();
int triggerDayCountSuc = item.getSucCount();
int triggerDayCountFail = item.getFailCount();
triggerDayList.add(day);
triggerDayCountRunningList.add(triggerDayCountRunning);
triggerDayCountSucList.add(triggerDayCountSuc);
triggerDayCountFailList.add(triggerDayCountFail);
triggerCountRunningTotal += triggerDayCountRunning;
triggerCountSucTotal += triggerDayCountSuc;
triggerCountFailTotal += triggerDayCountFail;
}
} else {
for (int i = -6; i <= 0; i++) {
triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i)));
triggerDayCountRunningList.add(0);
triggerDayCountSucList.add(0);
triggerDayCountFailList.add(0);
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("triggerDayList", triggerDayList);
result.put("triggerDayCountRunningList", triggerDayCountRunningList);
result.put("triggerDayCountSucList", triggerDayCountSucList);
result.put("triggerDayCountFailList", triggerDayCountFailList);
result.put("triggerCountRunningTotal", triggerCountRunningTotal);
result.put("triggerCountSucTotal", triggerCountSucTotal);
result.put("triggerCountFailTotal", triggerCountFailTotal);
return new ReturnT<Map<String, Object>>(result);
}
}

View File

@@ -0,0 +1,76 @@
package com.xxl.job.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.dao.XxlJobUserDao;
import com.xxl.job.admin.service.XxlJobUserService;
import com.yunzhupaas.util.StringUtil;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class XxlJobUserServiceImpl extends ServiceImpl<XxlJobUserDao, XxlJobUser> implements XxlJobUserService {
@Override
public List<XxlJobUser> pageList(int offset, int pagesize, String username, int role) {
QueryWrapper<XxlJobUser> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(username)) {
queryWrapper.lambda().like(XxlJobUser::getUsername, username);
}
if (role > -1) {
queryWrapper.lambda().eq(XxlJobUser::getRole, role);
}
queryWrapper.lambda().orderByAsc(XxlJobUser::getUsername);
Page<XxlJobUser> page = new Page<>(offset/pagesize + 1, pagesize);
IPage<XxlJobUser> iPage = this.page(page, queryWrapper);
return iPage.getRecords();
}
@Override
public int pageListCount(int offset, int pagesize, String username, int role) {
QueryWrapper<XxlJobUser> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNotEmpty(username)) {
queryWrapper.lambda().like(XxlJobUser::getUsername, username);
}
if (role > -1) {
queryWrapper.lambda().eq(XxlJobUser::getRole, role);
}
queryWrapper.lambda().orderByAsc(XxlJobUser::getUsername);
return this.list(queryWrapper).size();
}
@Override
public XxlJobUser loadByUserName(String username) {
QueryWrapper<XxlJobUser> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(XxlJobUser::getUsername, username);
return this.getOne(queryWrapper);
}
@Override
public int create(XxlJobUser xxlJobUser) {
return this.save(xxlJobUser) ? 1 : 0;
}
@Override
public int update(XxlJobUser xxlJobUser) {
UpdateWrapper<XxlJobUser> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(XxlJobUser::getId, xxlJobUser.getId());
if (StringUtil.isNotEmpty(xxlJobUser.getPassword())) {
updateWrapper.lambda().set(XxlJobUser::getPassword, xxlJobUser.getPassword());
}
updateWrapper.lambda().set(XxlJobUser::getRole, xxlJobUser.getRole());
updateWrapper.lambda().set(XxlJobUser::getPermission, xxlJobUser.getPermission());
return this.update(updateWrapper) ? 1 : 0;
}
@Override
public int delete(String id) {
return this.removeById(id) ? 1 : 0;
}
}

View File

@@ -0,0 +1,48 @@
spring:
# 数据源配置
# ===================== MySQL数据库-Start =====================
datasource:
url: jdbc:mysql://mysql.szlecheng.cn:13306/jnpfsoft_xxjob?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true
username: jnpfsoft_xxjob
password: FK3NyRAsQNEfHtQx
driver-class-name: com.mysql.cj.jdbc.Driver
# ===================== MySQL数据库-Start =====================
# ===================== SQLServer数据库-Start =====================
# datasource:
# url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;Databasename=yunzhupaas_xxljob
# username: sa
# password: 123456
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# ===================== SQLServer数据库-End =====================
# ===================== Oracle数据库-Start =====================
# datasource:
# url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
# username: YUNZHUPAAS_XXLJOB
# password: dbpasswd
# driver-class-name: oracle.jdbc.OracleDriver
# ===================== Oracle数据库-End =====================
# ===================== PostgreSQL数据库-Start =====================
# datasource:
# url: jdbc:postgresql://127.0.0.1:5432/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: org.postgresql.Driver
# ===================== PostgreSQL数据库-End =====================
# ===================== 达梦dm8数据库-Start =====================
# datasource:
# url: jdbc:dm://127.0.0.1:5236/YUNZHUPAAS_XXLJOB?yunzhupaasDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
# username: dbuser
# password: dbpasswd
# driver-class-name: dm.jdbc.driver.DmDriver
# ===================== 达梦dm8数据库-End =====================
# ===================== 人大金仓KingbaseES数据库-Start =====================
# datasource:
# url: jdbc:kingbase8://127.0.0.1:54321/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: com.kingbase8.Driver
# ===================== 人大金仓KingbaseES数据库-End =====================
mybatis-plus:
type-aliases-package: com.yunzhupaas.*.entity;com.xxl.job.admin.core.model
mapper-locations: classpath*:/mybatis-mapper/*Mapper.xml

View File

@@ -0,0 +1,48 @@
spring:
# 数据源配置
# ===================== MySQL数据库-Start =====================
datasource:
url: jdbc:mysql://127.0.0.1:3306/yunzhupaas_xxljob?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# ===================== MySQL数据库-Start =====================
# ===================== SQLServer数据库-Start =====================
# datasource:
# url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;Databasename=yunzhupaas_xxljob
# username: sa
# password: 123456
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# ===================== SQLServer数据库-End =====================
# ===================== Oracle数据库-Start =====================
# datasource:
# url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
# username: YUNZHUPAAS_XXLJOB
# password: dbpasswd
# driver-class-name: oracle.jdbc.OracleDriver
# ===================== Oracle数据库-End =====================
# ===================== PostgreSQL数据库-Start =====================
# datasource:
# url: jdbc:postgresql://127.0.0.1:5432/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: org.postgresql.Driver
# ===================== PostgreSQL数据库-End =====================
# ===================== 达梦dm8数据库-Start =====================
# datasource:
# url: jdbc:dm://127.0.0.1:5236/YUNZHUPAAS_XXLJOB?yunzhupaasDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
# username: dbuser
# password: dbpasswd
# driver-class-name: dm.jdbc.driver.DmDriver
# ===================== 达梦dm8数据库-End =====================
# ===================== 人大金仓KingbaseES数据库-Start =====================
# datasource:
# url: jdbc:kingbase8://127.0.0.1:54321/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: com.kingbase8.Driver
# ===================== 人大金仓KingbaseES数据库-End =====================
mybatis-plus:
type-aliases-package: com.yunzhupaas.*.entity;com.xxl.job.admin.core.model
mapper-locations: classpath*:/mybatis-mapper/*Mapper.xml

View File

@@ -0,0 +1,48 @@
spring:
# 数据源配置
# ===================== MySQL数据库-Start =====================
datasource:
url: jdbc:mysql://127.0.0.1:3306/yunzhupaas_xxljob?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# ===================== MySQL数据库-Start =====================
# ===================== SQLServer数据库-Start =====================
# datasource:
# url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;Databasename=yunzhupaas_xxljob
# username: sa
# password: 123456
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# ===================== SQLServer数据库-End =====================
# ===================== Oracle数据库-Start =====================
# datasource:
# url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
# username: YUNZHUPAAS_XXLJOB
# password: dbpasswd
# driver-class-name: oracle.jdbc.OracleDriver
# ===================== Oracle数据库-End =====================
# ===================== PostgreSQL数据库-Start =====================
# datasource:
# url: jdbc:postgresql://127.0.0.1:5432/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: org.postgresql.Driver
# ===================== PostgreSQL数据库-End =====================
# ===================== 达梦dm8数据库-Start =====================
# datasource:
# url: jdbc:dm://127.0.0.1:5236/YUNZHUPAAS_XXLJOB?yunzhupaasDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
# username: dbuser
# password: dbpasswd
# driver-class-name: dm.jdbc.driver.DmDriver
# ===================== 达梦dm8数据库-End =====================
# ===================== 人大金仓KingbaseES数据库-Start =====================
# datasource:
# url: jdbc:kingbase8://127.0.0.1:54321/yunzhupaas_xxljob
# username: dbuser
# password: dbpasswd
# driver-class-name: com.kingbase8.Driver
# ===================== 人大金仓KingbaseES数据库-End =====================
mybatis-plus:
type-aliases-package: com.yunzhupaas.*.entity;com.xxl.job.admin.core.model
mapper-locations: classpath*:/mybatis-mapper/*Mapper.xml

View File

@@ -0,0 +1,70 @@
management:
health:
mail:
enabled: false
server:
# servlet:
# context-path: /actuator
base-path: /actuator
# endpoints:
# web:
# exposure:
# include: '*'
# endpoint:
# health:
# show-details: always
# # 开启在线日志查看功能
# logfile:
# enabled: true
server:
port: 30020
servlet:
context-path: /xxl-job-admin
spring:
profiles:
# 指定环境配置 dev(开发环境-默认)、test(测试环境)、preview(预生产环境)、prod(生产环境)
active: dev
main:
allow-bean-definition-overriding: true
application:
name: xxl-job-register
freemarker:
charset: UTF-8
request-context-attribute: request
settings:
number_format: 0.##########
new_builtin_class_resolver: safer
suffix: .ftl
templateLoaderPath: classpath:/templates/
mail:
from: xxx@qq.com
host: smtp.qq.com
password: xxx
port: 25
properties:
mail:
smtp:
auth: true
socketFactory:
class: javax.net.ssl.SSLSocketFactory
starttls:
enable: true
required: true
username: xxx@qq.com
mvc:
servlet:
load-on-startup: 0
static-path-pattern: /static/**
web:
resources:
static-locations: classpath:/static/
xxl:
job:
accessToken: '432e62f3b488bc861d91b0e274e850cc'
i18n: zh_CN
logretentiondays: 30
triggerpool:
fast:
max: 200
slow:
max: 100

View File

@@ -0,0 +1,44 @@
## 微服务版本可选application-dev或bootstrap.yml
## 若使用本配置文件需注释application-dev.yml
#spring:
# application:
# name: yunzhupaas-scheduletask-register
# mvc:
# servlet:
# # 启动之后立即加载servlet
# load-on-startup: 0
# main:
# #解决bean重复定义的。设置为true时后定义的bean会覆盖之前定义的相同名称的bean
# allow-bean-definition-overriding: true
# allow-circular-references: true
# cloud:
# nacos:
# username: nacos
# password: nacos
## discovery:
## # 服务注册地址
## server-addr: 127.0.0.1:30099
## namespace: 69c4eecb-05bd-4041-81fe-1473f95f578c
# config:
# server-addr: ${spring.cloud.nacos.discovery.server-addr}
# file-extension: yaml
# group: DEFAULT_GROUP
# namespace: 69c4eecb-05bd-4041-81fe-1473f95f578c
# extension-configs:
# - # 系统配置
# data-id: system-config.yaml
# group: DEFAULT_GROUP
# refresh: true
# - # 数据源及Redis配置 配置中添加了关闭多租户 加载顺序往后放
# data-id: datasource-scheduletask.yaml
# group: DEFAULT_GROUP
# refresh: true
# - # 框架中间件配置
# data-id: frame-config.yaml
# group: DEFAULT_GROUP
# refresh: true
# - # 日志配置
# data-id: logger.yaml
# group: DEFAULT_GROUP
# refresh: true
#

View File

@@ -0,0 +1,277 @@
admin_name=Scheduling Center
admin_name_full=Distributed Task Scheduling Platform XXL-JOB
admin_version=2.4.2
admin_i18n=en
## system
system_tips=System message
system_ok=Confirm
system_close=Close
system_save=Save
system_cancel=Cancel
system_search=Search
system_status=Status
system_opt=Operate
system_please_input=please input
system_please_choose=please choose
system_success=success
system_fail=fail
system_add_suc=add success
system_add_fail=add fail
system_update_suc=update success
system_update_fail=update fail
system_all=All
system_api_error=net error
system_show=Show
system_empty=Empty
system_opt_suc=operate success
system_opt_fail=operate fail
system_opt_edit=Edit
system_opt_del=Delete
system_opt_copy=Copy
system_unvalid=illegal
system_not_found=not exist
system_nav=Navigation
system_digits=digits
system_lengh_limit=Length limit
system_permission_limit=Permission limit
system_welcome=Welcome
## daterangepicker
daterangepicker_ranges_recent_hour=recent one hour
daterangepicker_ranges_today=today
daterangepicker_ranges_yesterday=yesterday
daterangepicker_ranges_this_month=this month
daterangepicker_ranges_last_month=last month
daterangepicker_ranges_recent_week=recent one week
daterangepicker_ranges_recent_month=recent one month
daterangepicker_custom_name=custom
daterangepicker_custom_starttime=start time
daterangepicker_custom_endtime=end time
daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat
daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
## dataTable
dataTable_sProcessing=processing...
dataTable_sLengthMenu= _MENU_ records per page
dataTable_syunzhupaasRecords=No matching results
dataTable_sInfo=page _PAGE_ ( Total _PAGES_ pages_TOTAL_ records )
dataTable_sInfoEmpty=No Record
dataTable_sInfoFiltered=(Filtered by _MAX_ results)
dataTable_sSearch=Search
dataTable_sEmptyTable=Table data is empty
dataTable_sLoadingRecords=Loading...
dataTable_sFirst=FIRST PAGE
dataTable_sPrevious=Previous Page
dataTable_sNext=Next Page
dataTable_sLast=LAST PAGE
dataTable_sSortAscending=: Rank this column in ascending order
dataTable_sSortDescending=: Rank this column in descending order
## login
login_btn=Login
login_remember_me=Remember Me
login_username_placeholder=Please enter username
login_password_placeholder=Please enter password
login_username_empty=Please enter username
login_username_lt_4=Username length should not be less than 4
login_password_empty=Please enter password
login_password_lt_4=Password length should not be less than 4
login_success=Login success
login_fail=Login fail
login_param_empty=Username or password is empty
login_param_unvalid=Username or password error
## logout
logout_btn=Logout
logout_confirm=Confirm logout?
logout_success=Logout success
logout_fail=Logout fail
## change pwd
change_pwd=Change password
change_pwd_suc_to_logout=Change password successful, about to log out login
change_pwd_field_oldpwd=old password
change_pwd_field_newpwd=new password
## dashboard
job_dashboard_name=Run report
job_dashboard_job_num=Job number
job_dashboard_job_num_tip=The number of tasks running in the scheduling center
job_dashboard_trigger_num=trigger number
job_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center
job_dashboard_jobgroup_num=Executor number
job_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center
job_dashboard_report=Scheduling report
job_dashboard_report_loaddata_fail=Scheduling report load data error
job_dashboard_date_report=Date distribution
job_dashboard_rate_report=Percentage distribution
## job info
jobinfo_name=Job Manage
jobinfo_job=Job
jobinfo_field_add=Add Job
jobinfo_field_update=Edit Job
jobinfo_field_id=Job ID
jobinfo_field_jobgroup=Executor
jobinfo_field_jobdesc=Job description
jobinfo_field_timeout=Job timeout period
jobinfo_field_gluetype=GLUE Type
jobinfo_field_executorparam=Param
jobinfo_field_author=Author
jobinfo_field_alarmemail=Alarm email
jobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated
jobinfo_field_executorRouteStrategy=Route Strategy
jobinfo_field_childJobId=Child Job ID
jobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated
jobinfo_field_executorBlockStrategy=Block Strategy
jobinfo_field_executorFailRetryCount=Fail Retry Count
jobinfo_field_executorFailRetryCount_placeholder=Fail Retry Count. effect if greater than yunzhupaas
jobinfo_script_location=Script location
jobinfo_shard_index=Shard index
jobinfo_shard_total=Shard total
jobinfo_opt_stop=Stop
jobinfo_opt_start=Start
jobinfo_opt_log=Query Log
jobinfo_opt_run=Run Once
jobinfo_opt_run_tips=Please input the address for this trigger. Null will be obtained from the executor
jobinfo_opt_registryinfo=Registry Info
jobinfo_opt_next_time=Next trigger time
jobinfo_glue_remark=Resource Remark
jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100
jobinfo_glue_rollback=Version Backtrack
jobinfo_glue_jobid_unvalid=Job ID is illegal
jobinfo_glue_gluetype_unvalid=The job is not GLUE Type
jobinfo_field_executorTimeout_placeholder=Job Timeout periodin seconds. effect if greater than yunzhupaas
schedule_type=Schedule Type
schedule_type_none=None
schedule_type_cron=Cron
schedule_type_fix_rate=Fix rate
schedule_type_fix_delay=Fix delay
schedule_type_none_limit_start=The current schedule type disables startup
misfire_strategy=Misfire strategy
misfire_strategy_do_nothing=Do nothing
misfire_strategy_fire_once_now=Fire once now
jobinfo_conf_base=Base configuration
jobinfo_conf_schedule=Schedule configuration
jobinfo_conf_job=Job configuration
jobinfo_conf_advanced=Advanced configuration
## job log
joblog_name=Trigger Log
joblog_status=Status
joblog_status_all=All
joblog_status_suc=Success
joblog_status_fail=Fail
joblog_status_running=Running
joblog_field_triggerTime=Trigger Time
joblog_field_triggerCode=Trigger Result
joblog_field_triggerMsg=Trigger Msg
joblog_field_handleTime=Handle Time
joblog_field_handleCode=Handle Result
joblog_field_handleMsg=Trigger Msg
joblog_field_executorAddress=Executor Address
joblog_clean=Clean
joblog_clean_log=Clean Log
joblog_clean_type=Clean Type
joblog_clean_type_1=Clean up log data a month ago
joblog_clean_type_2=Clean up log data three month ago
joblog_clean_type_3=Clean up log data six month ago
joblog_clean_type_4=Clean up log data a year ago
joblog_clean_type_5=Clean up log data a thousand record ago
joblog_clean_type_6=Clean up log data ten thousand record ago
joblog_clean_type_7=Clean up log data thirty thousand record ago
joblog_clean_type_8=Clean up log data hundred thousand record ago
joblog_clean_type_9=Clean up all log data
joblog_clean_type_unvalid=Clean type is illegal
joblog_handleCode_200=Success
joblog_handleCode_500=Fail
joblog_handleCode_502=Timeout
joblog_kill_log=Kill Job
joblog_kill_log_limit=Trigger Fail, can not kill job
joblog_kill_log_byman=Manual operation, kill job
joblog_lost_fail=Job result lost, marked as failure
joblog_rolling_log=Rolling log
joblog_rolling_log_refresh=Refresh
joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log
joblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page
joblog_logid_unvalid=Log ID is illegal
## job group
jobgroup_name=Executor Manage
jobgroup_list=Executor List
jobgroup_add=Add Executor
jobgroup_edit=Edit Executor
jobgroup_del=Delete Executor
jobgroup_field_title=Title
jobgroup_field_addressType=Registry Type
jobgroup_field_addressType_0=Automatic registration
jobgroup_field_addressType_1=Manual registration
jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty
jobgroup_field_registryList=machine address
jobgroup_field_registryList_unvalid=registry machine address is illegal
jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated
jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen.
jobgroup_field_appname_length=AppName length is limited to 4~64
jobgroup_field_title_length=Title length is limited to 4~12
jobgroup_field_order_digits=Please enter a positive integer
jobgroup_field_orderrange=Order is limited to 1~1000
jobgroup_del_limit_0=Refuse to delete, the executor is being used
jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor
jobgroup_empty=There is no valid executor. Please contact the administrator
## job conf
jobconf_block_SERIAL_EXECUTION=Serial execution
jobconf_block_DISCARD_LATER=Discard Later
jobconf_block_COVER_EARLY=Cover Early
jobconf_route_first=First
jobconf_route_last=Last
jobconf_route_round=Round
jobconf_route_random=Random
jobconf_route_consistenthash=Consistent Hash
jobconf_route_lfu=Least Frequently Used
jobconf_route_lru=Least Recently Used
jobconf_route_failover=Failover
jobconf_route_busyover=Busyover
jobconf_route_shard=Sharding Broadcast
jobconf_idleBeat=Idle check
jobconf_beat=Heartbeats
jobconf_monitor=Task Scheduling Center monitor alarm
jobconf_monitor_detail=monitor alarm details
jobconf_monitor_alarm_title=Alarm Type
jobconf_monitor_alarm_type=Trigger Fail
jobconf_monitor_alarm_content=Alarm Content
jobconf_trigger_admin_adress=Trigger machine address
jobconf_trigger_exe_regtype=Execotor-Registry Type
jobconf_trigger_exe_regaddress=Execotor-Registry Address
jobconf_trigger_address_empty=Trigger Failregistry address is empty
jobconf_trigger_run=Trigger Job
jobconf_trigger_child_run=Trigger child job
jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4} <br>
jobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal <br>
jobconf_trigger_type=Job trigger type
jobconf_trigger_type_cron=Cron trigger
jobconf_trigger_type_manual=Manual trigger
jobconf_trigger_type_parent=Parent job trigger
jobconf_trigger_type_api=Api trigger
jobconf_trigger_type_retry=Fail retry trigger
jobconf_trigger_type_misfire=Misfire compensation trigger
## user
user_manage=User Manage
user_username=Username
user_password=Password
user_role=Role
user_role_admin=Admin User
user_role_normal=Normal User
user_permission=Permission
user_add=Add User
user_update=Edit User
user_username_repeat=Username Repeat
user_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers
user_password_update_placeholder=Please input password, empty means not update
user_update_loginuser_limit=Operation of current login account is not allowed
## help
job_help=Tutorial
job_help_document=Official Document

View File

@@ -0,0 +1,277 @@
admin_name=任务调度中心
admin_name_full=分布式任务调度平台XXL-JOB
admin_version=2.4.2
admin_i18n=
## system
system_tips=系统提示
system_ok=确定
system_close=关闭
system_save=保存
system_cancel=取消
system_search=搜索
system_status=状态
system_opt=操作
system_please_input=请输入
system_please_choose=请选择
system_success=成功
system_fail=失败
system_add_suc=新增成功
system_add_fail=新增失败
system_update_suc=更新成功
system_update_fail=更新失败
system_all=全部
system_api_error=接口异常
system_show=查看
system_empty=
system_opt_suc=操作成功
system_opt_fail=操作失败
system_opt_edit=编辑
system_opt_del=删除
system_opt_copy=复制
system_unvalid=非法
system_not_found=不存在
system_nav=导航
system_digits=整数
system_lengh_limit=长度限制
system_permission_limit=权限拦截
system_welcome=欢迎
## daterangepicker
daterangepicker_ranges_recent_hour=最近一小时
daterangepicker_ranges_today=今日
daterangepicker_ranges_yesterday=昨日
daterangepicker_ranges_this_month=本月
daterangepicker_ranges_last_month=上个月
daterangepicker_ranges_recent_week=最近一周
daterangepicker_ranges_recent_month=最近一月
daterangepicker_custom_name=自定义
daterangepicker_custom_starttime=起始时间
daterangepicker_custom_endtime=结束时间
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
## dataTable
dataTable_sProcessing=处理中...
dataTable_sLengthMenu=每页 _MENU_ 条记录
dataTable_syunzhupaasRecords=没有匹配结果
dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页_TOTAL_ 条记录 )
dataTable_sInfoEmpty=无记录
dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤)
dataTable_sSearch=搜索
dataTable_sEmptyTable=表中数据为空
dataTable_sLoadingRecords=载入中...
dataTable_sFirst=首页
dataTable_sPrevious=上页
dataTable_sNext=下页
dataTable_sLast=末页
dataTable_sSortAscending=: 以升序排列此列
dataTable_sSortDescending=: 以降序排列此列
## login
login_btn=登录
login_remember_me=记住密码
login_username_placeholder=请输入登录账号
login_password_placeholder=请输入登录密码
login_username_empty=请输入登录账号
login_username_lt_4=登录账号不应低于4位
login_password_empty=请输入登录密码
login_password_lt_4=登录密码不应低于4位
login_success=登录成功
login_fail=登录失败
login_param_empty=账号或密码为空
login_param_unvalid=账号或密码错误
## logout
logout_btn=注销
logout_confirm=确认注销登录?
logout_success=注销成功
logout_fail=注销失败
## change pwd
change_pwd=修改密码
change_pwd_suc_to_logout=修改密码成功,即将注销登陆
change_pwd_field_oldpwd=旧密码
change_pwd_field_newpwd=新密码
## dashboard
job_dashboard_name=运行报表
job_dashboard_job_num=任务数量
job_dashboard_job_num_tip=调度中心运行的任务数量
job_dashboard_trigger_num=调度次数
job_dashboard_trigger_num_tip=调度中心触发的调度次数
job_dashboard_jobgroup_num=执行器数量
job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量
job_dashboard_report=调度报表
job_dashboard_report_loaddata_fail=调度报表数据加载异常
job_dashboard_date_report=日期分布图
job_dashboard_rate_report=成功比例图
## job info
jobinfo_name=任务管理
jobinfo_job=任务
jobinfo_field_add=新增
jobinfo_field_update=更新任务
jobinfo_field_id=任务ID
jobinfo_field_jobgroup=执行器
jobinfo_field_jobdesc=任务描述
jobinfo_field_gluetype=运行模式
jobinfo_field_executorparam=任务参数
jobinfo_field_author=负责人
jobinfo_field_timeout=任务超时时间
jobinfo_field_alarmemail=报警邮件
jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔
jobinfo_field_executorRouteStrategy=路由策略
jobinfo_field_childJobId=子任务ID
jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔
jobinfo_field_executorBlockStrategy=阻塞处理策略
jobinfo_field_executorFailRetryCount=失败重试次数
jobinfo_field_executorFailRetryCount_placeholder=失败重试次数,大于零时生效
jobinfo_script_location=脚本位置
jobinfo_shard_index=分片序号
jobinfo_shard_total=分片总数
jobinfo_opt_stop=停止
jobinfo_opt_start=启动
jobinfo_opt_log=查询日志
jobinfo_opt_run=执行一次
jobinfo_opt_run_tips=请输入本次执行的机器地址,为空则从执行器获取
jobinfo_opt_registryinfo=注册节点
jobinfo_opt_next_time=下次执行时间
jobinfo_glue_remark=源码备注
jobinfo_glue_remark_limit=源码备注长度限制为4~100
jobinfo_glue_rollback=版本回溯
jobinfo_glue_jobid_unvalid=任务ID非法
jobinfo_glue_gluetype_unvalid=该任务非GLUE模式
jobinfo_field_executorTimeout_placeholder=任务超时时间,单位秒,大于零时生效
schedule_type=调度类型
schedule_type_none=
schedule_type_cron=CRON
schedule_type_fix_rate=固定速度
schedule_type_fix_delay=固定延迟
schedule_type_none_limit_start=当前调度类型禁止启动
misfire_strategy=调度过期策略
misfire_strategy_do_nothing=忽略
misfire_strategy_fire_once_now=立即执行一次
jobinfo_conf_base=基础配置
jobinfo_conf_schedule=调度配置
jobinfo_conf_job=任务配置
jobinfo_conf_advanced=高级配置
## job log
joblog_name=调度日志
joblog_status=状态
joblog_status_all=全部
joblog_status_suc=成功
joblog_status_fail=失败
joblog_status_running=进行中
joblog_field_triggerTime=调度时间
joblog_field_triggerCode=调度结果
joblog_field_triggerMsg=调度备注
joblog_field_handleTime=执行时间
joblog_field_handleCode=执行结果
joblog_field_handleMsg=执行备注
joblog_field_executorAddress=执行器地址
joblog_clean=清理
joblog_clean_log=日志清理
joblog_clean_type=清理方式
joblog_clean_type_1=清理一个月之前日志数据
joblog_clean_type_2=清理三个月之前日志数据
joblog_clean_type_3=清理六个月之前日志数据
joblog_clean_type_4=清理一年之前日志数据
joblog_clean_type_5=清理一千条以前日志数据
joblog_clean_type_6=清理一万条以前日志数据
joblog_clean_type_7=清理三万条以前日志数据
joblog_clean_type_8=清理十万条以前日志数据
joblog_clean_type_9=清理所有日志数据
joblog_clean_type_unvalid=清理类型参数异常
joblog_handleCode_200=成功
joblog_handleCode_500=失败
joblog_handleCode_502=失败(超时)
joblog_kill_log=终止任务
joblog_kill_log_limit=调度失败,无法终止日志
joblog_kill_log_byman=人为操作,主动终止
joblog_lost_fail=任务结果丢失,标记失败
joblog_rolling_log=执行日志
joblog_rolling_log_refresh=刷新
joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志
joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志
joblog_logid_unvalid=日志ID非法
## job group
jobgroup_name=执行器管理
jobgroup_list=执行器列表
jobgroup_add=新增执行器
jobgroup_edit=编辑执行器
jobgroup_del=删除执行器
jobgroup_field_title=名称
jobgroup_field_addressType=注册方式
jobgroup_field_addressType_0=自动注册
jobgroup_field_addressType_1=手动录入
jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空
jobgroup_field_registryList=机器地址
jobgroup_field_registryList_unvalid=机器地址格式非法
jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔
jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成
jobgroup_field_appname_length=AppName长度限制为4~64
jobgroup_field_title_length=名称长度限制为4~12
jobgroup_field_order_digits=请输入整数
jobgroup_field_orderrange=取值范围为1~1000
jobgroup_del_limit_0=拒绝删除,该执行器使用中
jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器
jobgroup_empty=不存在有效执行器,请联系管理员
## job conf
jobconf_block_SERIAL_EXECUTION=单机串行
jobconf_block_DISCARD_LATER=丢弃后续调度
jobconf_block_COVER_EARLY=覆盖之前调度
jobconf_route_first=第一个
jobconf_route_last=最后一个
jobconf_route_round=轮询
jobconf_route_random=随机
jobconf_route_consistenthash=一致性HASH
jobconf_route_lfu=最不经常使用
jobconf_route_lru=最近最久未使用
jobconf_route_failover=故障转移
jobconf_route_busyover=忙碌转移
jobconf_route_shard=分片广播
jobconf_idleBeat=空闲检测
jobconf_beat=心跳检测
jobconf_monitor=任务调度中心监控报警
jobconf_monitor_detail=监控告警明细
jobconf_monitor_alarm_title=告警类型
jobconf_monitor_alarm_type=调度失败
jobconf_monitor_alarm_content=告警内容
jobconf_trigger_admin_adress=调度机器
jobconf_trigger_exe_regtype=执行器-注册方式
jobconf_trigger_exe_regaddress=执行器-地址列表
jobconf_trigger_address_empty=调度失败:执行器地址为空
jobconf_trigger_run=触发调度
jobconf_trigger_child_run=触发子任务
jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>
jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>
jobconf_trigger_type=任务触发类型
jobconf_trigger_type_cron=Cron触发
jobconf_trigger_type_manual=手动触发
jobconf_trigger_type_parent=父任务触发
jobconf_trigger_type_api=API触发
jobconf_trigger_type_retry=失败重试触发
jobconf_trigger_type_misfire=调度过期补偿
## user
user_manage=用户管理
user_username=账号
user_password=密码
user_role=角色
user_role_admin=管理员
user_role_normal=普通用户
user_permission=权限
user_add=新增用户
user_update=更新用户
user_username_repeat=账号重复
user_username_valid=限制以小写字母开头,由小写字母、数字组成
user_password_update_placeholder=请输入新密码,为空则不更新密码
user_update_loginuser_limit=禁止操作当前登录账号
## help
job_help=使用教程
job_help_document=官方文档

View File

@@ -0,0 +1,277 @@
admin_name=任務調度中心
admin_name_full=分布式任務調度平臺XXL-JOB
admin_version=2.4.2
admin_i18n=
## system
system_tips=系統提示
system_ok=確定
system_close=關閉
system_save=儲存
system_cancel=取消
system_search=搜尋
system_status=狀態
system_opt=操作
system_please_input=請輸入
system_please_choose=请選擇
system_success=成功
system_fail=失敗
system_add_suc=新增成功
system_add_fail=新增失敗
system_update_suc=更新成功
system_update_fail=更新失敗
system_all=全部
system_api_error=API錯誤
system_show=查看
system_empty=
system_opt_suc=操作成功
system_opt_fail=操作失敗
system_opt_edit=編輯
system_opt_del=刪除
system_opt_copy=復制
system_unvalid=非法
system_not_found=不存在
system_nav=導航
system_digits=整數
system_lengh_limit=長度限制
system_permission_limit=權限控管
system_welcome=歡迎
## daterangepicker
daterangepicker_ranges_recent_hour=最近一小時
daterangepicker_ranges_today=今日
daterangepicker_ranges_yesterday=昨日
daterangepicker_ranges_this_month=本月
daterangepicker_ranges_last_month=上個月
daterangepicker_ranges_recent_week=最近一周
daterangepicker_ranges_recent_month=最近一月
daterangepicker_custom_name=自定義
daterangepicker_custom_starttime=起始時間
daterangepicker_custom_endtime=結束時間
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
## dataTable
dataTable_sProcessing=處理中...
dataTable_sLengthMenu=每頁 _MENU_ 條記錄
dataTable_syunzhupaasRecords=沒有相符合記錄
dataTable_sInfo=第 _PAGE_ 頁 ( 總共 _PAGES_ 頁_TOTAL_ 條記錄 )
dataTable_sInfoEmpty=無記錄
dataTable_sInfoFiltered=(由 _MAX_ 項結果過濾)
dataTable_sSearch=搜尋
dataTable_sEmptyTable=表中資料為空
dataTable_sLoadingRecords=載入中...
dataTable_sFirst=首頁
dataTable_sPrevious=上頁
dataTable_sNext=下頁
dataTable_sLast=末頁
dataTable_sSortAscending=: 以升幂排序此列
dataTable_sSortDescending=: 以降幂排序此列
## login
login_btn=登入
login_remember_me=記住密碼
login_username_placeholder=請輸入登入帳號
login_password_placeholder=請輸入登入密碼
login_username_empty=請輸入登入帳號
login_username_lt_4=登入帳號不應低於4位數
login_password_empty=請輸入登入密碼
login_password_lt_4=登入密碼不應低於4位數
login_success=登入成功
login_fail=登入失敗
login_param_empty=帳號或密碼為空值
login_param_unvalid=帳號或密碼錯誤
## logout
logout_btn=登出
logout_confirm=確認登出?
logout_success=登出成功
logout_fail=登出失敗
## change pwd
change_pwd=修改密碼
change_pwd_suc_to_logout=修改密碼成功,即將登出
change_pwd_field_oldpwd=舊密碼
change_pwd_field_newpwd=新密碼
## dashboard
job_dashboard_name=運行報表
job_dashboard_job_num=任務數量
job_dashboard_job_num_tip=調度中心運行的任務數量
job_dashboard_trigger_num=調度次數
job_dashboard_trigger_num_tip=調度中心觸發的調度次數
job_dashboard_jobgroup_num=執行器數量
job_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量
job_dashboard_report=調度報表
job_dashboard_report_loaddata_fail=調度報表資料加載異常
job_dashboard_date_report=日期分布圖
job_dashboard_rate_report=成功比例圖
## job info
jobinfo_name=任務管理
jobinfo_job=任務
jobinfo_field_add=新增
jobinfo_field_update=更新任務
jobinfo_field_id=任務ID
jobinfo_field_jobgroup=執行器
jobinfo_field_jobdesc=任務描述
jobinfo_field_gluetype=運行模式
jobinfo_field_executorparam=任務參數
jobinfo_field_author=負責人
jobinfo_field_timeout=任務超時秒數
jobinfo_field_alarmemail=告警郵件
jobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址,請以逗號分隔
jobinfo_field_executorRouteStrategy=路由策略
jobinfo_field_childJobId=子任務ID
jobinfo_field_childJobId_placeholder=輸入子任務ID如有多個請以逗號分隔
jobinfo_field_executorBlockStrategy=阻塞處理策略
jobinfo_field_executorFailRetryCount=失敗重試次數
jobinfo_field_executorFailRetryCount_placeholder=失敗重試次數,大於零時生效
jobinfo_script_location=腳本位置
jobinfo_shard_index=分片序號
jobinfo_shard_total=分片總數
jobinfo_opt_stop=停止
jobinfo_opt_start=啟動
jobinfo_opt_log=查詢日誌
jobinfo_opt_run=執行一次
jobinfo_opt_run_tips=請輸入本次執行的機器地址,為空則從執行器獲取
jobinfo_opt_registryinfo=注冊節點
jobinfo_opt_next_time=下次執行時間
jobinfo_glue_remark=源碼備註
jobinfo_glue_remark_limit=源碼備註長度限制為4~100
jobinfo_glue_rollback=版本回復
jobinfo_glue_jobid_unvalid=任務ID非法
jobinfo_glue_gluetype_unvalid=該任務非GLUE模式
jobinfo_field_executorTimeout_placeholder=任務超時時間,單位秒,大於零時生效
schedule_type=調度類型
schedule_type_none=
schedule_type_cron=CRON
schedule_type_fix_rate=固定速度
schedule_type_fix_delay=固定延遲
schedule_type_none_limit_start=當前調度類型禁止啟動
misfire_strategy=調度過期策略
misfire_strategy_do_nothing=忽略
misfire_strategy_fire_once_now=立即執行壹次
jobinfo_conf_base=基礎配置
jobinfo_conf_schedule=調度配置
jobinfo_conf_job=任務配置
jobinfo_conf_advanced=高級配置
## job log
joblog_name=調度日誌
joblog_status=狀態
joblog_status_all=全部
joblog_status_suc=成功
joblog_status_fail=失敗
joblog_status_running=進行中
joblog_field_triggerTime=調度時間
joblog_field_triggerCode=調度結果
joblog_field_triggerMsg=調度備註
joblog_field_handleTime=執行時間
joblog_field_handleCode=執行结果
joblog_field_handleMsg=執行備註
joblog_field_executorAddress=執行器地址
joblog_clean=清理
joblog_clean_log=日誌清理
joblog_clean_type=清理方式
joblog_clean_type_1=清理一個月之前日誌資料
joblog_clean_type_2=清理三個月之前日誌資料
joblog_clean_type_3=清理六個月之前日誌資料
joblog_clean_type_4=清理一年之前日誌資料
joblog_clean_type_5=清理一千條以前日誌資料
joblog_clean_type_6=清理一萬條以前日誌資料
joblog_clean_type_7=清理三萬條以前日誌資料
joblog_clean_type_8=清理十萬條以前日誌資料
joblog_clean_type_9=清理所有日誌資料
joblog_clean_type_unvalid=清理類型參数異常
joblog_handleCode_200=成功
joblog_handleCode_500=失敗
joblog_handleCode_502=失敗(超時)
joblog_kill_log=终止任務
joblog_kill_log_limit=調度失敗,無法终止日誌
joblog_kill_log_byman=人為操作,主動終止
joblog_lost_fail=任務結果丟失,標記失敗
joblog_rolling_log=執行日誌
joblog_rolling_log_refresh=更新
joblog_rolling_log_triggerfail=任務發起調度失敗,無法查看執行日誌
joblog_rolling_log_failoften=終止請求Rolling日誌請求失敗次數超上限可刷新頁面重新加載日誌
joblog_logid_unvalid=日誌ID非法
## job group
jobgroup_name=執行器管理
jobgroup_list=執行器列表
jobgroup_add=新增執行器
jobgroup_edit=編輯執行器
jobgroup_del=刪除執行器
jobgroup_field_title=名稱
jobgroup_field_addressType=注冊方式
jobgroup_field_addressType_0=自動注冊
jobgroup_field_addressType_1=手動登錄
jobgroup_field_addressType_limit=手動登錄注冊方式,機器地址不可為空
jobgroup_field_registryList=機器地址
jobgroup_field_registryList_unvalid=機器地址格式非法
jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔
jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成
jobgroup_field_appname_length=AppName長度限制為4~64
jobgroup_field_title_length=名稱長度限制為4~12
jobgroup_field_order_digits=請輸入整數
jobgroup_field_orderrange=取值範圍為1~1000
jobgroup_del_limit_0=拒絕刪除,該執行器使用中
jobgroup_del_limit_1=拒絕删除,系统至少保留一個執行器
jobgroup_empty=不存在有效執行器,請聯絡系統管理員
## job conf
jobconf_block_SERIAL_EXECUTION=單機串行
jobconf_block_DISCARD_LATER=丢棄后續調度
jobconf_block_COVER_EARLY=覆蓋之前調度
jobconf_route_first=第一個
jobconf_route_last=最後一個
jobconf_route_round=輪詢
jobconf_route_random=隨機
jobconf_route_consistenthash=一致性HASH
jobconf_route_lfu=最不經常使用
jobconf_route_lru=最近最久未使用
jobconf_route_failover=故障轉移
jobconf_route_busyover=忙碌轉移
jobconf_route_shard=分片廣播
jobconf_idleBeat=空閒檢測
jobconf_beat=心跳檢測
jobconf_monitor=任務調度中心監控告警
jobconf_monitor_detail=監控告警明细
jobconf_monitor_alarm_title=告警類型
jobconf_monitor_alarm_type=調度失敗
jobconf_monitor_alarm_content=告警内容
jobconf_trigger_admin_adress=調度機器
jobconf_trigger_exe_regtype=執行器-注冊方式
jobconf_trigger_exe_regaddress=執行器-地址列表
jobconf_trigger_address_empty=調度失敗:執行器地址為空
jobconf_trigger_run=觸發調度
jobconf_trigger_child_run=觸發子任務
jobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4} <br>
jobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤 <br>
jobconf_trigger_type=任務觸發類型
jobconf_trigger_type_cron=Cron觸發
jobconf_trigger_type_manual=手動觸發
jobconf_trigger_type_parent=父任務觸發
jobconf_trigger_type_api=API觸發
jobconf_trigger_type_retry=失敗重試觸發
jobconf_trigger_type_misfire=調度過期補償
## user
user_manage=用户管理
user_username=帳號
user_password=密碼
user_role=角色
user_role_admin=管理員
user_role_normal=普通用戶
user_permission=權限
user_add=新增用戶
user_update=更新用戶
user_username_repeat=帳號重複
user_username_valid=限制以小寫字母開頭,由小寫字母、數字組成
user_password_update_placeholder=請輸入新密碼,為空則不更新密碼
user_update_loginuser_limit=禁止操作當前登入帳號
## help
job_help=使用教程
job_help_document=官方文件

View File

@@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--日志格式应用spring boot默认的格式也可以自己更改-->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<property name="FILE_LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n" />
<springProperty scope="context" name="SERVICE_NAME" source="spring.application.name" defaultValue="yunzhupaas"/>
<!--定义日志存放的位置,默认存放在项目启动的相对路径的目录-->
<springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="log/${SERVICE_NAME}"/>
<!-- 全局日志等级 -->
<springProperty scope="context" name="LOG_LEVEL_ROOT" source="log.level.root" defaultValue="INFO"/>
<!-- 服务自定义等级 如需自定义服务日志等级 修改下方的【自定义服务名】与nacos上的log.level.自定义服务名=等级 -->
<springProperty scope="context" name="LOG_LEVEL" source="log.level.自定义服务名" defaultValue="${LOG_LEVEL_ROOT}"/>
<!-- 日志记录器日期滚动记录level为 ERROR 日志 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_error.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/error/%d{yyyy-MM-dd,aux}/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录error级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志记录器日期滚动记录level为 INFO 日志 -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_info.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/info/%d{yyyy-MM-dd,aux}/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志记录器日期滚动记录level为 WARN 日志 -->
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_warn.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/warn/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志记录器日期滚动记录level为 DEBUG 日志 -->
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_debug.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/debug/%d{yyyy-MM-dd,aux}/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志记录器,日期滚动记录,所有日志 -->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_total.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/total/%d{yyyy-MM-dd,aux}/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 日志记录器日期滚动记录level 根据配置动态输出日志 -->
<appender name="FILE_RELEASE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_release.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/release/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志最大的历史7天-->
<maxHistory>7</maxHistory>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>${LOG_LEVEL}</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 DEBUG -->
<appender name="ASYNC_FILE_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="FILE_DEBUG"/>
</appender>
<!-- 异步输出 INFO -->
<appender name="ASYNC_FILE_INFO" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="FILE_INFO"/>
</appender>
<!-- 异步输出 WARN -->
<appender name="ASYNC_FILE_WARN" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="FILE_WARN"/>
</appender>
<!-- 异步输出 ERROR -->
<appender name="ASYNC_FILE_ERROR" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="FILE_ERROR"/>
</appender>
<!-- 异步输出 ALL -->
<appender name="ASYNC_FILE_ALL" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="FILE_ALL"/>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 异步输出 控制台 -->
<appender name="ASYNC_STDOUT" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="STDOUT"/>
</appender>
<root level="${LOG_LEVEL}">
<appender-ref ref="ASYNC_STDOUT"/>
<appender-ref ref="ASYNC_FILE_ERROR"/>
<appender-ref ref="ASYNC_FILE_INFO"/>
<appender-ref ref="ASYNC_FILE_WARN"/>
<appender-ref ref="ASYNC_FILE_DEBUG"/>
<appender-ref ref="ASYNC_FILE_ALL"/>
</root>
</configuration>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxl.job.admin.dao.XxlJobGroupDao">
</mapper>

Some files were not shown because too many files have changed in this diff Show More