Codeworld-cloud-shop XXl-Job Dynamic Task Creation Detail 2– Wet Nurse Level Teaching

preface

In codeWorld-Cloud-shop xxl-job dynamic task creation section 1, we explained the defects of xxL-job dynamic task creation in codeWorld-Cloud-shop xxl-Job dynamic task creation section 1, we explained the defects of XXL-job dynamic task creation in codeWorld-Cloud-shop XXl-Job dynamic task creation section 2

Example Modify the xxl-job-admin interface

We know that before we call the interface, we need to be logged in to call it, but then we realize that we can put a PermissionLimit and set the limit to false so that we don’t have to log in to call the interface

Add the following interfaces to JobInfoController

// Custom methods
	/** * Add task *@param jobInfo
	 * @return* /
	@RequestMapping("/addJob")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> addJob(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.add(jobInfo);
	}
Copy the code
We can add @permissionLimit (limit = false) // to allow @requestBody // to receive json parametersCopy the code

Here we only need to add this interface, the implementation of the logic is the same as the original, do not make any changes we just need to provide the required parameters can be

Create a new project

One of the requirements we implemented here is that we create a User, add 1 minute to the created time, and automatically add it at this time for example: 2020-01-01 12:00:00:00 so we should add it at 2020-01-01 12:00:01

POM file

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.2. 0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.247.</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>  <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.06.</version>
        </dependency>
Copy the code

Application. Yml file

server:
  port: 10001

xxl:
  job:
    accessToken:
    admin:
      addresses: http://localhost:9999/xxl-job-admin
    executor:
      address:
      appname: xxl-job-test
      ip:
      logpath: /data/applogs/xxl-job/jobhandler
      logretentiondays: 30
      port: 10010
Copy the code

I’m sure you’re familiar with these configurations. We saw them in section 1. Now that we have a configuration file, we’re going to create a configuration class

XxlJobConfig

XxlJobConfig

@Configuration
@Slf4j
public class XxlJobConfig {

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

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

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

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

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

    @Value("${xxl.job.executor.port}")
    private int port;

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

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor(a) {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        returnxxlJobSpringExecutor; }}Copy the code

Basic utility classes

DateUtils Date utility class

/** * date tools **@author Lenovo
 */
public class DateUtils {

    /** * Date format YYYY-MM-DD */
    public static final String pattern_date = "yyyy-MM-dd";

    /** * Date and time format YYYY-MM-DD HH: MM :ss */
    public static final String pattern_time = "yyyy-MM-dd HH:mm:ss";

    /** * Description: Date formatting **@paramThe date date *@returnThe output format is yyyY-MM-DD string */
    public static String formatDate(Date date) {

        return formatDate(date, pattern_time);

    }

    /** * Description: Date formatting **@paramThe date date *@paramPattern Indicates the format type *@return* /
    public static String formatDate(Date date, String pattern) {

        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);

        return dateFormat.format(date);
    }

    /***
     * convert Date to cron ,eg.  "0 07 10 15 1 ? 2016"
     * @paramDate: indicates the time *@return* /
    public static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        returnformatDate(date, dateFormat); }}Copy the code

JsonUtils tools

public class JsonUtils {

    public static final ObjectMapper mapper = new ObjectMapper();

    private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);

    @Nullable
    public static String serialize(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj.getClass() == String.class) {
            return (String) obj;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error(Json serialization error: + obj, e);
            return null; }}@Nullable
    public static <T> T parse(String json, Class<T> tClass) {
        try {
            return mapper.readValue(json, tClass);
        } catch (IOException e) {
            logger.error(Json parsing error: + json, e);
            return null; }}@Nullable
    public static <E> List<E> parseList(String json, Class<E> eClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (IOException e) {
            logger.error(Json parsing error: + json, e);
            return null; }}@Nullable
    public static <K, V> Map<K, V> parseMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
        } catch (IOException e) {
            logger.error(Json parsing error: + json, e);
            return null; }}@Nullable
    public static <T> T nativeRead(String json, TypeReference<T> type) {
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error(Json parsing error: + json, e);
            return null; }}}Copy the code

Create Response Response information

ApiResponse

@Data
public class FcResponse<T> {

    private Integer code;

    private String msg;

    private T data;

    public FcResponse(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data; }}Copy the code

Create a domain

XxlJobInfo

@Data
public class XxlJobInfo {

    private int id;				/ / the primary key ID

    private int jobGroup;		// Primary key ID of the actuator
    private String jobDesc;

    private Date addTime;
    private Date updateTime;

    private String author;		/ / head
    private String alarmEmail;	// Alarm email

    private String scheduleType;			// Scheduling type
    private String scheduleConf;			// Scheduling configuration, value meaning depends on scheduling type
    private String misfireStrategy;			// Schedule expiration policies

    private String executorRouteStrategy;	// Execute the routing policy
    private String executorHandler;		    // Executor, task Handler name
    private String executorParam;		    // Actuator, task parameters
    private String executorBlockStrategy;	// Block processing policy
    private int executorTimeout;     		// Task execution timeout duration, in seconds
    private int executorFailRetryCount;		// Number of failed retries

    private String glueType;		/ / GLUE type # com. XXL. Job. Core. GLUE. GlueTypeEnum
    private String glueSource;		// GLUE source code
    private String glueRemark;		/ / GLUE remark
    private Date glueUpdatetime;	// GLUE update time

    private String childJobId;		// Subtask ID, separated by multiple commas

    private int triggerStatus;		// Scheduling status: 0- Stopped, 1- running
    private long triggerLastTime;	// Last dispatch time
    private long triggerNextTime;	// Next schedule time
}
Copy the code

So this is the argument we need to pass in

XxlUtil tools

XxlUtil

@Component
public class XxlUtil {

    /** * address */
    private final String adminAddress = "http://localhost:9999/xxl-job-admin";

