跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaSaaS大前端java

基于 JeecgBoot 低代码平台构建请假审批系统实战

基于 JeecgBoot 低代码平台开发请假审批系统的实战流程。内容包括架构解析、在线表单设计、代码自动生成、工作流配置及报表统计。通过具体案例展示如何利用可视化工具减少重复编码,实现一天内完成功能完备的后台系统,同时兼顾复杂业务逻辑的自定义开发能力。

雾岛听风发布于 2026/4/6更新于 2026/5/2325 浏览
基于 JeecgBoot 低代码平台构建请假审批系统实战

基于 JeecgBoot 低代码平台构建请假审批系统实战

引言:低代码开发模式与架构优势

在当今快速变化的商业环境中,企业应用开发的传统瓶颈日益凸显:开发周期长、成本高、对专业开发人员依赖度强、难以快速响应业务变化。低代码开发平台正成为解决这一困境的关键技术。

JeecgBoot 作为主流的 Java 低代码开发平台,凭借其强大的代码生成能力和可视化开发工具,让开发者能够以高效的速度构建企业级应用。本文将通过一个完整的'请假审批系统'实战案例,深入解析 JeecgBoot 的低代码核心原理,并展示如何完成一个功能完备的后台系统开发。

一、JeecgBoot 低代码架构深度解析

1.1 JeecgBoot 整体架构概览

JeecgBoot 采用经典的前后端分离架构,但其核心价值在于提供了一系列可视化低代码工具,大幅降低了开发门槛。下面的架构图展示了 JeecgBoot 的核心组件及其协作关系:

JeecgBoot 架构图

这种架构设计的核心优势在于分层解耦和工具集成。JeecgBoot 不仅提供了技术框架,更重要的是集成了完整的低代码开发工具链,使得开发者可以专注于业务逻辑,而非重复的技术实现。

1.2 低代码核心组件原理解析
1.2.1 在线表单设计器:可视化 UI 构建

JeecgBoot 的在线表单设计器是其低代码能力的核心体现。它通过 JSON Schema 来描述表单结构和行为,实现了完全可视化的表单构建。其工作原理如下:

{
  "schemas": [
    {
      "field": "leaveType",
      "label": "请假类型",
      "component": "JRadioButton",
      "componentProps": {
        "options": [
          {"label": "年假", "value": "1"},
          {"label": "病假", "value": "2"},
          {"label": "事假", "value": "3"},
          {"label": "调休", "value": "4"}
        ]
      },
      "rules": [{"required": true, "message": "请选择请假类型"}]
    },
    {
      "field": "startTime",
      "label": "开始时间",
      "component": "JDatePicker",
      "componentProps": {"showTime": true, "format": "YYYY-MM-DD HH:mm:ss"},
      "rules": [{"required": true, "message": "请选择开始时间"}]
    }
  ]
}

表单设计器的技术实现基于以下关键机制:

  1. 组件注册中心:维护所有可用表单组件的元数据
  2. Schema 解析引擎:将 JSON Schema 转换为实际的 Vue 组件
  3. 双向数据绑定:实时同步表单数据与 UI 状态
  4. 验证规则引擎:动态应用表单验证规则
1.2.2 代码生成器:自动化 CRUD 开发

JeecgBoot 的代码生成器是其'快速开发'的基石。它采用模板驱动的代码生成策略,支持高度定制化。代码生成的工作流程如下:

  1. 用户选择数据表
  2. 解析表结构
  3. 生成基础代码模板
  4. 选择生成模式(单表模式、树表模式、一对多模式、ERP 模式)
  5. 应用 Velocity 模板
  6. 生成源代码文件、SQL 文件、前端页面
  7. 输出到项目目录
  8. 用户二次开发

代码生成器的核心技术包括:

  1. 数据库元数据解析:通过 JDBC DatabaseMetaData 接口获取表结构信息
  2. 模板引擎:使用 Velocity 模板引擎进行代码生成
  3. 类型映射系统:将数据库字段类型映射为 Java 类型和前端组件
  4. 路径计算算法:根据命名规范自动计算包路径和文件路径
1.2.3 流程设计器:可视化工作流配置

JeecgBoot 集成了 Activiti 工作流引擎,并提供可视化流程设计器。这使得非技术人员也能设计和修改业务流程:

@Entity
@Table(name = "act_re_procdef")
public class ProcessDefinition {
    @Id
    private String id;
    
    @Column(name = "category_")
    private String category; // 流程分类
    
    @Column(name = "name_")
    private String name; // 流程名称
    
    @Column(name = "key_")
    private String key; // 流程 KEY
    
    @Column(name = "version_")
    private Integer version; // 版本
    
    @Column(name = "deployment_id_")
    private String deploymentId; // 部署 ID
    
    @Column(name = "resource_name_")
    private String resourceName; // 资源名称
    
    @Column(name = "diagram_resource_name_")
    private String diagramResourceName; // 流程图资源
    
    @Column(name = "suspension_state_")
    private Integer suspensionState; // 挂起状态
}

流程设计器的核心特性:

  1. BPMN 2.0 兼容:支持标准 BPMN 流程图设计
  2. 节点类型丰富:包括用户任务、服务任务、网关、事件等
  3. 表单绑定:支持将流程节点与动态表单关联
  4. 权限配置:可视化配置任务处理人和候选组
