项目讲解之火爆全网的开源后台管理系统RuoYi

项目,讲解,火爆,全网,开源,后台,管理系统,ruoyi · 浏览次数 : 1509

小编点评

**模块设计** * 将项目划分成多个模块,包括 framework -> admin -> common -> ruoyi-generator。 * 模块之间尽量松耦合,方便模块升级、增减模块。 **操作日志记录** * 通过 com.ruoyi.framework.aspectj.LogAspect 日志切面,将请求前后执行记录日志,以及请求后后执行记录日志结束时间,填充操作日志最后异步插入。 * 使用线程池插入日志记录,可以缩短接口响应时长。 **切面处理** * 使用切面处理,可以集中处理单一逻辑、方便增添关注点、减少重复代码、对控制层零侵入性以及提高可维护性。 * 例如,日常开发中数据过滤权限、多数据源切换等也都使用了切面处理。 **其他** * 模块设计可以使项目更加可维护,易于理解和修改。 * 对于操作日志记录,可以通过切面处理将逻辑分离,减少代码的重复编写。 * 使用线程池插入日志记录可以缩短接口响应时长。

正文

博主是在2018年中就接触了 RuoYi 项目 这个项目,对于当时国内的开源后台管理系统来说,RuoYi 算是一个完成度较高,易读易懂、界面简洁美观的前后端不分离项目。

对于当时刚入行还在写 jsp 模板的博主来说,RuoYi 项目在后台基础功能、模块划分、易用性和页面美观度上,对比同期用 Java 开源的前后端不分离后台项目整体上是高了一个等级的。并且项目 commit 频繁,代码质量不断提高、bug不断修复,使得这个项目在今天来说任然是具有学习价值的。

本文博主尽量用一个理性视角带领大家由浅入深看 RuoYi 项目v4.7.6版本的优秀设计。

一、快速了解

RuoYi 项目是一个基于 SpringBoot + Mybatis + Shiro 开发的轻量级 Java 快速开发框架,它包含基础的后台管理功能以及权限控制。项目作者对于 RuoYi 项目的定调是这样的:

RuoYi是一款基于SpringBoot+Bootstrap的极速后台开发框架。

RuoYi 是一个 Java EE 企业级快速开发平台,基于经典技术组合(Spring Boot、Apache Shiro、MyBatis、Thymeleaf、Bootstrap)。内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、通知公告等。在线定时任务配置;支持集群,支持多数据源,支持分布式事务。

二、多模块设计

如果想快速了解一个项目的设计理念那直接下载这个项目,查看项目结构即可略知一二。这里参考官网给出的项目结构:

com.ruoyi     
├── ruoyi-common            // 工具类
│       └── annotation                    // 自定义注解
│       └── config                        // 全局配置
│       └── constant                      // 通用常量
│       └── core                          // 核心控制
│       └── enums                         // 通用枚举
│       └── exception                     // 通用异常
│       └── json                          // JSON数据处理
│       └── utils                         // 通用类处理
│       └── xss                           // XSS过滤处理
├── ruoyi-framework         // 框架核心
│       └── aspectj                       // 注解实现
│       └── config                        // 系统配置
│       └── datasource                    // 数据权限
│       └── interceptor                   // 拦截器
│       └── manager                       // 异步处理
│       └── shiro                         // 权限控制
│       └── web                           // 前端控制
├── ruoyi-generator   // 代码生成(不用可移除)
├── ruoyi-quartz      // 定时任务(不用可移除)
├── ruoyi-system      // 系统代码
├── ruoyi-admin       // 后台服务
├── ruoyi-xxxxxx      // 其他模块

由上可知,RuoYi 前后端不分离项目按照模块划分成了七个模块

  • ruoyi-common 包含了整个项目基础的注解、枚举、异常、帮助类的定义以及在 core 包中定义的基础用户、角色、菜单、字典类的 entity 对象以及其他 ajax 响应结果、分页参数、文本处理等一众基础类
  • ruoyi-framework 是整个项目的核心模块,因为这里面有整个项目的核心配置代码,全部在 config 目录下

    其中 ShiroConfig 是最核心的配置,整合了 shiro 框架,给项目提供了权限管理功能
  • ruoyi-generator 主要用作代码生成,目包含一个对外提供服务模块所需的 contrller、domain、mapper、service、util、config 等包。如果添加 Spring Boot 启动类就可以直接作为独立项目启动。作为 ruoyi-admin 模块的插件存在,通过增添 pom 依赖来控制插件是否开启
  • ruoyi-quartz 主要用作定时任务,集成了分布式定时任务调度框架 quartz ,目录与ruoyi-generator类似,也是作为 ruoyi-admin 模块的插件存在,通过增添 pom 依赖来控制插件是否开启
  • ruoyi-system 包含后台系统中非核心用户、角色、菜单、字典类实体对象之外的 mapper、service 层功能代码
  • ruoyi-admin 用作后台web服务,包含后台系统的 controlelr 层代码以及配置文件。也是整个 RuoYi 项目后台的启动入口
  • ruoyi-xxxxxx 作为由开发人员引入的其他模块,一般是新业务模块代码

