基于SSM框架的货车运输调度管理系统 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQLFreemarker
2026-03-014 浏览

文章摘要

本项目是一款基于SSM(Spring+Spring MVC+MyBatis)框架构建的货车运输调度管理系统,旨在为物流运输企业提供高效、精准的车辆调度与数据一体化管理解决方案。系统核心解决了传统物流调度中依赖人工经验、信息传递滞后、运力资源分配不均等关键痛点,通过数字化手段将车辆状态、运输任务、司机...

在物流行业高速发展的今天,高效、精准的车辆调度与数据管理已成为企业提升核心竞争力的关键。传统依赖人工电话沟通、纸质单据传递的调度模式,不仅效率低下、错误率高,更难以对分散的运力资源进行全局优化,导致车辆空驶率高、运营成本难以控制。针对这些行业痛点,我们设计并实现了一套基于SSM(Spring + Spring MVC + MyBatis)技术栈的智能货车运输调度管理平台,旨在通过数字化、系统化的手段,为物流企业提供一体化的解决方案。

该系统严格遵循软件工程的高内聚、低耦合原则,采用经典的三层架构模式。Spring Framework作为项目的核心控制容器,负责管理所有业务对象(Bean)的生命周期,并通过其强大的依赖注入(DI)和控制反转(IoC)特性,解耦了组件间的依赖关系。同时,Spring的声明式事务管理为系统核心业务操作,如运单创建、状态更新、费用结算等,提供了可靠的数据一致性保障。表现层由Spring MVC框架支撑,它清晰地划分了控制器(Controller)、服务层(Service)和数据访问层(DAO),使得请求路由、参数绑定、视图渲染等流程井然有序。数据持久化层则选用MyBatis框架,其灵活的SQL映射能力,无论是简单的CRUD操作,还是涉及多表关联、动态条件的复杂查询,都能通过XML配置文件或注解方式优雅地实现,极大提升了开发效率和SQL的可控性。前端界面采用JSP结合jQuery、Bootstrap等前端库进行构建,确保了用户交互的流畅性与界面的美观性。

数据库架构设计与核心表解析

一个稳健的后台系统离不开精心设计的数据库模型。本系统共设计了37张数据表,构建了覆盖用户、车辆、运单、财务等所有业务维度的完整数据模型。以下重点分析几个核心表的设计亮点。

1. 运单表(waybill) 运单是系统的核心业务实体,其表结构设计直接关系到调度业务的准确性和效率。

