logo

RuoYi v3.6.0

基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构

## 端口占用说明 ---- 常用 80/443 nginx 8848/9848/9849 nacos 4500/500 vpn 9000 docker可视化 8000 jenkins 27017 mongodb 8718 sentinel 6379 redis 60001 探访项目前端 60002 探访项目公众号 60003 探访项目大屏 30301 探访项目大屏后端 30101 探访项目后端 60044 一汽项目前端 30144 一汽项目后端 8080 考试系统网关 9200 考试系统认证 9100 考试系统监控 9300 考试系统文件上传 9202 考试系统代码生成器 9203 考试系统定时任务 9201 考试系统系统模块 8122 考试系统教育 8121 考试系统资源 800 考试系统前端 60077 考试系统uniapp 9090 民政系统网关 9400 民政系统认证 9101 民政系统监控 9399 民政系统文件上传 9402 民政系统代码生成器 9403 民政系统定时任务 9401 民政系统系统模块 8280 民政系统机构模块 8290 民政系统政务模块 8340 民政系统搜索模块 8345 民政系统门户模块 8600 民政系统数据同步模块 801 民政系统前端 7070 智能养老系统网关 7200 智能养老系统认证 7201 智能养老系统模块 8131 智能养老业务模块 802 智能养老系统前端 6060 OKC系统后端 803 OKC系统前端 ## 升级改造 0.由于很多项目都使用若伊框架开发,如果放在同一个服务器上,那么cookies和redis的存储会重叠,因此这边做了处理 ```js // 前端在appjs把cookie存储的方法加上前缀 import Cookies from 'js-cookie' let get_method = Cookies.get let set_method = Cookies.set let remove_method = Cookies.remove Cookies.get = (key) => { return get_method('mz_' + key) } Cookies.set = (key, value, attributes) => { return set_method('mz_' + key, value, attributes) } Cookies.remove = (key, attributes) => { return remove_method('mz_' + key, attributes) } ``` ```java // 后端在redis配置里添加key前缀 @Component public class RedisKeySerializer implements RedisSerializer { private final Charset charset; public final static String key = "mz"; public RedisKeySerializer() { this(Charset.forName("UTF8")); } public RedisKeySerializer(Charset charset) { Assert.notNull(charset, "字符集不允许为NULL"); this.charset = charset; } @Override public byte[] serialize(String string) throws SerializationException { // 通过项目名称ruoyi.name来定义Redis前缀,用于区分项目缓存 return new StringBuilder(key).append(":").append(string).toString().getBytes(charset); } @Override public String deserialize(byte[] bytes) throws SerializationException { return (bytes == null ? null : new String(bytes, charset)); } } @Configuration @EnableCaching @AutoConfigureBefore(RedisAutoConfiguration.class) public class RedisConfig extends CachingConfigurerSupport { @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory,RedisKeySerializer redisKeySerializer) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(redisKeySerializer);//template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(redisKeySerializer);//template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } } ``` 1.首先在根目录的pom文件添加 ```xml dev dev 139.9.138.217:8848 MZ f4b2e449-3ed7-4338-8fcd-717e6066baf3 MZ f4b2e449-3ed7-4338-8fcd-717e6066baf3 true prod prod 139.9.138.217:8848 MZ MZ ``` 2.复制docker文件夹 复制ruoyi-ui下的Dockerfile,nginx.conf到新工程 3.替换配置方式: sentinel的 127.0.0.1:8718 换成 139.9.138.217:8718 127.0.0.1:8848 换成 139.9.138.217:8848 active: dev 换 active: @profiles.active@ ```yaml nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 配置文件格式 file-extension: yml # 共享配置 shared-configs: - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} ``` 换成 ```yaml nacos: # nacos 服务地址 server-addr: @nacos.server@ discovery: # 注册组 group: @nacos.discovery.group@ namespace: @nacos.discovery.namespace@ config: # 配置组 group: @nacos.config.group@ namespace: @nacos.config.namespace@ # 配置文件格式 file-extension: yml # 共享配置 shared-configs: - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} group: @nacos.config.group@ namespace: @nacos.discovery.namespace@ ``` 每个需要启动的pom的build节点下添加 ``` src/main/resources true ``` 4.添加新依赖 gateway添加kinfe ```xml com.github.xiaoymin knife4j-spring-ui 3.0.3 ``` 添加mybaitsplus,lombok 复制一份 ruoyi-api-system 添加ruoyi-api-ext模块 ruoyi-api-ext依赖tool工具库 ``` cn.hutool hutool-all 5.5.8 ``` ruoyi-common-swagger添加 ``` com.github.xiaoymin knife4j-spring-boot-starter 3.0.3 ``` 5.业务改造: (0)本身业务只有用户管理和部门管理存在数据权限 (1)部门改为懒加载,并且新增行政区划表和部门表对应,部门区划选择 限制只能选择部门层级或者上一级(直属) (2)角色增删改,不对外开放,数据权限去掉,改造为增加角色可分配权限的字段,由超管进行 角色分配后选择可分配角色进行下级角色分配,需要同步处理用户里角色选择的问题,非自己能分配的角色禁止分配,但是可以取消用户角色 (3)内部调用的服务 不走@requirePermissions相关注解 ``` PreAuthorizeAspect.java @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE); // 内部请求验证 if (!StringUtils.equals(SecurityConstants.INNER, source)) { // 注解鉴权 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); checkMethodAnnotation(signature.getMethod()); } try { // 执行原有逻辑 Object obj = joinPoint.proceed(); return obj; } catch (Throwable e) { throw e; } } ``` (3)用户管理左侧部门改为懒加载+触发搜索 (4)修改gen里的模板生成,添加注解验证等功能 (5)扩展数据权限为mybatisplus拦截器,并且做了多菜单分别对应不同的数据权限 (6)内置固定角色 养老机构用户,社区养老服务机构用户,评定专家用户, 内置角色不自由分配 指定业务进行授予,该3个内置角色授予后 根据业务不能改变部门和角色。可以扩展(指定内置角色和对应菜单关系,暂时未锁定),角色表添加字段,内置角色只允许更改菜单,其他功能代码做好逻辑限制(不允许修改其他,不允许外部分配,分配只分配指定类型)。 (7)扩展字典表 添加dict_parent_value 组成树形字典,默认框架字典为平级字典,通过该字段扩展为树形字典,一版规则为10是1x的父级 (8)查询系统表字段不存在注释得结果 ```mysql SELECT * FROM `COLUMNS` WHERE TABLE_SCHEMA = 'mz-cloud' and TABLE_NAME not LIKE '%act%' and TABLE_NAME not LIKE '%www%' and TABLE_NAME not LIKE '%v_%' and COLUMN_COMMENT ='' and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state') GROUP BY TABLE_NAME ``` (9)查询系统表字段是日期 但是长度不是8的 ```mysql SELECT * FROM `COLUMNS` WHERE TABLE_SCHEMA = 'mz-cloud' and COLUMN_COMMENT like '%日期%' and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state') and CHARACTER_MAXIMUM_LENGTH != 8 ``` (10)查询系统表字段是时间 但是长度不是14的 ```mysql SELECT * FROM `COLUMNS` WHERE TABLE_SCHEMA = 'mz-cloud' and COLUMN_COMMENT like '%时间%' and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state') and CHARACTER_MAXIMUM_LENGTH != 14 ``` (11)查询权限重复 ```mysql SELECT count(1)as count ,perms FROM sys_menu GROUP BY perms HAVING count > 1 ``` (12)查询涉及行政区划id的 ```mysql SELECT * FROM COLUMNS WHERE TABLE_SCHEMA = 'mz-cloud' and (COLUMN_COMMENT like '%行政%' or COLUMN_COMMENT like '%区划%' or COLUMN_COMMENT like '%居住%' or COLUMN_COMMENT like '%籍贯%' or COLUMN_COMMENT like '%户籍%' or COLUMN_COMMENT like '%现居%') and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state') ``` (13)比较文档里缺少的表和字段 ```mysql SELECT * FROM ( SELECT a1.TABLE_NAME, a1.COLUMN_NAME,a1.COLUMN_COMMENT,a1.IS_NULLABLE,a1.DATA_TYPE,a1.CHARACTER_MAXIMUM_LENGTH,a1.COLUMN_KEY, a2.zdmc,a2.zdlx,a2.zdgs,a2.sfbx,a2.dictid,a2.dbtype,a2.dblength,a2.ispk,a2.bbb,a2.zdbs, case when a1.COLUMN_COMMENT = IF(a2.dictid = '' or a2.dictid is null,a2.zdmc,CONCAT(a2.zdmc,'(',a2.dictid,')')) then 'true' else 'false' end as c1, case when a1.IS_NULLABLE = case when a2.sfbx = 'Y' then 'NO' else 'YES' end then 'true' else 'false' end as c2, case when a1.DATA_TYPE = a2.dbtype then 'true' else 'false' end as c3, case when a1.CHARACTER_MAXIMUM_LENGTH = a2.dblength or a2.dbtype= 'int' or a2.dbtype = 'decimal' then 'true' else 'false' end as c4, case when a1.COLUMN_KEY = case when a2.ispk = '1' then 'PRI' else '' end then 'true' else 'false' end as c5 FROM (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'mz-cloud' and TABLE_NAME NOT like '%act%' and TABLE_NAME NOT like '%www%' and TABLE_NAME NOT like '%v_%' and TABLE_NAME NOT like '%qrtz%' and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state')) a1 LEFT JOIN (SELECT b1.*,b2.bid as bbb,b2.bmc FROM ry.`columns` b1, ry.`tables` b2 WHERE b1.bid = b2.id) a2 ON a2.bbb = a1.TABLE_NAME and a2.zdbs = a1.COLUMN_NAME ) a WHERE ISNULL(a.bbb) ``` (14)比较文档里现有字段和实际数据库不一致的地方 ```mysql SELECT * FROM ( SELECT a1.TABLE_NAME, a1.COLUMN_NAME,a1.COLUMN_COMMENT,a1.IS_NULLABLE,a1.DATA_TYPE,a1.CHARACTER_MAXIMUM_LENGTH,a1.COLUMN_KEY, a2.zdmc,a2.zdlx,a2.zdgs,a2.sfbx,a2.dictid,a2.dbtype,a2.dblength,a2.ispk,a2.bbb,a2.zdbs, case when a1.COLUMN_COMMENT = IF(a2.dictid = '' or a2.dictid is null,a2.zdmc,CONCAT(a2.zdmc,'(',a2.dictid,')')) then 'true' else 'false' end as c1, case when a1.IS_NULLABLE = case when a2.sfbx = 'Y' then 'NO' else 'YES' end then 'true' else 'false' end as c2, case when a1.DATA_TYPE = a2.dbtype then 'true' else 'false' end as c3, case when a1.CHARACTER_MAXIMUM_LENGTH = a2.dblength or a2.dbtype= 'int' or a2.dbtype = 'decimal' or ISNULL(a1.CHARACTER_MAXIMUM_LENGTH) then 'true' else 'false' end as c4, case when ((a1.COLUMN_KEY = (case when a2.ispk = '1' then 'PRI' else '' end) ) or (a1.COLUMN_KEY = (case when a2.ispk = '1' then 'PRI' else 'MUL' end) )) then 'true' else 'false' end as c5 FROM (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'mz-cloud' and TABLE_NAME NOT like '%act%' and TABLE_NAME NOT like '%www%' and TABLE_NAME NOT like '%v_%' and TABLE_NAME NOT like '%qrtz%' and COLUMN_NAME not IN('create_time_str','create_user_id','create_user_type','create_by','create_unit','create_unit_name','update_time_str','update_user_id','update_by','update_unit','update_unit_name','state')) a1 LEFT JOIN (SELECT b1.*,b2.bid as bbb,b2.bmc FROM ry.`columns` b1, ry.`tables` b2 WHERE b1.bid = b2.id) a2 ON a2.bbb = a1.TABLE_NAME and a2.zdbs = a1.COLUMN_NAME ) a WHERE a.bbb is not null and (c1 != 'true' or c2 !='true' or c3 != 'true' or c4 != 'true' or c5 != 'true') ``` (15)开发完成后 数据库字段和代码字段的核对 待考虑 测试人员进行一次注解核对 还是自动化写个脚本进行核对,业务逻辑判断的核对需要用代码走查的形式,review (16)该模式下的权限字符核对模式:也同样考虑 自动化脚本核对,但是如果改造成 自动生成权限+菜单则不需要核对。 (99)目前信息统计相关业务菜单权限 是 隐式的, 并且没有子集区分功能,如养老机构下 A类型统计单独控制菜单显示,接口权限由于采用共有接口 没做菜单和接口的对应权限关联 (100)针对目前系统里 业务里的非空项目 在库里没有设置非空的情况: 若是严格按照实体非空限制,最好采用kotlin 带有非空字段的定义,目前非移动端项目 js弱类型只需要考虑空情况和类型不匹配情况即可 ## 平台简介 若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 * 采用前后端分离的模式,微服务版本前端(基于 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue))。 * 后端采用Spring Boot、Spring Cloud & Alibaba。 * 注册中心、配置中心选型Nacos,权限认证使用Redis。 * 流量控制框架选型Sentinel,分布式事务选型Seata。 * 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://github.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。 * 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) * 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)   * 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   #### 友情链接 [若依/RuoYi-Cloud](https://gitee.com/zhangmrit/ruoyi-cloud) Ant Design版本。 ## 系统模块 ~~~ 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-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 // 公共依赖 ~~~ ## 架构图 ## 内置功能 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 3. 岗位管理:配置系统用户所属担任职务。 4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 7. 参数管理:对系统动态配置常用参数。 8. 通知公告:系统通知公告信息发布维护。 9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 10. 登录日志:系统登录日志记录查询包含登录异常。 11. 在线用户:当前系统中活跃用户状态监控。 12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 14. 系统接口:根据业务代码自动生成相关的api接口文档。 15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 16. 在线构建器:拖动表单元素生成相应的HTML代码。 17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 ## 在线体验 - admin/admin123 - 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 演示地址:http://ruoyi.vip 文档地址:http://doc.ruoyi.vip ## 演示图
## 若依微服务交流群 QQ群: [![加入QQ群](https://img.shields.io/badge/已满-42799195-blue.svg)](https://jq.qq.com/?_wv=1027&k=yqInfq0S) [![加入QQ群](https://img.shields.io/badge/已满-170157040-blue.svg)](https://jq.qq.com/?_wv=1027&k=Oy1mb3p8) [![加入QQ群](https://img.shields.io/badge/已满-130643120-blue.svg)](https://jq.qq.com/?_wv=1027&k=rvxkJtXK) [![加入QQ群](https://img.shields.io/badge/已满-225920371-blue.svg)](https://jq.qq.com/?_wv=1027&k=0Ck3PvTe) [![加入QQ群](https://img.shields.io/badge/已满-201705537-blue.svg)](https://jq.qq.com/?_wv=1027&k=FnHHP4TT) [![加入QQ群](https://img.shields.io/badge/已满-236543183-blue.svg)](https://jq.qq.com/?_wv=1027&k=qdT1Ojpz) [![加入QQ群](https://img.shields.io/badge/已满-213618602-blue.svg)](https://jq.qq.com/?_wv=1027&k=nw3OiyXs) [![加入QQ群](https://img.shields.io/badge/148794840-blue.svg)](https://jq.qq.com/?_wv=1027&k=kiU5WDls) 点击按钮入群。