Procházet zdrojové kódy

暴露调度规则设置接口

zhangqiankun před 3 roky
rodič
revize
9badacf4a9

+ 1 - 1
job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java

@@ -12,5 +12,5 @@ public class XxlJobAdminApplication {
 	public static void main(String[] args) {
         SpringApplication.run(XxlJobAdminApplication.class, args);
 	}
-
+	
 }

+ 124 - 2
job-admin/src/main/java/com/xxl/job/admin/config/GlobalExceptionHandler.java

@@ -1,15 +1,137 @@
 package com.xxl.job.admin.config;
 
+import java.sql.SQLException;
+
+import javax.validation.ValidationException;
+
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.xxl.job.core.biz.model.ReturnT;
+
+import lombok.extern.slf4j.Slf4j;
 
-import com.persagy.common.aop.CommonExceptionHandler;
 
 /**
  * @description 
  * @author zhangqiankun
  * @since 2020年8月26日:	下午5:17:08
  */
+@Slf4j
 @RestControllerAdvice
-public class GlobalExceptionHandler extends CommonExceptionHandler {
+public class GlobalExceptionHandler {
+	
+	/**
+	 * 空指针异常
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ExceptionHandler(NullPointerException.class)
+	public ReturnT<String> handleNullPointerException(NullPointerException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
+	}
+	
+	/**
+	 * 自定义业务异常
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ExceptionHandler(BusinessException.class)
+	public ReturnT<String> handleBusinessRuntimeException(BusinessException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getErrorDesc());
+	}
+
+	/**
+	 * 入参校验异常
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ExceptionHandler(MethodArgumentNotValidException.class)
+	public ReturnT<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage());
+	}
+
+	/**
+	 * 入参校验异常
+	 */
+	@ExceptionHandler(BindException.class)
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	public ReturnT<String> handleBindException(BindException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage());
+	}
+	
+	/**
+	 * 参数校验异常,message 为手动抛出时定义的具体异常信息
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ExceptionHandler(ValidationException.class)
+	public ReturnT<String> handleValidationException(ValidationException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getCause().getMessage());
+	}
+	
+	/**
+	 * 参数校验异常,message 为手动抛出时定义的具体异常信息
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ExceptionHandler(IllegalArgumentException.class)
+	public ReturnT<String> handleIllegalArgumentException(IllegalArgumentException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
+	}
+	
+	/**
+	 * URI请求链接没有映射
+	 */
+	//@ResponseStatus(HttpStatus.NOT_FOUND)
+	@ExceptionHandler(NoHandlerFoundException.class)
+	public ReturnT<String> handleNoHandlerFoundException(NoHandlerFoundException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
+	}
+	
+	/**
+	 * Feign 调用异常
+	 */
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	/*@ExceptionHandler(FeignException.class)
+	public ReturnT<String> handleFeignException(FeignException e) {
+		log.error(e.getMessage(), e);
+		return ResponseUtil.errorResult(ResponseCode.C0110.getCode(), e.getMessage());
+	}*/
+	
+	/**
+	 *  body体未找到
+	 */
+	//@ResponseStatus(HttpStatus.BAD_REQUEST)
+	@ExceptionHandler(HttpMessageNotReadableException.class)
+	public ReturnT<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, ResponseCode.A0402.getDesc());
+	}
+	
+	@ExceptionHandler(SQLException.class)
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	public ReturnT<String> SQLException(SQLException e) {
+		log.error("sql语句异常", e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, ResponseCode.C0341.getDesc());
+	}
+	
+	/**
+	 * 系统默认繁忙
+	 */
+	@ExceptionHandler(Exception.class)
+	//@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	public ReturnT<String> handleException(Exception e) {
+		log.error(e.getMessage(), e);
+		return new ReturnT<String>(ReturnT.FAIL_CODE, ResponseCode.Z9999.getDesc());
+	}
 	
 }

+ 50 - 17
job-admin/src/main/java/com/xxl/job/admin/controller/custom/CustomInfoController.java

@@ -2,8 +2,10 @@ package com.xxl.job.admin.controller.custom;
 
 import javax.annotation.Resource;
 
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
@@ -12,12 +14,17 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.persagy.common.utils.StringUtil;
 import com.xxl.job.admin.core.model.DictQuery;
+import com.xxl.job.admin.core.model.XxlJobGroup;
 import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobInfoIdValid;
+import com.xxl.job.admin.core.model.XxlJobInfoValid;
 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.JobTriggerPoolHelper;
 import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
+import com.xxl.job.admin.dao.XxlJobGroupDao;
+import com.xxl.job.admin.dao.XxlJobInfoDao;
 import com.xxl.job.admin.service.XxlJobService;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.constant.CommonConstant;
