SpringBoot集成XXL-JOB实现任务管理全流程

2025-08-20 10:50

本文主要是介绍SpringBoot集成XXL-JOB实现任务管理全流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl...

一、前言

XXL-JOB 是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展。本文介绍如何通过 Spring Boot 项目,使用 RestTemplate 和 Feign 的方式调用 XXL-JOB 后台管理接口,实现任务的全生命周期管理(包括添加、修改、启动、停止、删除、查询执行器、查询日志等操作)。

二、项目结构简述

主要包含三个部分:

  1. Controller:对外提供 REST 接口;
  2. Service:封装对 XXL-JOB 后台的具体调用逻辑;
  3. FeignClient(可选):用于部分接口远程调用。

三、Maven 依赖

只需引入 xxl-job-core 依赖(用于调度执行器 JobHandler 的注册等):

<!-- xxl-job 核心依赖 -->
<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.3.1</version>
</dependency>

四、Controller 代码详解

@androidRestController
@RequestMapping("/xxl")
public class XxlJobController {

    @Autowired
    private XxlJobService jobService;

    /**
     * 添加任务
     */
    @PostMapping("/add/job")
    public Map addJob(@RequestParam String user, @RequestParam String pass) {
        String cookie = jobService.login(user, pass);
        return jobService.createJob(cookie);
    }

    /**
     * 修改任务
     */
    @PostMapping("/update/job")
    public Map updateJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.updateJob(cookie, jobId);
    }

    /**
     * 删除任务
     */
    @PostMapping("/remove/job")
    public ResultModel removeJob(@RequestParam Integer jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.removeJob(cookie, jobId);
    }

    /**
     * 启动作业
     */
    @PostMapping("/start/job")
    public Map startJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.startJob(cookie, jobId);
    }

    /**
     * 停止作业
     */
    @Postwww.chinasem.cnMapping("/stop/job")
    public Map stopJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.stopJob(cookie, jobId);
    }

    /**
     * 获取执行器列表
     */
    @GetMapping("/jobgroups")
    public List<Map<String, Object>> getJobGroupList() {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobGroupList(cookie);
    }

    /**
     * 获取任务列表
     */
    @GetMapping("/tasks")
    public Map getJobList() {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobList(null, cookie);
    }

    /**
     * 获取任务日志
     */
    @PostMapping("/jobLogs")
    public Map getJobLogs(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobLogs(cookie, jobId);
    }
}

五、Service 接口设计

public interface XxlJobService {

    String login(String user, String pass);

    Map createJob(String cookie);

    Map updateJob(String cookie, String jobId);

    ResultModel removeJob(String cookie, Integer jobId);

    Map startJob(String cookie, String jobId);

    Map stopJob(String cookie, String jobId);

    List<Map<String, Object>> getJobGroupList(String cookie);

    Map getJobList(Integer jobGroup, String cookie);

    Map getJobLogs(String cookie, String jobId);
}

六、Service 实现详解

下面是部分关键实现说明。

1. 登录获取 Cookie

@Override
public String login(String user, String pass) {
    Response response = client.login("application/x-www-form-urlencoded", user, pass);
    Collection<String> cookies = response.headers().get("Set-Cookie");
    for (String cookie : cookies) {
        if (cookie.contains("XXL_JOB_LOGIN_IDENTITY")) {
            return cookie.split(";")[0];
        }
    }
    throw new RuntimeException("登录失败");
}
  • 使用 FeignClient 调用登录接口,提取 Cookie,用于后续请求认证。

2. 添加任务

