xxl-job通过代码的方式动态添加任务,修改任务,执行任务,停止任务等

Xxl-job 是目前比较主流的轻量级定时任务框架,该框架以相对简单的使用方式,灵活的配置,和可读性强的源码 等优势,深得广大开发者的喜欢。让我们的定时任务实现起来变得简单。具体的使用方法这里就不介绍了,想了解的可以直接访问官网:分布式任务调度平台XXL-JOB

今天我们主要解决一下使用xxl-job中的一个痛点,就是动态创建任务。使用过xxl-job的朋友们都知道,xxl-job给我们提供一个管理后台,我们可以在管理后台上,配置执行器,配置任务,管理任务。如下图。

这种方式使用起来虽然方便,可以有时候,我们就是需要在代码中动态创建一个定时任务,而不是到页面上进行配置,这个时候该怎么办呢?方式就是动态的扩展源码中提供的api。 这里着重强调一下,截止至当前,xxl-job的最新版本是2.2.0,这个版本中已经提供了一些开放的Rest Api供我们调用,不过只有心跳检测,忙碌检测,触发任务,终止任务,查看执行日志,等接口,如果你的需求是上述的这几个功能,完全可以使用开放的api进行扩展。但是这几个接口是不包含动态创建修改的。

好了,接下来回归正题,如果想动态创建任务该怎么办呢?目前的方式是只能通过调用xxl-job中的新增修改等接口完成。我们可以去github上把xxl-job的源码下载下来,其实我们正常部署xxl-job服务也是这个过程,在源码中主要有两个模块,一个是admin,一个是core, admin就是我们部署的服务,是一个springboot项目。

在admin项目中,有一个JobInfoController, 这个类就是处理各种新增任务,修改任务,触发任务的Controller, 

但是有个问题就是,这些接口都是后台使用的,要想调用,就必须得登录才行,不登录是没有办法访问的。那怎么办?难道还要模拟登录一次,其实大可不必,因为xxl-job中已经为我们提供了一个口子,就是一个注解和一个拦截器,通过这个注解可以配置接口是否可以跳过登录进行访问。也就是我们可以把接口配置成跳过登录验证进行访问就可以了,这样我们就能不登录而进行请求 。这个注解就是 @PermissionLimit(limit = false)  ,默认是true,也就是需要做登录验证。

好了有了这个注解就好办了,但是这里要注意,我们最好不要直接把这个注解配置到刚才截图中的对任务的操作的方法上,因为这些方法都是通过后台调用的,也就是对于操作者这些接口是可见的,如果打开了他们的权限,其实对于接口是有威胁的。所以我们可以自己扩展几个接口,保留原接口不变。那么我们直接在JobInfoController中添加几个方法

/*------------------自定义方法----------------------  */
	@RequestMapping("/addJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> addJobInfo(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.add(jobInfo);
	}

	@RequestMapping("/updateJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> updateJobCron(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.updateCron(jobInfo);
	}

	@RequestMapping("/removeJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> removeJob(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.remove(jobInfo.getId());
	}

	@RequestMapping("/pauseJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> pauseJob(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.stop(jobInfo.getId());
	}

	@RequestMapping("/startJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> startJob(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.start(jobInfo.getId());
	}

	@RequestMapping("/addAndStart")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> addAndStart(@RequestBody XxlJobInfo jobInfo) {
		ReturnT<String> result = xxlJobService.add(jobInfo);
		int id = Integer.valueOf(result.getContent());
		xxlJobService.start(id);
		return result;
	}

【新增】在  JobGroupController 中添加一个方法:获取groupId,

@RequestMapping("/getGroupId")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> getGroupId(@RequestBody XxlJobGroup jobGroup) {
	XxlJobGroup group = xxlJobGroupDao.findByName(jobGroup.getAppname());
	return new ReturnT<String>(String.valueOf(group.getId()));
}

如果上面的findByName找不到,那就自己写一个,就是根据名字查询数据的一个方法:因为我忘了这个方法是自带的还是我自己加的。

<select id="findByName" parameterType="java.lang.String" resultMap="XxlJobGroup">
		SELECT <include refid="Base_Column_List" />
		FROM xxl_job_group AS t
		WHERE t.app_name = #{appName}
	</select>

然后重新打包部署。然后在我们的项目中直接访问刚刚加好的接口就可以了。 但是说实话这种方式确实也不是很安全,毕竟相当于如果被别人发现了这些接口都是可以无限制进行调用的,所以大家还是要谨慎使用,最好用的时候在内网中访问,同时开启xxl-job的accessToken.

还有一个问题,也说明一下,我们在新增任务的时候,其实是要给这个任务选择一个执行器,也就是有一个jobGroup字段需要设置,这个最好不要写死,我们可以按照上面的方式在扩展一个根据appname获取group表中id的接口,这样通过appname去获取到groupid,在设置到任务中,就更加灵活一下。好了这篇文章就先分享到这里了,有问题的话,欢迎大家留言。最后附一个xxl-job的调用工具类:

@Slf4j
@Component
public class XxlJobUtil {

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    private RestTemplate restTemplate = new RestTemplate();

    private static final String ADD_URL = "/jobinfo/addJob";
    private static final String UPDATE_URL = "/jobinfo/updateJob";
    private static final String REMOVE_URL = "/jobinfo/removeJob";
    private static final String PAUSE_URL = "/jobinfo/pauseJob";
    private static final String START_URL = "/jobinfo/startJob";
    private static final String ADD_START_URL = "/jobinfo/addAndStart";
    private static final String GET_GROUP_ID = "/jobgroup/getGroupId";


