若依:看完你也能十分钟一套CRUD,开发Web就是这么快

为什么要基于若依框架开发?

  1. 快速开发:若依框架提供了许多现成的模块和工具,能够快速搭建起一个基本的应用框架,从而减少了开发的时间和工作量。
  2. 高度可定制性:若依框架提供了丰富的插件和扩展点,可以根据项目的需求进行定制和扩展,满足不同项目的特定需求。
  3. 简化开发流程:若依框架提供了许多常用的功能模块,如权限管理、数据字典、定时任务等,能够简化开发流程,提高开发效率。
  4. 易于维护和管理:若依框架采用了模块化的设计,代码结构清晰,易于维护和管理,有助于降低项目的维护成本。
  5. 社区支持和更新迭代:若依框架有一个活跃的开发社区,能够及时提供技术支持和更新迭代,保证项目的稳定性和安全性。

1. 若依介绍

若依(RuoYi)框架是一款基于Spring Boot、Spring Cloud等开源框架搭建的企业级开发平台。它的主要目标是提供全面的解决方案,以简化企业级应用开发,**提高开发效率**。

若依官网地址:ruoyi.vip/

以下是若依框架的详细介绍:

  1. 模块化设计:若依框架采用模块化的设计,使得应用可以根据需求进行灵活的扩展和定制。每个模块都可以独立部署和升级,这大大提高了系统的可维护性和可扩展性。
  2. 前后端分离:框架采用前后端分离的开发模式,后端专注于数据处理和API接口的提供,前端则负责页面的展示和用户交互。这种模式使得前后端职责明确,进一步提高了开发效率和代码的可维护性。
  3. 权限管理:若依框架提供了完善的用户权限管理功能,包括角色管理、菜单授权、部门管理等,便于对系统权限进行灵活的配置和管理。
  4. 代码生成器:框架内置代码生成器,能够快速生成前后端代码,减少重复劳动,提高开发效率。通过简单的配置即可生成基础的增删改查代码。
  5. 定时任务:若依框架集成了定时任务模块,支持动态添加定时任务,可以通过界面对定时任务进行管理与调度。此外,框架还能实时查看系统运行日志和在线用户信息,监控服务状态和性能。
  6. 易于集成:若依框架可以轻松地与其他常用技术栈集成,如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"
        }
    }
陌生注解
  1. @PreAuthorize 在方法上使用,主要作用判断当前登录人是否有权限访问该方法 ps:后期会细讲
  2. @Log在方法上使用,作用是把操作这个方法的行为做一个日志记录 ps:后期会细讲
后端其它代码

比如service、mapper,这些代码都是基础的CRUD,操作数据使用的mybatis,详细请阅读代码

分页逻辑

当Controller里调用了startPage()方法后主要干了两件事:

  1. 从请求参数中获取到pageNum和pageSize两个参数,如果有其他参数也会获取,比如是orderBy参数
  2. 调用了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组件进行开发
  • 完成了护理项目的增删改查

六、总结:从入门到进阶的成长路径​

通过本文的学习,您已掌握若依框架的核心优势、安装部署和基础开发流程。

若依框架的价值不仅在于快速开发,更在于提供了一个标准化的企业级后台开发模板。无论是毕业设计、创业项目还是企业信息化建设,选择若依都能让您的开发效率事半功倍。开启您的高效开发之旅吧!​

您在使用若依框架时遇到过哪些有趣的业务场景?

相关推荐
二闹3 分钟前
LambdaQueryWrapper VS QueryWrapper:安全之选与灵活之刃
后端
得物技术3 分钟前
Rust 性能提升“最后一公里”:详解 Profiling 瓶颈定位与优化|得物技术
后端·rust
XiangCoder9 分钟前
Java编程案例:从数字翻转到成绩统计的实用技巧
后端
aiopencode10 分钟前
iOS 文件管理全流程实战,从开发调试到数据迁移
后端
Lemon程序馆38 分钟前
Kafka | 集群部署和项目接入
后端·kafka
集成显卡38 分钟前
Rust 实战五 | 配置 Tauri 应用图标及解决 exe 被识别为威胁的问题
后端·rust
阑梦清川39 分钟前
派聪明知识库项目---关于IK分词插件的解决方案
后端
jack_yin40 分钟前
飞书机器人实战:用MuseBot解锁AI聊天与多媒体能力
后端
阑梦清川40 分钟前
派聪明知识库项目--关于elasticsearch重置密码的解决方案
后端
K神41 分钟前
Go之封装Http请求和日志
后端·物联网