@Override
public Map createJob(String cookie) {
    RestTemplate restTemplate = new RestTemplate();

    HttpHeaders headers = new HttpHeaders();
    headers.add("Cookie", cookie);

    MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
    paramMap.add("jobDesc", "定时任务");
    paramMap.add("scheduleConf", "0 */1 * * * ?");
    paramMap.add("executorHandler", "checkTimeout");
    paramMap.add("executorParam", "xxl-feign");
    paramMap.add("jobGroup", "1");
    paramMap.add("author", "admin");
    paramMap.add("scheduleType", "CRON");
    paramMap.add("glueType", "BEAN");
    paramMap.add("executorRouteStrategy", "FIRST");
    paramMap.add("misfireStrategy", "DO_NOTHING");
    paramMap.add("executorblockStrategy", "SERIAL_EXECUTION");

    HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(paramMap, headers);

    ResponseEntity<String> response = restTemplate.postForEntity(
        "http://xxl-job-host:port/xxl-job-admin/jobinfo/add", entity, String.class);

    return new ObjectMapper().readValue(response.getBody(), HashMap.class);
}
  • 替换 xxl-job-host:port 为你部署的地址;
  • 参数含义详见 XXL-JOB 后台手动添加任务页面。

3. 修改任务

@Override
public Map updateJob(String cookie, String jobId) {
    // 和添加类似,带上任务 ID 即可更新
}

4. 启动/停止任务

@Override
public Map startJob(String cookie, String jobId) {
    // 调用接口:/jobinfo/start
}
@Override
public Map stopJob(String cookie, String jobId) {
    // 调用接口:/jobinfo/stop
}

5. 获取执行器/任务/日志列表

  • /jobgroup/pageList:获取执行器;
  • /jobinfo/pageList:获取任务列表;
  • /joblog/pageList:查询任务日志。

七、统一响应模型(可选)

可以封装一个通用 ResultModel 响应类统一格式返回。

八、调用测试建议

可使用 Postman 测试每个接口,注意设置:

  • Content-Type 为 application/x-www-form-urlencoded
  • 传入正确的账号密码和参数值。

九、总结

通过本文提供的代码,你可以用 Java 实现对 XXL-JOB 管理后台的编程式控制,实现任务的全生命周期管理,非常适合自定义调度中心或自动化平台集成。

十、 完整代码

控制器层 XxlJobController.java

@RestController
@RequestMapping("/xxl")
public class XxlJobController {

    @Autowired
    private XxlJobService jobService;

    /**
     * 新增定时任务
     */
    @PostMapping("/add/job")
    public Map addJob(@RequestParam String user, @RequestParam String pass) {
        String cookie = jobService.login(user, pass);
        return jobService.createJob(cookie);
    }

    /**
     * 修改定时任务
     */
    @PostMapping("/update/job")
    public Map updateJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.updateJob(cookie, jobId);
    }

    /**
     * 删除定时任务
     */
    @PostMapping("/remove/job")
    public ResultModel removeJob(@RequestParam Integer jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.removeJob(cookie, jobId);
    }

    /**
     * 启动作业
     */
    @PostMapping("/start/job")
    public Map startJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.startJob(cookie, jobId);
    }

    /**
     * 停止作业
     */
    @PostMapping("/stop/job")
    public Map stopJob(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.stopJob(cookie, jobId);
    }

    /**
     * 获取执行器列表
     */
    @GetMapping("/jobgroups")
    public List<Map<String, Object>> getJobGroupList() {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobGroupList(cookie);
    }

    /**
     * 获取任务列表
     */
    @GetMapping("/tasks")
    public Map getJobList() {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobList(null, cookie);
    }

    /**
     * 查询任务日志
     */
    @PostMapping("/jobLogs")
    public Map getJobLogs(@RequestParam String jobId) {
        String cookie = jobService.login("admin", "123456");
        return jobService.getJobLogs(cookie, jobId);
    }
}

接口层:XxlJobService.java

public interface XxlJobService {

    /**
     * 登录获取 Cookie
     */
    String login(String user, String pass);

    /**
     * 创建任务
     */
    Map createJob(String cookie);

    /**
     * 修改任务
     */
    Map updateJob(String cookie, String jobId);

    /**
     * 删除任务
     */
    ResultModel removeJob(String cookie, Integer jobId);

    /**
     * 启动作业
     */
    Map startJob(String cookie, String jobId);

    /**
     * 停止作业
     */
    Map stopJob(String cookie, String jobId);

    /**
     * 查询执行器列表
     */
    List<Map<String, Object>> getJobGroupList(String cookie);