最后再列出项目 ruoyi-admin 的模块依赖图,简单讲解下各个模块间的依赖关系

  • ruoyi-common 基础通用模块
  • ruoyi-system依赖ruoyi-common模块
  • ruoyi-framework依赖ruoyi-system模块
  • ruoyi-generator依赖ruoyi-common模块
  • ruoyi-quartz依赖ruoyi-common模块
  • ruoyi-admin依赖ruoyi-frameworkruoyi-generatorruoyi-quartz

看完了 RuoYi 的项目结构与模块依赖关系,大家可以看看自己日常开发业务后台的项目结构。或多或少,大家都可能遇到过那种一把梭所以代码都全部放在同一个 Maven 模块的项目。对比 RuoYi 的项目结构,相信大家都会觉得多模块设计是比单模块更优的设计。

拆分出ruoyi-common模块后,其他插件模块可以只引用ruoyi-common的通用代码就能完成插件功能开发。拆分出ruoyi-framework模块后,项目中的核心配置代码全部放在ruoyi-framework中与ruoyi-admin分离,防止对ruoyi-admin的修改影响到项目核心配置。博主认为合理的模块拆分可以减少模块间的耦合与改动模块所带来的影响范围。

通过多模块设计将项目划分成 common -> system -> framework -> admin 由低到高的核心模块以及插件形式的 common -> ruoyi-generator|ruoyi-quartz 模块。模块之间尽量松耦合,方便模块升级、增减模块。

三、优雅的操作日志记录

在 RuoYi 项目中通过 com.ruoyi.framework.aspectj.LogAspect 日志切面,以自定义日志注解作为切点来记录日志信息,这样可以避免在接口中进行重复的操作日志记录代码编写,以及日志记录发生异常也不影响接口返回。

自定义日志注解如下:

/**  
* 自定义操作日志记录注解  
*  
* @author ruoyi  
*/  
@Target({ ElementType.PARAMETER, ElementType.METHOD })  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface Log {  
    /**  
    * 模块  
    */  
    public String title() default "";  

    /**  
    * 功能  
    */  
    public BusinessType businessType() default BusinessType.OTHER;  

    /**  
    * 操作人类别  
    */  
    public OperatorType operatorType() default OperatorType.MANAGE;  

    /**  
    * 是否保存请求的参数  
    */  
    public boolean isSaveRequestData() default true;  

    /**  
    * 是否保存响应的参数  
    */  
    public boolean isSaveResponseData() default true;  

    /**  
    * 排除指定的请求参数  
    */  
    public String[] excludeParamNames() default {};  
}

可以看到 LogAspect 注解类中定义了模块名称、业务操作类型(新增、修改、删除、导出等业务操作)、操作人类别(其他、后台、手机等)、是否保存请求的参数、是否保存响应的参数、排除指定的请求参数等六个属性。我们在使用自定义注解时,通常只用根据接口作用指定模块名称和业务操作类型就可以,日志注解使用如下:

@Log(title = "参数管理", businessType = BusinessType.INSERT)  
@PostMapping("/add")  
@ResponseBody  
public AjaxResult addSave(@Validated SysConfig config) {...}

自定义日志注解切面代码如下:

/**  
* 操作日志记录处理  
*  
* @author ruoyi  
*/  
@Aspect  
@Component  
public class LogAspect {  
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);  

    /** 排除敏感属性字段 */  
    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword" ... };  

    /** 计算操作消耗时间 */  
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");  

    /**  
    * 处理请求前执行  
    */  
    @Before(value = "@annotation(controllerLog)")  
    public void boBefore(JoinPoint joinPoint, Log controllerLog) {  
    TIME_THREADLOCAL.set(System.currentTimeMillis());  
    }  

    /**  
    * 处理完请求后执行  
    *  
    * @param joinPoint 切点  
    */  
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")  
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {  
    handleLog(joinPoint, controllerLog, null, jsonResult);  
    }  

    /**  
    * 拦截异常操作  
    *  
    * @param joinPoint 切点  
    * @param e 异常  
    */  
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")  
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {  
    handleLog(joinPoint, controllerLog, e, null);  
    }  

    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, 
        final Exception e, Object jsonResult)  
        ...
    } 
}

通过 aop 切面对使用了日志注解的方法进行三个方面的切入:

  • @Before(value = "@annotation(controllerLog)") 处理请求前执行记录日志记录开始时间
  • @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") 处理完请求后执行记录日志结束时间,填充操作日志最后异步插入
  • @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") 以及处理完请求发生异常后执行记录日志结束时间,填充操作日志、异常原因最后异步插入日志

