若依开源框架解析

article/2025/6/27 2:29:54

 1、框架介绍 

RuoYi是一个基于Java技术开发的后台管理系统,目前官方同步在维护的有3个版本。

开源协议:MIT

解释:MIT是和BSD一样宽松的许可协议,作者只想保留版权,而无任何其他了限制.也就是说,你必须在你的发行版里包含原许可协议的声明,无论你是以二进制发布的还是以源代码发布的。

(1)若依不分离版本

        RuoYi是基于经典技术组合(Spring Boot、Apache Shiro、MyBatis、Thymeleaf)主要目的让开发者注重专注业务,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。

Gitee开源地址:RuoYi: 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用

在线文档地址:http://doc.ruoyi.vip/ruoyi/

在线演示地址:登录若依系统

(2)若依前后端分离版本

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

Gitee开源地址:RuoYi-Vue: 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统

在线文档地址:介绍 | RuoYi

在线演示地址:若依管理系统

 

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

(3)若依微服务版本(在用

        RuoYi-Cloud 是一个 Java EE 分布式微服务架构平台,基于经典技术组合(Spring Boot、Spring Cloud & Alibaba、Vue、Element),内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定时任务配置;支持集群,支持多数据源。

Gitee开源地址:RuoYi-Cloud: 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统

在线文档地址:介绍 | RuoYi

在线演示地址:与前后端分离在线演示地址一样

 

若依总结:
知识点1:
domain层:它的JavaBean类,必须对应数据库中的数据。抽象的对象

pojo层:全称为(Plain Ordinary Java Object 普通Java对象) 存放普通的JavaBean类

Model层:它的JavaBean类,封装的是前端在数据库中需要使用的数据。

知识点2:

若依的前后端未分离版本和vue版本都是基于SpringBoot开发的轻量级Java快速开发框架,他们分模块开发,在我理解其实也是把其他的模块引入主模块使用,保证大家可以分模块开发。和引入jar包是一样的。

知识点3:

若依的@excel注解是为了实现导出excel表。

知识点4:

若依cloud中各个微服务的作用:

com.ruoyi     
├── ruoyi-ui              // 前端框架 [80]
├── ruoyi-gateway         // 网关模块 [8080]
├── ruoyi-auth            // 认证中心 [9200]           // 独立的认认证授权中心,有启动类
├── ruoyi-api             // 接口模块
│       └── ruoyi-api-system                          // 系统接口   系统抽取的统一的接口api,没有启动类
├── ruoyi-common                                      // 抽离的通用模块工具,没有启动类
│       └── ruoyi-common-core                         // 核心模块
│       └── ruoyi-common-datascope                    // 权限范围
│       └── ruoyi-common-datasource                   // 多数据源
│       └── ruoyi-common-log                          // 日志记录
│       └── ruoyi-common-redis                        // 缓存服务
│       └── ruoyi-common-security                     // 安全模块
│       └── ruoyi-common-swagger                      // 系统接口
├── ruoyi-modules         // 业务模块
│       └── ruoyi-system                              // 系统模块 [9201]
│       └── ruoyi-gen                                 // 代码生成 [9202]
│       └── ruoyi-job                                 // 定时任务 [9203]
│       └── ruoyi-file                                // 文件服务 [9300]
├── ruoyi-visual          // 图形化管理模块
│       └── ruoyi-visual-monitor                      // 监控中心 [9100]
├──pom.xml                // 公共依赖

知识点5:用到了匿名内部类写法

/*** 文件服务降级处理* * @author ruoyi*/
@Component
public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService>
{private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);@Overridepublic RemoteFileService create(Throwable throwable){log.error("文件服务调用失败:{}", throwable.getMessage());return new RemoteFileService(){@Overridepublic R<SysFile> upload(MultipartFile file){return R.fail("上传文件失败:" + throwable.getMessage());}};}
}

知识点6:微服务若依环境搭建(重点)

若依微服务版手把手教你本地搭建环境并运行前后端项目 - 霸道流氓 - 博客园

知识点7:nacos.config是nacos的初始化数据库,ry-cloud是业务库,ry-config是若依的nacos库。ry_20200924.sql和quartz.sql是ry-cloud的sql,ry_config_20200924.sql是ry-config的sql

知识点7:若依aop理解,冰山一角

深入分析若依数据权限@datascope (注解+AOP+动态sql拼接) 【循序渐进,附分析过程】_金发罗婕的博客-CSDN博客_若依数据权限

知识点8:若依异常理解,见自定义异常和全局异常处理类博客

知识点9:为什么接口返回类型有的用R 有的用AjaxResult?