1.2.4 报表设计器:可视化数据分析

JeecgBoot 的报表设计器支持拖拽式报表设计,集成了多种图表类型和数据源:

# 报表配置示例
report:
  id: leave_statistics
  name: 请假统计报表
  type: chart
  dataSource:
    type: sql
    query: |
      SELECT DATE_FORMAT(start_time, '%Y-%m') as month, leave_type, COUNT(*) as count, SUM(DATEDIFF(end_time, start_time)) as total_days FROM sys_leave WHERE status = '2' -- 已批准 GROUP BY DATE_FORMAT(start_time, '%Y-%m'), leave_type
  charts:
    - type: bar
      title: 月度请假统计
      xAxis: month
      yAxis: count
      series: leave_type
    - type: pie
      title: 请假类型分布
      data: leave_type
      value: count

二、实战演练:一天构建请假审批系统

2.1 需求分析与系统设计
2.1.1 业务需求

我们要构建的请假审批系统需要满足以下核心需求:

  1. 员工功能:提交请假申请(包括类型、时间、事由等)、查看请假申请状态和历史记录、撤销未审批的申请
  2. 审批功能:部门经理审批(1-3 天请假)、人事部门审批(3 天以上请假或特殊类型)、总经理审批(7 天以上请假)
  3. 管理功能:请假类型管理、审批流程配置、请假统计报表
  4. 系统功能:消息通知(邮件、站内信)、日历视图展示、导出请假记录
2.1.2 数据库设计
-- 请假申请表
CREATE TABLE `sys_leave` (
  `id` varchar(32) NOT NULL COMMENT '主键 ID',
  `user_id` varchar(32) NOT NULL COMMENT '申请人 ID',
  `user_name` varchar(50) NOT NULL COMMENT '申请人姓名',
  `dept_id` varchar(32) DEFAULT NULL COMMENT '部门 ID',
  `dept_name` varchar(50) DEFAULT NULL COMMENT '部门名称',
  `leave_type` varchar(2) NOT NULL COMMENT '请假类型 1 年假 2 病假 3 事假 4 调休',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `leave_days` decimal(10,1) NOT NULL COMMENT '请假天数',
  `reason` varchar(500) NOT NULL COMMENT '请假事由',
  `emergency_contact` varchar(50) DEFAULT NULL COMMENT '紧急联系人',
  `emergency_phone` varchar(20) DEFAULT NULL COMMENT '紧急联系电话',
  `attachment` varchar(500) DEFAULT NULL COMMENT '附件',
  `status` varchar(2) NOT NULL DEFAULT '0' COMMENT '状态 0 草稿 1 审批中 2 已批准 3 已拒绝 4 已撤销',
  `process_instance_id` varchar(64) DEFAULT NULL COMMENT '流程实例 ID',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_status` (`status`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='请假申请表';

-- 请假审批记录表
CREATE TABLE `sys_leave_approval` (
  `id` varchar(32) NOT NULL COMMENT '主键 ID',
  `leave_id` varchar(32) NOT NULL COMMENT '请假 ID',
  `approval_user_id` varchar(32) NOT NULL COMMENT '审批人 ID',
  `approval_user_name` varchar(50) NOT NULL COMMENT '审批人姓名',
  `approval_result` varchar(2) NOT NULL COMMENT '审批结果 1 通过 2 拒绝',
  `approval_comment` varchar(500) DEFAULT NULL COMMENT '审批意见',
  `approval_time` datetime NOT NULL COMMENT '审批时间',
  `approval_node` varchar(50) NOT NULL COMMENT '审批节点',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `idx_leave_id` (`leave_id`),
  KEY `idx_approval_user_id` (`approval_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='请假审批记录表';

-- 请假类型表
CREATE TABLE `sys_leave_type` (
  `id` varchar(32) NOT NULL COMMENT '主键 ID',
  `type_code` varchar(20) NOT NULL COMMENT '类型编码',
  `type_name` varchar(50) NOT NULL COMMENT '类型名称',
  `max_days` int(11) DEFAULT NULL COMMENT '最大天数',
  `need_approval` tinyint(1) DEFAULT '1' COMMENT '是否需要审批',
  `description` varchar(200) DEFAULT NULL COMMENT '描述',
  `sort_no` int(11) DEFAULT '0' COMMENT '排序号',
  `status` varchar(2) DEFAULT '1' COMMENT '状态 1 启用 0 停用',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_type_code` (`type_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='请假类型表';
2.2 步骤一:使用在线开发创建请假模块
2.2.1 创建数据表并导入

首先在数据库中创建上述表结构,然后进入 JeecgBoot 的在线开发功能模块:

  1. 登录 JeecgBoot 系统,进入'系统管理' → '在线开发'
  2. 点击'导入数据库表',选择 sys_leave 表
  3. 系统自动解析表结构,生成字段配置
2.2.2 配置表单字段

在字段配置界面,我们可以对每个字段进行详细配置:

字段名字段描述表单组件校验规则列表显示查询条件
leave_type请假类型下拉框必填是是
start_time开始时间时间选择必填是范围查询
end_time结束时间时间选择必填是-
leave_days请假天数输入框数字校验是-
reason请假事由文本域必填,最大 500 字是模糊查询
status状态下拉框-是是

特殊字段配置示例:

{
  "field": "leave_type",
  "title": "请假类型",
  "component": "JSearchSelect",
  "options": [
    {"text": "年假", "value": "1"},
    {"text": "病假", "value": "2"},
    {"text": "事假", "value": "3"},
    {"text": "调休", "value": "4"}
  ],
  "dictCode": "leave_type",
  "validateRules": [{"required": true}],
  "tableShow": true,
  "queryShow": true
}
2.2.3 生成代码并导入项目

配置完成后,点击'生成代码'按钮,系统将生成以下文件:

  1. 后端代码:
    • SysLeaveController.java - 控制器
    • ISysLeaveService.java - 服务接口
    • SysLeaveServiceImpl.java - 服务实现
    • SysLeaveMapper.java - 数据访问接口
    • SysLeaveMapper.xml - MyBatis 映射文件
    • SysLeave.java - 实体类
  2. 前端代码:
    • SysLeaveList.vue - 列表页面
    • SysLeaveModal.vue - 表单弹窗
    • SysLeave.js - API 接口文件
  3. SQL 脚本:
    • 初始化数据脚本
    • 菜单权限脚本

下载生成的代码包,解压并按照说明导入到 JeecgBoot 项目中。

2.3 步骤二:使用流程设计器配置审批流程
2.3.1 设计请假审批流程

进入'流程设计'模块,新建一个名为'请假审批流程'的流程:

  1. 开始:提交请假申请
  2. 判断:请假天数
    • 1-3 天:部门经理审批 -> 结束
    • 3-7 天:部门经理审批 -> 人事审批 -> 结束
    • 7 天以上:部门经理审批 -> 人事审批 -> 总经理审批 -> 结束
  3. 结束:更新请假状态,通知申请人
2.3.2 配置流程节点

每个审批节点都需要配置以下信息:

  1. 节点基本信息:名称、处理人/组、表单
  2. 表单绑定:关联请假申请表单
  3. 处理规则:自动通过、手动审批等
  4. 通知配置:邮件、站内信通知

部门经理审批节点配置示例:

<userTask id="deptManagerApprove" name="部门经理审批">
  <extensionElements>
    <activiti:formProperty id="approvalResult" name="审批结果" type="enum" required="true">
      <activiti:value id="1" name="通过"/>
      <activiti:value id="2" name="拒绝"/>
    </activiti:formProperty>
    <activiti:formProperty id="approvalComment" name="审批意见" type="string"/>
    <activiti:taskListener event="create" class="com.jeecg.listener.LeaveTaskListener"/>
  </extensionElements>
  <documentation>部门经理审批请假申请</documentation>
</userTask>
2.3.3 配置流程网关

流程中的决策网关需要配置条件表达式:

<sequenceFlow id="flow1" sourceRef="start" targetRef="judgeDays">
  <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave != null}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow2" sourceRef="judgeDays" targetRef="deptManagerOnly">
  <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.leaveDays <= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="judgeDays" targetRef="deptManagerFirst">
  <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.leaveDays > 3 && leave.leaveDays <= 7}]]></conditionExpression>