在使用了日志切面后,操作日志记录的逻辑与后台各功能接口的业务逻辑相分离,减少了日志记录代码的的重复编写,后期修改日志记录逻辑只用修改切面代码,提高了操作日志记录的可维护性,也避免了日志记录发生异常时影响业务接口,使用线程池插入日志记录还可以缩短接口响应时长。可以看到通过切面完成日志记录有这么多好处。

其实 RuoYi 中不仅仅只有日志记录使用了切面处理,像是日常开发中数据过滤权限、多数据源切换等也都使用了切面处理。使用切面可以让我们集中处理单一逻辑、方便增添关注点、减少重复代码、对控制层零侵入性以及提高可维护性

四、总结

本文目前从模块设计、操作日志记录等两个方面对 RuoYi 项目进行了讲解。如果大家也使用过 RuoYi 项目,欢迎大家讨论发言给出想法,最后希望本文对大家日常项目开发有所帮助,喜欢的朋友们可以点赞加关注😘。

与项目讲解之火爆全网的开源后台管理系统RuoYi相似的内容:

项目讲解之火爆全网的开源后台管理系统RuoYi

博主是在2018年中就接触了 RuoYi 项目 这个项目,对于当时国内的开源后台管理系统来说,RuoYi 算是一个完成度较高,易读易懂、界面简洁美观的前后端不分离项目。 对于当时刚入行还在写 jsp 模板的博主来说,RuoYi 项目在后台基础功能、模块划分、易用性和页面美观度上,对比同期用 Java

项目讲解之常见安全漏洞

本文是从开源项目 RuoYi 的提交记录文字描述中根据关键字漏洞|安全|阻止筛选而来。旨在为大家介绍日常项目开发中需要注意的一些安全问题以及如何解决。 项目安全是每个开发人员都需要重点关注的问题。如果项目漏洞太多,很容易遭受黑客攻击与用户信息泄露的风险。本文将结合3个典型案例,解释常见的安全漏洞及修

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(1)-后端项目框架搭建

前言: 前面的四个章节我们主要讲解了MongoDB的相关基础知识,接下来我们就开始进入使用.NET7操作MongoDB开发一个ToDoList系统实战教程。本章节主要介绍的是如何快熟搭建一个简单明了的后端项目框架。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战之MongoDB简介

面向状态机编程:复杂业务逻辑应对之道

在研发项目中,经常能遇到复杂的状态流转类的业务场景,比如游戏编程中NPC的跳跃、前进、转向等状态变化,电商领域订单的状态变化等。这类情况其实可以有一种优雅的实现方法:状态机。本文重点介绍有限状态机,并结合具体项目,通过状态机的应用将状态和业务逻辑解耦,便于简化复杂业务逻辑,降低理解成本。另外,重点讲解如何优雅的解决更广泛的复杂业务问题。

quarkus实战之七:使用配置

通过各种方式设置的配置项,在代码中如何获取呢?本文会详细讲解

产品代码都给你看了,可别再说不会DDD(七):实体与值对象

这是一个讲解DDD落地的文章系列,作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云(https://www.mryqr.com)为例,系统性地讲解DDD在落地实施过程中的各种典型实践,以及在面临实际业务场景时的诸多取舍。 本系列包含以下文章: DDD入门

如何在现有的Vue项目中嵌入 Blazor项目?

目前官方只提供了angular和react俩种示例,所以本教程将来讲解如何在Vue的现有项目中使用,上期已经做好了react的教材! 准备流程 Vue 项目创建流程 使用Vue创建一个Demo项目 全部选择默认No即可 然后项目名称就用demo了 npm init vue@latest cd dem

Falcon-7B大型语言模型在心理健康对话数据集上使用QLoRA进行微调

文本是参考文献[1]的中文翻译,主要讲解了Falcon-7B大型语言模型在心理健康对话数据集上使用QLoRA进行微调的过程。项目GitHub链接为https://github.com/iamarunbrahma/finetuned-qlora-falcon7b-medical,如下所示: 使用领域适

[转帖]一文读懂Redis6的--bigkeys选项源码以及redis-bigkey-online项目介绍

https://www.jianshu.com/p/9e150d72ffc9 本文分为两个部分,第一是详细讲解Redis6的--bigkeys选项相关源码是怎样实现的,第二部分为自己对--bigkeys源码的优化项目redis-bigkey-online的介绍。redis-bigkey-online

如何实现在react现有项目中嵌入Blazor?

如何实现在react现有项目中嵌入Blazor? 目前官方只提供了angular和react俩种示例所以本教程只讲react教程 思路讲解: 首先在现有react项目中我们可能某些组件是在Blazor中完成,但是我们没办法找到怎么在react中轻量级使用blazor组件,可能会有人会使用iframe