序列化方式不同,AjaxResult继承了HashMap HashMap虽然也实现了Serializable但是有些秘密在里面 有兴趣可以了解下,也可以去了解下 不同序列化 方式的利弊~

知识点9:若依通过自定义注解@innerAuth+AOP来拒绝外部请求

若依框架解读(微服务版)——2.模块间的调用逻辑(ruoyi-api模块)(OpenFeign)_初见qwer的博客-CSDN博客_若依微服务框架原理

知识点10:(重点)若依权限注解:注解类RequiresLogin、RequiresPermissions、RequiresRoles,分别用于登录认证、权限认证和角色认证
切面类PreAuthorizeAspect,基于 Spring Aop 的注解鉴权
被代理类SysJobController,被代理类就是添加注解的方法所在的类,可以是任意一个类

若依权限校验源码分析_紫荆之后-的博客-CSDN博客_若依权限验证

知识点11:若依拦截器过滤器使用

若依登陆过程及过滤器拦截器的使用:

用户登陆接口:1、把用户信息通过uuid即token作为key,存储在缓存中,并设置过期时间,2、通过jwt存储token,userId,userName在map中,设置过期时间,通过jwt创建一个编码后的access_token和expireTime,并返回token在前端

过滤器:用户前端传递的access_token通过Jwt解析,尝试获取userkey(即token),userid,username

并判断是否过期,为空等。如果异常即刻报错,否则将解析的userkey,userid,username纳入请求头中,请求接着交给拦截器。

拦截器:拦截器从请求头中获取userkey,userid,username,通过userkey从缓存中获取用户信息,并刷新缓存中用户信息的过期时间。并将用户信息加入到本地的TransmittableThreadLocal<Map<String, Object>>中,方便用户获取当前用户信息。

知识点12:幂等性 _ 防重复提交(若依前后端分离版中的代码)

幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。 调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。

比如下面这些情况,如果没有实现接口幂等性会有很严重的后果: 支付接口,重复支付会导致多次扣钱 ;订单接口,同一个订单可能会多次创建。
 

gitee:RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本

使用拦截器实现,在接口方法上添加@RepeatSubmit注解,注解参数说明:

参数类型默认值描述
intervalint5000间隔时间(ms),小于此时间视为重复提交
messageString不允许重复提交,请稍后再试提示消息

使用redis缓存接口的请求URL及参数信息,如果存在且一致并在额定时间范围内,不让重复提交。

package com.byd.rental.common.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解防止表单重复提交* * @author ruoyi**/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit
{/*** 间隔时间(ms),小于此时间视为重复提交*/public int interval() default 5000;/*** 提示消息*/public String message() default "不允许重复提交,请稍候再试";
}
package com.byd.rental.framework.interceptor;import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.byd.rental.common.core.domain.AjaxResult;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson2.JSON;
import com.byd.rental.common.annotation.RepeatSubmit;
import com.byd.rental.common.utils.ServletUtils;/*** 防止重复提交拦截器** @author ruoyi*/
@Component
public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
{@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{if (handler instanceof HandlerMethod){HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);if (annotation != null){if (this.isRepeatSubmit(request, annotation)){AjaxResult ajaxResult = AjaxResult.error(annotation.message());ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));return false;}}return true;}else{return true;}}/*** 验证是否重复提交由子类实现具体的防重复提交的规则** @param request* @return* @throws Exception*/public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
}

package com.byd.rental.framework.interceptor.impl;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;import com.byd.rental.common.core.redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSON;
import com.byd.rental.common.annotation.RepeatSubmit;
import com.byd.rental.common.constant.CacheConstants;
import com.byd.rental.common.filter.RepeatedlyRequestWrapper;
import com.byd.rental.common.utils.StringUtils;
import com.byd.rental.common.utils.http.HttpHelper;
import com.byd.rental.framework.interceptor.RepeatSubmitInterceptor;/*** 判断请求url和数据是否和上一次相同,* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。* * @author ruoyi*/
@Component
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
{public final String REPEAT_PARAMS = "repeatParams";public final String REPEAT_TIME = "repeatTime";// 令牌自定义标识@Value("${token.header}")private String header;@Autowiredprivate RedisCache redisCache;@SuppressWarnings("unchecked")@Overridepublic boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation){String nowParams = "";if (request instanceof RepeatedlyRequestWrapper){RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;nowParams = HttpHelper.getBodyString(repeatedlyRequest);}// body参数为空,获取Parameter的数据if (StringUtils.isEmpty(nowParams)){nowParams = JSON.toJSONString(request.getParameterMap());}Map<String, Object> nowDataMap = new HashMap<String, Object>();nowDataMap.put(REPEAT_PARAMS, nowParams);nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());// 请求地址(作为存放cache的key值)String url = request.getRequestURI();// 唯一值(没有消息头则使用请求地址)String submitKey = StringUtils.trimToEmpty(request.getHeader(header));// 唯一标识(指定key + url + 消息头)String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);if (sessionObj != null){Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;if (sessionMap.containsKey(url)){Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())){return true;}}}Map<String, Object> cacheMap = new HashMap<String, Object>();cacheMap.put(url, nowDataMap);redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);return false;}/*** 判断参数是否相同*/private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap){String nowParams = (String) nowMap.get(REPEAT_PARAMS);String preParams = (String) preMap.get(REPEAT_PARAMS);return nowParams.equals(preParams);}/*** 判断两次间隔时间*/private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval){long time1 = (Long) nowMap.get(REPEAT_TIME);long time2 = (Long) preMap.get(REPEAT_TIME);if ((time1 - time2) < interval){return true;}return false;}
}

