跳到主要内容
超越 CRUD:用 JeecgBoot 低代码模式一天搭建请假审批系统 | 极客日志
Java SaaS 大前端 java
超越 CRUD:用 JeecgBoot 低代码模式一天搭建请假审批系统 综述由AI生成 通过实战案例演示如何使用 JeecgBoot 低代码平台快速构建请假审批系统。内容涵盖架构解析、在线表单设计、代码生成器、流程设计器及报表设计器的核心原理。详细步骤包括数据库设计、模块创建、审批流程配置、自定义业务逻辑开发及统计图表集成。此外还剖析了前后端分离架构、统一响应规范及开发者角色演变,提供了分层开发策略与代码管理规范建议,旨在帮助开发者利用低代码工具提升企业应用开发效率。
赛博行者 发布于 2026/4/6 更新于 2026/5/23 25 浏览超越 CRUD:用 JeecgBoot 低代码模式一天搭建请假审批系统
引言:低代码革命与 JeecgBoot 的崛起
在当今快速变化的商业环境中,企业应用开发的传统瓶颈 日益凸显:开发周期长、成本高、对专业开发人员依赖度强、难以快速响应业务变化。根据 Forrester Research 的报告,超过 60% 的企业应用开发项目存在延期交付问题,而低代码开发平台 正成为解决这一困境的关键技术。
JeecgBoot 作为国内领先的 Java 低代码开发平台,凭借其强大的代码生成能力 和可视化开发工具 ,让开发者能够以惊人的速度构建企业级应用。本文将通过一个完整的'请假审批系统'实战案例,深入解析 JeecgBoot 的低代码核心原理,并展示如何在一天内 完成一个功能完备的后台系统开发。
一、JeecgBoot 低代码架构深度解析
1.1 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"
:
"请选择开始时间"
}
]
}
]
}
组件注册中心 :维护所有可用表单组件的元数据
Schema 解析引擎 :将 JSON Schema 转换为实际的 Vue 组件
双向数据绑定 :实时同步表单数据与 UI 状态
验证规则引擎 :动态应用表单验证规则
1.2.2 代码生成器:自动化 CRUD 开发 JeecgBoot 的代码生成器是其'快速开发'的基石。它采用模板驱动 的代码生成策略,支持高度定制化。代码生成的工作流程如下:
用户选择数据表
解析表结构
生成基础代码模板
选择生成模式(单表模式、树表模式、一对多模式、ERP 模式)
应用 Velocity 模板
生成源代码文件、SQL 文件、前端页面
输出到项目目录
用户二次开发
数据库元数据解析 :通过 JDBC DatabaseMetaData 接口获取表结构信息
模板引擎 :使用 Velocity 模板引擎进行代码生成
类型映射系统 :将数据库字段类型映射为 Java 类型和前端组件
路径计算算法 :根据命名规范自动计算包路径和文件路径
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;
@Column(name = "version_")
private Integer version;
@Column(name = "deployment_id_")
private String deploymentId;
@Column(name = "resource_name_")
private String resourceName;
@Column(name = "diagram_resource_name_")
private String diagramResourceName;
@Column(name = "suspension_state_")
private Integer suspensionState;
}
BPMN 2.0 兼容 :支持标准 BPMN 流程图设计
节点类型丰富 :包括用户任务、服务任务、网关、事件等
表单绑定 :支持将流程节点与动态表单关联
权限配置 :可视化配置任务处理人和候选组
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-3 天请假)
人事部门审批(3 天以上请假或特殊类型)
总经理审批(7 天以上请假)
管理功能 :
系统功能 :
消息通知(邮件、站内信)
日历视图展示
导出请假记录
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 的在线开发 功能模块:
登录 JeecgBoot 系统,进入'系统管理' → '在线开发'
点击'导入数据库表',选择 sys_leave 表
系统自动解析表结构,生成字段配置
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 生成代码并导入项目 配置完成后,点击'生成代码'按钮,系统将生成以下文件:
后端代码 :
SysLeaveController.java - 控制器
ISysLeaveService.java - 服务接口
SysLeaveServiceImpl.java - 服务实现
SysLeaveMapper.java - 数据访问接口
SysLeaveMapper.xml - MyBatis 映射文件
SysLeave.java - 实体类
前端代码 :
SysLeaveList.vue - 列表页面
SysLeaveModal.vue - 表单弹窗
SysLeave.js - API 接口文件
SQL 脚本 :
下载生成的代码包,解压并按照说明导入到 JeecgBoot 项目中。
2.3 步骤二:使用流程设计器配置审批流程
2.3.1 设计请假审批流程 进入'流程设计'模块,新建一个名为'请假审批流程'的流程:
开始 -> 提交请假申请 -> 请假天数判断
1-3 天 -> 部门经理审批 -> 结束
3-7 天 -> 部门经理审批 -> 人事审批 -> 结束
7 天以上 -> 部门经理审批 -> 人事审批 -> 总经理审批 -> 结束
审批结果 -> 更新请假状态 -> 通知申请人
2.3.2 配置流程节点
节点基本信息 :名称、处理人/组、表单
表单绑定 :关联请假申请表单
处理规则 :自动通过、手动审批等
通知配置 :邮件、站内信通知
<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 BaseService <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 );
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);
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" ;
leave.setStatus(finalStatus);
leaveService.updateById(leave);
sendFinalNotification(leave, finalStatus);
}
}
}
2.5 步骤四:使用报表设计器创建统计图表
2.5.1 设计请假统计报表
数据源配置 :连接 sys_leave 表
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
图表设计 :
柱状图 :每月各类型请假天数对比
饼图 :请假类型分布
折线图 :请假趋势分析
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></div>
</a-card>
</a-col>
<a-col :span="12">
<a-card title="请假类型分布" size="small">
<div></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 响应格式:
@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 => {
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
}
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)
}
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 适合低代码开发的场景
常规业务管理系统 :OA、CRM、ERP 等
数据收集与展示系统 :报表系统、数据分析平台
工作流审批系统 :各种审批流程管理
内部管理工具 :员工管理、资产管理等
4.2.2 不适合低代码开发的场景
高性能计算系统 :科学计算、实时交易等
复杂算法实现 :机器学习、图像处理等
特定硬件交互 :物联网设备控制、驱动程序
超高并发系统 :大型电商、社交平台等
4.3 开发者需要关注的底层技术
4.3.1 数据库设计与优化
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);
}
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 系统监控与性能优化
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 分层开发策略
基础层 :使用低代码工具快速生成基础 CRUD
业务层 :手动开发复杂业务逻辑和服务
集成层 :处理外部系统对接和消息队列
表现层 :使用低代码表单和报表设计器
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 在一天内构建请假审批系统的实际效果:
开发效率提升 :相比传统开发,效率提升 300% 以上
代码质量保证 :生成的代码规范统一,减少人为错误
维护成本降低 :可视化配置使得后期修改更加容易
团队协作优化 :前后端分离,并行开发成为可能
5.2 JeecgBoot 的适用场景总结 JeecgBoot 特别适合以下类型的项目和团队:
项目类型 适合程度 关键考量 企业内部管理系统 ★★★★★ 快速响应业务变化需求 政府政务系统 ★★★★☆ 需要流程审批和权限控制 中小型企业 ERP ★★★★☆ 定制化需求多,预算有限 教育管理系统 ★★★★☆ 用户角色复杂,权限细分 互联网创新项目 MVP ★★★☆☆ 快速验证产品思路
5.3 未来发展趋势
AI 增强 :集成 AI 能力,实现智能代码生成和建议
多端统一 :一套代码生成多端应用(Web、小程序、App)
云原生集成 :深度集成云服务,实现一键部署和扩缩容
可视化深度 :从界面可视化到业务逻辑可视化
生态开放 :建立插件市场,汇集第三方组件和服务
5.4 给开发者的建议 对于正在或计划使用 JeecgBoot 等低代码平台的开发者,建议:
掌握核心原理 :不要只停留在使用层面,要理解实现机制
保持编码能力 :低代码不是无代码,复杂逻辑仍需编码实现
关注业务价值 :从技术实现者转变为业务解决方案提供者
持续学习更新 :低代码技术发展迅速,需要不断学习新特性
参与社区贡献 :积极反馈问题,贡献代码,共同推动平台发展
结语 JeecgBoot 作为国内领先的 Java 低代码开发平台,通过本文的深度解析和实战演示,我们不仅看到了它如何大幅提升开发效率,更理解了其背后的技术原理和设计哲学。低代码不是要取代开发者,而是要解放开发者 ,让开发者从重复的 CRUD 编码中解脱出来,专注于更有价值的业务创新和技术攻关。
在数字化转型的浪潮中,掌握 JeecgBoot 这样的低代码工具,意味着你拥有了快速响应业务变化、高效交付企业应用的能力。这不仅是技术能力的提升,更是职业竞争力的重要组成部分。
希望本文能够帮助你深入理解 JeecgBoot 的低代码开发模式,并在实际项目中应用这些知识,真正实现'一天搭建一个功能完备的后台系统'的目标。
相关免费在线工具 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