若依框架实战:5步搞定SpringBoot+Vue后台管理系统(附完整代码)
最近在帮一个朋友的公司搭建内部运营平台,他们需要一个功能完整、能快速上线的后台管理系统。我评估了几个主流方案,最终还是选择了若依(RuoYi)。原因很简单:它开箱即用的模块化设计,加上前后端分离的架构,能让一个三五人的小团队在几天内就搭出一个像模像样的管理后台。但说实话,第一次接触时我也踩了不少坑,尤其是Redis连接和代码生成器那块,折腾了大半天。这篇文章,我就把从零搭建到核心功能定制的完整流程,结合我实际趟过的那些“坑”,给你拆解清楚。
如果你正面临类似的场景——需要快速交付一个企业级管理系统,但又不想从零造轮子,或者你是刚接触SpringBoot和Vue,想找一个能贯穿学习前后端协作的实战项目,那若依会是一个绝佳的起点。它不仅仅是一个框架,更像是一个“最佳实践”的集合,把权限管理、菜单配置、日志监控这些通用又繁琐的功能都打包好了。接下来,我会用五个清晰的步骤,带你走完从环境搭建到功能定制的全过程,并提供可直接复用的代码片段和调试技巧。
1. 环境准备与项目初始化
在开始敲代码之前,把环境理顺是避免后续各种诡异报错的关键。若依对运行环境有明确要求,我建议你严格按照官方推荐的版本进行配置,这能省去大量版本兼容性排查的时间。
核心环境清单:
- JDK: 1.8 或更高版本(推荐 OpenJDK 11 或 Oracle JDK 17,注意若依新版可能对高版本JDK有更好支持)。
- MySQL: 5.7 或更高版本(务必确认已安装并启动服务)。
- Redis: 3.0 或更高版本(这是若依用于会话管理和缓存的核心组件,启动前必须确保它正在运行)。
- Maven: 3.0+,用于后端依赖管理。
- Node.js: 12.0+ 及 npm,用于前端构建。
注意:很多新手最容易忽略的就是Redis。我曾不止一次遇到项目启动失败,控制台报一堆连接异常,最后发现都是因为本地Redis服务没开。启动项目前,务必用
redis-cli ping命令测试一下连通性。
1.1 获取项目源码与数据库初始化
若依的代码托管在Gitee上,前后端是分离的两个仓库。我习惯用Git命令直接克隆,这样后续更新也方便。
# 克隆后端项目
git clone https://gitee.com/y_project/RuoYi.git
# 克隆前端项目
git clone https://gitee.com/y_project/RuoYi-Vue.git
克隆完成后,先别急着启动。打开后端项目的 ruoyi-admin 模块下的配置文件 src/main/resources/application-druid.yml,找到数据库连接部分进行修改:
spring:
datasource:
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root # 改为你的数据库用户名
password: 123456 # 改为你的数据库密码
这里有个小细节,ry-vue 是若依默认的数据库名。你需要在MySQL中先创建这个数据库(CREATE DATABASE ry-vue;),然后执行项目 sql 目录下的两个SQL脚本。顺序很重要:先执行 quartz.sql(用于定时任务),再执行 ry_2024xxxx.sql(主业务表结构及数据)。这一步是构建系统基础数据(如管理员账号、菜单、部门等)的关键。
1.2 后端项目启动与常见问题排查
环境配置好后,进入 ruoyi-admin 目录,找到 RuoYiApplication.java 这个启动类,直接运行它的 main 方法即可。如果使用IDE(如IntelliJ IDEA或Eclipse),通常右键就能找到运行选项。
启动过程中,最常遇到的“拦路虎”有两个:
- Redis连接失败:控制台如果出现
Connection refused或Failed to connect to Redis之类的错误,九成是Redis服务没启动。去终端执行redis-server启动服务,或者检查application.yml中Redis的配置(主机、端口、密码)是否正确。 - 端口占用:若依后端默认使用8080端口。如果这个端口已被其他程序(比如你之前启动的其他SpringBoot应用)占用,启动会失败。解决方法一是关闭占用端口的进程,二是在
application.yml中修改server.port为其他端口,例如 8088。
一个健康的启动日志,最后应该能看到类似下面的信息,表明各模块已成功加载:
Started RuoYiApplication in 5.897 seconds (JVM running for 6.523)
1.3 前端项目启动与联调
后端服务跑起来后,我们转向前端。进入 ruoyi-ui 目录,首先安装依赖:
npm install --registry=https://registry.npmmirror.com
这里我使用了淘宝的镜像源,速度会快很多。安装完成后,运行开发服务器:
npm run dev
正常情况下,终端会输出本地访问地址,通常是 http://localhost:80。在浏览器中打开它,你应该能看到若依的登录界面。使用默认账号 admin 和密码 admin123 即可登录。
至此,一个完整的若依前后端分离项目已经在你的本地运行起来了。登录后,你会看到一个功能齐全的管理后台,涵盖了用户、角色、菜单、部门、日志等几乎所有后台系统需要的通用模块。但这只是开始,接下来我们要学习如何让它为我们自己的业务服务。
2. 核心功能模块解析与代码生成器实战
若依的强大之处在于其“骨架”非常完整。在深入定制前,有必要理解它的核心模块是如何组织的。后端项目主要分为几个模块:
| 模块名称 | 核心职责 | 是否必需 |
|---|---|---|
ruoyi-admin | 应用启动入口,存放主配置和控制器。 | 是 |
ruoyi-framework | 框架核心,包含权限、日志、工具类等通用组件。 | 是 |
ruoyi-system | 系统业务模块,如用户、角色、菜单管理的具体实现。 | 是 |
ruoyi-common | 通用工具、常量、异常定义等。 | 是 |
ruoyi-quartz | 定时任务调度模块(基于Quartz)。 | 可选 |
ruoyi-generator | 代码生成器模块,开发效率利器。 | 可选,但强烈推荐 |
对于快速开发而言,ruoyi-generator 是必须重点掌握的“神器”。它能根据数据库表结构,一键生成包含Controller、Service、Mapper、Entity以及Vue页面在内的全套基础CRUD代码。
2.1 使用代码生成器创建业务模块
假设我们要开发一个“产品管理”功能。第一步是在数据库中创建对应的表。
CREATE TABLE `tb_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '产品ID',
`product_name` varchar(255) NOT NULL COMMENT '产品名称',
`product_code` varchar(100) DEFAULT NULL COMMENT '产品编码',
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品信息表';
建好表后,启动你的前后端项目。在系统左侧菜单找到 “系统工具” -> “代码生成”。你会看到数据库中所有表的列表。找到刚创建的 tb_product 表,点击“生成代码”。
在配置页面,有几个关键选项需要填写:
- 生成模块名:例如
product,这会影响生成代码的包路径。 - 生成包路径:例如
com.ruoyi.product,这是后端Java代码的根包名。 - 生成业务名:例如
product,用于生成菜单和权限前缀。 - 上级菜单:选择新生成的菜单要挂在哪个现有菜单下,比如“系统管理”。
配置完成后,点击“生成代码”,系统会打包下载一个ZIP文件。解压后,你会得到两个文件夹:main(Java后端代码)和 vue(前端Vue代码)。
2.2 集成生成的代码
后端集成:将 main/java 下的文件复制到后端项目对应的包路径下(如 com.ruoyi.product),将 main/resources 下的Mapper XML文件复制到 resources/mapper/product 目录下。
前端集成:将 vue/api 下的JS文件复制到前端项目的 src/api 目录下(可新建 product 文件夹归类)。将 vue/views 下的Vue文件复制到 src/views 目录下。
菜单生成:在下载的ZIP文件中,通常还包含一个 sql 文件夹,里面有生成菜单的SQL语句。在数据库中执行它,或者直接在若依后台的 “系统管理” -> “菜单管理” 中,手动添加对应的菜单项,配置其路径指向刚生成的Vue组件。
完成这些步骤后,重启后端服务,刷新前端页面,你就能在指定的上级菜单下看到全新的“产品管理”功能了,它已经具备了列表查询、新增、修改、删除、导出等基础能力。整个过程可能只需要10分钟,这就是代码生成器的威力。
3. 深度定制:超越基础CRUD
代码生成器给了我们一个完美的起点,但真实业务需求往往更复杂。比如,产品列表里我们想显示产品分类的名称(来自另一张表),而不仅仅是分类ID。又或者,我们想在删除产品前做一个二次确认,并记录操作日志。这就需要我们对生成的代码进行定制。
3.1 实现关联查询与VO对象封装
继续以产品表为例,假设我们还有一张分类表 tb_category。产品表中有一个 category_id 字段。现在需要在产品列表页显示分类名称。
第一步,创建视图对象(VO)。在 product 包下新建一个 ProductVo.java 类,它继承自 Product 实体类,并增加 categoryName 字段。
package com.ruoyi.product.domain.vo;
import com.ruoyi.product.domain.Product;
public class ProductVo extends Product {
private String categoryName;
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
第二步,编写关联查询的SQL。修改 ProductMapper.xml 文件,在原有的 selectProductList 方法基础上,编写一个新的查询语句,使用 LEFT JOIN 关联分类表。
<select id="selectProductVoList" parameterType="Product" resultMap="ProductVoResult">
select p.*, c.category_name
from tb_product p
left join tb_category c on p.category_id = c.id
<where>
<if test="productName != null and productName != ''">
AND p.product_name like concat('%', #{productName}, '%')
</if>
<!-- 其他查询条件 -->
</where>
</select>
同时,需要在Mapper接口 ProductMapper.java 和Service层中增加对应的方法声明与实现。
第三步,修改Controller。将产品列表查询的接口,从调用返回 Product 列表的方法,改为调用返回 ProductVo 列表的新方法。这样,前端接收到的数据就包含了分类名称。
第四步,前端微调。在Vue的列表页面 index.vue 中,为表格增加一列,将 prop 属性绑定到 categoryName 即可。
<el-table-column label="产品分类" align="center" prop="categoryName" />
这个过程体现了若依框架良好的扩展性。你不需要改动框架底层,只需在业务层进行增补和替换。
3.2 增强业务逻辑与操作拦截
另一个常见需求是给删除操作增加确认对话框和日志。若依前端基于Element UI,实现确认对话框非常简单。找到列表页中删除按钮的代码段,通常是 @click="handleDelete(scope.row)",我们可以将其改为调用一个自定义的确认方法。
<el-button
size="small"
type="text"
icon="Delete"
@click="confirmDelete(scope.row)"
v-hasPermi="['product:product:remove']"
>删除</el-button>
在Vue组件的 <script> 部分,添加 confirmDelete 方法:
// 删除按钮弹窗确认操作
function confirmDelete(row) {
proxy.$modal.confirm('是否确认删除产品名称为"' + row.productName + '"的数据项?').then(function() {
return delProduct(row.id);
}).then(() => {
proxy.$modal.msgSuccess("删除成功");
getList(); // 重新查询列表
// 这里可以调用一个记录日志的API
// logOperation('删除产品', '产品ID: ' + row.id);
}).catch(() => {});
}
proxy.$modal.confirm 是若依封装好的消息确认框。在删除成功后,我们不仅可以刷新列表,还可以调用一个自定义的后端接口来记录详细的操作日志。这需要在后端新增一个日志服务方法,并在Controller中调用。
这种定制让系统更健壮、更符合审计要求。通过这几个例子,你应该能感受到,基于若依进行开发,大部分工作是在“填空”和“连接”,而不是从零构建地基。
4. 权限控制与数据安全实践
若依集成了Spring Security,提供了细粒度的权限控制。你可能会注意到,在生成的Controller方法上,经常有 @PreAuthorize("@ss.hasPermi('product:product:list')") 这样的注解。这就是权限控制的钥匙。
4.1 理解权限标识符
权限字符串的格式通常是 模块:业务:操作。例如:
system:user:view表示“系统管理:用户管理:查询”product:product:add表示“产品管理:产品:新增”
这个标识符需要与数据库 sys_menu 表中的 perms 字段对应。当你通过代码生成器生成菜单时,这些权限标识会自动插入数据库。前端按钮上的 v-hasPermi 指令(如 v-hasPermi="['product:product:edit']")会根据当前用户的权限,动态决定是否渲染这个按钮。
4.2 自定义数据权限
除了菜单和按钮权限,数据权限(即用户只能看到或操作自己部门/角色的数据)是另一个核心需求。若依通过“数据范围”来实现。在 sys_role 表中,有一个 data_scope 字段,定义了角色的数据权限范围,如“全部数据权限”、“本部门数据权限”、“自定义”等。
实现自定义数据权限,通常需要以下步骤:
- 在实体类中,添加一个
params属性(Map类型),用于在查询时传递数据权限参数。 - 在Mapper的查询SQL中,通过
<if>标签动态拼接数据过滤条件。例如,只查询创建人是自己的数据:<if test="params.createBy != null and params.createBy != ''"> AND create_by = #{params.createBy} </if>。 - 在Service层,通过SecurityUtils获取当前登录用户信息,并将其ID或其他标识设置到实体类的
params中。
// 在Service实现类中
public TableDataInfo selectProductList(Product product) {
startPage();
// 获取当前用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
// 假设我们实现“仅查看自己创建的数据”
product.getParams().put("createBy", loginUser.getUsername());
}
List<Product> list = productMapper.selectProductList(product);
return getDataTable(list);
}
这样,不同角色的用户登录后,看到的数据列表就会根据预设的规则进行过滤。这套机制对于构建多租户或具有复杂组织架构的系统至关重要。
5. 部署上线与性能调优要点
当本地开发调试完成后,最终需要将系统部署到生产环境。若依前后端分离的架构使得部署可以非常灵活。
5.1 前端构建与部署
首先,我们需要将Vue项目编译成静态文件。在 ruoyi-ui 目录下执行:
npm run build:prod
这个命令会进行代码压缩、混淆,并在 dist 目录下生成优化后的静态资源。你可以将这些文件(index.html, css, js, fonts 等)部署到任何静态文件服务器,如Nginx、Apache或对象存储(OSS)中。
一个简单的Nginx配置示例如下:
server {
listen 80;
server_name your-domain.com;
location / {
root /path/to/your/ruoyi-ui/dist;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 代理后端API请求
location /prod-api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这里的关键是 try_files $uri $uri/ /index.html;,它让Vue Router能正确处理前端路由。同时,我们将所有以 /prod-api/ 开头的请求反向代理到后端的SpringBoot服务(假设运行在8080端口)。
5.2 后端打包与部署
后端项目使用Maven打包。在项目根目录执行:
mvn clean package -DskipTests
打包完成后,在 ruoyi-admin/target 目录下会生成一个 ruoyi-admin.jar 文件。这就是可执行的SpringBoot应用jar包。
在生产服务器上,你可以使用 java -jar 命令直接运行,但更推荐使用进程管理工具(如 systemd 或 supervisor)来守护进程,确保应用崩溃后能自动重启。一个基本的 systemd 服务文件 (ruoyi.service) 可能长这样:
[Unit]
Description=RuoYi Admin Service
After=network.target
[Service]
Type=simple
User=appuser
ExecStart=/usr/bin/java -Xms512m -Xmx1024m -jar /path/to/ruoyi-admin.jar
Restart=on-failure
[Install]
WantedBy=multi-user.target
这里我设置了JVM堆内存的初始值(-Xms)和最大值(-Xmx),你可以根据服务器实际内存情况调整。
5.3 基础性能与安全考量
- 数据库连接池:若依默认使用Druid。在生产环境中,务必在
application-druid.yml中调整连接池参数,如initialSize、minIdle、maxActive、maxWait等,以匹配你的并发访问量。 - Redis缓存:确保生产环境的Redis配置了密码,并考虑使用持久化方案。若依的会话和部分缓存数据存储在Redis中,其稳定性直接影响系统可用性。
- 日志管理:生产环境应将日志级别调整为
WARN或ERROR,并配置日志滚动策略,避免日志文件无限膨胀占满磁盘。可以在application.yml中配置logback-spring.xml文件路径进行详细定制。 - 静态资源:将前端构建的静态文件与后端服务分离部署(如前文Nginx方案),能显著减轻应用服务器压力,并利于CDN加速。
走完这五步,从环境搭建、功能生成、深度定制、权限整合到最终部署,一个基于若依框架的、可投入使用的后台管理系统就基本成型了。这套流程我已在多个中小型项目中验证过,能稳定地将开发周期从以“月”计压缩到以“周”甚至“天”计。当然,若依更像一个坚实的起点,面对极其复杂的业务流时,你仍然需要深入理解SpringBoot和Vue本身,在它的基础上进行更精巧的设计。但无论如何,它已经为你扫清了至少70%的重复性障碍,让你能更专注于业务逻辑本身。
1726



被折叠的 条评论
为什么被折叠?