@@ -25,7 +32,6 @@ import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
 
 /**
  * 暴露接口
@@ -42,17 +48,32 @@ public class CustomInfoController {
 	@Resource
 	private XxlJobService xxlJobService;
 	
+	@Resource
+	private XxlJobInfoDao xxlJobInfoDao;
+	
+	@Resource
+	private XxlJobGroupDao xxlJobGroupDao;
+	
 	@Autowired
 	private CustomInfoHandler customInfoHandler;
 	
+	/**
+	 * 旧数据转移
+	 * 
+	 * @return
+	 */
 	@RequestMapping(value = "/transfer")
 	public ReturnT<String> transfer() {
 		return customInfoHandler.transfer();
 	}
 	
 	@RequestMapping(value = "/addOrUpdateAndStart")
-	public ReturnT<String> addOrUpdateAndStart(@RequestBody XxlJobInfo jobInfo) {
-		if (jobInfo.getId() == null) {
+	public ReturnT<String> addOrUpdateAndStart(@RequestBody @Validated XxlJobInfoValid valid) {
+		XxlJobInfo jobInfo = new XxlJobInfo();
+		BeanUtils.copyProperties(valid, jobInfo);
+		jobInfo.setExecutorParam(valid.getExecutorParam().toJSONString());
+		
+		if (valid.getId() == null) {
 			xxlJobService.add(jobInfo);
 		} else {
 			xxlJobService.update(jobInfo);
@@ -62,38 +83,50 @@ public class CustomInfoController {
 	}
 	
 	@RequestMapping(value = "/add")
-	public ReturnT<String> add(@RequestBody XxlJobInfo jobInfo) {
+	public ReturnT<String> add(@RequestBody @Validated XxlJobInfoValid valid) {
+		XxlJobInfo jobInfo = new XxlJobInfo();
+		BeanUtils.copyProperties(valid, jobInfo);
+		jobInfo.setExecutorParam(valid.getExecutorParam().toJSONString());
 		return xxlJobService.add(jobInfo);
 	}
 	
 	@RequestMapping(value = "/update")
-	public ReturnT<String> update(@RequestBody XxlJobInfo jobInfo) {
+	public ReturnT<String> update(@RequestBody @Validated XxlJobInfoValid valid) {
+		XxlJobInfo jobInfo = new XxlJobInfo();
+		BeanUtils.copyProperties(valid, jobInfo);
+		
+		jobInfo.setExecutorParam(valid.getExecutorParam().toJSONString());
 		return xxlJobService.update(jobInfo);
 	}
 	
 	@RequestMapping(value = "/remove")
-	public ReturnT<String> remove(@RequestBody XxlJobInfo jobInfo) {
-		return xxlJobService.remove(jobInfo.getId());
+	public ReturnT<String> remove(@RequestBody @Validated XxlJobInfoIdValid valid) {
+		return xxlJobService.remove(valid.getId());
 	}
 	
 	@RequestMapping(value = "/stop")
-	public ReturnT<String> pause(@RequestBody XxlJobInfo jobInfo) {
-		return xxlJobService.stop(jobInfo.getId());
+	public ReturnT<String> pause(@RequestBody @Validated XxlJobInfoIdValid valid) {
+		return xxlJobService.stop(valid.getId());
 	}
 	
 	@RequestMapping(value = "/start")
-	public ReturnT<String> start(@RequestBody XxlJobInfo jobInfo) {
-		return xxlJobService.start(jobInfo.getId());
+	public ReturnT<String> start(@RequestBody @Validated XxlJobInfoIdValid valid) {
+		return xxlJobService.start(valid.getId());
 	}
 	
 	@RequestMapping(value = "/trigger")
-	public ReturnT<String> triggerJob(@RequestBody XxlJobInfo jobInfo) {
-		String executorParam = jobInfo.getExecutorParam();
-		if (StringUtil.isBlank(executorParam)) {
-			executorParam = StringUtil.EMPTY;
+	public ReturnT<String> triggerJob(@RequestBody @Validated XxlJobInfoIdValid valid) {
+		XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(valid.getId());
+		if (xxlJobInfo == null || StringUtil.isBlank(xxlJobInfo.getExecutorParam())) {
+			throw new IllegalArgumentException("非法请求,任务参数不存在");
 		}
-
-		JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MANUAL, -1, null, executorParam, jobInfo.getAddressList());
+		
+		XxlJobGroup xxlJobGroup = xxlJobGroupDao.load(xxlJobInfo.getJobGroup());
+		if (xxlJobGroup == null) {
+			throw new IllegalArgumentException("非法请求,执行器不存在");
+		}
+		
+		JobTriggerPoolHelper.trigger(xxlJobInfo.getId(), TriggerTypeEnum.MANUAL, -1, null, xxlJobInfo.getExecutorParam(), xxlJobGroup.getAddressList());
 		return ReturnT.SUCCESS;
 	}
 	

+ 31 - 0
job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroupValid.java

@@ -0,0 +1,31 @@
+package com.xxl.job.admin.core.model;
+
+import javax.validation.constraints.NotBlank;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * Created by xuxueli on 16/9/30.
+ */
+@Getter
+@Setter
+@ToString
+public class XxlJobGroupValid {
+
+    private int id;
+    
+    @NotBlank(message = "执行器名称,不可为空")
+    private String appname;
+    
+    @NotBlank(message = "执行器标题,不可为空")
+    private String title;
+    
+    //@NotBlank(message = "执行器地址类型,不可为空")
+    private int addressType;        // 执行器地址类型:0=自动注册、1=手动录入
+    
+    //@NotBlank(message = "执行器地址列表,不可为空")
+    private String addressList;     // 执行器地址列表,多地址逗号分隔(手动录入)
+
+}

+ 1 - 1
job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java

@@ -11,7 +11,7 @@ public class XxlJobInfo {
 	
 	private Integer id;				// 主键ID
 	
-	private int jobGroup;		// 执行器主键ID
+	private Integer jobGroup;		// 执行器主键ID
 	private String jobDesc;
 	
 	private Date addTime;

+ 22 - 0
job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfoIdValid.java

@@ -0,0 +1,22 @@
+package com.xxl.job.admin.core.model;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * xxl-job info
+ *
+ * @author xuxueli  2016-1-12 18:25:49
+ */
+@Getter
+@Setter
+@ToString
+public class XxlJobInfoIdValid {
+	
+	@NotNull(message = "主键ID,不可为空")
+	private Integer id;				// 主键ID
+	
+}

+ 74 - 0
job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfoValid.java

@@ -0,0 +1,74 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
+import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
+import com.xxl.job.core.constant.CommonConstant;
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
+import com.xxl.job.core.glue.GlueTypeEnum;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * xxl-job info
+ *
+ * @author xuxueli  2016-1-12 18:25:49
+ */
+@Getter
+@Setter
+@ToString
+public class XxlJobInfoValid {
+	
+	private Integer id;				// 主键ID
+	
+	@NotNull(message = "执行器ID,不可为空")
+	private Integer jobGroup;		// 执行器主键ID
+	
+	@NotBlank(message = "任务描述,不可为空")
+	private String jobDesc;
+	
+	@NotBlank(message = "负责人,不可为空")
+	private String author;		// 负责人
+	
+	private String alarmEmail;	// 报警邮件
+
+	@NotBlank(message = "调度类型,不可为空")
+	private String scheduleType;			// 调度类型
+	
+	@NotBlank(message = "调度配置,不可为空")
+	private String scheduleConf;			// 调度配置,值含义取决于调度类型
+	
+	private String misfireStrategy = MisfireStrategyEnum.DO_NOTHING.name();			// 调度过期策略
+
+	private String executorRouteStrategy = ExecutorRouteStrategyEnum.ROUND.name();	// 执行器路由策略
+	private String executorHandler = CommonConstant.COMMON_TIME_RULE_JOB;		    // 执行器,任务Handler名称
+	
+	@NotNull(message = "任务参数,不可为空")
+	private JSONObject executorParam;		    // 执行器,任务参数
+	
+	private String executorBlockStrategy = ExecutorBlockStrategyEnum.SERIAL_EXECUTION.name();	// 阻塞处理策略
+	
+	@Size(min = 0, message = "任务执行超时时间,不可小于0")
+	private int executorTimeout = 0;     		// 任务执行超时时间,单位秒
+	
+	@Size(min = 0, message = "失败重试次数,不可小于0")
+	private int executorFailRetryCount = 0;		// 失败重试次数
+	
+	private String glueType = GlueTypeEnum.BEAN.name();		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
+	private String glueSource;		// GLUE源代码
+	private String glueRemark;		// GLUE备注
+	private Date glueUpdatetime;	// GLUE更新时间
+
+	private String childJobId;		// 子任务ID,多个逗号分隔
+
+	private String addressList;		//执行器地址
+
+}

+ 2 - 0
job-admin/src/main/resources/application.properties

@@ -2,6 +2,8 @@
 management.server.servlet.context-path=/actuator
 management.health.mail.enabled=false
 
+#spring.jackson.parser.ALLOW_COMMENTS=true
+
 ### resources
 spring.mvc.servlet.load-on-startup=0
 spring.mvc.static-path-pattern=/static/**

+ 4 - 0
job-admin/src/main/resources/bootstrap.yml

@@ -6,6 +6,10 @@ server:
 spring:
   application:
     name: job-admin
+
+  jackson:
+    parser: 
+      ALLOW_COMMENTS: true
     
 logback:
   # 单日志文件最大可以达到多大