知识点13:菜单部门接口使用递归返回树结构

03【若依框架解读】Tree树形结构的控制(菜单,部门)_如何在5年薪百万的博客-CSDN博客

知识点14:若依的用户权限模型分析(多对多的都使用中间表存储之间的关联关系)

用户-角色-菜单      多对多对多   

用户-部门              多对一

用户-岗位              多对多

用户-角色-部门     多对多对多

若依系统用户权限模型分析_若依 角色 部门_baobao555#的博客-CSDN博客


http://chatgpt.dhexx.cn/article/dvDHmMA4.shtml

相关文章

若依框架的入门介绍及使用

若依框架的入门介绍及使用 文章目录 引言1.什么是若依2 .使用若依2.1系统需求2.1下载并运行2.2配置数据库 MySQL、Reids2.2.1MySQL配置2.2.2Redis配置 2.3前端启动 3. 框架结构和模块3.1后端结构3.2前端结构3.3内置功能3.4其他功能和扩展3.4.1代码生成器 总结 引言 若依&#…

从零入门开源框架---若依(前后端分离版)

一、若依是什么&#xff1f; 若依它就是一个开源项目&#xff0c;别人写好的代码&#xff0c;我们拿来进行二次开发,它主要是做数据和权限管理系统。 二、使用背景 任何公司的各种大的项目必然需要一个后台权限管理系统&#xff0c;这是必然的&#xff0c;但是如果不想投入太多…

若依框架学习笔记

若依框架简介 若依框架简介若依框架版本介绍若依框架&#xff08;vue前后端分离版本&#xff09;首页系统管理用户管理角色管理菜单管理 系统监控系统工具表单构建 代码生成 若依框架简介 根据官网介绍若依框架就是一个后台管理框架&#xff0c;主要使用技术在官网上也有介绍我…

若依框架入门(前后端分离版本)

目录 一 若依下载以及配置启动 1.下载地址 2.数据库引入及配置 3.前端vue启动 4.登录及验证 二.关于若依框架的基本使用方法 1.自动生成 2.菜单的配置 3.数据字典 4.关于api接口 5.关于定时任务 6.关于分页 一 若依下载以及配置启动 1.下载地址 学习基础:Spring…

若依框架详细使用

目录 &#x1f3f3;‍&#x1f308;若依是用来干什么的❓ &#x1f6a9;技术支持&#xff1a; &#x1f3f3;‍&#x1f308;如何下载❓ &#x1f6a9;官网地址: &#x1f3f3;‍&#x1f308;如何搭建ruoyi环境❓ &#x1f6a9;若依框架的目录结构 &#x1f6a9; 修改配…

js元素距离和鼠标位置整理