</sequenceFlow>
2.4 步骤三:自定义业务逻辑开发

虽然 JeecgBoot 的在线开发可以生成大部分 CRUD 代码,但复杂的业务逻辑仍需要手动开发。

2.4.1 请假天数自动计算

在 SysLeaveServiceImpl.java 中添加业务逻辑:

@Service
public class SysLeaveServiceImpl extends ServiceImpl<SysLeaveMapper, SysLeave> implements ISysLeaveService {
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveLeave(SysLeave sysLeave) {
        // 自动计算请假天数
        sysLeave.setLeaveDays(calculateLeaveDays(sysLeave.getStartTime(), sysLeave.getEndTime()));
        
        // 设置默认状态
        if (sysLeave.getStatus() == null) {
            sysLeave.setStatus("0"); // 草稿状态
        }
        
        // 设置申请人信息
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        sysLeave.setUserId(loginUser.getId());
        sysLeave.setUserName(loginUser.getRealname());
        
        // 保存请假申请
        boolean result = this.save(sysLeave);
        
        // 如果状态是提交审批,则启动流程
        if ("1".equals(sysLeave.getStatus())) {
            startLeaveProcess(sysLeave);
        }
        return result;
    }
    
    /**
     * 计算请假天数(考虑工作日)
     */
    private BigDecimal calculateLeaveDays(Date startTime, Date endTime) {
        // 简单的天数计算,实际应排除周末和节假日
        long diff = endTime.getTime() - startTime.getTime();
        double days = (double) diff / (1000 * 60 * 60 * 24);
        // 向上取整,半天按 0.5 天计算
        if (days % 1 > 0) {
            days = Math.ceil(days * 2) / 2;
        }
        return BigDecimal.valueOf(days);
    }
    
