若依(ruoyi | 您所在的位置:网站首页 › 若依cloud代码生成 › 若依(ruoyi |
视频教程传送门:
基于SpringCloud Alibaba技术栈,若依微服务版(RuoYi-Cloud)脚手架入门精解,保证上手那种~_哔哩哔哩_bilibili基于SpringCloud Alibaba技术栈,若依微服务版(RuoYi-Cloud)脚手架入门精解,保证上手那种~共计23条视频,包括:01.前期准备与教学目标、02.若依框架基本了解、03.若依框架源码下载等,UP主更多精彩视频,请关注UP账号。 Java WEB 知识体系 Spring、SpringMVC、SpringBoot 传统MVC框架体系 MyBatis 持久层框架体系 SpringCloud Alibaba 微服务落地方案 Maven、Git、Idea 常规开发工具 MySQL、Redis 常见关系/非关系型数据库 1.2 教学目标掌握陌生项目解读技巧 掌握若依(RuoYi-Cloud)框架 掌握SpringCloud Alibaba体系项目开发套路 二、框架介绍 2.1 简介一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 性别男,若依是给女儿取的名字(寓意:你若不离不弃,我必生死相依) 若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 2.2 内置功能用户管理:用户是系统操作者,该功能主要完成系统用户配置。 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 岗位管理:配置系统用户所属担任职务。 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 参数管理:对系统动态配置常用参数。 通知公告:系统通知公告信息发布维护。 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 登录日志:系统登录日志记录查询包含登录异常。 在线用户:当前系统中活跃用户状态监控。 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 系统接口:根据业务代码自动生成相关的api接口文档。 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 缓存监控:对系统的缓存查询,删除、清空等操作。 在线构建器:拖动表单元素生成相应的HTML代码。 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 2.3 主要特性完全响应式布局(支持电脑、平板、手机等所有主流设备) 强大的一键生成功能(包括控制器、模型、视图、菜单等) 支持多数据源,简单配置即可实现切换。 支持按钮及数据权限,可自定义部门数据权限。 对常用js插件进行二次封装,使js代码变得简洁,更加易维护 完善的XSS防范及脚本过滤,彻底杜绝XSS攻击 Maven多项目依赖,模块及插件分项目,尽量松耦合,方便模块升级、增减模块。 国际化支持,服务端及客户端支持 完善的日志记录体系简单注解即可实现 支持服务监控,数据监控,缓存监控功能。 2.4 演示地址登录若依系统 账号:admin 密码:admin123 2.5 分类 2.5.1 传统版 2.5.1.1 源码地址RuoYi: 🎉 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 2.5.1.2 在线文档介绍 | RuoYi 2.5.1.3 技术选型2.5.2 前后端分离版本 2.5.2.1 源码地址 RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本 2.5.2.2 在线文档介绍 | RuoYi 2.5.2.3 技术选型后端结构 com.ruoyi ├── common // 工具类 │ └── annotation // 自定义注解 │ └── config // 全局配置 │ └── constant // 通用常量 │ └── core // 核心控制 │ └── enums // 通用枚举 │ └── exception // 通用异常 │ └── filter // 过滤器处理 │ └── utils // 通用类处理 ├── framework // 框架核心 │ └── aspectj // 注解实现 │ └── config // 系统配置 │ └── datasource // 数据权限 │ └── interceptor // 拦截器 │ └── manager // 异步处理 │ └── security // 权限控制 │ └── web // 前端控制 ├── ruoyi-generator // 代码生成(可移除) ├── ruoyi-quartz // 定时任务(可移除) ├── ruoyi-system // 系统代码 ├── ruoyi-admin // 后台服务 ├── ruoyi-xxxxxx // 其他模块前端结构 ├── build // 构建相关 ├── bin // 执行脚本 ├── public // 公共文件 │ ├── favicon.ico // favicon图标 │ └── index.html // html模板 │ └── robots.txt // 反爬虫 ├── src // 源代码 │ ├── api // 所有请求 │ ├── assets // 主题 字体等静态资源 │ ├── components // 全局公用组件 │ ├── directive // 全局指令 │ ├── layout // 布局 │ ├── plugins // 通用方法 │ ├── router // 路由 │ ├── store // 全局 store管理 │ ├── utils // 全局公用方法 │ ├── views // view │ ├── App.vue // 入口页面 │ ├── main.js // 入口 加载组件 初始化等 │ ├── permission.js // 权限管理 │ └── settings.js // 系统配置 ├── .editorconfig // 编码格式 ├── .env.development // 开发环境配置 ├── .env.production // 生产环境配置 ├── .env.staging // 测试环境配置 ├── .eslintignore // 忽略语法检查 ├── .eslintrc.js // eslint 配置项 ├── .gitignore // git 忽略项 ├── babel.config.js // babel.config.js ├── package.json // package.json └── vue.config.js // vue.config.js 2.5.3 微服务版本 2.5.3.1 源码地址RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 2.5.3.2 在线文档介绍 | RuoYi 2.5.3.3 技术选型后端结构 com.ruoyi ├── ruoyi-ui // 前端框架 [80] ├── ruoyi-gateway // 网关模块 [8080] ├── ruoyi-auth // 认证中心 [9200] ├── ruoyi-api // 接口模块 │ └── ruoyi-api-system // 系统接口 ├── ruoyi-common // 通用模块 │ └── ruoyi-common-core // 核心模块 │ └── ruoyi-common-datascope // 权限范围 │ └── ruoyi-common-datasource // 多数据源 │ └── ruoyi-common-log // 日志记录 │ └── ruoyi-common-redis // 缓存服务 │ └── ruoyi-common-seata // 分布式事务 │ └── 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 // 公共依赖前端结构 ├── build // 构建相关 ├── bin // 执行脚本 ├── public // 公共文件 │ ├── favicon.ico // favicon图标 │ └── index.html // html模板 ├── src // 源代码 │ ├── api // 所有请求 │ ├── assets // 主题 字体等静态资源 │ ├── components // 全局公用组件 │ ├── directive // 全局指令 │ ├── layout // 布局 │ ├── plugins // 通用方法 │ ├── router // 路由 │ ├── store // 全局 store管理 │ ├── utils // 全局公用方法 │ ├── views // view │ ├── App.vue // 入口页面 │ ├── main.js // 入口 加载组件 初始化等 │ ├── permission.js // 权限管理 │ └── settings.js // 系统配置 ├── .editorconfig // 编码格式 ├── .env.development // 开发环境配置 ├── .env.production // 生产环境配置 ├── .env.staging // 测试环境配置 ├── .eslintignore // 忽略语法检查 ├── .eslintrc.js // eslint 配置项 ├── .gitignore // git 忽略项 ├── babel.config.js // babel.config.js ├── package.json // package.json └── vue.config.js // vue.config.js 2.5.4 移动版 2.5.4.1 源码地址RuoYi-App: 🎉 RuoYi APP 移动端框架,基于uniapp+uniui封装的一套基础模版,支持H5、APP、微信小程序、支付宝小程序等,实现了与RuoYi-Vue、RuoYi-Cloud后台完美对接。 2.5.4.2 在线文档介绍 | RuoYi 2.5.4.3 技术选型三、源码下载 3.1 说明 本教程以若依微服版(RuoYi-Cloud)为解读蓝本,所有源码、文件、截图、演示均为该版本。 3.2 下载国内:RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 国外:https://github.com/yangzongzhuan/RuoYi-Cloud 3.3 Idea克隆 标准开源项目:指符合特定标准和规范的开源软件项目。这些标准和规范通常由开源社区、行业组织或相关标准制定机构定义和推广。标准开源项目的目的是提供一致的质量标准和最佳实践,以促进开源软件的可靠性、互操作性和可持续发展。 大白话:代码、文件、教程等各种配套都齐全的项目。 4.1.1 看README.md标准开源项目,都是有一个README.md这种文档,这个文档是项目的简介,一般会用大白话方式讲清楚项目背景,项目技术点,项目具体使用等。 4.1.2 看演示项目若依管理系统 好处:快速了解项目具体功能,能做啥,实现效果怎么样。 4.1.3 看文档介绍 | RuoYi 好处:该有的都有了 一个问题:看文档,看哪些内容? 0>视频教程(如果有) 1>项目结构/架构(如果有) 2>技术选型 3>功能模块 4>项目部署 5>项目其他 4.2 非标准开源项目非标准开源项目是指没有遵循特定标准或规范的开源软件项目。这些项目可能是由个人、小团队或组织开发,其开发方式和治理模式可能与传统的标准开源项目有所不同。 大白话:代码、文件、教程等各种配套都不齐全的项目。 4.2.1 看README.md如果有,必须看。但一般情况,都是下面这种:啥都是没有
没有使用Maven/Gradle传统项目,比如Java SE/JavaWeb项目,Jar依赖一般放置在lib文件夹,优先找它 如果使用Maven/Gradle常规项目,找pom.xml文件或build.gradle 一个问题:看Jar依赖目的是啥? 1>大体把握项目技术栈 要求:结合技术栈,YY一下代码可能的结构,后续项目解读时有参照蓝本。 比如: MyBatis---domain----mapper.java-----mapper.xml Springboot----Spring----Springmvc----Controller----启动类 SpringCloud Alibaba-----8个基本组件 2>大体推测项目有哪些功能 要求:常见的功能jar有熟悉,不认识,可以搜。 比如: io.springfox springfox-swagger-ui ${swagger.fox.version} io.jsonwebtoken jjwt org.apache.poi poi-ooxml4.2.3 看代码结构 没有文档的帮助,只能借助代码结构名称大体推测项目可能具有模块,拥有的功能。 非开源项目最麻烦一个点就是文件不齐全,少文档,少sql数据库,甚至代码不完整。这时候想解读通这代码就需要很丰富的想象能力。 类似一拳超人中地表最强的男人:King !哥的厉害全靠你想象
这个得结合个人开发经验,项目经验,生活阅历,连蒙靠猜推测去补齐项目逻辑啦。 比如: 缺SQL:找Mapper.xml/domain实体补齐 缺Jar包:根据项目启动报错信息,缺哪个补哪个 缺配置文件:项目依赖用到哪些jar,结合常规配置,补齐配置 缺少各种环境:结合个人开发经验,尝试补齐。 4.3 若依初探若依脚手架算是一个较为标准的开源项目了,那它阶段就按照标准项目方式解读即可。 4.3.1 标准开源项目 4.3.1.1 看README.md--了解项目整体 --了解项目效果 地址:若依管理系统 账号密码:admin/admin123
4.3.1.3 看文档 --了解项目细节 地址:介绍 | RuoYi 从图中解析出RuoYi-Cloud 使用微服务技术栈 网关:Gateway 远程调用:Ribbon/Feign 注册中心:Nacos Discovery 熔断降级:Sentinel 配置中心:Nacos Config 链路追踪:Sleuth+ZipKin/SkyWalking (没有集成,需要自己加) 4.3.3 代码结构 com.ruoyi ├── ruoyi-ui // 前端框架 [80] ├── ruoyi-gateway // 网关模块 [8080] ├── ruoyi-auth // 认证中心 [9200] ├── ruoyi-api // 接口模块 │ └── ruoyi-api-system // 系统接口 ├── ruoyi-common // 通用模块 │ └── ruoyi-common-core // 核心模块 │ └── ruoyi-common-datascope // 权限范围 │ └── ruoyi-common-datasource // 多数据源 │ └── ruoyi-common-log // 日志记录 │ └── ruoyi-common-redis // 缓存服务 │ └── ruoyi-common-seata // 分布式事务 │ └── 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.1 语言环境项目运行离不开语言支持,若依(RuoYi-Cloud)后端为Java项目,需要java环境,前端为Vue项目,需要Node.js环境,运行若依前需要将这些环境安装成功。 5.1.1 Java环境一个node.js环境,一个事npm 软件安装工具
若依(RuoYi-Cloud)目前使用的数据库暂时只有MySQL跟Redis,后续可以根据项目需要添加其他数据库,比如MongoDB,Elasticsearch等。 5.2.1 MySQL环境
若依(RuoYi-Cloud)使用的是SpringCloud Alibaba体系微服务落地方法,那就得安装2个必须组件:Nacos跟Sentinel。 5.3.1 Nacos环境若依(RuoYi-Cloud)使用Nacos做注册中心与配置中心,所以需要提前准备该环境。 下载路径:Releases · alibaba/nacos · GitHub 这里注意,若依(RuoYi-Cloud)要求是Nacos 2.x版本,不要下错
进入bin目录启动,执行startup.cmd命令,注意需要使用单例模式启动,否则闪退 使用cmd 命令,进入命令框,执行下面命令 startup.cmd -m standalone 若依(RuoYi-Cloud)使用Sentinel熔断降级组件,那么项目启动前,需要提前准备好 下载地址:https://github.com/alibaba/Sentinel/releases 下载完之后是一个jar包:sentinel-dashboard-1.8.0.jar, 使用java 命令执行就行 java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar5.3.3 Seata环境 若依(RuoYi-Cloud)支持Seata实现分布式事务,如果需要,项目启动前就应该提前准备好 下载地址:https://github.com/seata/seata/releases 进入bin目录启动,执行seata-server.bat命令 seata-server.bat --add-opens=java.base/java.lang=ALL-UNNAMED 六、项目配置与启动当上面环境全部准备好之后,接下来就是项目配置。需要将项目相关配置修改成当前相关环境。 6.1 后端配置 6.1.1 数据库新建数据库:ry-cloud 存储常规数据 字符编码:utf8mb4 导入SQL:sql/ry_20230223.sql sql/quartz.sql(可选--需要定时任务操作必须导入)
新建数据库:ry-config 存储nacos配置数据 字符编码:utf8mb4 导入SQL:sql/ry_config_20220929.sql 若依(RuoYi-Cloud) 配置中心的项目配置文件,持久化在ry-config.config_info 表中,项目启动需要将这些配置文件加载到配置中心,所以需要额外配置一下Nacos,以增加对mysql数据源的支持。 进入nacos-server-2.2.2/conf 目录找:application.properties
修改配置 # db mysql spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=数据库账号 db.password=数据库密码 Nacos配置好之后,启动成功后访问:http://localhost:8848/nacos 账号/密码 nacos/nacos 修改下面画红线的服务配置文件
主要改动: Redis 的ip,端口,密码 MySQL ip,端口,账号,密码,数据库等。 比如:
打开项目,执行XxxxApplication的启动类(启动没有先后顺序) RuoYiGatewayApplication (网关模块 必须) RuoYiAuthApplication (认证模块 必须) RuoYiSystemApplication (系统模块 必须) RuoYiMonitorApplication (监控中心 可选) RuoYiGenApplication (代码生成 可选) RuoYiJobApplication (定时任务 可选) RuoYFileApplication (文件服务 可选)
加粗的启动即可。
6.3 前端配置与启动 若依(RuoYi-Cloud) 项目前端跟后端是保存在同一个目录夹的。 先进入这个目录,然后使用前端编辑工具打开即可,这里使用Visual Studio Code 打开
进入vscode之后,打开项目README.md文件
打开vscode 的终端,执行上面命令
当后端,前端都启动成功之后,若依(RuoYi-Cloud) 项目就算运行成功啦。 访问地址:http://localhost/
项目解读可以说分为2部分: 1>项目结构解读(静态解读) 2>业务模块解读(动态解读) 前面种种都属于项目结构范畴,解下来就是业务模块解读,这里选择鉴权,网关,代码生成器3个核心模块讲解若依(RuoYi-Cloud)脚手架的使用。 7.1 解读技巧只要是Java Web项目,流程主干线永远不变: 发起请求---处理请求----响应请求 找一个业务逻辑相对简单的模块,围绕主线去追踪即可。根据以往的经验,请求到响应大体流程图如下: 把上面流程具体化之后就是: 前端 客户端如何发起请求(关注路径/方式/参数),一般使用浏览器的F12查看 后端 接口接收请求,处理请求,响应请求。(关注:单个服务操作/多服务协同操作),一般追踪请求流程。 简单流程:网关---过滤器---拦截器--微服务(请求处理) 复杂流程:网关---上游过滤器---上游拦截器--上游微服务(处理)-----下游过滤器---下游拦截器--下游微服务(处理) 7.2 请求闭环这里结合上面主线,走一个完整的请求闭环,以获取登录验证码获取为例子。 7.2.1 前端项目进入第一个页面是登录页面
浏览器F12,查看到第一个接口:http://localhost/dev-api/code localhost:前端项目启动默认访问ip, 为本地 端口:没有端口,默认端口为80 dev-api:若依框架约定的开发环境使用上下文,可以在.env.development中配置
code:请求路径 完整的:http://locallhost:80/dev-api/code 是由下面异步请求发起的
当前端发起请求后,就到后端接收请求处理,处理请求,与响应请求啦。 7.2.2 后端前端发起请求,后端接收请求,那请求最先去到哪呢? 看若依(RuoYi-Cloud)框架的架构图,请求最先进入的网关。当然也可以通过前端代理服务配置定位到请求会转发到网关服务。 当确认请求入口之后,只需快速定位ruoyi-gateway即可。 此时还存在一个问题,网关哪个类处理/code请求? 如果有WebFlux编程经验,大体能猜到RouterFunctionConfiguration类 @Configuration public class RouterFunctionConfiguration { @Autowired private ValidateCodeHandler validateCodeHandler; @SuppressWarnings("rawtypes") @Bean public RouterFunction routerFunction() { return RouterFunctions.route( RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), validateCodeHandler); } }
RouterFunction 是 Spring WebFlux 中定义路由的函数式编程方式。 在 Spring WebFlux 中,我们可以使用 RouterFunction 来定义路由规则,将请求映射到相应的处理器函数上。 上面代码意思是前端发过来/code由validateCodeHandler 来处理 @Component public class ValidateCodeHandler implements HandlerFunction { @Autowired private ValidateCodeService validateCodeService; @Override public Mono handle(ServerRequest serverRequest) { AjaxResult ajax; try { //构建验证码,封装成AjaxResult对象 ajax = validateCodeService.createCaptcha(); } catch (CaptchaException | IOException e) { return Mono.error(e); } return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax)); } } @Override public AjaxResult createCaptcha() throws IOException, CaptchaException { AjaxResult ajax = AjaxResult.success(); boolean captchaEnabled = captchaProperties.getEnabled(); ajax.put("captchaEnabled", captchaEnabled); .... ajax.put("uuid", uuid); ajax.put("img", Base64.encode(os.toByteArray())); return ajax; }最终将生成的验证码封装在AjaxResult 响应回客户端。 那如果说没有Spring WebFlux经验怎么办?很简单,使用idea 搜/code 字符,然后借助ChatGPT猜测代码啥意思
到这,一个完整请求闭环就完成了,后续其他请求便是同理可得。 7.3 网关模块网关为项目入口,若依(RuoYi-Cloud)项目入口结构可以简化为这样
在ruoyi-gateway网关微服务中配置了所有微服务路由映射
spring: cloud: gateway: discovery: locator: lowerCaseServiceId: true enabled: true routes: # 认证中心 - id: ruoyi-auth uri: lb://ruoyi-auth predicates: - Path=/auth/** filters: # 验证码处理 - CacheRequestFilter - ValidateCodeFilter - StripPrefix=1 # 代码生成 - id: ruoyi-gen uri: lb://ruoyi-gen predicates: - Path=/code/** filters: - StripPrefix=1 # 定时任务 - id: ruoyi-job uri: lb://ruoyi-job predicates: - Path=/schedule/** filters: - StripPrefix=1 # 系统模块 - id: ruoyi-system uri: lb://ruoyi-system predicates: - Path=/system/** filters: - StripPrefix=1 # 文件服务 - id: ruoyi-file uri: lb://ruoyi-file predicates: - Path=/file/** filters: - StripPrefix=1 前端发起所有请都统一经过网关,再借由网关路由统一转发。 访问ruoyi-file微服务路径规则: http://localhost:80/dev-api/file/** 访问ruoyi-gen微服务路径规则: http://localhost:80/dev-api/code/** 访问ruoyi-job微服务路径规则: http://localhost:80/dev-api/schule/** 访问ruoyi-system微服务路径规则: http://localhost:80/dev-api/system/** 访问ruoyi-auth微服务路径规则: http://localhost:80/dev-api/auth/** 7.4 鉴权模块若依(RuoYi-Cloud)鉴权模块涉及到这几个组件
若依(RuoYi-Cloud)框架登录鉴权有2种模式: 外部鉴权:客户端访问服务端(微服务),以JWT令牌为判断依据,有且合法放行,没有或不合法拒绝 内部鉴权:上游微服务访问下游微服务,以请求头标记:from-source=inner有无位依据,有放行,没有拒绝 7.4.1 外部鉴权 7.4.1.1 步骤1:JWT获取登录页面点击登录发起:http://localhost/dev-api/auth/login 请求
请求中auth前缀为网关配置ry-auth服务路由映射
借助网格路由,进入ry-auth微服务,TokenController请求处理类 @RestController public class TokenController { @PostMapping("login") public R login(@RequestBody LoginBody form) { // 用户登录 LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword()); // 获取登录token return R.ok(tokenService.createToken(userInfo)); } } /** * 创建令牌 */ public Map createToken(LoginUser loginUser) { String token = IdUtils.fastUUID(); Long userId = loginUser.getSysUser().getUserId(); String userName = loginUser.getSysUser().getUserName(); loginUser.setToken(token); loginUser.setUserid(userId); loginUser.setUsername(userName); loginUser.setIpaddr(IpUtils.getIpAddr()); refreshToken(loginUser); //redis缓存令牌 // Jwt存储信息 Map claimsMap = new HashMap(); claimsMap.put(SecurityConstants.USER_KEY, token); claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName); // 接口返回信息 Map rspMap = new HashMap(); rspMap.put("access_token", JwtUtils.createToken(claimsMap)); rspMap.put("expires_in", expireTime); return rspMap; }响应返回: 当客户登录成功之后,后续请求进入网关,网关转发到对应的微服务,该微服务会引用:ruoyi-common-security 鉴权模块,请求进来后,切面判断请求持有的JWT令牌,有且合法放行,没有或不合法拒绝
阅读上面的切面代码,最终得出 只要接口方法只要贴有上面3个注解,都需要进行外部鉴权。比如: /** * 获取用户列表 */ @RequiresPermissions("system:user:list") @GetMapping("/list") public TableDataInfo list(SysUser user) { startPage(); List list = userService.selectUserList(user); return getDataTable(list); }7.4.2 内部鉴权 内部鉴权是微服务与微服务间鉴权,发生在上游微服务访问下游微服务,以请求头标记:from-source=inner有无位依据,有放行,没有拒绝,其目的是实现网络隔离。 来自网关请求,以JWT进行鉴权,来自内部远程调用请求,以from-source=inner进行鉴权,其他非法请求直接拒绝。 还是以ry-auth微服务的TokenController类的登录方法为案例 7.4.2.1 步骤1:远程调用过程登录请求,先到TokenController类login方法 @RestController public class TokenController { @Autowired private TokenService tokenService; @Autowired private SysLoginService sysLoginService; @PostMapping("login") public R login(@RequestBody LoginBody form) { // 用户登录 LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword()); // 获取登录token return R.ok(tokenService.createToken(userInfo)); } }login方法中用到:SysLoginService接口login逻辑 private SysLoginService sysLoginService; sysLoginService.login(form.getUsername(), form.getPassword());观察SysLoginService类,里面引用了接口:RemoteUserService @Component public class SysLoginService { @Autowired private RemoteUserService remoteUserService; /** * 登录 */ public LoginUser login(String username, String password) { ...... // 查询用户信息 R userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); ...... } }观察RemoteUserService接口所在位置,明显与TokenController/SysLoginService不在同一微服务。 RemoteUserService 属于ry-system微服务,而TokenController类属于ry-auth微服务,那么此处的remoteUserService.getUserInfo为远程调用。 一个问题:既然为远程调用,跟普通接口调用有啥区别? 定义区别: 使用feign组件,定义远程接口 @FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class) public interface RemoteUserService { /** * 通过用户名查询用户信息 * * @param username 用户名 * @param source 请求来源 * @return 结果 */ @GetMapping("/user/info/{username}") public R getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); }接口定义,除了正常的username参数之外,多了一个请求头 @RequestHeader(SecurityConstants.FROM_SOURCE) String source调用区别: 使用Feign组件发起远程接口调用,需要多传一个SecurityConstants.INNER 参数 remoteUserService.getUserInfo(username, SecurityConstants.INNER);
这是为何? SecurityConstants.INNER为内部微服务间远程调用请求头标识,上游微服务调用时,添加该标识的请求头,下游微服务接收请求前,进行请求头校验。 即: 定义是指定请求头key:SecurityConstants.FROM_SOURCE getUserInfo( @PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);调用时,指定请求头value:SecurityConstants.INNER remoteUserService.getUserInfo(username, SecurityConstants.INNER);最终合并 SecurityConstants.FROM_SOURCE = SecurityConstants.INNER from-source = inner 7.4.2.2 步骤2:远程正式调用上面定义的远程接口,最终通过feign方式调用到ruoyi-system微服务SysUserController类的info接口 SysUserController类的info接口 @RestController @RequestMapping("/user") public class SysUserController extends BaseController { /** * 获取当前用户信息 */ @InnerAuth @GetMapping("/info/{username}") public R info(@PathVariable("username") String username) { SysUser sysUser = userService.selectUserByUserName(username); if (StringUtils.isNull(sysUser)) { return R.fail("用户名或密码错误"); } // 角色集合 Set roles = permissionService.getRolePermission(sysUser); // 权限集合 Set permissions = permissionService.getMenuPermission(sysUser); LoginUser sysUserVo = new LoginUser(); sysUserVo.setSysUser(sysUser); sysUserVo.setRoles(roles); sysUserVo.setPermissions(permissions); return R.ok(sysUserVo); } } 这里留意,info方法上面有个@InnerAuth 注解,表示当前info方法为远程调用方法,需要进行远程校验,也即:内部鉴权。 7.4.2.3 步骤3:内部鉴权 @Aspect @Component public class InnerAuthAspect implements Ordered { @Around("@annotation(innerAuth)") public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable { String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE); // 内部请求验证 if (!StringUtils.equals(SecurityConstants.INNER, source)) { throw new InnerAuthException("没有内部访问权限,不允许访问"); } String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID); String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME); // 用户信息验证 if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) { throw new InnerAuthException("没有设置用户信息,不允许访问 "); } return point.proceed(); } /** * 确保在权限认证aop执行前执行 */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 1; } }阅读上面的切面代码,发起切面是切入点事贴有@InnerAuth接口方法。 若依(RuoYi-Cloud)代码生成模块是一个简单模块,功能顾名思义,用于构建若依体系的代码。
启动后,访问页面:
这里演示一下代码生成器使用过程。 7.5.1 步骤1:创建表在ry-cloud库中创建一个Employee表 CREATE TABLE `sys_employee` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(255) DEFAULT NULL COMMENT '名称', `age` int DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) ) ENGINE=InnoDB COMMENT='员工表';7.5.2 步骤2:导入新建表 在代码生成界面导入新建表
7.5.3.2 字段信息
字段列名:表中列的名称 字段描述:生成实体类属性注释 物理类型:表中列的类型 Java类型:生成实体类属性变量类型 Java属性:生成实体类属性名 插入:定义添加操作模态框表单控件,选中表示模态框有这个输入空间 编辑:定义编辑操作模态框表单控件,选中表示模态框有这个输入空间 列表:表中数据在列表时,该列数据是否显示,选中为要显示 查询:该列是否作为列表的查询条件,选中为需要作为查询条件 查询方式:作为查询条件时,使用匹配方式 显示类型:查询条件输入类型 字典类型:查询条件显示类型如果是下拉框,使用字典类型,实现下拉选择
生成模板:一般不动,以单表操作为主 生成包路径:指定当前代码生成根包路径 生成模块名:该功能所属模块,落地到代码就是所在微服务名称,ruoyi-gateway配置的路由映射路径名 生成业务名:该功能英文名,落地到代码就是controller中操作资源名, 比如:/employee 生成功能名:该功能中文名称 上级菜单:该功能页面展示菜单连接挂载在哪个上级菜单。 7.5.3.4 预览配置上面各种信息成功之后,可以点击预览,根据需要微调
确定无误之后,直接点生成代码
压缩包解压得到几个文件:
涉及要添加的菜单,菜单权限,在navicat中执行即可。 -- 菜单 SQL insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工', '1', '1', 'employee', 'system/employee/index', 1, 0, 'C', '0', '0', 'system:employee:list', '#', 'admin', sysdate(), '', null, '员工菜单'); -- 按钮父菜单ID SELECT @parentId := LAST_INSERT_ID(); -- 按钮 SQL insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', 'system:employee:query', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', 'system:employee:add', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', 'system:employee:edit', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', 'system:employee:remove', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values('员工导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', 'system:employee:export', '#', 'admin', sysdate(), '', null, '');执行成功后,刷新前端项目,可以看到菜单 ruoyi-ui前端employee这个模块设计到vue页面,与js
分别拷贝到项目api目录,跟views目录 刷新之后,点击员工菜单,缺少后端接口
后端接口代码,将main代码拷贝到ruoyi-system main目录中即可
然后,重启ruoyi-system服务,再访问。
定制微服务-ruoyi-modules-test 8.2 代码结构对外api:ruoyi-api-test 微服务:ruoyi-modules-test 8.3 实现步骤 8.3.1 步骤1:定义ruoyi-api-test
导入依赖参考ruoyi-api-system 创建包结构参考ruoyi-api-system
这里注意包命名规则: com.ruoyi-----公司域名倒写 system------微服务名 api------模块名 8.3.2 步骤2:等级ruoyi-api-test依赖去父项目ruoyi pom.xml文件中登记新建的api com.ruoyi ruoyi-api-test ${ruoyi.version}8.3.3 步骤3:定义ruoyi-modules-test 导入依赖参考,ruoyi-system 注意要导入ruoyi-api-test依赖 创建包结构参考ruoyi-system
nacos克隆一份配置文件--克隆自ruoyi-system-dev.yml
8.3.5 步骤5:定制网关微服务路由
到这,定制微服务就结束了,剩下操作就是常规crud了。 九、小结将整篇教程总结一下:若依(Ruoyi-Cloud)版本使用 启动 1>官网克隆项目到idea 2>按照文档,建库,建表,配置nacos 3>准备各种环境,修改本地配置 4>前后端启动,测试。 模块解读 1>网关模块,所有请求入口 2>鉴权模块,外部鉴权,内部鉴权 3>代码生成模块,先建表,再定制,后覆盖 微服务定制 1>拷贝模仿现有api/modules 2>配置中心加配置文件 3>网关配置转发路由
|
CopyRight 2018-2019 实验室设备网 版权所有 |