返回 化神・若依架构御界

克隆基础版本

博主
大约 11 分钟

若依框架入门:从快速搭建到二次开发的实战指南

若依不是简单的脚手架,而是企业级快速开发平台

开篇:为什么选择若依框架?

在Java企业级开发中,项目初始化和基础架构搭建往往占用大量时间。若依框架(RuoYi)作为一款成熟的快速开发平台,能够帮助开发者快速搭建项目骨架,专注于业务逻辑的实现。

若依框架

快速搭建:从0到1创建若依项目

1. 下载源码

若依框架提供了多种版本,包括:

  • RuoYi:基础版本,适合学习和小型项目
  • RuoYi-Vue:前后端分离版本,使用Vue作为前端框架
  • RuoYi-Cloud:微服务版本,基于Spring Cloud
# 克隆基础版本
git clone https://gitee.com/y_project/RuoYi.git

# 克隆前后端分离版本
git clone https://gitee.com/y_project/RuoYi-Vue.git

# 克隆微服务版本
git clone https://gitee.com/y_project/RuoYi-Cloud.git

2. 环境准备

  • JDK 1.8+
  • Maven 3.6+
  • MySQL 5.7+
  • Redis 3.0+(可选,用于缓存)
  • Node.js 14+(前后端分离版本需要)

3. 初始化数据库

  1. 创建数据库 ry
  2. 执行 sql 目录下的初始化脚本:
    • ry_2021xxxx.sql:核心表结构和数据
    • quartz.sql:定时任务表结构

4. 配置文件修改

# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

# Redis配置(可选)
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

5. 启动项目

基础版本:

前后端分离版本:

  • 后端:运行 RuoYiApplication.java
  • 前端:进入 ruoyi-ui 目录,执行 npm install 安装依赖,然后执行 npm run dev
  • 访问:http://localhost:80

框架结构:若依的核心组件

后端结构

src/main/java/com/ruoyi/
├── common/          # 通用模块
│   ├── annotation/  # 自定义注解
│   ├── config/      # 全局配置
│   ├── constant/    # 常量定义
│   ├── core/        # 核心配置
│   ├── domain/      # 通用实体
│   ├── exception/   # 异常处理
│   ├── utils/       # 工具类
├── framework/       # 框架核心
│   ├── aspectj/     # 切面处理
│   ├── config/      # 框架配置
│   ├── datasource/  # 数据源配置
│   ├── interceptor/ # 拦截器
│   ├── manager/     # 管理器
│   ├── security/    # 安全控制
│   ├── web/         # Web配置
├── system/          # 系统模块
│   ├── controller/  # 控制器
│   ├── domain/      # 实体类
│   ├── mapper/      # 数据访问
│   ├── service/     # 业务逻辑
├── project/         # 业务模块(可自定义)
│   ├── controller/  # 控制器
│   ├── domain/      # 实体类
│   ├── mapper/      # 数据访问
│   ├── service/     # 业务逻辑
├── RuoYiApplication.java # 启动类

前端结构(前后端分离版本)

ruoyi-ui/
├── public/          # 静态资源
├── src/             # 源代码
│   ├── api/         # API接口
│   ├── assets/      # 静态资源
│   ├── components/  # 公共组件
│   ├── directive/   # 自定义指令
│   ├── layout/      # 布局组件
│   ├── router/      # 路由配置
│   ├── store/       # 状态管理
│   ├── utils/       # 工具类
│   ├── views/       # 页面视图
│   ├── App.vue      # 应用入口
│   ├── main.js      # 主入口
├── package.json     # 依赖配置
├── vue.config.js    # Vue配置

二次开发:基于若依的业务扩展

1. 代码生成器:快速创建CRUD

若依框架提供了强大的代码生成器,能够根据数据库表结构自动生成前后端代码。

使用步骤:

  1. 登录系统,进入「系统工具 → 代码生成」
  2. 点击「导入」按钮,选择数据库表
  3. 配置表信息和字段信息
  4. 点击「生成代码」按钮,下载生成的代码
  5. 将生成的代码复制到对应的目录中

2. 自定义业务模块