    /**
     * 启动请假审批流程
     */
    private void startLeaveProcess(SysLeave leave) {
        try {
            // 获取流程定义
            ProcessDefinition processDefinition = repositoryService
                    .createProcessDefinitionQuery()
                    .processDefinitionKey("leave_approval_process")
                    .latestVersion()
                    .singleResult();
            
            // 设置流程变量
            Map<String, Object> variables = new HashMap<>();
            variables.put("leave", leave);
            variables.put("applicant", leave.getUserId());
            variables.put("deptManager", getDeptManager(leave.getDeptId()));
            
            // 启动流程实例
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(
                    processDefinition.getId(), leave.getId(), variables);
            
            // 更新请假申请的流程实例 ID
            leave.setProcessInstanceId(processInstance.getId());
            this.updateById(leave);
            
            // 发送通知
            sendProcessStartNotification(leave);
        } catch (Exception e) {
            log.error("启动请假流程失败", e);
            throw new JeecgBootException("启动审批流程失败");
        }
    }
}
2.4.2 审批结果处理

创建审批服务类处理流程任务:

@Component
public class LeaveApprovalService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private ISysLeaveService leaveService;
    
    @Autowired
    private ISysLeaveApprovalService leaveApprovalService;
    
    /**
     * 处理审批任务
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleApprovalTask(String taskId, String approvalResult, String comment, String userId) {
        // 获取当前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new JeecgBootException("任务不存在或已完成");
        }
        
        // 获取流程变量
        String leaveId = task.getBusinessKey();
        SysLeave leave = leaveService.getById(leaveId);
        
        // 保存审批记录
        SysLeaveApproval approval = new SysLeaveApproval();
        approval.setLeaveId(leaveId);
        approval.setApprovalUserId(userId);
        approval.setApprovalResult(approvalResult);
        approval.setApprovalComment(comment);
        approval.setApprovalNode(task.getTaskDefinitionKey());
        approval.setApprovalTime(new Date());
        leaveApprovalService.save(approval);
        
        // 设置任务变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("approvalResult", approvalResult);
        variables.put("approvalComment", comment);
        variables.put("approvalUser", userId);
        
        // 完成任务
        taskService.complete(taskId, variables);
        
        // 如果流程结束,更新请假状态
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        
        if (processInstance == null) {
            // 流程已结束
            String finalStatus = "1".equals(approvalResult) ? "2" : "3"; // 2-已批准 3-已拒绝
            leave.setStatus(finalStatus);
            leaveService.updateById(leave);
            
            // 发送最终通知
            sendFinalNotification(leave, finalStatus);
        }
    }
}
2.5 步骤四:使用报表设计器创建统计图表
2.5.1 设计请假统计报表

进入'报表设计'模块,创建请假统计报表:

  1. 数据源配置:连接 sys_leave 表
  2. SQL 查询设计:
SELECT DATE_FORMAT(start_time,'%Y-%m') as 月份,leave_type as 请假类型,COUNT(*) as 申请次数,SUM(leave_days) as 总天数,AVG(leave_days) as 平均天数 
FROM sys_leave 
WHERE status='2' -- 仅统计已批准的
GROUP BY DATE_FORMAT(start_time,'%Y-%m'), leave_type 
ORDER BY 月份 DESC
  1. 图表设计:
    • 柱状图:每月各类型请假天数对比
    • 饼图:请假类型分布
    • 折线图:请假趋势分析
2.5.2 报表页面集成

将报表集成到请假管理模块中:

<template>
  <div>
    <a-card :bordered="false">
      <!-- 报表筛选条件 -->
      <div>
        <a-form layout="inline" @keyup.enter.native="searchQuery">
          <a-row :gutter="24">
            <a-col :md="6" :sm="8">
              <a-form-item label="统计月份">
                <a-month-picker v-model="queryParam.month" format="YYYY-MM" placeholder="请选择月份" />
              </a-form-item>
            </a-col>
            <a-col :md="6" :sm="8">
              <a-form-item label="部门">
                <j-select-depart v-model="queryParam.departId" :multi="false" />
              </a-form-item>
            </a-col>
            <a-col :md="6" :sm="8">
              <span>
                <a-button type="primary" @click="searchQuery">查询</a-button>
                <a-button @click="searchReset">重置</a-button>
              </span>
            </a-col>
          </a-row>
        </a-form>
      </div>
      <!-- 图表展示 -->
      <a-row :gutter="24">
        <a-col :span="12">
          <a-card title="月度请假统计" size="small">
            <div id="monthChart"></div>
          </a-card>
        </a-col>
        <a-col :span="12">
          <a-card title="请假类型分布" size="small">
            <div id="typeChart"></div>
          </a-card>
        </a-col>
      </a-row>
      <!-- 数据表格 -->
      <div>
        <a-table ref="table" size="middle" :columns="columns" :dataSource="dataSource" :pagination="ipagination" @change="handleTableChange" rowKey="id">
        </a-table>
      </div>
    </a-card>
  </div>
</template>
<script>
import { getLeaveStatistics } from '@/api/system/leave'
import { Chart } from '@antv/g2'

export default {
  name: 'LeaveStatistics',
  data() {
    return {
      queryParam: {},
      ipagination: {
        current: 1,
        pageSize: 10,
        total: 0
      },
      columns: [
        { title: '月份', dataIndex: 'month', align: 'center' },
        { title: '请假类型', dataIndex: 'leaveType', align: 'center' },
        { title: '申请次数', dataIndex: 'applyCount', align: 'center' },
        { title: '总天数', dataIndex: 'totalDays', align: 'center' },
        { title: '平均天数', dataIndex: 'avgDays', align: 'center' }
      ],
      dataSource: [],
      monthChart: null,
      typeChart: null
    }
  },
  mounted() {
    this.loadData()
    this.initCharts()
  },
  methods: {
    loadData() {
      const params = { ...this.queryParam, pageNo: this.ipagination.current, pageSize: this.ipagination.pageSize }
      getLeaveStatistics(params).then(res => {
        if (res.success) {
          this.dataSource = res.result.records || []
          this.ipagination.total = res.result.total
          // 更新图表数据
          this.updateCharts(res.result.records)
        }
      })
    },
    initCharts() {
      // 初始化月度统计图表
      this.monthChart = new Chart({ container: 'monthChart', autoFit: true, height: 300 })
      // 初始化类型分布图表
      this.typeChart = new Chart({ container: 'typeChart', autoFit: true, height: 300 })
    },
    updateCharts(data) {
      // 更新月度统计
      const monthData = this.processMonthData(data)
      this.monthChart.data(monthData)
      this.monthChart.scale({ month: { alias: '月份' }, value: { alias: '请假天数' }, type: { alias: '请假类型' } })
      this.monthChart.interval().position('month*value').color('type')
      this.monthChart.render()
      
      // 更新类型分布
      const typeData = this.processTypeData(data)
      this.typeChart.data(typeData)
      this.typeChart.coordinate('theta', { radius: 0.75 })
      this.typeChart.tooltip({ showTitle: false, showMarkers: false })
      this.typeChart.interval()
        .position('value')
        .color('type')
        .label('type', { content: (data) => {
          return `${data.type}: ${data.value}`
        }})
      this.typeChart.render()
    },
    processMonthData(data) {
      // 处理月度数据逻辑
      return []
    },
    processTypeData(data) {
      // 处理类型数据逻辑
      return []
    }
  }
}
</script>

三、JeecgBoot 前后端分离架构剖析

3.1 前端架构:Ant Design Vue 深度集成

JeecgBoot 前端基于 Ant Design Vue,并进行了深度定制和扩展:

3.1.1 组件封装体系

JeecgBoot 封装了大量业务组件,提高开发效率:

// 自定义业务组件示例
import JDate from '@/components/jeecg/JDate'
import JSelectUser from '@/components/jeecg/JSelectUser'
import JSelectDepart from '@/components/jeecg/JSelectDepart'
import JSearchSelect from '@/components/jeecg/JSearchSelect'
import JEditor from '@/components/jeecg/JEditor'
import JUpload from '@/components/jeecg/JUpload'
import JTreeSelect from '@/components/jeecg/JTreeSelect'

// 组件全局注册
const components = [JDate, JSelectUser, JSelectDepart, JSearchSelect, JEditor, JUpload, JTreeSelect]
const install = function(Vue) {
  components.forEach(component => {
    Vue.component(component.name, component)
  })
}
export default { install }
3.1.2 表单渲染引擎

JeecgBoot 的表单渲染引擎是其低代码能力的关键:

// 表单渲染引擎核心逻辑
export default {
  name: 'JFormEngine',
  props: {
    schema: { type: Array, required: true },
    model: { type: Object, required: true },
    disabled: { type: Boolean, default: false }
  },
  render(h) {
    // 动态渲染表单字段
    const children = this.schema.map(field => {
      // 根据字段配置选择组件
      const component = this.getComponent(field)
      // 构建组件属性
      const props = {
        value: this.model[field.field],
        disabled: this.disabled || field.disabled,
        ...field.componentProps
      }
      // 构建组件事件
      const on = {
        input: value => {
          this.$set(this.model, field.field, value)
          this.$emit('change', field.field, value)
        }
      }
      // 渲染表单项
      return h('a-form-item', {
        props: {
          label: field.label,
          required: field.rules && field.rules.some(r => r.required)
        }
      }, [h(component, { props, on })])
    })
    return h('a-form', children)
  },
  methods: {
    getComponent(field) {
      // 组件映射表
      const componentMap = {
        input: 'a-input',
        select: 'a-select',
        date: 'j-date',
        user: 'j-select-user',
        depart: 'j-select-depart',
        editor: 'j-editor',
        upload: 'j-upload'
      }
      return componentMap[field.component] || 'a-input'
    }
  }
}
3.2 后端架构:统一响应与异常处理
3.2.1 统一响应格式

JeecgBoot 定义了标准的 API 响应格式:

/**
 * 统一 API 响应对象
 */