    public String add(XxlJobInfo jobInfo){
        // 查询对应groupId:
        Map<String,Object> param = new HashMap<>();
        param.put("appname", appname);
        String json = JSON.toJSONString(param);
        String result = doPost(adminAddresses + GET_GROUP_ID, json);

        JSONObject jsonObject = JSON.parseObject(result);
        String groupId = jsonObject.getString("content");
        jobInfo.setJobGroup(Integer.parseInt(groupId));
        String json2 = JSON.toJSONString(jobInfo);
        return doPost(adminAddresses + ADD_URL, json2);
    }

    public String update(int id, String cron){
        Map<String,Object> param = new HashMap<>();
        param.put("id", id);
        param.put("jobCron", cron);
        String json = JSON.toJSONString(param);
        return doPost(adminAddresses + UPDATE_URL, json);
    }

    public String remove(int id){
        Map<String,Object> param = new HashMap<>();
        param.put("id", id);
        String json = JSON.toJSONString(param);
        return doPost(adminAddresses + REMOVE_URL, json);
    }

    public String pause(int id){
        Map<String,Object> param = new HashMap<>();
        param.put("id", id);
        String json = JSON.toJSONString(param);
        return doPost(adminAddresses + PAUSE_URL, json);
    }

    public String start(int id){
        Map<String,Object> param = new HashMap<>();
        param.put("id", id);
        String json = JSON.toJSONString(param);
        return doPost(adminAddresses + START_URL, json);
    }

    public String addAndStart(XxlJobInfo jobInfo){
        Map<String,Object> param = new HashMap<>();
        param.put("appname", appname);
        String json = JSON.toJSONString(param);
        String result = doPost(adminAddresses + GET_GROUP_ID, json);

        JSONObject jsonObject = JSON.parseObject(result);
        String groupId = jsonObject.getString("content");
        jobInfo.setJobGroup(Integer.parseInt(groupId));
        String json2 = JSON.toJSONString(jobInfo);

        return doPost(adminAddresses + ADD_START_URL, json2);
    }

    public String doPost(String url, String json){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(json ,headers);
        log.info(entity.toString());
        ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(url, entity, String.class);
        return stringResponseEntity.getBody().toString();
    }

}

  • 32
    点赞
  • 156
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
可以通过以下步骤实现在Java代码动态xxl-job-admin添加任务: 1. 引入xxl-job的依赖: ```xml <dependency> <groupId>com.xxl-job</groupId> <artifactId>xxl-job-core</artifactId> <version>${xxl-job.version}</version> </dependency> ``` 2. 创建一个Http请求,向xxl-job-admin发送添加任务的请求。可以使用Apache HttpClient或者OkHttp等第三方库来发送Http请求。 ```java HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost("http://xxl-job-admin:8080/xxl-job-admin/jobinfo/add"); ``` 3. 构造请求参数,将任务的信息以JSON格式放入请求体中。 ```java JSONObject jobInfo = new JSONObject(); jobInfo.put("jobGroup", 1); jobInfo.put("jobCron", "0 0/1 * * * ?"); jobInfo.put("jobDesc", "测试任务"); jobInfo.put("author", "test"); jobInfo.put("executorRouteStrategy", "FIRST"); jobInfo.put("executorHandler", "testHandler"); jobInfo.put("executorParam", ""); jobInfo.put("executorBlockStrategy", "SERIAL_EXECUTION"); jobInfo.put("executorFailStrategy", "FAIL_RETRY"); jobInfo.put("glueType", "BEAN"); jobInfo.put("glueRemark", ""); jobInfo.put("glueUpdatetime", new Date()); jobInfo.put("childJobId", ""); jobInfo.put("triggerStatus", 1); StringEntity entity = new StringEntity(jobInfo.toJSONString(), ContentType.APPLICATION_JSON); httpPost.setEntity(entity); ``` 4. 发送请求,并获取响应结果。 ```java HttpResponse httpResponse = httpClient.execute(httpPost); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String result = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); JSONObject responseJson = JSONObject.parseObject(result); int code = responseJson.getIntValue("code"); if (code == 200) { System.out.println("任务添加成功!"); } else { System.out.println("任务添加失败!"); } } ``` 完整代码示例: ```java import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import com.alibaba.fastjson.JSONObject; public class AddJobDemo { public static void main(String[] args) throws Exception { HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost("http://xxl-job-admin:8080/xxl-job-admin/jobinfo/add"); JSONObject jobInfo = new JSONObject(); jobInfo.put("jobGroup", 1); jobInfo.put("jobCron", "0 0/1 * * * ?"); jobInfo.put("jobDesc", "测试任务"); jobInfo.put("author", "test"); jobInfo.put("executorRouteStrategy", "FIRST"); jobInfo.put("executorHandler", "testHandler"); jobInfo.put("executorParam", ""); jobInfo.put("executorBlockStrategy", "SERIAL_EXECUTION"); jobInfo.put("executorFailStrategy", "FAIL_RETRY"); jobInfo.put("glueType", "BEAN"); jobInfo.put("glueRemark", ""); jobInfo.put("glueUpdatetime", new Date()); jobInfo.put("childJobId", ""); jobInfo.put("triggerStatus", 1); StringEntity entity = new StringEntity(jobInfo.toJSONString(), ContentType.APPLICATION_JSON); httpPost.setEntity(entity); HttpResponse httpResponse = httpClient.execute(httpPost); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String result = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); JSONObject responseJson = JSONObject.parseObject(result); int code = responseJson.getIntValue("code"); if (code == 200) { System.out.println("任务添加成功!"); } else { System.out.println("任务添加失败!"); } } } } ```
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值