由于xxl-job提供了图形化界面添加任务,所有针对业务系统如果是固定时间需要调度任务时,则可以用通过这种图形化界面方式添加,但是有些业务系统需要根据自己的业务去创建任务,这样图形化的添加方式就不满足使用了,所以需要提供对外接口供业务系统调用,例如新增,编辑,删除,挂起。下面就是操作过程。
2.编写对外接口
package com.xxl.job.admin.rest;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.util.Date;
/**
* @Description TODO
* @Author jiuwei
* @Date Created in 下午8:13 2020/2/15
* @Version 1.0
*/
@RestController
@RequestMapping("/api/jobinfo")
public class XxlJobAdminRestController {
private static Logger logger = LoggerFactory.getLogger(XxlJobAdminRestController.class);
@Autowired
private XxlJobService xxlJobService;
@Autowired
private LoginService loginService;
@RequestMapping(value = "/save",method = RequestMethod.POST)
public ReturnT add(@RequestBody(required = true)XxlJobInfo jobInfo) throws Exception {
// next trigger time (5s后生效,避开预读周期)
long nextTriggerTime = 0;
try {
Date nextValidTime = new CronExpression(jobInfo.getJobCron()).getNextValidTimeAfter(new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
if (nextValidTime == null) {
return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_never_fire"));
}
nextTriggerTime = nextValidTime.getTime();
} catch (ParseException e) {
logger.error(e.getMessage(), e);
return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid")+" | "+ e.getMessage());
}
jobInfo.setTriggerStatus(1);
jobInfo.setTriggerLastTime(0);
jobInfo.setTriggerNextTime(nextTriggerTime);
jobInfo.setUpdateTime(new Date());
if(jobInfo.getId()==0){
return xxlJobService.add(jobInfo);
}else{
return xxlJobService.update(jobInfo);
}
}
@RequestMapping(value = "/delete",method = RequestMethod.GET)
public ReturnT delete(int id) {
return xxlJobService.remove(id);
}
@RequestMapping(value = "/start",method = RequestMethod.GET)
public ReturnT start(int id) {
return xxlJobService.start(id);
}
@RequestMapping(value = "/stop",method = RequestMethod.GET)
public ReturnT stop(int id) {
return xxlJobService.stop(id);
}
@RequestMapping(value="login", method=RequestMethod.GET)
@PermissionLimit(limit=false)
public ReturnT loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
ReturnT result= loginService.login(request, response, userName, password, ifRem);
return result;
}
}
3.编写HttpClient工具类
package com.xxl.job.executor.util;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import net.sf.json.JSONObject;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import java.io.IOException;
/**
* @Description TODO
* @Author jiuwei
* @Date Created in 下午8:13 2020/2/15
* @Version 1.0
*/
public class ApiUtil {
public static Logger logger = LoggerFactory.getLogger(ApiUtil.class);
private static String cookie="";
/**
* 新增/编辑任务
* @param url
* @param requestInfo
* @return
* @throws HttpException
* @throws IOException
*/
public static JSONObject addJob(String url,JSONObject requestInfo) throws HttpException, IOException {
String path = "/api/jobinfo/save";
String targetUrl = url + path;
HttpClient httpClient = new HttpClient();
PostMethod post = new PostMethod(targetUrl);
RequestEntity requestEntity = new StringRequestEntity(requestInfo.toString(), "application/json", "utf-8");
post.setRequestEntity(requestEntity);
httpClient.executeMethod(post);
JSONObject result = new JSONObject();
result = getJsonObject(post, result);
return result;
}
/**
* 删除任务
* @param url
* @param id
* @return
* @throws HttpException
* @throws IOException
*/
public static JSONObject deleteJob(String url,int id) throws HttpException, IOException {
String path = "/api/jobinfo/delete?id="+id;
return doGet(url,path);
}
/**
* 开始任务
* @param url
* @param id
* @return
* @throws HttpException
* @throws IOException
*/
public static JSONObject startJob(String url,int id) throws HttpException, IOException {
String path = "/api/jobinfo/start?id="+id;
return doGet(url,path);
}
/**
* 停止任务
* @param url
* @param id
* @return
* @throws HttpException
* @throws IOException
*/
public static JSONObject stopJob(String url,int id) throws HttpException, IOException {
String path = "/api/jobinfo/stop?id="+id;
return doGet(url,path);
}
public static JSONObject doGet(String url,String path) throws HttpException, IOException {
String targetUrl = url + path;
HttpClient httpClient = new HttpClient();
HttpMethod get = new GetMethod(targetUrl);
get.setRequestHeader("cookie", cookie);
httpClient.executeMethod(get);
JSONObject result = new JSONObject();
result = getJsonObject(get, result);
return result;
}
private static JSONObject getJsonObject(HttpMethod get, JSONObject result) throws IOException {
if (get.getStatusCode() == 200) {
String responseBodyAsString = get.getResponseBodyAsString();
result = JSONObject.fromObject(responseBodyAsString);
} else {
try {
result = JSONObject.fromObject(get.getResponseBodyAsString());
} catch (Exception e) {
result.put("error", get.getResponseBodyAsString());
}
}
return result;
}
public static String login(String url, String userName, String password) throws HttpException, IOException {
String path = "/api/jobinfo/login?userName="+userName+"&password="+password;
String targetUrl = url + path;
HttpClient httpClient = new HttpClient();
HttpMethod get = new GetMethod(targetUrl);
httpClient.executeMethod(get);
if (get.getStatusCode() == 200) {
Cookie[] cookies = httpClient.getState().getCookies();
StringBuffer tmpcookies = new StringBuffer();
for (Cookie c : cookies) {
tmpcookies.append(c.toString() + ";");
}
cookie = tmpcookies.toString();
} else {
try {
cookie = "";
} catch (Exception e) {
cookie="";
}
}
return cookie;
}
}
4:编写测试接口
package com.xxl.job.executor.rest;
import com.xxl.job.executor.util.ApiUtil;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import response.ResponseData;
import java.io.IOException;
/**
* @Description TODO
* @Author jiuwei
* @Date Created in 下午8:13 2020/2/15
* @Version 1.0
*/
@RestController
@RequestMapping("/taskDemo")
public class JobInfoRestResource {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
/**
* 添加任务
* @return
* @throws IOException
*/
@RequestMapping(value = "/add",method = RequestMethod.GET)
public ResponseData add() throws IOException {
JSONObject requestInfo = new JSONObject();
requestInfo.put("jobGroup",1);
requestInfo.put("jobDesc","我是任务");
requestInfo.put("executorRouteStrategy","FIRST");
requestInfo.put("cronGen_display","0 0/1 * * * ?");
requestInfo.put("jobCron","0 0/1 * * * ?");
requestInfo.put("glueType","BEAN");
requestInfo.put("executorHandler","demoJobHandler");
requestInfo.put("executorBlockStrategy","SERIAL_EXECUTION");
requestInfo.put("executorTimeout",0);
requestInfo.put("executorFailRetryCount",1);
requestInfo.put("author","admin");
requestInfo.put("alarmEmail","[email protected]");
requestInfo.put("executorParam","att");
requestInfo.put("glueRemark","GLUE代码初始化");
JSONObject response=ApiUtil.addJob(adminAddresses,requestInfo);
if(response.containsKey("code")&&200==response.getInt("code")){
return ResponseData.success();
}else{
return ResponseData.error("调用api接口失败!");
}
}
/**
* 删除任务
* @param id
* @return
* @throws IOException
*/
@RequestMapping(value = "/delete",method = RequestMethod.GET)
public ResponseData delete(int id) throws IOException {
JSONObject response=ApiUtil.deleteJob(adminAddresses,id);
if(response.containsKey("code")&&200==response.getInt("code")){
return ResponseData.success();
}else{
return ResponseData.error("调用api接口失败!");
}
}
/**
* 开始任务
* @param id
* @return
* @throws IOException
*/
@RequestMapping(value = "/start",method = RequestMethod.GET)
public ResponseData start(int id) throws IOException {
JSONObject response=ApiUtil.startJob(adminAddresses,id);
if(response.containsKey("code")&&200==response.getInt("code")){
return ResponseData.success();
}else{
return ResponseData.error("调用api接口失败!");
}
}
/**
* 挂起任务
* @param id
* @return
* @throws IOException
*/
@RequestMapping(value = "/stop",method = RequestMethod.GET)
public ResponseData stop(int id) throws IOException {
JSONObject response=ApiUtil.stopJob(adminAddresses,id);
if(response.containsKey("code")&&200==response.getInt("code")){
return ResponseData.success();
}else{
return ResponseData.error("调用api接口失败!");
}
}
/**
* 登陆
* @param userName
* @param password
* @return
* @throws IOException
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public ResponseData login(String userName,String password) throws IOException {
String cookie=ApiUtil.login(adminAddresses,userName,password);
if(StringUtils.isNotBlank(cookie)){
return ResponseData.success(cookie);
}else{
return ResponseData.error("调用api接口失败!");
}
}
}
5.封装返回实体类
package response;
/**
* 请求失败的返回
*
*/
public class ErrorResponseData extends ResponseData {
/**
* 异常的具体类名称
*/
private String exceptionClazz;
public ErrorResponseData(String message) {
super(false, ResponseData.DEFAULT_ERROR_CODE, message, null);
}
public ErrorResponseData(Integer code, String message) {
super(false, code, message, null);
}
public ErrorResponseData(Integer code, String message, String exceptionClazz) {
super(false, code, message, null);
this.exceptionClazz = exceptionClazz;
}
public ErrorResponseData(Integer code, String message, T object) {
super(false, code, message, object);
}
public ErrorResponseData(Integer code, String message, T object, String exceptionClazz) {
super(false, code, message, object);
this.exceptionClazz = exceptionClazz;
}
public String getExceptionClazz() {
return exceptionClazz;
}
public void setExceptionClazz(String exceptionClazz) {
this.exceptionClazz = exceptionClazz;
}
}
package response;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* 返回给前台的通用包装
*
*/
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class ResponseData {
public static final String DEFAULT_SUCCESS_MESSAGE = "请求成功";
public static final String DEFAULT_ERROR_MESSAGE = "网络异常";
public static final Integer DEFAULT_SUCCESS_CODE = 0;
public static final Integer DEFAULT_ERROR_CODE = 500;
/**
* 请求是否成功
*/
private Boolean success;
/**
* 响应状态码
*/
private Integer errcode;
/**
* 响应信息
*/
private String errmessage;
/**
* 响应对象
*/
private T data;
public ResponseData() {
}
public ResponseData(Boolean success, Integer code, String message, T data) {
this.success = success;
this.errcode = code;
this.errmessage = message;
this.data = data;
}
public static SuccessResponseData> success() {
return new SuccessResponseData<>();
}
public static SuccessResponseData success(T object) {
return new SuccessResponseData(object);
}
public static SuccessResponseData success(Integer code, String message, T object) {
return new SuccessResponseData(code, message, object);
}
public static ErrorResponseData> error(String message) {
return new ErrorResponseData<>(message);
}
public static ErrorResponseData> error(Integer code, String message) {
return new ErrorResponseData<>(code, message);
}
public static ErrorResponseData error(Integer code, String message, T object) {
return new ErrorResponseData(code, message, object);
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public Integer getErrcode() {
return errcode;
}
public void setErrcode(Integer errcode) {
this.errcode = errcode;
}
public String getErrmessage() {
return errmessage;
}
public void setErrmessage(String errmessage) {
this.errmessage = errmessage;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package response;
/**
* 请求成功的返回
*
*/
public class SuccessResponseData extends ResponseData {
public SuccessResponseData() {
super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, null);
}
public SuccessResponseData(T object) {
super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, object);
}
public SuccessResponseData(Integer code, String message, T object) {
super(true, code, message, object);
}
}
到此,对外新增/编辑,删除,挂起等接口就已经写好了。