距离 offsetTop / offsetLeft ( 元素与父级 定位元素/table/td/th/body 的距离 ) clientTop / clientLeft ( 元素边框宽度 ) scrollTop / scrollLeft ( 元素滚动距离 ) window.scrollY / window.scrollX ( 文档/页面 滚动距离 ) window.pageYOffset / window.pageXOffset ( 另…

原生js实现跑马灯效果,鼠标放下可以停止跑动

js原生代码跑马灯效果纯js代码如下&#xff1a; 1.首先html的内容&#xff08;里面图片自己可以换&#xff0c;li里面也可以填文字&#xff09; <div> <ul><li>呵呵呵呵呵3</li> <li>叽叽叽叽叽4</li> <li…

unity拖拽UI生成Cube并跟随鼠标移动,放置点可放下

代码&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI;public class DragCreate : MonoBehaviour {public GameObject Cube;public GameObje…

JavaScript的拖拽事件。

在浏览器可以随意的拖拽&#xff0c;我们来看下怎么实现&#xff1f; 我们具体分析一下步骤&#xff1a; 第一步&#xff1a;鼠标选中需要拖拽的地方&#xff0c;鼠标按下。&#xff08;需要使用事件onmousedown&#xff09; 第二步&#xff1a;鼠标按下后&#xff0c;我们接着…

html修改鼠标手势,css要怎么设置鼠标手势?

在CSS中&#xff0c;可以使用cursor属性来设置鼠标手势。下面本篇文章就来给大家介绍一下cursor属性。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。 cursor属性定义了鼠标指针放在一个元素边界范围内时所用的光标形状。有时我们需要…

java 鼠标响应_java小程序中鼠标事件的响应处理

如何在小程序中实现鼠标响应&#xff1f; public class Hello extends Applet implements MouseListener{ public void init(){ addMouseListener(this); } public void mouseEntered(MouseEvent e){ au.play(); setBackground(Color.blue); } public void mouseExited(MouseEv…

html修改鼠标手势,css设置鼠标手势的方法

css设置鼠标手势的方法 相对于传统HTML的表现而言&#xff0c;CSS能够对网页中的对象的位置排版进行像素级的精确控制&#xff0c;支持几乎所有的字体字号样式&#xff0c;下面小编给大家整理了css设置鼠标手势的方法&#xff0c;供大家参阅。 属性名&#xff1a;cursor 属性值…

鼠标拖动生成画框

需求&#xff1a;鼠标按下拖动生成一个画框 注意点&#xff1a; div 的left和top&#xff1a;如果鼠标当前位置>鼠标起始位置&#xff0c;则为鼠标起始位置&#xff08;鼠标往右拉&#xff09;&#xff1b;如果鼠标当前位置<鼠标起始位置&#xff0c;则为鼠标当前位置(…

QT 实现鼠标拖动(drag)和放下(drop)代码(图形操作四)

拖动的对象&#xff1a; #include "outlistitem.h" #include "ui_outlistitem.h"OutListItem::OutListItem(QWidget *parent) :QWidget(parent),ui(new Ui::OutListItem) {ui->setupUi(this); }OutListItem::~OutListItem() {delete ui; }void OutList…

放下鼠标 全键盘定义你的浏览器

在linux上用过vim的朋友相信都被这个编辑器惊艳到了吧, 但是它只是在linux系统中存在而且是在字符操作界面。但是如果将这种可以全键盘的操作搬到windows上这样的图形界面又是怎样令人去感到惊艳呢&#xff1f; 本文介绍的插件是基于谷歌和火狐的&#xff0c;它可以使你在很大的…

外企工作日常:全英文CrossTalk反串讲-讲前紧张,讲后淡定

起因&#xff1a; 在三周之前我接到了一个任务&#xff0c;更准确讲是我自己“作死”主动领取了一个更复杂的任务。这个任务包含了三个相关联的需求。这个需求说简单也简单&#xff0c;说复杂也复杂&#xff5e; 简单在&#xff1a;就是更改一下更新token时间的一个逻辑&am…

linux周六串讲

esc. //粘贴复制上一条命令的参数 cat /etc/resolv.conf //查看DNS地址 route -n //查看网关 hostname //临时修改主机名 hostnamectl set-hostname 名称 //永久修改主机名 ssh root192.168.10.233 //用windows远程的格式&#xff0c;在CMD窗口输入这个命令 …

【Linux】Linux指令串讲

大家好&#xff0c;今天要开启一个新的专题&#xff1a;Linux 今天的内容是指令还有一些基本的Linux知识补充 由于Linux的知识很难明确写出分类&#xff0c;所以目录就不会做的特别详细完全 喜欢的小伙伴点赞收藏一下不迷路哦 目录 1.目录 2.文件 3.路径 1.目录 1.创建目录…

kafka 串讲:架构模型、角色功能梳理

kafka 串讲&#xff1a;架构模型、角色功能梳理 kafka 的 what why how&#xff0c;先有一个粗略宏观的理解 rabbitmq、各种 mq 的技术选型、横向对比 首先&#xff0c;kafka 是一个消息中间件。我们从一个本质的点聊起&#xff0c;我们有一个系统 service&#xff0c;如果这…

【视频理解】论文串讲

视频理解论文串讲 2020-视频理解综述-A Comprehensive Study of Deep Video Action Recognition2014-CVPR-Large-scale Video Classification with Convolutional Neural Networks2014-NIPS-Two-Stream Convolutional Networks for Action Recognition in Videos2015-CVPR-Beyo…