@Data
public class Result<T> {
  /**
   * 是否成功
   */
  private boolean success;
  
  /**
   * 响应代码
   */
  private Integer code;
  
  /**
   * 响应消息
   */
  private String message;
  
  /**
   * 响应数据
   */
  private T result;
  
  /**
   * 时间戳
   */
  private Long timestamp;
  
  /**
   * 成功响应
   */
  public static <T> Result<T> OK() {
    Result<T> r = new Result<>();
    r.setSuccess(true);
    r.setCode(CommonConstant.SC_OK_200);
    r.setMessage("操作成功");
    r.setTimestamp(System.currentTimeMillis());
    return r;
  }
  
  /**
   * 成功响应(带数据)
   */
  public static <T> Result<T> OK(T data) {
    Result<T> r = new Result<>();
    r.setSuccess(true);
    r.setCode(CommonConstant.SC_OK_200);
    r.setResult(data);
    r.setMessage("操作成功");
    r.setTimestamp(System.currentTimeMillis());
    return r;
  }
  
  /**
   * 失败响应
   */
  public static <T> Result<T> error(String msg) {
    return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);
  }
  
  /**
   * 失败响应(带错误码)
   */
  public static <T> Result<T> error(int code, String msg) {
    Result<T> r = new Result<>();
    r.setCode(code);
    r.setMessage(msg);
    r.setSuccess(false);
    r.setTimestamp(System.currentTimeMillis());
    return r;
  }
}
3.2.2 全局异常处理
/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class JeecgBootExceptionHandler {
  
  /**
   * 处理业务异常
   */
  @ExceptionHandler(JeecgBootException.class)
  public Result<?> handleJeecgBootException(JeecgBootException e) {
    log.error(e.getMessage(), e);
    return Result.error(e.getMessage());
  }
  
  /**
   * 处理数据库异常
   */
  @ExceptionHandler(DaoException.class)
  public Result<?> handleDaoException(DaoException e) {
    log.error("数据库操作异常", e);
    return Result.error("数据库操作失败");
  }
  
  /**
   * 处理权限异常
   */
  @ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})
  public Result<?> handleAuthorizationException(AuthorizationException e) {
    log.error("权限校验异常", e);
    return Result.error(CommonConstant.SC_JEECG_NO_AUTHZ, "没有权限,请联系管理员授权");
  }
  
  /**
   * 处理所有其他异常
   */
  @ExceptionHandler(Exception.class)
  public Result<?> handleException(Exception e) {
    log.error("系统异常", e);
    return Result.error("系统异常,请联系管理员");
  }
}
3.3 前后端通信规范
3.3.1 API 请求封装
// 请求拦截器
service.interceptors.request.use(config => {
  // 设置 token
  const token = Vue.ls.get(ACCESS_TOKEN)
  if (token) {
    config.headers['X-Access-Token'] = token
  }
  // 设置时间戳,防止缓存
  if (config.method === 'get') {
    config.params = { ...config.params, _t: new Date().getTime() }
  }
  return config
}, error => {
  return Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(response => {
  // 处理文件下载
  if (response.config.responseType === 'blob') {
    return response
  }
  const res = response.data
  // 处理成功响应
  if (res.success) {
    return res.result
  }
  // 处理 token 过期
  if (res.code === 401) {
    Modal.error({
      title: '登录过期',
      content: '登录已过期,请重新登录',
      okText: '重新登录',
      onOk: () => {
        store.dispatch('Logout').then(() => {
          location.reload()
        })
      }
    })
    return Promise.reject(new Error(res.message || 'Error'))
  }
  // 处理其他错误
  const errMsg = res.message || '请求失败'
  message.error(errMsg)
  return Promise.reject(new Error(errMsg))
}, error => {
  // 网络错误处理
  if (!error.response) {
    message.error('网络连接异常')
    return Promise.reject(error)
  }
  // HTTP 状态码错误处理
  const { status, data } = error.response
  switch (status) {
    case 400: message.error(data.message || '请求参数错误'); break
    case 404: message.error('请求的资源不存在'); break
    case 500: message.error('服务器内部错误'); break
    default: message.error('请求失败')
  }
  return Promise.reject(error)
})

四、低代码模式下的开发者角色演变

4.1 从编码者到架构设计者

在低代码开发模式下,开发者的角色发生了重大转变:

开发者角色演变

4.2 低代码开发的边界与限制

虽然 JeecgBoot 等低代码平台大幅提升了开发效率,但仍存在明确的边界:

4.2.1 适合低代码开发的场景
  1. 常规业务管理系统:OA、CRM、ERP 等
  2. 数据收集与展示系统:报表系统、数据分析平台
  3. 工作流审批系统:各种审批流程管理
  4. 内部管理工具:员工管理、资产管理等
4.2.2 不适合低代码开发的场景
  1. 高性能计算系统:科学计算、实时交易等
  2. 复杂算法实现:机器学习、图像处理等
  3. 特定硬件交互:物联网设备控制、驱动程序
  4. 超高并发系统:大型电商、社交平台等
4.3 开发者需要关注的底层技术

即使在低代码环境下,开发者仍需掌握以下核心技术:

4.3.1 数据库设计与优化
-- 虽然低代码平台可以生成基础 CRUD,但复杂查询仍需手动优化
-- 示例:请假统计的优化查询
EXPLAIN
SELECT l.user_id, u.realname, d.depart_name,
       COUNT(*) as total_count, SUM(l.leave_days) as total_days, MAX(l.create_time) as last_leave 
FROM sys_leave l 
LEFT JOIN sys_user u ON l.user_id = u.id 
LEFT JOIN sys_depart d ON u.depart_id = d.id 
WHERE l.status='2' AND l.create_time >= DATE_SUB(NOW(), INTERVAL 1 YEAR)
GROUP BY l.user_id, u.realname, d.depart_name 
HAVING total_days > 10
ORDER BY total_days DESC LIMIT 100;

-- 创建优化索引
CREATE INDEX idx_leave_user_status ON sys_leave(user_id, status, create_time);
CREATE INDEX idx_leave_dept_time ON sys_leave(dept_id, create_time);
4.3.2 缓存策略设计
/**
 * 请假信息缓存服务
 */
@Service
@Slf4j
public class LeaveCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ISysLeaveService leaveService;
    
    /**
     * 获取用户请假统计(带缓存)
     */
    public UserLeaveStats getUserLeaveStats(String userId) {
        String cacheKey = String.format("leave:stats:user:%s", userId);
        // 尝试从缓存获取
        UserLeaveStats stats = (UserLeaveStats) redisTemplate.opsForValue().get(cacheKey);
        if (stats != null) {
            return stats;
        }
        // 缓存未命中,查询数据库
        stats = leaveService.calculateUserLeaveStats(userId);
        // 写入缓存,设置过期时间
        if (stats != null) {
            redisTemplate.opsForValue().set(cacheKey, stats, 1, TimeUnit.HOURS); // 缓存 1 小时
        }
        return stats;
    }
    
    /**
     * 清除用户请假缓存
     */
    public void clearUserLeaveCache(String userId) {
        String cacheKey = String.format("leave:stats:user:%s", userId);
        redisTemplate.delete(cacheKey);
        // 同时清除相关的列表缓存
        String listKey = String.format("leave:list:user:%s:*", userId);
        Set<String> keys = redisTemplate.keys(listKey);
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }
}
4.3.3 系统监控与性能优化
# application-monitor.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics, prometheus
  endpoint:
    health:
      show-details: always
  metrics:
    export:
      prometheus:
        enabled: true
        tags:
          application: jeecg-leave-system
  distribution:
    percentiles-histogram:
      http.server.requests: true

# 自定义监控指标
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
  return registry -> registry.config().commonTags(
    "application", "leave-system",
    "region", System.getProperty("region", "unknown")
  );
}