以创建一个「商品管理」模块为例:

后端开发:

// 1. 创建实体类
public class Goods {
    private Long goodsId;
    private String goodsName;
    private BigDecimal price;
    private Integer stock;
    private String description;
    // getter/setter
}

// 2. 创建Mapper接口
public interface GoodsMapper {
    List<Goods> selectGoodsList(Goods goods);
    Goods selectGoodsById(Long goodsId);
    int insertGoods(Goods goods);
    int updateGoods(Goods goods);
    int deleteGoodsByIds(Long[] goodsIds);
}

// 3. 创建Service接口和实现
public interface IGoodsService {
    List<Goods> selectGoodsList(Goods goods);
    Goods selectGoodsById(Long goodsId);
    int insertGoods(Goods goods);
    int updateGoods(Goods goods);
    int deleteGoodsByIds(Long[] goodsIds);
}

@Service
public class GoodsServiceImpl implements IGoodsService {
    @Autowired
    private GoodsMapper goodsMapper;
    
    @Override
    public List<Goods> selectGoodsList(Goods goods) {
        return goodsMapper.selectGoodsList(goods);
    }
    // 其他方法实现
}

// 4. 创建Controller
@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private IGoodsService goodsService;
    
    @GetMapping("/list")
    public TableDataInfo list(Goods goods) {
        startPage();
        List<Goods> list = goodsService.selectGoodsList(goods);
        return getDataTable(list);
    }
    // 其他接口
}

前端开发:

<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="商品名称" prop="goodsName">
        <el-input
          v-model="queryParams.goodsName"
          placeholder="请输入商品名称"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @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="el-icon-plus"
          size="mini"
          @click="handleAdd"
          v-hasPermi="['goods:add']"
        >新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="el-icon-delete"
          size="mini"
          :disabled="multipleSelection.length === 0"
          @click="handleDelete"
          v-hasPermi="['goods:delete']"
        >删除</el-button>
      </el-col>
    </el-row>

    <el-table
      v-loading="loading"
      :data="goodsList"
      @selection-change="handleSelectionChange"
      border
      style="width: 100%"
    >
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="商品ID" width="80" align="center" prop="goodsId" />
      <el-table-column label="商品名称" align="center" prop="goodsName" />
      <el-table-column label="价格" align="center" prop="price" />
      <el-table-column label="库存" align="center" prop="stock" />
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['goods:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row.goodsId)"
            v-hasPermi="['goods:delete']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
    />

    <!-- 新增/修改对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="商品名称" prop="goodsName">
          <el-input v-model="form.goodsName" 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="stock">
          <el-input v-model="form.stock" placeholder="请输入库存" />
        </el-form-item>
        <el-form-item label="描述" prop="description">
          <el-input type="textarea" v-model="form.description" placeholder="请输入描述" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确定</el-button>
        <el-button @click="cancel">取消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listGoods, getGoods, delGoods, addGoods, updateGoods } from "@/api/goods";

export default {
  name: "Goods",
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      multipleSelection: [],
      // 非单个禁用
      single: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 商品表格数据
      goodsList: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        goodsName: null
      },
      // 表单参数
      form: {},
      // 表单校验
      rules: {
        goodsName: [
          { required: true, message: "商品名称不能为空", trigger: "blur" }
        ],
        price: [
          { required: true, message: "价格不能为空", trigger: "blur" }
        ],
        stock: [
          { required: true, message: "库存不能为空", trigger: "blur" }
        ]
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    // 获取列表
    getList() {
      this.loading = true;
      listGoods(this.queryParams).then(response => {
        this.goodsList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },
    // 搜索
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    // 重置
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    // 新增
    handleAdd() {
      this.reset();
      this.open = true;
      this.title = "添加商品";
    },
    // 修改
    handleUpdate(row) {
      this.reset();
      const goodsId = row.goodsId || this.ids;
      getGoods(goodsId).then(response => {
        this.form = response.data;
        this.open = true;
        this.title = "修改商品";
      });
    },
    // 删除
    handleDelete(row) {
      const goodsIds = row.goodsId || this.ids;
      this.$confirm(
        "是否确认删除商品编号为" + goodsIds + "的数据项?",
        "警告",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      ).then(function() {
        return delGoods(goodsIds);
      }).then(() => {
        this.getList();
        this.msgSuccess("删除成功");
      }).catch(() => {});
    },
    // 提交表单
    submitForm() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          if (this.form.goodsId != null) {
            updateGoods(this.form).then(response => {
              this.msgSuccess("修改成功");
              this.open = false;
              this.getList();
            });
          } else {
            addGoods(this.form).then(response => {
              this.msgSuccess("新增成功");
              this.open = false;
              this.getList();
            });
          }
        }
      });
    },
    // 重置表单
    reset() {
      this.form = {
        goodsId: null,
        goodsName: null,
        price: null,
        stock: null,
        description: null
      };
      this.resetForm("form");
    },
    // 取消按钮
    cancel() {
      this.open = false;
      this.reset();
    }
  }
};
</script>