    /**
     * 查询任务列表
     */
    Map getJobList(Integer jobGroup, String cookie);

    /**
     * 获取任务日志
     */
    Map getJobLogs(String cookie, String jobId);
}

实现层:XxlJobServiceImpl.java

@Service
public class XxlJobServiceImpl implements XxlJobService {

    @Autowired
    private XxlJobFeignClient client;

    /**
     * 调用 XXL-JOB 登录接口,返回 Cookie
     */
    @Override
    public String login(String user, String pass) {
        Response response = client.login("application/x-www-form-urlencoded", user, pass);
        Collection<String> cookies = response.headers().get("Set-Cookie");
        if (cookies != null) {
            for (String cookie : cookies) {
                if (cookie.contains("XXL_JOB_LOGIN_IDENTITY")) {
                    // 截取真正的 cookie 值
                    // 只取第一个部分
                    return cookie.split(";")[0];
                }
            }
        }
        throw new RuntimeException("登录失败,未获取到认证 Cookie");
    }


    

    @Override
    public Map createJob(String cookie) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);
        MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("jobDesc", "定时任务");
        paramMap.add("scheduleConf",  "0 */1 * * * ?");
        paramMap.add("cronGen_display",  "0 */1 * * * ?");
        paramMap.add("schedule_conf_CRON",  "0 */1 * * * ?");
        paramMap.add("executorHandler", "checkTimeout");
        paramMap.add("executorParam", "xxl-feign");
        paramMap.add("jobGroup", "33");
        paramMap.add("author", "admin");
        paramMap.add("scheduleType", "CRON");
        paramMap.add("glueType", "BEAN");
        paramMap.add("executorRouteStrategy", "FIRST");
        paramMap.add("misfireStrategy", "DO_NOTHING");
        paramMap.add("executorBlockStrategy", "SERIAL_EXECUTION");
        paramMap.add("executorTimeout", "0");
        paramMap.add("executorFailRetryCount", "0");
        paramMap.add("glueRemark", "GLUE代码初始化");
        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(paramMap, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin/jobinfo/add", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (jsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 修改任务(如修改调度频率等)
     */
    @Override
    public Map updateJob(String cookie, String jobId) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);
        MultiValueMap<String, String> job = new LinkedMultiValueMap<>();
        job.add("id", jobId);
        job.add("jobGroup", "1");
        job.add("jobDesc", "修改任务");
        job.add("author", "admin");
        job.add("scheduleType", "CRON");
        // 改为每5分钟执行
        job.add("scheduleConf", "0 */5 * * * ?");
        job.add("executorRouteStrategy", "ROUND");
        job.add("executorHandler", "demoJobHandler");
        job.add("executorParam", "param-updated");
        job.add("executorBlockStrategy", "SERIAL_EXECUTION");
        job.add("glueType", "BEAN");
        job.add("misfireStrategy", "DO_NOTHING");

        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(job, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin/jobinfo/update", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除任务
     */
    @Override
    public ResultModel removeJob(String cookie, Integer jobId) {
        return client.removeJob(cookie, jobId);
    }

    /**
     * 启动作业
     */
    @Override
    public Map starhttp://www.chinasem.cntJob(String cookie, String jobId) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);

        MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("id", jobId);

        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(paramMap, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin//jobinfo/start", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 停止作业
     */
    @Override
    public Map stopJob(String cookie, String jobId) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);

        MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("id", jobId);

        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(paramMap, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin//jobinfo/stop", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;

    }


    @Override
    public List<Map<String, Object>> getJobGroupList(String cookie) {
        // 调用 Feign 客户端获取执行器列表
        Map<String, Object> response = client.getJobGroups(cookie, 0, 100);
        // 从返回结果中获取执行器数据列表
        return (List<Map<String, Object>>) response.get("data");
    }

    @Override
    public Map getJobList(Integer jobGroup, String cookie) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);

        MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
        parameters.add("jobGroup", "33");
            // 表示全部
        parameters.add("triggerStatus","-1");

        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(parameters, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin/jobinfo/pageList", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
        }

    @Override
    public Map getJobLogs(String cookie, String jobId) {
        RestTemplate restTemplate = new RestTemplate();

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cookie", cookie);

        // 构建查询参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        //执行器id(必传)
        params.add("jobGroup", "33");
        //任务状态(必传)
        params.add("logStatus", "-1");
        // 任务ID
        params.add("jobId", jobId);
        // 当前页码
        params.add("pageNum", "1");
        // 每页大小
        params.add("pageSize", "10");

        // 调用 Feign 客户端的查询日志接口
//        return client.getJobLogs(cookie, params);


        // 创建 HttpEntity 实例,包含请求头和参数
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);

        // 发送 POST 请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://192.168.1.xxx:8080/xxl-job-admin//joblog/pageList", entity, String.class);

        // 解析响应为 HashMap
        try {
            return new ObjectMapper().readValue(response.getBody(), HashMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

Feign 客户端:XxlJobFeignClient.java

@FeignClient(name = "xxlJobClient", url = "http://192.168.1.xxx:8080/xxl-job-admin")
public interface XxlJobFeignClient {
    /**
     * 登录接口,必须先调用获取 Cookie 才能访问其它接口
     */
    @PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    Response login(@RequestHeader("Content-Type") String contentType,
                   @RequestParam("userName") String userName,
                   @RequestParam("password") String password);

    /**
     * 新建任务接口
     */
    @PostMapping("/jobinfo/add")
    ResultModel addJob(@RequestHeader("Cookie") String cookie,
                       @RequestBody Map<String, Object> jobInfo);

    /**
     * 更新任务接口
     */
    @PostMapping("/jobinfo/update")
    ResultModel updateJob(@RequestHeader("Cookie") String cookie,
                          @RequestBody Map<String, Object> jobInfo);

    /**
     * 删除任务接口
     */
    @PostMapping("/jobinfo/remove")
    ResultModel removeJob(@RequestHeader("Cookie") String cookie,
                          @RequestParam("id") Integer jobId);

    /**
     * 启动任务接口
     */
    @PostMapping("/jobinfo/start")
    ResultModel startJob(@RequestHeader("Cookie") String cookie,
                         @RequestParam("id") Integer jobId);

    /**
     * 暂停任务接口
     */
    @PostMapping("/jobinfo/stop")
    ResultModel stopJob(@RequestHeader("Cookie") String cookie,
                        @RequestParam("id") Integer jobId);


    /**
     * 查执行器列表接口
     * @param cookie
     * @param start
     * @param length
     * @return
     */
    @GetMapping("/jobgroup/pageList")
    Map<String, Object> getJobGroups(@RequestHeader("Cookie") String cookie,
                                     @RequestParam("start") int start,
                                     @RequestParam("length") int length);


    /**
     * 获取任务列表
     * @param cookie 登录时获得的 Cookie
     * @param params 请求参数
     * @return 任务列表
     */
    @PostMapping("/jobinfo/pageList")
    ResultModel getJobList(@RequestHeader("Cookie") String coopythonkie, @RequestParam  Map<String, Object> params);

    /**
     * 查询日志
     * @param cookie
     * @param params
     *编程 @return
     */
    @PostMapping("/joblog/pageList")
    ResultModel getJobLogs(@RequestHeader("Cookie") String cookie, @RequestBody MultiValueMap<String, String> params);
}

以上就是SpringBoot集成XXL-JOB实现任务管理全流程的详细内容,更多关于SpringBoot XXL-JOB任务管理的资料请关注China编程(www.chinasem.cn)其它相关文章!

这篇关于SpringBoot集成XXL-JOB实现任务管理全流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155828

相关文章

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

Java中的stream流分组示例详解

《Java中的stream流分组示例详解》Java8StreamAPI以函数式风格处理集合数据,支持分组、统计等操作,可按单/多字段分组,使用String、Map.Entry或Java16record... 目录什么是stream流1、根据某个字段分组2、按多个字段分组(组合分组)1、方法一:使用 Stri

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装