CREATE TABLE `waybill` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '运单ID',
  `order_number` varchar(64) NOT NULL COMMENT '运单号',
  `shipper_id` int(11) NOT NULL COMMENT '发货方ID',
  `consignee_id` int(11) NOT NULL COMMENT '收货方ID',
  `truck_id` int(11) DEFAULT NULL COMMENT '指派车辆ID',
  `driver_id` int(11) DEFAULT NULL COMMENT '指派司机ID',
  `cargo_name` varchar(255) NOT NULL COMMENT '货物名称',
  `cargo_weight` decimal(10,2) NOT NULL COMMENT '货物重量(吨)',
  `planned_departure_time` datetime DEFAULT NULL COMMENT '计划发车时间',
  `actual_departure_time` datetime DEFAULT NULL COMMENT '实际发车时间',
  `planned_arrival_time` datetime DEFAULT NULL COMMENT '计划到达时间',
  `actual_arrival_time` datetime DEFAULT NULL COMMENT '实际到达时间',
  `transport_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '运输状态(0:待调度 1:已派车 2:运输中 3:已到达 4:已签收 5:已取消)',
  `freight` decimal(12,2) DEFAULT NULL COMMENT '运费',
  `remark` text COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_number` (`order_number`),
  KEY `idx_truck_id` (`truck_id`),
  KEY `idx_driver_id` (`driver_id`),
  KEY `idx_status` (`transport_status`),
  KEY `idx_departure_time` (`planned_departure_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运单表';

设计亮点分析:

  • 状态驱动设计transport_status字段使用TINYINT类型定义了清晰的运单生命周期(0-5),所有业务逻辑都围绕状态流转展开,如从“待调度”到“已派车”意味着资源分配完成。这种设计使得流程控制非常清晰。
  • 时空信息完备:表结构同时记录了计划和实际的发车、到达时间(planned_departure_time, actual_arrival_time等)。这为后续计算准点率、分析运输效率提供了关键数据基础。
  • 索引优化:针对高频查询场景,建立了复合索引。例如,idx_statusidx_departure_time可以高效支持调度员查询“所有待调度的今日运单”。uk_order_number唯一索引确保了运单号的全局唯一性,防止重复录入。
  • 财务信息集成freight字段的存在,将业务操作与财务结算紧密关联,体现了业务闭环的设计思想。

2. 车辆信息表(truck) 车辆作为最重要的运力资源,其信息管理需要兼顾静态属性与动态状态。

CREATE TABLE `truck` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '车辆ID',
  `license_plate` varchar(32) NOT NULL COMMENT '车牌号',
  `vehicle_model` varchar(64) NOT NULL COMMENT '车辆型号',
  `max_load` decimal(8,2) NOT NULL COMMENT '最大载重(吨)',
  `volume` decimal(8,2) NOT NULL COMMENT '容积(立方米)',
  `current_location` varchar(255) DEFAULT NULL COMMENT '当前位置',
  `gps_device_id` varchar(128) DEFAULT NULL COMMENT 'GPS设备ID',
  `maintenance_due_date` date DEFAULT NULL COMMENT '下次保养日期',
  `insurance_expiry_date` date DEFAULT NULL COMMENT '保险到期日',
  `operational_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '运营状态(1:可用 2:运输中 3:维修中 4:停用)',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除标志(0:未删除 1:已删除)',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_license_plate` (`license_plate`),
  KEY `idx_status` (`operational_status`),
  KEY `idx_maintenance` (`maintenance_due_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆信息表';

设计亮点分析:

  • 状态与业务解耦operational_status字段管理车辆的实时可用性,这与运单的transport_status是解耦的。例如,一辆车在完成上一个任务后,状态会从“运输中”变回“可用”,而不是依赖运单状态来反推,设计更为合理。
  • 资源能力量化max_loadvolume字段将车辆的运力进行了精确量化,这是实现智能调度、根据货物重量和体积自动筛选合适车辆的基础。
  • 全生命周期管理:通过maintenance_due_dateinsurance_expiry_date等字段,系统能够对车辆的年检、保养、保险等进行预警管理,避免因证件或车况问题影响正常运营,体现了精细化管理的理念。
  • 逻辑删除is_deleted字段是实现逻辑删除的经典模式,确保数据可追溯的同时,不会在界面上展示已“删除”的车辆,兼顾了数据安全与用户体验。

核心功能模块深度解析

1. 智能车辆调度与派单

这是系统的核心价值所在。调度员在创建运单后,系统并非简单地列出所有车辆,而是通过后台算法,综合车辆状态、当前位置、载重能力、计划时间等多重因素,智能推荐最合适的车辆和司机。

后端Controller层处理调度请求的核心代码:

@RestController
@RequestMapping("/api/dispatch")
public class DispatchController {

    @Autowired
    private DispatchService dispatchService;

    /**
     * 智能推荐车辆
     * @param waybillId 运单ID
     * @return 推荐的车辆和司机列表
     */
    @PostMapping("/recommend/{waybillId}")
    public ResponseResult<List<Recommendation>> recommendTruckAndDriver(@PathVariable Integer waybillId) {
        try {
            List<Recommendation> recommendations = dispatchService.recommendForWaybill(waybillId);
            return ResponseResult.success(recommendations);
        } catch (BusinessException e) {
            return ResponseResult.error(e.getMessage());
        }
    }

    /**
     * 执行派单操作
     * @param dispatchRequest 派单请求,包含运单ID、车辆ID、司机ID
     * @return 派单结果
     */
    @PostMapping("/assign")
    @Transactional(rollbackFor = Exception.class) // 声明式事务,确保数据一致性
    public ResponseResult assignTruck(@RequestBody DispatchRequest dispatchRequest) {
        return dispatchService.assignTruckAndDriver(dispatchRequest);
    }
}

Service层实现智能推荐逻辑的代码片段:

@Service
public class DispatchServiceImpl implements DispatchService {

    @Autowired
    private TruckMapper truckMapper;
    @Autowired
    private DriverMapper driverMapper;
    @Autowired
    private WaybillMapper waybillMapper;

    @Override
    public List<Recommendation> recommendForWaybill(Integer waybillId) {
        // 1. 获取运单详情
        Waybill waybill = waybillMapper.selectById(waybillId);
        if (waybill == null) {
            throw new BusinessException("运单不存在");
        }

        // 2. 构建查询条件:可用状态、载重大于货物重量、不在维修期等
        TruckQuery query = new TruckQuery();
        query.setOperationalStatus(OperationalStatus.AVAILABLE); // 状态为可用
        query.setMinLoadCapacity(waybill.getCargoWeight()); // 最小载重需满足货物重量
        query.setExcludeUnderMaintenance(true); // 排除正在维修的车辆

        // 3. 查询符合条件的车辆
        List<Truck> availableTrucks = truckMapper.selectByCondition(query);

        List<Recommendation> recommendations = new ArrayList<>();
        for (Truck truck : availableTrucks) {
            Recommendation rec = new Recommendation();
            rec.setTruck(truck);

            // 4. 为每辆车寻找匹配的司机(例如,司机熟悉该路线、当前无任务)
            DriverQuery driverQuery = new DriverQuery();
            driverQuery.setTruckId(truck.getId());
            driverQuery.setStatus(DriverStatus.AVAILABLE);
            List<Driver> availableDrivers = driverMapper.selectByCondition(driverQuery);
            rec.setAvailableDrivers(availableDrivers);

            // 5. 可以在此处加入评分逻辑,如距离优先、经验优先等
            // rec.setScore(calculateScore(truck, drivers, waybill));

            recommendations.add(rec);
        }

        // 6. 根据评分排序后返回
        recommendations.sort(Comparator.comparing(Recommendation::getScore).reversed());
        return recommendations;
    }
}

智能调度推荐界面 上图展示了调度管理界面,在创建或编辑运单时,系统可以列出待调度的任务,并调用智能推荐接口。

2. 运单全生命周期跟踪

系统对每一张运单从创建到归档的整个生命周期进行可视化跟踪。状态机的设计是这一功能的关键。

MyBatis Mapper接口与XML映射,用于更新运单状态:

// Mapper 接口
public interface WaybillMapper {
    int updateStatus(@Param("id") Integer id, @Param("newStatus") TransportStatus newStatus);
    Waybill selectDetailById(Integer id);
}
<!-- WaybillMapper.xml -->
<mapper namespace="com.transport.mapper.WaybillMapper">

    <update id="updateStatus">
        UPDATE waybill
        SET transport_status = #{newStatus},
            update_time = NOW()
        WHERE id = #{id}
        <!-- 乐观锁或状态校验可以在此添加 -->
    </update>

    <!-- 复杂的运单详情查询,关联查询车辆、司机、客户等信息 -->
    <select id="selectDetailById" resultMap="WaybillDetailResultMap">
        SELECT
            w.*,
            t.license_plate,
            t.vehicle_model,
            d.name as driver_name,
            d.phone as driver_phone,
            s.company_name as shipper_name,
            c.company_name as consignee_name
        FROM waybill w
        LEFT JOIN truck t ON w.truck_id = t.id
        LEFT JOIN driver d ON w.driver_id = d.id
        LEFT JOIN customer s ON w.shipper_id = s.id
        LEFT JOIN customer c ON w.consignee_id = c.id
        WHERE w.id = #{id}
    </select>

</mapper>

驱动状态流转的Service方法:

@Service
public class WaybillStatusService {

    @Autowired
    private WaybillMapper waybillMapper;

    // 状态流转规则定义,例如:已派车 -> 运输中 需要司机APP确认发车
    private static final Map<TransportStatus, Set<TransportStatus>> STATUS_FLOW_RULES = new HashMap<>();

    static {
        STATUS_FLOW_RULES.put(TransportStatus.PENDING, Set.of(TransportStatus.ASSIGNED, TransportStatus.CANCELLED));
        STATUS_FLOW_RULES.put(TransportStatus.ASSIGNED, Set.of(TransportStatus.IN_TRANSIT, TransportStatus.CANCELLED));
        // ... 其他规则
    }

    public void changeStatus(Integer waybillId, TransportStatus newStatus, String operator) {
        Waybill waybill = waybillMapper.selectById(waybillId);
        TransportStatus currentStatus = waybill.getTransportStatus();

        // 校验状态流转是否合法
        if (!STATUS_FLOW_RULES.get(currentStatus).contains(newStatus)) {
            throw new BusinessException("当前状态[" + currentStatus.getDescription() + "]不允许变更为[" + newStatus.getDescription() + "]");
        }

        // 更新状态,并记录操作日志(例如,通过AOP实现)
        waybillMapper.updateStatus(waybillId, newStatus);
        // logOperation(waybillId, currentStatus, newStatus, operator);
    }
}

运单信息管理 在运单管理界面,不同角色可以查看运单列表及其当前状态,并执行权限内的状态更新操作。

3. 多维度报表与数据分析

系统内置了强大的数据报表功能,帮助管理人员从宏观层面掌握运营情况。这依赖于复杂的SQL查询和数据聚合。

生成车辆运营报表的Service逻辑:

@Service
public class ReportService {

    @Autowired
    private TruckReportMapper truckReportMapper;

    public TruckReport generateTruckReport(Date startDate, Date endDate, Integer truckId) {
        TruckReport report = new TruckReport();

        // 1. 查询指定时间段内车辆的基本运营数据
        TruckWorkload workload = truckReportMapper.selectWorkload(truckId, startDate, endDate);
        report.setTotalMileage(workload.getTotalMileage());
        report.setTotalFreight(workload.getTotalFreight());
        report.setCompletedWaybills(workload.getCompletedWaybills());

        // 2. 计算车辆利用率 (运输天数 / 总天数)
        long totalDays = Duration.between(startDate.toInstant(), endDate.toInstant()).toDays() + 1;
        long workingDays = truckReportMapper.countWorkingDays(truckId, startDate, endDate);
        report.setUtilizationRate((double) workingDays / totalDays);

        // 3. 查询油耗、维修成本等明细
        List<CostDetail> costDetails = truckReportMapper.selectCostDetails(truckId, startDate, endDate);
        report.setCostDetails(costDetails);

        return report;
    }
}

MyBatis中执行复杂聚合查询的XML配置:

<!-- 查询车辆工作负荷 -->
<select id="selectWorkload" resultType="com.transport.report.model.TruckWorkload">
    SELECT
        truck_id,
        COALESCE(SUM(actual_mileage), 0) as totalMileage,
        COALESCE(SUM(freight), 0) as totalFreight,
        COUNT(CASE WHEN transport_status = 3 THEN 1 END) as completedWaybills
    FROM waybill
    WHERE truck_id = #{truckId}
        AND planned_departure_time BETWEEN #{startDate} AND #{endDate}
        AND is_deleted = 0
    GROUP BY truck_id
</select>

车辆报表查看 报表模块能够以图表和列表相结合的方式,直观展示车辆利用率、收入成本、任务完成情况等关键指标。

4. 基于角色的权限访问控制

系统为老板、管理员、司机等不同角色提供了差异化的操作界面和功能权限。这是通过拦截器和注解实现的。

自定义权限注解:

/**
 * 权限注解,用于标记需要特定权限才能访问的方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermissions {
    String[] value(); // 权限标识符数组,如 {"waybill:view", "waybill:edit"}
}

Spring MVC拦截器进行权限校验:

public class AuthorizationInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            RequiresPermissions rp = handlerMethod.getMethodAnnotation(RequiresPermissions.class);

            // 如果方法上标注了权限注解
            if (rp != null) {
                HttpSession session = request.getSession();
                User currentUser = (User) session.getAttribute("currentUser");
                if (currentUser == null) {
                    response.sendError(401, "未登录");
                    return false;
                }

                List<String> userPermissions = getUserPermissions(currentUser.getId());
                String[] requiredPerms = rp.value();

                // 检查
本文关键词
SSM框架货车运输调度管理系统源码解析物流行业

上下篇

上一篇
没有更多文章
下一篇
没有更多文章