# 性能监控配置
logging:
  level:
    com.jeecg: DEBUG
  file:
    name: logs/jeecg-leave.log
  logback:
    rollingpolicy:
      max-file-size: 10MB
      max-history: 30
4.4 低代码开发的最佳实践
4.4.1 分层开发策略
  1. 基础层:使用低代码工具快速生成基础 CRUD
  2. 业务层:手动开发复杂业务逻辑和服务
  3. 集成层:处理外部系统对接和消息队列
  4. 表现层:使用低代码表单和报表设计器
4.4.2 代码管理规范
# JeecgBoot 项目代码管理规范

## 目录结构
src/main/java/com/jeecg/
├── modules/ # 业务模块
│   ├── leave/ # 请假模块
│   │   ├── entity/ # 实体类(低代码生成)
│   │   ├── mapper/ # 数据访问(低代码生成)
│   │   ├── service/ # 服务层
│   │   │   ├── impl/ # 服务实现
│   │   │   └── task/ # 定时任务
│   │   ├── controller/ # 控制器(低代码生成 + 手动增强)
│   │   └── api/ # API 接口定义
├── common/ # 通用模块
└── system/ # 系统模块(低代码生成)

## 命名规范
- 低代码生成的文件:保留原名
- 手动新增的文件:添加业务前缀,如 LeaveStatService.java
- 重写低代码生成的方法:添加@Override 注解

