为什么要基于若依框架开发?
- 快速开发:若依框架提供了许多现成的模块和工具,能够快速搭建起一个基本的应用框架,从而减少了开发的时间和工作量。
- 高度可定制性:若依框架提供了丰富的插件和扩展点,可以根据项目的需求进行定制和扩展,满足不同项目的特定需求。
- 简化开发流程:若依框架提供了许多常用的功能模块,如权限管理、数据字典、定时任务等,能够简化开发流程,提高开发效率。
- 易于维护和管理:若依框架采用了模块化的设计,代码结构清晰,易于维护和管理,有助于降低项目的维护成本。
- 社区支持和更新迭代:若依框架有一个活跃的开发社区,能够及时提供技术支持和更新迭代,保证项目的稳定性和安全性。
1. 若依介绍
若依(RuoYi)框架是一款基于Spring Boot、Spring Cloud等开源框架搭建的企业级开发平台。它的主要目标是提供全面的解决方案,以简化企业级应用开发,**提高开发效率**。
若依官网地址:ruoyi.vip/
以下是若依框架的详细介绍:
- 模块化设计:若依框架采用模块化的设计,使得应用可以根据需求进行灵活的扩展和定制。每个模块都可以独立部署和升级,这大大提高了系统的可维护性和可扩展性。
- 前后端分离:框架采用前后端分离的开发模式,后端专注于数据处理和API接口的提供,前端则负责页面的展示和用户交互。这种模式使得前后端职责明确,进一步提高了开发效率和代码的可维护性。
- 权限管理:若依框架提供了完善的用户权限管理功能,包括角色管理、菜单授权、部门管理等,便于对系统权限进行灵活的配置和管理。
- 代码生成器:框架内置代码生成器,能够快速生成前后端代码,减少重复劳动,提高开发效率。通过简单的配置即可生成基础的增删改查代码。
- 定时任务:若依框架集成了定时任务模块,支持动态添加定时任务,可以通过界面对定时任务进行管理与调度。此外,框架还能实时查看系统运行日志和在线用户信息,监控服务状态和性能。
- 易于集成:若依框架可以轻松地与其他常用技术栈集成,如MySQL、Redis、消息队列等。这使得开发者可以根据项目需求灵活地选择合适的技术组件,降低技术门槛和成本。
此外,若依框架还集成了许多常用功能模块,如文件上传下载、消息推送、数据字典、日志管理等。
总的来说,若依框架是一款功能丰富、易于扩展和定制的企业级开发平台,适用于各种Web应用程序的开发。它能够帮助开发者快速构建功能完备的应用,提高开发效率,降低维护成本。
2. 若依前后端分离版
若依框架分为四个版本:前三个都提供了前后端的项目,移动版可以适配RuoYi-Vue和RuoYi-Cloud
- 前后端不分离版本RuoYi(单体)
- 前后端分离版RuoYi-Vue(单体)本项目使用版本
- 微服务版本RuoYi-Cloud
- 移动端版RuoYi-App
我们重点讲解的是RuoYi-Vue前后端分离版本,文档地址:doc.ruoyi.vip/ruoyi-vue/
2.1 概述
RuoYi-Vue 是一个 Java EE 企业级快速开发平台,基于经典技术组合(Spring Boot、Spring Security、MyBatis、Jwt、Vue),内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定时任务配置;支持集群,支持多数据源,支持分布式事务。
演示地址:vue.ruoyi.vip
二、环境搭建
熟悉了若依的基本情况之后,我们来把这个框架搭建起来,并且需要顺利跑起来
1. 准备工作
1.1 基础环境说明
官方推荐 | 优化升级 |
---|---|
JDK >= 1.8 (推荐1.8版本) | 升级为JDK 11 |
Maven >= 3.0 | 直接使用我们配置好的maven即可 |
Node >= 12 | 前端代码由vue2升级为vue3,需要Node 18及以上的版本 |
Mysql >= 5.7.0 (推荐5.7版本) | 升级为MySQL 8 |
Redis >= 3.0 | 本地启动 |
1.2 准备虚拟机环境
一般企业中服务器都是部署了一些项目中公用的基础环境,比如MySQL、Redis等这些。这些服务都是部署在linux服务器中,这些服务可能是部署在公司的一个机房 中,也有可能是云服务器(中小企业居多)。
在我们教学的过程中,为了还原更真实的企业环境,我们可以在VMWare软件中来部署linux服务器,当做我们开发中的公用服务器。
在目前提供的虚拟机环境中已经使用docker安装了对应的基础环境
2. 运行后端项目
2.1 下载项目代码
代码下载地址:gitee.com/y_project/R...
由于若依提供的代码的包名和项目名和咱们的需求不一致,因此这里暂时不要采用Git克隆 的方式下载代码,直接下载ZIP包到本地,然后先替换所有的包名和项目名,再使用idea打开项目
2.2 准备数据库
虚拟机中提供的数据库是MySQL 8,在idea中连接MySQL
2.2.1 执行SQL脚本
双击打开项目中《sql/ry_20250522.sql》,在最顶部添加以下语句,然后执行整个ry_2024xxxx.sql脚本文件,导入数据库
mysql
create database if not exists xxx;
use xxx;
2.2.2 修改配置文件
数据库导入成功之后,修改zzyl-admin模块中的配置文件 src\main\resources\application-druid.yml,修改数据库连接信息
2.3 配置Redis
找到zzyl-admin模块中的resources
目录下的application.yml
,配置密码
2.4 运行项目
找到zzyl-admin模块中的运行com.ruoyi.RuoYiApplication.java
,出现如下图表示启动成功。
Bash
(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙
.-------. ____ __
| _ _ \ \ \ / /
| ( ' ) | \ _. / '
|(_ o _) / _( )_ .'
| (_,_).' __ ___(_ o _)'
| |\ \ | || |(_,_)'
| | \ `' /| `-' /
| | \ / \ /
''-' `'-' `-..-'
3. 运行前端项目
:bulb:官方推荐的前端项目,使用的是vue3,需要使用node 18版本以上
如果没有安装node18或者更高版本的同学,可以在资料中找到对应的安装包进行安装
3.1 下载前端项目
目前下载的代码中,其中ruoyi-ui这个目录就是前端的代码,不过这个代码是基于vue2开发的。 如果需要使用vue2为基础开发语言的前端,就可以使用上述的代码,运行方式跟下方描述相同
我们需要使用基于vue3开发的代码,官方推荐的地址:github.com/yangzongzhu...
将zip包解压到你自己的代码目录,然后使用VSCode打开
4.2 安装依赖
进入到代码的根目录,然后执行以下命令:
### 4.3 修改配置
打开前端根目录下的vite.config.js文件,把目标地址改为若依后端的服务地址,如下图:
### 4.4 启动项目
如果依赖已经安装完成,配置也已修改,则可以直接启动项目
启动前后端成功后,可以访问页面,地址:http://localhost:80/
三、前后端项目结构【理解】
环境搭建完毕之后,接下来,我们深入熟悉一下若依这个框架,我们主要从代码的层面来熟悉项目
- 熟悉前后端的代码结构
- 阅读部分代码,熟悉开发流程和规范
- 所以,接下来我们分两步来熟悉项目代码,一是后端的代码结构及配置,二是前端的代码结构及执行流程
1. 后端代码
1.1 代码结构
官方文档介绍的项目结构:
Bash
com.ruoyi
├── ruoyi-admin // 后台服务 存放 controller
├── common // 工具类
│ └── annotation // 自定义注解
│ └── config // 全局配置
│ └── constant // 通用常量
│ └── core // 核心控制
│ └── enums // 通用枚举
│ └── exception // 通用异常
│ └── filter // 过滤器处理
│ └── utils // 通用类处理
├── framework // 框架核心
│ └── aspectj // 注解实现
│ └── config // 系统配置
│ └── datasource // 数据权限
│ └── interceptor // 拦截器
│ └── manager // 异步处理
│ └── security // 权限控制
│ └── web // 前端控制
├── ruoyi-generator // 代码生成(可移除)
├── ruoyi-quartz // 定时任务(可移除)
├── ruoyi-system // 系统代码 存放 domain,mapper,service
├── ruoyi-xxxxxx // 其他模块
模块间的依赖关系
1.2 项目中的配置
最主要的2个配置文件:application.yml和application-druid.yml
-
application.yml
YAML# 项目相关配置 ruoyi: # 名称 name: RuoYi # 版本 version: 3.8.7 # 版权年份 copyrightYear: 2024 # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数字计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # 用户配置 user: password: # 密码最大错误次数 maxRetryCount: 5 # 密码锁定时间(默认10分钟) lockTime: 10 # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 192.168.100.168 # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码 password: 123456 # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 30 # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/*
-
application-druid.yml
YAML# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://192.168.100.168:3306/zzyl?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: heima123 # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置连接超时时间 connectTimeout: 30000 # 配置网络超时时间 socketTimeout: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true
1.3 表结构
若依项目目前已经提供了19张表,我们可以先简单熟悉一下每个表代表的含义:
2. 前端代码
2.1 代码结构
详细目录或文件说明:
Bash
├── bin // 执行脚本
├── public // 公共文件
│ ├── favicon.ico // favicon图标
├── src // 源代码
│ ├── api // 所有请求,后台的api接口,后期开发重点目录
│ ├── assets // 主题 字体等静态资源
│ ├── components // 全局公用组件
│ ├── directive // 全局指令
│ ├── layout // 布局
│ ├── plugins // 通用方法
│ ├── router // 路由
│ ├── store // 全局 store管理
│ ├── utils // 全局公用方法
│ ├── views // view,存储vue组件,后期开发重点目录
│ ├── App.vue // 入口页面
│ ├── main.js // 入口 加载组件 初始化等
│ ├── permission.js // 权限管理
│ └── settings.js // 系统配置
├── vite // 前端构建工具
├── .env.development // 开发环境配置
├── .env.production // 生产环境配置
├── .env.staging // 测试环境配置
├── .gitignore // git 忽略项
├── LICENSE // 许可证
├── package-lock.json // 锁定项目依赖的具体版本号
├── package.json // 配置项目的信息、名称、版本号、描述信息等
├── pnpm-lock.yaml // 锁定项目依赖的具体版本号
└── vite.config.js // 用于配置 Vue.js 项目的全局选项,可修改后台访问接口路径
2.2 核心配置
在开发阶段,配置的修改是较少的,主要关于一个配置文件即可:vite.config.js
JavaScript
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd())
const { VITE_APP_ENV } = env
return {
// 部署生产环境和开发环境下的URL。
// 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
base: VITE_APP_ENV === 'production' ? '/' : '/',
plugins: createVitePlugins(env, command === 'build'),
resolve: {
// https://cn.vitejs.dev/config/#resolve-alias
alias: {
// 设置路径
'~': path.resolve(__dirname, './'),
// 设置别名
'@': path.resolve(__dirname, './src')
},
// https://cn.vitejs.dev/config/#resolve-extensions
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// vite 相关配置
server: {
port: 80,
host: true,
open: true,
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
target: 'http://localhost:8080',
// target: 'https://api.wzs.pub/mock/13',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
}
}
},
//fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
css: {
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove();
}
}
}
}
]
}
}
}
})
-
别名
~
代表./
@
代表src目录
-
前端服务端口--->
port: 80
-
后端服务地址--->
target: '``http://localhost:8080``'
-
路径重写--->
rewrite: (p) => p.replace(/^\/dev-api/, '')
四、功能快速开发
接下来,我们来快速感受一下若依框架的代码生成的功能
若依提供的代码生成功能,可以基于表结构快速生成前后端的代码,下面,我们快速感受一下单表的代码生成
1. 准备工作
我们首先开发的是护理项目模块,我们需要准备两部分内容,一个是一级菜单,第二个是表结构
1.1 准备主菜单
我们要开发的模块是护理项目模块,而护理项目是子菜单,我们需要先在若依项目中创建一个服务管理的主菜单,方便对服务管理下的功能进行分类。
最终效果如下:

详细操作步骤配置,如下:

1.2 表结构
护理项目表结构定义SQL如下,连接上zzyl数据库执行SQL:
mysql
CREATE TABLE `nursing_project` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '名称',
`order_no` int DEFAULT NULL COMMENT '排序号',
`unit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '单位',
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',
`image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片',
`nursing_requirement` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '护理要求',
`status` int NOT NULL DEFAULT '1' COMMENT '状态(0:禁用,1:启用)',
`create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='护理项目表';

2. 代码生成
2.1 导入表
找到系统工具 -->代码生成 ,然后点击导入按钮

选中nursing_project表结构,点击确定

2.2 修改配置
目前在代码生成列表中,可以看到需要生成的数据。 该数据对应了5个按钮

在生成之前,我们需要对代码生成做一些配置,我们可以点击修改按钮,可以看到有三部分的配置
- 基本信息
- 字段信息
- 生成信息
2.2.1 基本信息
下图是**基本信息,**可以根据自己的需求修改:表、实体、表描述、作者相关的数据

2.2.2 字段信息
下图是字段信息,详细描述如下图:
字段信息 | 描述 |
---|---|
字段列名 | 表中的字段列名称 |
字段描述 | 字段的描述,读取的comment信息,可根据实际情况更改 |
物理类型 | 数据库所对应的字段类型 |
Java类型 | Java实体类中属性的类型,可改,例如,状态字段:Long类型可以修改为Integer |
Java属性 | Java实体类中所对应的属性名称 |
插入 | 新增的时候,需要插入的字段 |
编辑 | 修改的时候,需要插入的字段 |
列表 | 列表查询需要展示的字段 |
查询 | 列表查询,需要的条件字段 |
查询方式 | 与上面查询条件配合,选择对应的查询方式 |
必填 | 在插入和新增的时候,这个字段是否是必填项,可生成校验 |
显示类型 | 前端代码使用的组件,可根据实际情况选择 |
字典类型 | 字典管理是用来维护数据类型的数据,如下拉框、单选按钮等,可自定义 |

2.2.3 生成信息
下图是**生成信息,**可以按照自己的实际情况,来修改包路径,模块名称,上级菜单

修改完成后,点击提交按钮
2.3 下载代码
等我们修改完毕后,回到了列表页,这个时候就可以点击下载按钮,去下载代码包

下载后的代码包,经解压后 可看到包含了三部分:

2.3.1 执行菜单SQL
执行projectMenu.sql文件中的内容,将会为页面左侧菜单位置添加子菜单
2.3.2 拷贝后端代码
把main目录拷贝后,找到后端ruoyi-admin
模块,在main目录上点右键-Open In Explorer ,然后在==main文件夹内==执行粘贴
最终效果如下

2.3.3 拷贝前端代码
下载下来的代码中,打开vue文件夹,里面包含了两部分内容

复制这两个文件夹 ,粘贴到前端项目的src目录内(不要直接在VSCode里粘贴,而是打开文件夹,在文件夹里粘贴),效果如下:

2.4 查看效果
等代码拷贝完成后,重新启动前后端项目,打开页面,可以在服务管理 中看到子菜单护理项目,如下图。
可以对护理项目进行一些操作,比如,新增、修改、删除、查询等

3. 代码阅读
刚才自动生成的代码,我们已经测试过了,可以做到基本的增删改查,我们是不需要修改任何代码的,当然生成的代码也不是很完美,后面,我们还会进行修改调整。
在修改优化之前,我们先来读一下自动生成的代码长什么样子,共分为两部分:后端和前端
3.1 后端代码
3.1.1 后端原始代码
下面这个是控制层的代码NursingProjectController ,详细如下:
Java
package com.zzyl.serve.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zzyl.common.annotation.Log;
import com.zzyl.common.core.controller.BaseController;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.enums.BusinessType;
import com.zzyl.serve.domain.NursingProject;
import com.zzyl.serve.service.INursingProjectService;
import com.zzyl.common.utils.poi.ExcelUtil;
import com.zzyl.common.core.page.TableDataInfo;
/**
* 护理项目Controller
*
* @author ruoyi
* @date 2025-07-29
*/
@RestController
@RequestMapping("/nursing/project")
public class NursingProjectController extends BaseController
{
@Autowired
private INursingProjectService nursingProjectService;
/**
* 查询护理项目列表
*/
@PreAuthorize("@ss.hasPermi('nursing:project:list')")
@GetMapping("/list")
public TableDataInfo list(NursingProject nursingProject)
{
startPage();
List<NursingProject> list = nursingProjectService.selectNursingProjectList(nursingProject);
return getDataTable(list);
}
/**
* 导出护理项目列表
*/
@PreAuthorize("@ss.hasPermi('nursing:project:export')")
@Log(title = "护理项目", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, NursingProject nursingProject)
{
List<NursingProject> list = nursingProjectService.selectNursingProjectList(nursingProject);
ExcelUtil<NursingProject> util = new ExcelUtil<NursingProject>(NursingProject.class);
util.exportExcel(response, list, "护理项目数据");
}
/**
* 获取护理项目详细信息
*/
@PreAuthorize("@ss.hasPermi('nursing:project:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(nursingProjectService.selectNursingProjectById(id));
}
/**
* 新增护理项目
*/
@PreAuthorize("@ss.hasPermi('nursing:project:add')")
@Log(title = "护理项目", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody NursingProject nursingProject)
{
return toAjax(nursingProjectService.insertNursingProject(nursingProject));
}
/**
* 修改护理项目
*/
@PreAuthorize("@ss.hasPermi('nursing:project:edit')")
@Log(title = "护理项目", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody NursingProject nursingProject)
{
return toAjax(nursingProjectService.updateNursingProject(nursingProject));
}
/**
* 删除护理项目
*/
@PreAuthorize("@ss.hasPermi('nursing:project:remove')")
@Log(title = "护理项目", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(nursingProjectService.deleteNursingProjectByIds(ids));
}
}
3.1.2 代码说明
我们可以使用AI协助我们来阅读以上代码,我们可以让AI为每一行代码添加上注释,方便我们阅读
- 先把整个类的代码给AI,
- 然后在最后添加一句话: 你是一个资深的Java开发工程师,帮我给上述代码的每一行都添加上注释进行说明
继承了BaseController
NursingController类继承了BaseController,其中BaseController详细定义如下图:

Controller里方法返回值
Controller里所有方法处理请求时都符合RestFul请求风格。
Controller里所有方法的返回值有以下2种:TableDataInfo 和 AjaxResult
-
TableDataInfo,用于返回分页相关数据。分页查询的功能使用这个返回值类型
JSON{ "total": 2, "rows": [ { "createBy": "admin", "createTime": "2024-03-25 21:29:45", "updateBy": "", "updateTime": null, "remark": "管理员", "noticeId": "2", "noticeTitle": "维护通知:2018-07-01 若依系统凌晨维护", "noticeType": "1", "noticeContent": "维护内容", "status": "0" } ], "code": 200, "msg": "查询成功" }
-
AjaxResult 继承了HashMap,有标准的接口响应结构。非分页查询的其它功能 返回值使用这种类型
JSON{"msg":"操作成功","code":200} { "msg": "操作成功", "code": 200, "data": { "createBy": "admin", "createTime": "2024-03-25 21:29:45", "remark": "管理员", "noticeId": "1", "noticeTitle": "温馨提醒:2018-07-01 若依新版本发布啦", "noticeType": "2", "noticeContent": "新版本内容", "status": "0" } }
陌生注解
@PreAuthorize
在方法上使用,主要作用判断当前登录人是否有权限访问该方法 ps:后期会细讲@Log
在方法上使用,作用是把操作这个方法的行为做一个日志记录 ps:后期会细讲
后端其它代码
比如service、mapper,这些代码都是基础的CRUD,操作数据使用的mybatis,详细请阅读代码
分页逻辑
当Controller里调用了startPage()方法后主要干了两件事:
- 从请求参数中获取到pageNum和pageSize两个参数,如果有其他参数也会获取,比如是orderBy参数
- 调用了PageHelper.startPage()方法,来进行分页处理

3.2 前端代码
3.2.1 菜单路由规则
:bulb:路由:实现不同页面间的导航和视图切换,是路径与组件的对应关系
路由规则说明
我们来看一下目前护理项目这个菜单的配置项,如下图

- 这个菜单的类型为菜单,菜单需要有对应的组件路径
- 父菜单的路由地址+当前菜单的路由地址 就可以访问组件路径对应的组件
- 即: nursing/project 加载组件为 @/views/nursing/project/index.vue
测试路由规则
我们可以自己定义一个菜单,手动设置路由,验证路由规则的效果。
比如:在服务管理中新增一个菜单(护理计划),配置如下:
- 路由地址:nursingPlan
- 组件路径:nursing/nursingPlan/index

在@/views/nursing/nursingPlan目录中新增一个index.vue组件
测试是否能正常访问这个组件
3.2.2 代码阅读
刚才生成代码中包含了两部分内容,第一个是api,第二个是组件
我们先来看@/api/nursing/project.js
JavaScript
import request from '@/utils/request'
// 查询护理项目列表
export function listProject(query) {
return request({
url: '/nursing/project/list',
method: 'get',
params: query
})
}
// 查询护理项目详细
export function getProject(id) {
return request({
url: '/nursing/project/' + id,
method: 'get'
})
}
// 新增护理项目
export function addProject(data) {
return request({
url: '/nursing/project',
method: 'post',
data: data
})
}
// 修改护理项目
export function updateProject(data) {
return request({
url: '/nursing/project',
method: 'put',
data: data
})
}
// 删除护理项目
export function delProject(id) {
return request({
url: '/nursing/project/' + id,
method: 'delete'
})
}
- 这里面的5个接口定义,与后台提供的接口是一一对应的
- 其中
@/utils/request
这个js封装了拦截器和工具函数,实现了对HTTP请求和响应的统一处理和管理
我们接下来再来看组件的代码,地址:src\views\nursing\project\index.vue
为了更方便阅读这个代码,我们依然可以使用通义灵码或者是AI大模型添加注释或者解释代码
把这个组件的代码给大模型,然后跟上一句话
你是一个资深的前端开发工程师,帮我给解读一下上述代码,并且给每行代码上添加注释说明
解释后的代码:
vue
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['nursing:project:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['nursing:project:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['nursing:project:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['nursing:project:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="排序号" align="center" prop="orderNo" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="价格" align="center" prop="price" />
<el-table-column label="图片" align="center" prop="image" width="100">
<template #default="scope">
<image-preview :src="scope.row.image" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="护理要求" align="center" prop="nursingRequirement" />
<el-table-column label="状态" align="center" prop="status" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['nursing:project:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['nursing:project:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改护理项目对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="projectRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="排序号" prop="orderNo">
<el-input v-model="form.orderNo" placeholder="请输入排序号" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入单位" />
</el-form-item>
<el-form-item label="价格" prop="price">
<el-input v-model="form.price" placeholder="请输入价格" />
</el-form-item>
<el-form-item label="图片" prop="image">
<image-upload v-model="form.image"/>
</el-form-item>
<el-form-item label="护理要求" prop="nursingRequirement">
<el-input v-model="form.nursingRequirement" placeholder="请输入护理要求" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Project">
import { listProject, getProject, delProject, addProject, updateProject } from "@/api/nursing/project"
const { proxy } = getCurrentInstance()
const projectList = ref([])
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
status: null,
},
rules: {
name: [
{ required: true, message: "名称不能为空", trigger: "blur" }
],
price: [
{ required: true, message: "价格不能为空", trigger: "blur" }
],
image: [
{ required: true, message: "图片不能为空", trigger: "blur" }
],
nursingRequirement: [
{ required: true, message: "护理要求不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "状态不能为空", trigger: "change" }
],
}
})
const { queryParams, form, rules } = toRefs(data)
/** 查询护理项目列表 */
function getList() {
loading.value = true
listProject(queryParams.value).then(response => {
projectList.value = response.rows
total.value = response.total
loading.value = false
})
}
// 取消按钮
function cancel() {
open.value = false
reset()
}
// 表单重置
function reset() {
form.value = {
id: null,
name: null,
orderNo: null,
unit: null,
price: null,
image: null,
nursingRequirement: null,
status: null,
createBy: null,
updateBy: null,
remark: null,
createTime: null,
updateTime: null
}
proxy.resetForm("projectRef")
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加护理项目"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const _id = row.id || ids.value
getProject(_id).then(response => {
form.value = response.data
open.value = true
title.value = "修改护理项目"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["projectRef"].validate(valid => {
if (valid) {
if (form.value.id != null) {
updateProject(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addProject(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value
proxy.$modal.confirm('是否确认删除护理项目编号为"' + _ids + '"的数据项?').then(function() {
return delProject(_ids)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('nursing/project/export', {
...queryParams.value
}, `project_${new Date().getTime()}.xlsx`)
}
getList()
</script>
- 组件主要使用Vue3+Element plus组件进行开发
- 完成了护理项目的增删改查
六、总结:从入门到进阶的成长路径
通过本文的学习,您已掌握若依框架的核心优势、安装部署和基础开发流程。
若依框架的价值不仅在于快速开发,更在于提供了一个标准化的企业级后台开发模板。无论是毕业设计、创业项目还是企业信息化建设,选择若依都能让您的开发效率事半功倍。开启您的高效开发之旅吧!
您在使用若依框架时遇到过哪些有趣的业务场景?