简介:一套基于Java技术栈开发的物流运输管理系统源码包,面向物流企业、Java开发者和需要项目实战的中高级学习者。系统覆盖订单管理、车辆管理、路线规划、货物追踪、费用计算、报表分析、合同管理与客户服务等核心模块,可支撑货车快运业务的完整流程,具备配置后即可运营的成熟度。技术层面采用Java与MySQL构建,后端体现Spring Boot/MVC分层架构与ORM持久化设计,前端使用Bootstrap实现响应式界面,源码结构清晰,便于按模块二次开发。资源包约184.67MB,包含完整项目源码及运行所需的相关配置,导入IDE后按实际环境配置数据库连接即可启动,适合作为TMS系统设计参考、毕业设计原型或Java Web工程实践素材。对于希望深入理解物流运输业务信息化、快速搭建运输管理原型的人来说,这套代码能直接提供可运行的业务骨架。目前已有1162人学习下载。
1. 物流运输管理系统java.zip到底在交付什么:从一份源码包看运输项目的使用起点
你从网上下载了一个物流运输管理系统java.zip,大概率遇到的是这样的场景:文件解压后是一堆包名很深的 Java 源码,配一个残缺的 SQL 脚本,README 要么没有、要么写着一句“导入IDEA,改数据库配置即可运行”。这个 zip 里装的通常是一套以 Spring Boot + MyBatis 为骨架的运输管理后台,覆盖运输订单、车辆档案、司机信息、运单派发和签收记录这些核心链路。它能帮你解决的是:不用从零设计表结构,直接在一个现成的 Java 工程上做二次开发,把公司的线下运输流程搬到系统里。适合三类人——接手毕业设计或二手项目的初级 Java 工程师、打算快速搭一套内部运输系统的小团队、以及想搞清楚物流运输业务在代码里长什么样的学习者。
这套系统真正的难点不在登录、CRUD 这些表层功能,而在运输业务的状态流转:一张订单从“待调度”变成“运输中”,再变成“已签收”,每一步都牵扯到车辆空闲状态、司机任务分配、轨迹记录的一致性。你打开源码包之后,第一步不是急着点运行,而是先弄明白这个 zip 里的代码结构,和你脑子里的运输业务流程能不能对上号。
2. 拿到zip先别急着点运行:用目录树对齐项目骨架与运输业务数据流
2.1 解压前的文件体检:用 unzip 与 jar 命令快速判断 zip 包内容
java.zip这种交付物最容易出的问题是外层套目录。你明明只想要一个工程目录,解压后却得到两层嵌套,导入 IDEA 时选错了根目录,Maven 直接解析不到pom.xml。所以解压前我会先看一眼压缩包内部结构:
# 先看 zip 里有没有套一层外层目录,避免解压出一堆散文件 unzip -l logistics-transport-management-system.zip | head -40# Windows 上没有 unzip 时,用 JDK 自带的 jar 命令也能列 zip 内容 jar tf logistics-transport-management-system.zip | head -40unzip -l输出的是压缩包内所有文件的路径和原始大小,head -40只截前 40 行够看目录结构了。jar tf是 JDK 自带的列出压缩包内容的命令,效果一样,适合你没装解压工具时应急。看的时候重点判断三件事:第一,所有文件路径是否都带同一个前缀目录;第二,有没有sql/或db/目录,里面放着初始化脚本;第三,根目录有没有README.md。如果这三样全没有,这个包跑起来会相当难受。带前缀目录不是坏事,解压时用unzip -d ./work指定一个目标目录,把最外层那层壳去掉,工程根目录就能直接定位到pom.xml。
2.2 标准 Maven 骨架里,运输业务的分层往哪放
解压完落到 IDEA 里,你看到的应该是一个标准 Maven 工程。我一般先扫一眼目录树,心里把每个包对应到运输业务上一个角色:
work/logistics-transport-management ├── pom.xml ├── sql/ │ └── init.sql # 数据库初始化脚本,有些包里没有,没有就按第3章自己建 ├── src/main/java/com/transit/ │ ├── controller/ # 接 HTTP 请求,只做参数接收与结果转换 │ │ ├── OrderController.java │ │ ├── VehicleController.java │ │ └── DriverController.java │ ├── service/ # 业务规则,调度、状态流转都在这层 │ ├── mapper/ # MyBatis 数据访问层,一个接口对一张表 │ ├── entity/ # 和数据库表一一对应的实体 │ ├── dto/ # 页面入参/接口出参对象 │ ├── config/ # 跨域、拦截器、MyBatis-Plus 配置 │ └── TransitApplication.java # Spring Boot 启动类 ├── src/main/resources/ │ ├── application.yml │ ├── mapper/*.xml # 手写 SQL 的 XML 文件 │ └── static/ 或 templates/ # 前端页面或打包后的 dist └── README.md分层的核心逻辑是 controller 保持薄,service 承担业务规则,mapper 只做数据读写。运输系统里最容易写乱的是 service 层:创建运单时既要改订单状态为“已调度”,又要更新车辆为“出车中”,还要给司机生成一条任务记录,这三件事必须在一个事务里完成。如果代码把逻辑写在 controller 里,后面加需求会让你改到怀疑人生。看到entity下字段命名是驼峰风格,而表字段是下划线风格,就能判断出项目里大概率配了 MyBatis-Plus 的驼峰映射,这也是这类 zip 源码包最常见的技术选型。
2.3 运输业务的数据流:从订单、调度到轨迹,模块之间怎么咬合
物流运输管理系统的业务主线不复杂,但表与表之间的关系要理清。一张transport_order(运输订单)记录客户诉求:谁发的货、从哪里到哪里、运什么、运费多少。调度员创建waybill(运单)时,把订单、车辆、司机绑定在一起。司机出车后在waybill_track(运单轨迹)里按时间点上报位置和状态。最后客户签收,运单状态置为“已签收”,订单状态跟着变为“已完成”。
很多人看源码时只盯着单个 Controller 的接口,却忽略了这个流程,结果改一个功能牵动三张表的数据不一致。最典型的翻车是:订单状态改成了“已调度”,但车辆状态没人更新,导致同一辆车被重复派给两个运单。所以拿到源码后,先画一遍这条链路,再去看 service 层的@Transactional注解加在哪些方法上,比对代码逻辑和业务预期是否一致。目录树对你最大的价值就在这——它让你在 reading 代码之前,先建立起一个“这个系统应该长什么样”的地图,后面每个类都只是地图上的一个点。
3. 数据库立起来:MyBatis-Plus 实体类反推建表语句与运输核心表拆分
3.1 用 MyBatis-Plus 反射实体类生成建表语句,避免手写 SQL 和实体脱节
很多 zip 包里的 SQL 脚本是残缺的,或者表结构和你本地的实体类对不上。这时候与其对着实体类一个个手写CREATE TABLE,不如让代码自己生成。MyBatis-Plus 提供TableInfoHelper,能从实体类上读取@TableName、@TableId、字段类型这些元数据,配合 Spring 的JdbcTemplate就能在应用启动时自动补建缺失的表。这个做法适合开发环境和拿到项目后第一次初始化,生产环境还是建议用 Flyway 这类迁移工具来管理。下面是我常用的启动建表 Runner:
@Component public class TableCreateRunner implements ApplicationRunner { private final JdbcTemplate jdbcTemplate; public TableCreateRunner(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void run(ApplicationArguments args) { // 数组顺序就是建表依赖顺序,先建子表再建主表 String[] entities = {"WaybillTrack", "TransportOrder", "Vehicle", "Driver", "Waybill"}; for (String name : entities) { createTableIfAbsent(name); } } private void createTableIfAbsent(String className) { try { Class<?> clazz = Class.forName("com.transit.entity." + className); TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz); if (tableInfo == null) { return; // 实体类没被 MyBatis-Plus 扫描到,得先在启动类加 @MapperScan } Integer count = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?", Integer.class, tableInfo.getTableName()); if (count != null && count > 0) { return; // 表已存在,跳过,保证重复启动不报错 } String ddl = buildCreateSql(tableInfo); jdbcTemplate.execute(ddl); } catch (ClassNotFoundException ignored) { } } // buildCreateSql 方法体见下方说明 }这段代码的核心是TableInfoHelper.getTableInfo(clazz),它会解析实体类上的注解,拿到真实表名、字段列表、主键策略。information_schema.tables用来判断表是否存在,避免每次启动都报“表已存在”。buildCreateSql需要你自己实现一个类型映射——把 Java 的Long映射成BIGINT,String映射成VARCHAR(120),BigDecimal映射成DECIMAL(12,2),LocalDateTime映射成DATETIME,然后拼出完整的 DDL。这块有个血泪经验:字段统一 NOT NULL 会让 update 时传 null 直接报错,生成时给可空字段留空就行;VARCHAR 长度 120 对地址字段绝对不够,地址列建完表后要手动扩到 255。这个 Runner 放在config包里,启动类上别忘了@MapperScan("com.transit.mapper"),否则TableInfoHelper扫描不到实体类,代码会静默跳过。
3.2 运输核心表怎么拆:订单、车辆、司机、运单、轨迹五张表的职责边界
拆表的原则说起来就一句话:把变化的频率作为拆分依据。客户信息、车辆信息、司机信息属于基础档案,变化慢,独立成表;运输订单记录业务诉求,变化快;运单把订单和资源绑定,一张订单可以拆成多个运单(比如一车装不下拆两车);轨迹数据只增不改,所以单独放一张表,避免和运单主表混在一起导致行变宽、查询变慢。下面这套建表 SQL 是运输管理系统最常见的最小集:
CREATE DATABASE IF NOT EXISTS transit_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE transit_db; CREATE TABLE transport_order ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '订单号', customer_name VARCHAR(64) NOT NULL COMMENT '客户名称', start_address VARCHAR(255) NOT NULL COMMENT '起始地', end_address VARCHAR(255) NOT NULL COMMENT '目的地', goods_name VARCHAR(64) COMMENT '货物名称', freight DECIMAL(12,2) DEFAULT 0 COMMENT '运费', status TINYINT DEFAULT 0 COMMENT '0待调度 1已调度 2已完成', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, deleted TINYINT DEFAULT 0 COMMENT '逻辑删除', KEY idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运输订单表'; CREATE TABLE vehicle ( id BIGINT AUTO_INCREMENT PRIMARY KEY, plate_no VARCHAR(16) NOT NULL UNIQUE COMMENT '车牌号', vehicle_type VARCHAR(32) COMMENT '车型', max_load DECIMAL(10,2) DEFAULT 0 COMMENT '最大载重(吨)', status TINYINT DEFAULT 0 COMMENT '0空闲 1出车 2维修', KEY idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆表'; CREATE TABLE driver ( id BIGINT AUTO_INCREMENT PRIMARY KEY, driver_name VARCHAR(64) NOT NULL, phone VARCHAR(16) NOT NULL, license_no VARCHAR(32) COMMENT '驾驶证号', status TINYINT DEFAULT 0 COMMENT '0空闲 1在途 2休假', KEY idx_phone (phone) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='司机表'; CREATE TABLE waybill ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_id BIGINT NOT NULL COMMENT '关联 transport_order.id', vehicle_id BIGINT NOT NULL, driver_id BIGINT NOT NULL, status TINYINT DEFAULT 0 COMMENT '0待出车 1运输中 2已签收', plan_depart_time DATETIME, actual_arrive_time DATETIME, KEY idx_order_id (order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运单表'; CREATE TABLE waybill_track ( id BIGINT AUTO_INCREMENT PRIMARY KEY, waybill_id BIGINT NOT NULL, lng DECIMAL(10,6) COMMENT '经度', lat DECIMAL(10,6) COMMENT '纬度', report_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '上报时间', remark VARCHAR(255) COMMENT '备注,如"已到达xx仓库"', KEY idx_waybill_time (waybill_id, report_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运单轨迹表';五张表的字段设计有几个值得留意的点。waybill里没有冗余客户名和起止地址,查询时 JOINtransport_order拿,避免客户改地址时运单历史被篡改,这是运输系统的一个常见坑。vehicle和driver都有独立的status字段,调度时用SELECT ... WHERE status = 0筛可用资源,提交运单时再 UPDATE 成“出车/在途”,这两步必须在同一个事务里,否则会出现资源超卖。轨迹表的(waybill_id, report_time)联合索引是为了支撑“查某个运单的时间线”这个高频查询,单查waybill_id时这个索引也能命中前缀。
3.3 初始化数据:先灌司机、车辆和客户,系统才有东西可调度
建完表后第一件事是灌基础档案,否则页面打开后所有下拉框都是空的,调度功能完全没法验证。初始化数据我一般用 SQL 脚本直接 INSERT,不用代码生成。因为基础数据的值域很稳定,写死在sql/目录里方便重复执行;而业务数据(订单、运单)必须通过接口创建,直接插库容易把状态字段搞乱。初始化脚本长这样:
INSERT INTO driver (driver_name, phone, license_no, status) VALUES ('张师傅', '13800001111', 'A123456789', 0), ('李师傅', '13800002222', 'B987654321', 0); INSERT INTO vehicle (plate_no, vehicle_type, max_load, status) VALUES ('京A12345', '厢式货车', 5.0, 0), ('京A67890', '平板货车', 8.0, 0); INSERT INTO transport_order (order_no, customer_name, start_address, end_address, goods_name, freight, status) VALUES ('SO2024001', '华科电子', '北京市朝阳区', '天津市武清区', '电子元器件', 1200.00, 0);这些 INSERT 语句的注意点集中在状态字段上。司机和车辆的状态必须从 0(空闲)开始,因为后续调度逻辑会假设“状态为 0 才算可用”。订单的order_no在真实系统里通常由一个编号规则生成,比如“SO + 年月日 + 流水号”,你在这个 zip 包的后台代码里很可能能看到对应的工具类。如果源码包里自带sql/init.sql,先用它来初始化,再用show tables比对一下有没有缺表;缺表才轮得到 3.1 说的 Runner 上场,这个顺序能省掉大半截对字段的精力。
4. 本地跑通最小链路:JDK、MySQL、IDEA 三个环节的版本与参数设置
4.1 版本选型:先看 pom.xml 再决定 JDK,别凭感觉装
运输管理系统 java 源码最让人头疼的问题是版本错位。很多 zip 包是两三年前写的,用的 Spring Boot 2.x 必须跑在 JDK 8 上;你本地装了 JDK 17,启动时直接报UnsupportedClassVersionError。所以选型的第一原则是:打开pom.xml,看<parent>里的spring-boot-starter-parent版本和<java.version>标签,它写 1.8 你就老老实实装 JDK 8,它写 17 你用 JDK 17。
| 场景 | 建议组合 | 为什么这么选 |
|---|---|---|
| pom 里 java.version 是 1.8 | JDK 8 + Spring Boot 2.x + MySQL 5.7/8.0 | 和项目编译目标完全对齐,lombok 老版本也能跑 |
| pom 里是 Spring Boot 3.x | JDK 17 + Spring Boot 3.x + MySQL 8.0 | Spring Boot 3 强制 JDK 17,且javax.*全部换成jakarta.* |
| 包里有 Dockerfile 或 CI 配置 | 照着里面镜像的 JDK 版本装 | 作者能跑通的环境大概率就是它 |
MySQL 相对宽容,5.7 和 8.0 都能连,只要 JDBC 驱动别太老。这个表是给“拿不准用什么版本”的人用的,实际上你每换一个环境组合,都可能踩到不同的坑:JDK 8 + 新版 MySQL 驱动会因加密插件握手上报Public Key Retrieval is not allowed;JDK 17 + 老版 lombok 会直接InaccessibleObjectException。选型省下来的时间,后面排错都要还回去。
4.2 application.yml 里的三组必调参数:数据源、端口、MyBatis-Plus
打开src/main/resources/application.yml,先找到spring.datasource。这个 zip 包作者留在里面的大概率是本地测试库的地址,你要换成自己机器的。下面是这套运输系统最常见的配置形态:
server: port: 8080 servlet: context-path: /transit spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/transit_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: mapper-locations: classpath:mapper/*.xml global-config: db-config: id-type: auto logic-delete-field: deleted configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl三组参数各说一个容易翻车的地方。第一组数据源里,driver-class-name8.x 驱动必须写com.mysql.cj.jdbc.Driver,老写法com.mysql.jdbc.Driver在新驱动下直接启动失败;serverTimezone=Asia/Shanghai不写的话,Java 8 以后连接 MySQL 8 会报时区错误,页面上的创建时间差 8 小时也多半是这个引起的。第二组context-path: /transit决定了所有接口要带/transit前缀,前端页面里的 Ajax 请求如果写的是相对路径没问题,写绝对路径且忘了带前缀就会全部 404。第三组 MyBatis-Plus 配置里,logic-delete-field: deleted对应你表里的deleted字段,加上之后,MyBatis-Plus 的查询会自动追加AND deleted = 0,但手写在 XML 里的 SQL 不受这个保护,这是个隐蔽的坑——很多人删了数据查不出来,是因为逻辑删除字段没配,删除变成了 UPDATE。
log-impl值得单独说。设为StdOutImpl后,控制台会打印每条 SQL 和参数,这在调试运输调度逻辑时极其有用;但它也会刷屏,线上部署时改成org.apache.ibatis.logging.slf4j.Slf4jImpl走日志框架。改配置的套路是:每次只改一个变量,启动一次,失败了看错误堆栈,别一次改七八处。
4.3 启动的三种方式:IDEA、Maven 命令、打包后 java -jar
配置改完,启动方式决定了你在哪个阶段遇到问题。开发调试时在 IDEA 里直接运行TransitApplication最方便,但前提是 Project Structure 里把 SDK 切到 4.1 选定的版本;命令行更可控,适合把启动参数写进脚本里分发。三种方式覆盖的场景不同:
# 方式一:Maven 直接跑,适合开发环境快速验证 mvn spring-boot:run # 方式二:打包后跑 jar,适合验收环境和部署 mvn clean package -DskipTests java -jar target/transit-0.0.1-SNAPSHOT.jar # 方式三:用命令行参数临时覆盖端口,不用改文件 java -jar target/transit-0.0.1-SNAPSHOT.jar --server.port=8081 --spring.datasource.password=654321第三种方式是解决端口冲突和共用测试库的后悔药。两个同事同时调试,数据库密码不一样,又不想互相改配置文件,就在启动命令后面追加--spring.datasource.password=xxx,Spring Boot 的命令行参数优先级高于application.yml,不用动文件就能覆盖。启动成功后访问http://localhost:8080/transit/,看到登录页或接口文档页,说明最小链路已经通了。如果启动失败,先把log-impl打开看 SQL 执行到哪一步,再回到第 5 章对照常见坑逐个排查。
5. 常见问题排查:运输管理系统启动失败的五个高频坑
5.1 端口被占用:启动日志报Port 8080 was already in use
现象:Spring Boot 启动到 Tomcat 初始化那一步直接失败,日志末尾写着Web server failed to start. Port 8080 was already in use.。原因:本机某个进程已经占用了 8080,最常见的是另一个 Java 进程、Nginx 或者之前启动过的残留 jar 包。解决:先找到占用进程,确认不是别人的服务再处理。
# Windows 下查看 8080 被谁占用 netstat -ano | findstr 8080 # 结果最后一列是 PID,杀掉对应进程 taskkill /PID <PID> /FLinux 上把netstat换成ss -lntp | grep 8080再kill -9。这个坑看着基础,但我见过有人因此重装 IDEA、重装 MySQL,最后才发现是上次没关掉的旧进程。更省事的做法是启动命令直接加--server.port=8081,绕过占用。
5.2 数据库连不上:Access denied for user 'root'@'localhost'或通信链路异常
现象:启动时数据源初始化失败,报Access denied,或者Communications link failure。前者是账号密码/权限问题,后者是 MySQL 没启动或端口不对。我排查时的顺序是:先确认 MySQL 服务真的起来了(Windows 服务列表或mysqladmin ping),再确认账号密码在 MySQL 客户端能登录,最后才怀疑驱动的 URL 参数。解决Access denied时,优先用命令行参数覆盖而不改 yml,比如上面 4.3 写的--spring.datasource.username=root --spring.datasource.password=xxx。如果是 MySQL 8 的caching_sha2_password认证导致驱动握手失败,URL 里加上allowPublicKeyRetrieval=true,这个参数不加,Navicat 能连而 Java 连不上的场景非常典型。
5.3 中文乱码:控制台输出乱码,页面数据也乱码
现象:日志里的中文显示成???,或者页面上查出来的司机姓名、地址全是乱码。原因通常不在一个地方,而是三处之一:IDEA 的 Run Configuration 没有加-Dfile.encoding=UTF-8;Maven 编译时源码编码不是 UTF-8;数据库连接 URL 里没带characterEncoding=utf8。这个坑的玄学之处在于,开发环境正常、部署到服务器才乱码,多半是服务器系统默认编码是 GBK。解决要做全,漏一个都会复发:
<!-- pom.xml 里固定源码编码,和 IDE 解耦 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>数据库表在建表时已经用了utf8mb4,连接 URL 也带了编码参数,再把 IDEA 的 File Encodings 三处全改成 UTF-8,这个坑基本踩不到。注意 MySQL 的utf8mb4和utf8不是一回事,前者才是完整的中文支持。
5.4 MyBatis 报Invalid bound statement (not found)
现象:接口一调用就报Invalid bound statement (not found): com.transit.mapper.WaybillMapper.selectByOrderId,但 Mapper 接口和 XML 文件都存在于项目里。原因有三个:application.yml里mybatis-plus.mapper-locations没配或路径写错;XML 文件的 namespace 和接口全限定名不一致;XML 文件根本没打进编译目录。解决时先看 target/classes 下有没有对应 XML,没有的话是 Maven 默认不拷贝src/main/java下的 XML,要在 pom 里加resources配置把**/*.xml包含进来;有的话核对 namespace。这个坑最气人的地方是启动不报错,一调用才暴露,排查时盯着报错里的方法名去 XML 里搜id是最快的定位方式。
5.5 JDK 版本与 lombok 不兼容:启动直接报InaccessibleObjectException
现象:用 JDK 17 跑老项目,启动阶段报java.lang.reflect.InaccessibleObjectException: Unable to make field private ... accessible。原因:新版 JDK 对反射做了强封装,老版本 lombok(1.18.20 以前)访问内部 API 被拦。解决优先换 JDK 8 而不是升 lombok——因为项目里其他依赖可能也不兼容 JDK 17,换一个版本会牵一发动全身。这一步属于典型的“版本选型”教训:不要在没看 pom 之前就装新环境,JDK 不是越新越好,和项目匹配才最好。如果一定要 JDK 17,就把 lombok 升到 1.18.30 以上,并确认 Spring Boot 版本是 2.7+。
6. 进阶改造:给运单加一条轨迹查询,顺手验证整条链路的可扩展性
跑通之后,别急着做花哨功能,先给系统加一个最小的增量功能——运单轨迹查询。这个功能能验证你前面搭的 mapper、service、controller 链路是否通顺,也能暴露表设计里索引够不够用。做法是给waybill_track加一个按运单查时间线的接口,SQL 挂在 XML 里比 MyBatis-Plus 的 LambdaQueryWrapper 更直观:
SELECT id, waybill_id, lng, lat, report_time, remark FROM waybill_track WHERE waybill_id = #{waybillId} ORDER BY report_time ASC// Mapper 接口加一个方法 public interface WaybillTrackMapper extends BaseMapper<WaybillTrack> { List<WaybillTrack> selectTrackByWaybillId(@Param("waybillId") Long waybillId); }Controller 接查询参数,service 里把结果按时间顺序返回,前端在地图组件上把这些点连成线,一套链路就通了。这个改造最值得做的意义在于:你会发现改一个功能涉及的点有多少——XML、Mapper 接口、Service、Controller、前端页面对应的 JS,五处改动缺一处页面就白屏。所以做完这个功能后,你的第一手经验是“原来这个 zip 的每一层都耦合得这么紧”。我早年的教训是拿到一个二手项目先埋头读三个小时代码,最后才发现数据库连接串根本不对,连一次都没跑起来——从此养成的习惯是先点亮系统,再做任何改造,这个顺序能救大多数人半天时间。希望这个顺序也能帮到你,先把系统跑起来,再谈优化和扩展。
本文还有配套的精品资源,点击获取