## 版本控制
- 低代码生成的代码:单独提交,备注'低代码生成'
- 手动修改的代码:详细说明修改原因
- 业务逻辑代码:遵循特性分支工作流

五、总结:JeecgBoot 低代码实践的价值与展望

5.1 一天开发的价值体现

通过本文的实战演示,我们可以看到使用 JeecgBoot 在一天内构建请假审批系统的实际效果:

  1. 开发效率提升:相比传统开发,效率提升显著
  2. 代码质量保证:生成的代码规范统一,减少人为错误
  3. 维护成本降低:可视化配置使得后期修改更加容易
  4. 团队协作优化:前后端分离,并行开发成为可能
5.2 JeecgBoot 的适用场景总结

JeecgBoot 特别适合以下类型的项目和团队:

项目类型适合程度关键考量
企业内部管理系统★★★★★快速响应业务变化需求
政府政务系统★★★★☆需要流程审批和权限控制
中小型企业 ERP★★★★☆定制化需求多,预算有限
教育管理系统★★★★☆用户角色复杂,权限细分
互联网创新项目 MVP★★★☆☆快速验证产品思路
5.3 未来发展趋势

随着低代码技术的不断发展,我们可以预见以下趋势:

  1. AI 增强:集成 AI 能力,实现智能代码生成和建议
  2. 多端统一:一套代码生成多端应用(Web、小程序、App)
  3. 云原生集成:深度集成云服务,实现一键部署和扩缩容
  4. 可视化深度:从界面可视化到业务逻辑可视化
  5. 生态开放:建立插件市场,汇集第三方组件和服务
5.4 给开发者的建议

对于正在或计划使用 JeecgBoot 等低代码平台的开发者,建议:

  1. 掌握核心原理:不要只停留在使用层面,要理解实现机制
  2. 保持编码能力:低代码不是无代码,复杂逻辑仍需编码实现
  3. 关注业务价值:从技术实现者转变为业务解决方案提供者
  4. 持续学习更新:低代码技术发展迅速,需要不断学习新特性
  5. 参与社区贡献:积极反馈问题,贡献代码,共同推动平台发展