    @Autowired(required = false)
    private final RestTemplate restTemplate = new RestTemplate();

    / / request Url
    private static final String ADD_INFO_URL = "/jobinfo/addJob";
    private static final String UPDATE_INFO_URL = "/jobinfo/updateJob";
    private static final String REMOVE_INFO_URL = "/jobinfo/removeJob";
    private static final String GET_GROUP_ID = "/jobgroup/loadByAppName";

    /** * Add task *@param xxlJobInfo
     * @param appName
     * @return* /
    public String addJob(XxlJobInfo xxlJobInfo, String appName){
        Map<String, Object> params = new HashMap<>();
        params.put("appName",appName);
        String json = JsonUtils.serialize(params);
        String result = doPost(adminAddress + GET_GROUP_ID, json);
        JSONObject jsonObject = JSON.parseObject(result);
        Map<String, Object> map  = (Map<String, Object>) jsonObject.get("content");
        Integer groupId = (Integer) map.get("id");
        xxlJobInfo.setJobGroup(groupId);
        String json2 = JSONObject.toJSONString(xxlJobInfo);
        return doPost(adminAddress + ADD_INFO_URL, json2);
    }

    /** * remote call *@param url
     * @param json
     */
    private String doPost(String url, String json) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(json,headers);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, entity, String.class);
        returnresponseEntity.getBody(); }}Copy the code

Here’s a look at the code

@param url @param json */ private String doPost(String url, String json) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> entity = new HttpEntity<>(json,headers); ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, entity, String.class); return responseEntity.getBody(); // This is how we make the remote call, we have the request URL, the second is the parameter and then the call returns the body informationCopy the code
Map<String, Object> params = new HashMap<>(); params.put("appName",appName); String json = JsonUtils.serialize(params); String result = doPost(adminAddress + GET_GROUP_ID, json); JSONObject jsonObject = JSON.parseObject(result); Map<String, Object> map = (Map<String, Object>) jsonObject.get("content"); Integer groupId = (Integer) map.get("id"); xxlJobInfo.setJobGroup(groupId); String json2 = JSONObject.toJSONString(xxlJobInfo); return doPost(adminAddress + ADD_INFO_URL, json2); There's an appName, so what's the appName-- the name of the executor, which executor is our task executed under first of all we need to look up the id of the executor by the name of the executor, In the corresponding database xxl_job_group id field We're xxl_job_info this table also can clearly see a job_group this field So we set it to xxlJobInfo, and then makes a remote call we add an interface, thus to realize the remote callsCopy the code

Where is this interface? In fact, we need to develop a new interface as well

Example Modify JobGroupController in xxl-job-admin

Add the following interfaces

@RequestMapping("/loadByAppName")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<XxlJobGroup> loadByAppName(@RequestBody Map<String,Object> map){
		XxlJobGroup jobGroup = xxlJobGroupDao.loadByAppName(map);
		returnjobGroup! =null?new ReturnT<XxlJobGroup>(jobGroup):new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);
	}
Copy the code

Continue to create methods under dao

XxlJobGroup loadByAppName(Map<String, Object> map);
Copy the code

Create a query statement