权限管理:若依的安全体系

若依框架提供了完善的权限管理体系,包括:

1. 角色管理

  • 内置角色:超级管理员、角色管理员、用户管理员
  • 自定义角色:根据业务需求创建

2. 菜单管理

  • 菜单类型:目录、菜单、按钮
  • 权限控制:基于URL的权限控制

3. 用户管理

  • 用户信息管理
  • 密码重置
  • 角色分配

4. 权限注解

// 权限控制注解
@PreAuthorize("@ss.hasPermi('goods:add')")
@PostMapping("/add")
public AjaxResult add(@RequestBody Goods goods) {
    return toAjax(goodsService.insertGoods(goods));
}

// 前端权限控制指令
<el-button
  type="primary"
  plain
  icon="el-icon-plus"
  size="mini"
  @click="handleAdd"
  v-hasPermi="['goods:add']"
>新增</el-button>

定时任务:自动化操作的利器

若依框架集成了Quartz定时任务,可以用于:

  • 数据同步
  • 报表生成
  • 系统清理
  • 其他需要定期执行的操作

使用步骤:

  1. 实现 Job 接口
  2. 在系统中配置定时任务
  3. 启动任务
public class SyncDataJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 执行同步操作
        System.out.println("执行数据同步任务:" + new Date());
    }
}

代码规范:若依的最佳实践

  1. 命名规范

    • 类名:大驼峰命名法
    • 方法名:小驼峰命名法
    • 变量名:小驼峰命名法
    • 常量名:全大写,下划线分隔
  2. 目录结构

    • 严格按照框架规定的目录结构组织代码
    • 业务代码放在 project 目录下
  3. 注释规范

    • 类、方法、参数都要添加注释
    • 复杂逻辑要添加详细注释
  4. 异常处理

    • 使用框架提供的异常处理机制
    • 统一返回格式

部署与运维:从开发到生产

1. 打包

# 后端打包
mvn clean package -DskipTests

# 前端打包(前后端分离版本)
npm run build:prod

2. 部署

传统部署:

  • 将打包好的 jar 文件上传到服务器
  • 使用 java -jar 命令启动

Docker部署:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD ruoyi.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

Nginx配置(前后端分离版本):

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location /prod-api/ {
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 5;
    }
}

结语

若依框架是一个功能强大、易于扩展的企业级快速开发平台。通过本文的学习,你应该对若依框架有了一个全面的了解,从快速搭建到二次开发,从权限管理到定时任务,从代码规范到部署运维。

在实际项目中,合理使用若依框架的各种特性,能够显著提高开发效率,减少重复劳动,让开发者专注于业务逻辑的实现。

若依框架不是终点,而是起点。在掌握了若依框架的基础上,你可以根据项目需求进行定制和扩展,打造属于自己的企业级应用。

知识点测试

读完文章了?来测试一下你对知识点的掌握程度吧!

评论区

使用 GitHub 账号登录后即可发表评论,支持 Markdown 格式。

如果评论系统无法加载,请确保:

  • 您的网络可以访问 GitHub
  • giscus GitHub App 已安装到仓库
  • 仓库已启用 Discussions 功能