结语

JeecgBoot 作为国内主流的 Java 低代码开发平台,通过本文的深度解析和实战演示,我们不仅看到了它如何大幅提升开发效率,更理解了其背后的技术原理和设计哲学。低代码不是要取代开发者,而是要解放开发者,让开发者从重复的 CRUD 编码中解脱出来,专注于更有价值的业务创新和技术攻关。

在数字化转型的浪潮中,掌握 JeecgBoot 这样的低代码工具,意味着你拥有了快速响应业务变化、高效交付企业应用的能力。这不仅是技术能力的提升,更是职业竞争力的重要组成部分。

希望本文能够帮助你深入理解 JeecgBoot 的低代码开发模式,并在实际项目中应用这些知识,真正实现快速搭建功能完备后台系统的目标。

目录

  1. 基于 JeecgBoot 低代码平台构建请假审批系统实战
  2. 引言:低代码开发模式与架构优势
  3. 一、JeecgBoot 低代码架构深度解析
  4. 1.1 JeecgBoot 整体架构概览
  5. 1.2 低代码核心组件原理解析
  6. 1.2.1 在线表单设计器:可视化 UI 构建
  7. 1.2.2 代码生成器:自动化 CRUD 开发
  8. 1.2.3 流程设计器:可视化工作流配置
  9. 1.2.4 报表设计器:可视化数据分析
  10. 报表配置示例
  11. 二、实战演练:一天构建请假审批系统
  12. 2.1 需求分析与系统设计
  13. 2.1.1 业务需求
  14. 2.1.2 数据库设计
  15. 2.2 步骤一:使用在线开发创建请假模块
  16. 2.2.1 创建数据表并导入
  17. 2.2.2 配置表单字段
  18. 2.2.3 生成代码并导入项目
  19. 2.3 步骤二:使用流程设计器配置审批流程
  20. 2.3.1 设计请假审批流程
  21. 2.3.2 配置流程节点
  22. 2.3.3 配置流程网关
  23. 2.4 步骤三:自定义业务逻辑开发
  24. 2.4.1 请假天数自动计算
  25. 2.4.2 审批结果处理
  26. 2.5 步骤四:使用报表设计器创建统计图表
  27. 2.5.1 设计请假统计报表
  28. 2.5.2 报表页面集成
  29. 三、JeecgBoot 前后端分离架构剖析
  30. 3.1 前端架构:Ant Design Vue 深度集成
  31. 3.1.1 组件封装体系
  32. 3.1.2 表单渲染引擎
  33. 3.2 后端架构:统一响应与异常处理
  34. 3.2.1 统一响应格式
  35. 3.2.2 全局异常处理
  36. 3.3 前后端通信规范
  37. 3.3.1 API 请求封装
  38. 四、低代码模式下的开发者角色演变
  39. 4.1 从编码者到架构设计者
  40. 4.2 低代码开发的边界与限制
  41. 4.2.1 适合低代码开发的场景
  42. 4.2.2 不适合低代码开发的场景
  43. 4.3 开发者需要关注的底层技术
  44. 4.3.1 数据库设计与优化
  45. 4.3.2 缓存策略设计
  46. 4.3.3 系统监控与性能优化
  47. application-monitor.yml
  48. 自定义监控指标
  49. 性能监控配置
  50. 4.4 低代码开发的最佳实践
  51. 4.4.1 分层开发策略
  52. 4.4.2 代码管理规范
  53. JeecgBoot 项目代码管理规范
  54. 目录结构
  55. 命名规范
  56. 版本控制
  57. 五、总结:JeecgBoot 低代码实践的价值与展望
  58. 5.1 一天开发的价值体现
  59. 5.2 JeecgBoot 的适用场景总结
  60. 5.3 未来发展趋势
  61. 5.4 给开发者的建议
  62. 结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Tomcat 下载、安装及环境配置指南
  • Trae 结合 Vizro:低代码构建专业数据可视化仪表板
  • 8 个技术要点,帮助企业更好落地大模型知识库
  • 医疗 AI 中的马尔科夫链深度应用与 Python 实现
  • 6 种 Python 脚本打包成可执行文件的主流方法
  • VS Code 配置 Claude Code 时 Git Bash 路径报错解决
  • Stable Diffusion 整合包快速部署与实战指南
  • C++ 面试基础:与 C 语言区别及 C++11 新特性
  • 次模函数(Submodular Function)核心概念与机器学习应用
  • 老 MacBook 安装 Linux 部署 OpenClaw 实现 24 小时服务器
  • OpenAI 发布 GPT-4o:多模态实时交互与性能突破
  • RESTful API 接口设计规范
  • Midjourney 官网地址及中文环境下的使用指南
  • 前端面试核心考点解析:JavaScript 原理、Vue 机制与性能优化
  • Java 二维数组按列排序及行列互换实现
  • Flutter 集成 Google 生成式 AI 适配鸿蒙 HarmonyOS 实战
  • 本地搭建 Stable Diffusion AI 绘画工具完整指南
  • Git 入门实战:从环境配置到分支协作
  • 大模型入门教程:核心优势与学习路径指南
  • DOM 详解:使用 JavaScript 操作网页元素的核心方法

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online