<select id="loadByAppName" parameterType="hashmap" resultMap="XxlJobGroup">
		SELECT <include refid="Base_Column_List" />
		FROM xxl_job_group AS t
		WHERE t.app_name = #{appName}
	</select>
Copy the code

So we have our actuator ID queried

Well, now that our remote call interface is written, we’ll write the local interface

First create the UserController

UserController

@RestController
@RequestMapping("codeworld-xxl")
public class XxlController {

    @Autowired(required = false)
    private XxlService xxlService;

    /** * Add task *@return* /
    @PostMapping("add-job")
    public FcResponse<Void> addJob(a){
        return this.xxlService.addJob(); }}Copy the code

Then UserService

UserService

public interface XxlService {
    /** * Add task *@return* /
    FcResponse<Void> addJob(a);
}
Copy the code

Then UserServiceImpl

UserServiceImpl

@Service
@Slf4j
public class XxlServiceImpl implements XxlService {

    @Autowired(required = false)
    private XxlUtil xxlUtil;

    /** * Add task **@return* /
    @Override
    public FcResponse<Void> addJob(a) {
        User user = new User();
        user.setId(1000L);
        user.setUserName("code");
        user.setCreateTime(new Date());
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobDesc("Test user periodically added");
        xxlJobInfo.setAuthor("admin");
        xxlJobInfo.setScheduleType("CRON");
        Date startTime = new Date(user.getCreateTime().getTime() + 60000);
        xxlJobInfo.setScheduleConf(DateUtils.getCron(startTime));
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setExecutorHandler("addUser");
        xxlJobInfo.setExecutorParam(JsonUtils.serialize(user));
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        xxlJobInfo.setTriggerStatus(1);
        xxlUtil.addJob(xxlJobInfo, "xxl-job-test");
        log.info("Task added, task will start at {}",DateUtil.date(startTime));
        return new FcResponse<>(1."Task added successfully".null); }}Copy the code

In this case, we specify to create the user directly, not the user but our XxlJobInfo

Xxljobinfo. setJobDesc(" Test user added periodically "); // Description xxljobinfo. setAuthor("admin"); / / executor xxlJobInfo setScheduleType (" CRON "); // The CRON expression Date startTime = new Date(user.getCreateTime().getTime() + 60000); / / on the creation time plus 1 minute xxlJobInfo setScheduleConf (DateUtils. GetCron (startTime)); // set cron xxljobinfo. setGlueType("BEAN"); / / set the type of GLUE to BEAN mode xxlJobInfo setExecutorHandler (" addUser "); / / set the task Handler name xxlJobInfo. SetExecutorParam (JsonUtils. Serialize (user)); / / set parameters xxlJobInfo. SetExecutorRouteStrategy (" FIRST "); / / actuator routing policy xxlJobInfo. SetMisfireStrategy (" DO_NOTHING "); / / scheduling expiry policies xxlJobInfo. SetExecutorBlockStrategy (" SERIAL_EXECUTION "); / / block processing policy xxlJobInfo. SetTriggerStatus (1); // Scheduling status: 0- stop, 1- run xxlutil. addJob(xxlJobInfo, "xxl-job-test"); // Call the toolclass method with xxl-job-test as the executor nameCopy the code

So at this point we’re done with the interface so how do we do the task

UserTask

UserTask

@Component
@Slf4j
public class UserTask {

    @XxlJob(value = "addUser")
    public ReturnT<String> addUser(String param){
        log.info("Start task, add user at specified time, received parameter {}, current time {}",param, DateUtil.date(new Date()));
        returnReturnT.SUCCESS; }}Copy the code

This is the way we perform a task, we can see in this @ XxxlJob (value = “addUser”) and parameters in xxlJobInfo setExecutorHandler (” addUser “); It’s one to one

Well here I yao all the details on the end

But having said all that, will it work?

practice

Start xxl-job-admin first

Start local projects

If you see this, XXL has loaded successfully

We need to create an executor named xxl-job-test

CodeWorld- Cloud-shop xxl-Job Guide – Nurse level teaching

Call interface

http://localhost:10001/codeworld-xxl/add-job So that means that the interface was successfully called and let’s go back to our consoleOur task has been added successfully and we wait 1 minute to see if the task will execute

Wow, looks like it worked, so here we go. Then the problem of the wheel cast graph is solved. The dynamic creation task realizes the online and offline code address of the wheel cast graph

Okay, so that’s it for this technical analysis, okay? Codeworld-cloud-shop light up the star if you like!!

Welcome to join QQ group (964285437)