news 2026/9/13 2:02:07

Spring Boot企业管理系统:权限管控、多数据源与集群部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot企业管理系统:权限管控、多数据源与集群部署实战

简介:面向毕业设计、课程设计与 Java 后端学习的 Spring Boot 企业信息化管理系统资料包,涵盖部门管理、角色用户、菜单与按钮授权、数据权限、系统参数、日志管理、通知公告等核心模块,并支持在线定时任务配置、集群部署与多数据源。技术栈包括 Spring Boot、Apache Shiro、MyBatis、MySQL、Thymeleaf、Bootstrap 和 Hplus,可帮助读者理解 RBAC 权限模型、前后端代码生成、API 接口自动生成、服务状态监控、在线表单构建器及连接池 SQL 分析等企业级开发要点。包内共 892 个文件,以 Java 源码(215 个)、class、HTML、JS、CSS、XML、数据库脚本与文档为主,并配有搭建流程、表结构设计说明、系统说明书、部署文档、环境安装包及 SQL 脚本,压缩包整体约 60.09MB,目录清晰便于按需检索。已有 802 人学习下载,适合毕业设计参考,也可作为中小型管理系统后端开发的综合实战案例。

1. Spring Boot 企业信息化管理系统:从搭建流程切入权限、监控与定时任务设计

拿到这套项目时,压缩包里最显眼的是 clean.bat、package.bat 和一串编译后的 .class 文件,比如 ShiroConfig.class、SysUserController.class、Server.class。和普通源码包不同,这种内容构成的资源,更考验你对部署流程和运行结构的熟悉程度。只要先把数据库脚本导入、改好配置、执行打包,再进入权限和监控模块逐层拆解,这个系统就能真正成为你能讲清楚的开工项,而不仅仅是答辩时重复演示一遍。

项目选型是 Spring Boot + Apache Shiro + MyBatis + MySQL,前端用 Thymeleaf 模板配 Bootstrap 和 Hplus 后台主题,内置了用户、部门、岗位、角色、菜单、字典、参数、通知公告、定时任务、代码生成、系统接口、服务监控、在线构建器、连接池监控这些模块。对 Java 后端的人来说,这套结构相当于一个带权限控制、带定时任务、带数据权限过滤的企业后台样板间;对做毕设或课程设计的人来说,省掉了从空工程搭建到脚手架选型的大半时间。

真正值得花时间的不是启动它,而是搞明白权限链路如何串联、多数据源如何切换、集群下定时任务如何避免重复执行。下面按“设计拆解 → 搭建流程 → 业务模块实战 → 上线前排错”的顺序展开。

2. 权限设计与多数据源:先拆解这套系统的后端骨架

2.1 从 ShiroConfig 看认证拦截与权限注解

ShiroConfig.class 是整个权限链路的起点。Apache Shiro 在 Spring Boot 里主要负责两件事:认证当前登录人,以及为业务接口做授权判断。常见做法是通过 ShiroFilterFactoryBean 配置过滤器链,把静态资源、登录接口、Druid 监控页面和业务接口放到不同的过滤规则下。

@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager); // 登录地址和未授权页面 bean.setLoginUrl("/login"); bean.setUnauthorizedUrl("/403"); Map<String, String> filterChain = new LinkedHashMap<>(); filterChain.put("/css/**", "anon"); filterChain.put("/js/**", "anon"); filterChain.put("/login", "anon"); filterChain.put("/logout", "logout"); filterChain.put("/druid/**", "anon"); // 其余接口统一走登录校验 filterChain.put("/**", "user"); bean.setFilterChainDefinitionMap(filterChain); return bean; } }

逻辑说明:anon 表示匿名访问,logout 是 Shiro 自带的退出过滤器,user 表示需要登录后访问。LinkedHashMap 保证过滤器规则从上到下匹配,所以静态资源和登录接口必须放在 /** 之前,否则会被后面的全局规则抢先拦截。loginUrl 是会话失效或未登录时跳转的地址,unauthorizedUrl 则是权限不足时的提示页面。

大多数管理系统会在 Controller 方法上使用 @RequiresPermissions("system:user:add") 这类注解,配合 Shiro 注解或 AOP 拦截器,判断当前登录用户拥有的菜单权限。这里的权限标识 perms 来自菜单表,按钮类型的数据也会存储对应权限字符串,前端再根据用户菜单集合控制按钮是否渲染,命令放行与界面隐藏配合,权限链路才算完整。

权限模块里最关键的表关系可以整理成下面这张表:

数据对象表名关键字段作用
用户sys_useruser_id、dept_id、user_name登录账号,关联部门
部门sys_deptdept_id、parent_id、ancestors组织树,数据权限过滤范围
角色sys_rolerole_id、role_key、data_scope控制菜单范围和数据范围
菜单sys_menumenu_id、perms、menu_type目录、菜单、按钮的权限标识

角色表里的 data_scope 值得多说一句,它不是控制菜单,而是控制数据可见性。常见值包括 1 全部数据权限、2 自定义数据权限、3 本部门数据权限、4 本部门及以下数据权限。这个字段会直接参与查询 SQL 的拼接,回答数据权限怎么实现时,不能只说“菜单权限”。

2.2 MyBatis 多数据源:按 Mapper 路由到不同业务库

企业信息化系统常见的场景是配置库和业务库分离,或者部分模块需要读取另一个老系统的数据库。项目里的多数据源设计通常基于 Druid 连接池和 AbstractRoutingDataSource 来做,原理是维护一个动态数据源上下文,在执行 SQL 前把数据源 key 放入 ThreadLocal,执行结束后清空。

一个常见的设计是在 application.yml 里配置两个数据源:

spring: datasource: druid: master: url: jdbc:mysql://localhost:3306/ent_info?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver slave: url: jdbc:mysql://localhost:3306/ent_info_slave?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver enable: true

这里的 master 和 slave 不一定是主从复制,也可以理解成两个业务数据源。实际切换借助 AOP 和自定义注解完成,核心工具类如下:

public class DataSourceContextHolder { private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>(); public static void set(String dataSourceType) { CONTEXT.set(dataSourceType); } public static String get() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } }

逻辑说明:在切面里读取方法上的 @DataSource("slave") 注解,调用 set 设置当前数据源,业务执行后再调用 clear 清理。这样比在业务代码里手动切换干净得多,也方便维护多数据源扩展点。

参数说明:ThreadLocal 使用结束后必须 remove,否则线程池复用线程时,下个请求会拿到上一个请求的数据源信息,造成串库。另外,事务环境下数据源一旦切换,对后续同事务内的操作都生效,所以不要在同一个事务里频繁切换数据源,事务边界和数据源边界要保持一致。

2.3 集群部署的关注点:会话共享与定时任务锁

系统说明里写“支持集群”,集群环境首先要解决的是 Shiro 会话同步。Shiro 默认把会话存在本地内存,多节点部署后用户请求走到另一台服务器就识别不了登录态。简单方案是 nginx 按 ip_hash 把同一用户固定到同一节点;更通用的方案是把 Session 存到 Redis,或在网关层校验无状态 Token。

第二个问题是定时任务。如果使用 Spring 自带的 @Scheduled,每台节点都会触发同一段逻辑,订单提醒、数据统计等任务会重复执行。轻量级做法是使用数据库锁表:任务开始前执行一条 update,只有影响行数为 1 的节点可以继续;严格一点的方案是集成 Quartz 集群模式,把任务调度状态存储到数据库表中,并用 misfire 策略处理停机积压的任务。这块在系统说明书里最好表述清楚,否则答辩时“支持集群”这类描述容易站不住。

3. 搭建流程:从 clean.bat 到数据库脚本的完整初始化

3.1 用 package.bat 完成构建环境检查

项目根目录下常见的是 clean.bat 和 package.bat。clean.bat 一般负责清理 target、logs 和 release 目录;package.bat 则会执行 Maven 打包并复制产物。Windows 环境下,执行 package.bat 前需要确认 Java、Maven、MySQL 的环境变量都已经配置好。

常见 packaged 脚本内容大致如下:

@echo off set MAVEN_OPTS=-Xms256m -Xmx512m call mvn clean package -DskipTests -Pprod if %errorlevel% neq 0 ( echo 打包失败,请检查 Maven 错误信息 exit /b 1 ) copy /Y target\ent-info.jar release\ent-info.jar pause

逻辑说明:MAVEN_OPTS 控制 Maven 自身堆内存,避免编译大项目时内存不足;-DskipTests 跳过测试用例,防止数据库未准备导致单测失败;-Pprod 加载生产环境 profile,对应 application-prod.yml 中的独立配置。打包成功后把 jar 复制到 release 目录,便于部署时直接取用。

参数说明:如果项目源码是 JDK 8,而本机默认 JDK 是 17,Maven 使用的编译器版本不会自动切换,需在 pom.xml 中确认 maven.compiler.source 和 maven.compiler.target 的值。Spring Boot 2.x 推荐 JDK 8,Spring Boot 3.x 必须 JDK 17。

3.2 导入 MySQL 数据库脚本与初始化数据

部署文档中通常会提供数据库脚本和表结构设计说明。执行时尽量用命令行导入,避免图形客户端字符集选择不对造成中文乱码。

mysql -u root -p -h 127.0.0.1 --default-character-set=utf8mb4 -e "CREATE DATABASE IF NOT EXISTS ent_info DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p -h 127.0.0.1 --default-character-set=utf8mb4 ent_info < /path/to/ent_info.sql

说明:第一条命令创建数据库并指定 utf8mb4 字符集,因为 utf8mb4 能完整支持中文和特殊字符;第二条命令把 SQL 脚本导入到指定库。重定向符号<在 Windows 的 cmd 和 PowerShell 下都能使用,但要注意路径中尽量不包含空格和中文。

导入完成后至少检查 sys_user、sys_role、sys_user_role 三张表是否有初始化数据,默认管理员账号一般就存在 sys_user 表中。如果这三张表为空,登录页面几乎必然无法通过认证。还要确认 sys_menu 表里的 menu_type 是否正确,目录、菜单、按钮三种类型的 perm 标识不能混用,否则代码生成器或菜单授权时会出现按钮漏显示。

3.3 修改 application.yml 后启动应用

项目能否在一次部署内跑通,取决于配置修改是否完整。下面是一份开发环境常见的配置文件:

server: port: 8080 servlet: context-path: / spring: datasource: druid: master: url: jdbc:mysql://127.0.0.1:3306/ent_info?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: root123 thymeleaf: cache: false mybatis: mapper-locations: classpath*:mapper/**/*.xml type-aliases-package: com.enterprise.*.domain enterprise: profile: D:/data/upload

参数说明:serverTimezone=Asia/Shanghai 非常关键,新版 MySQL 驱动不带这个参数会报 CST 时区异常;thymeleaf.cache 在开发时可置为 false,生产环境记得改回 true;enterprise.profile 是项目自定义配置,用于设置文件上传路径,Spring Boot 中通过@Value("${enterprise.profile}")读取。

配置修改中最容易遇到错误的项可以参照下面这张表:

配置项典型报错处理方式
数据库 urlThe server time zone value 'CST' is unrecognized在 JDBC URL 后追加 serverTimezone=Asia/Shanghai
连接用户Access denied for user 'root'@'localhost'确认 MySQL 用户与密码,检查远程访问权限
上传路径FileNotFoundException提前创建目录,或配置为已有可写目录
前端接口前缀登录请求返回 404将 nginx 中 /prod-api/ 代理到后端根路径

启动方式可以用 IDEA 直接运行主类,也可以执行 java -jar target/ent-info.jar --spring.profiles.active=dev。前端部署到 nginx 后,需要把接口前缀 /prod-api/ 转发到后端 8080 端口。一个简洁的 nginx 代理配置如下:

location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

逻辑说明:proxy_pass 末尾的/表示将/prod-api/前缀替换为后端根路径,例如请求/prod-api/login实际会转发为/login。如果项目 context-path 不为空,这里的转发路径也要相应调整。

4. 业务实战:用户管理、数据权限过滤与代码生成

4.1 SysUserController 的接口风格与权限注解

SysUserController.class 是用户管理模块的核心控制器,包含用户列表、新增、修改、删除、重置密码、分配角色等接口。接口返回结构一般采用统一格式,表格数据返回 TableDataInfo,普通操作返回 AjaxResult。

@RestController @RequestMapping("/system/user") public class SysUserController { @RequiresPermissions("system:user:list") @GetMapping("/list") public TableDataInfo list(SysUser user) { startPage(); List<SysUser> list = userService.selectUserList(user); return getDataTable(list); } @RequiresPermissions("system:user:remove") @DeleteMapping("/{userIds}") public AjaxResult remove(@PathVariable Long[] userIds) { return toAjax(userService.deleteUserByIds(userIds)); } }

逻辑说明:startPage() 在查询前调用,PageHelper 拦截器会为下一条 SQL 拼接 limit 分页。@RequiresPermissions 注解让每个接口都有具体的权限标识,前端菜单管理维护同样的 perms 字符串,做到按钮级权限控制。

参数说明:列表查询直接使用 SysUser 对象接收前端参数,而不是散落多个参数。这样系统可以灵活扩展 status、deptId、phonenumber 等查询条件。当 selectUserList 方法内部发生第二次 SQL 查询时,分页拦截器也可能影响第二条 SQL,所以需要把 startPage 紧贴真正的列表查询。

权限闭环不仅靠后端拦截,前端也要控制按钮显示。菜单管理里按钮类型的菜单有 perms 标识,前端拿到用户菜单后根据 perms 判断是否渲染新增、删除、导出等按钮。只隐藏按钮不拦截后端接口,是不完整的权限方案。

4.2 数据权限的 SQL 拼接与部门过滤

数据权限的常见实现是自定义 MyBatis 拦截器,在查询执行前改写 SQL,自动拼上角色对应的部门条件。查询用户列表的 SQL 片段可参考:

<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult"> select u.user_id, u.dept_id, u.user_name, d.dept_name from sys_user u left join sys_dept d on u.dept_id = d.dept_id <where> <if test="userName != null and userName != ''"> AND u.user_name like concat('%', #{userName}, '%') </if> <if test="dataScope != null and dataScope != ''"> AND u.dept_id IN (${dataScope}) </if> </where> </select>

这里的${dataScope}已经由后端根据角色 data_scope 计算好,是一段可用的部门 id 列表,例如100, 101, 102。注意,${} 存在 SQL 注入风险,所以数据来源只能由后端计算,不能直接使用前端参数。

数据权限的规则可以整理成下表:

data_scope含义查询拼接条件
1全部数据权限不拼接部门条件
2自定义数据权限根据角色部门关系表查询部门 id
3本部门数据权限dept_id = 当前用户部门
4本部门及以下数据权限dept_id in 当前部门 + 所有子部门 id

子部门查询一般会写到递归方法里。如果部门层级很多,还可以利用 sys_dept 表的 ancestors 字段,通过字符串 like 匹配直接找出所有后代部门 id,避免多次递归查询。后端拿到最终的部门 id 集合后,再安全地拼接进查询 SQL 中,这一步完成,数据权限才真正生效。

4.3 代码生成器与在线构建器的提速逻辑

系统内置的代码生成模块可以按数据库表生成 java、html、xml、sql 四类文件,并支持 CRUD 下载。生成动作通常读取 information_schema 中的表结构,通过模板引擎渲染出 Controller、Service、Mapper 和前端页面。

生成后的文件一般落在以下结构中:

main/java/com/enterprise/ ├── controller/SysXxxController.java ├── service/ISysXxxService.java ├── service/impl/SysXxxServiceImpl.java ├── domain/SysXxx.java └── mapper/SysXxxMapper.java main/resources/ ├── mapper/system/SysXxxMapper.xml └── templates/system/xxx.html

使用代码生成器时要注意,生成前把表字段注释写完整,生成后的字段名和页面 label 都由注释决定;主键尽量使用单列自增,联合主键生成的模板代码一般需要手动调整。在线构建器拖动表单元素生成的 HTML 更适合作为原型,表单提交地址要人工绑定到后端 Controller,避免直接嵌入生产页面。

5. 服务监控、定时任务与连接池监视:上线前必须过一遍

5.1 用 Server.class 采集系统指标

服务监控页面中的 CPU、内存、磁盘、堆栈信息,通常由 Server.class 封装后输出。实现上可以基于 Oshi 库读取系统指标,也可以直接读取 Linux 下的 /proc/stat 和 /proc/memory。下面两个命令是排查 Java 进程堆栈时最常用的:

jstack $(pgrep -f ent-info.jar) > /tmp/jstack.log jmap -heap $(pgrep -f ent-info.jar)

如果输出中大量出现 BLOCKED 状态,说明线程在等待锁或连接池资源。此时应优先查慢 SQL,再去连接池监视页面看活跃连接数是否打满。含有 actuator 的项目,要避免将 heapdump 接口暴露到公网,因为堆转储文件会包含内存中的敏感数据,应限制 actuator 端点开放范围。

5.2 定时任务在线配置与持久化

在线定时任务能保存到数据库并通过反射调用目标 bean,修改 cron 后如果不重建触发器,任务可能继续使用旧表达式。正确做法是修改后先 unschedule,再用新 cron schedule 一次。多节点环境下,建议增加一个任务节点字段,执行前判断当前节点是否与任务节点一致,或使用数据库锁表来避免重复执行。

5.3 连接池监视与慢 SQL 定位

Druid 监视页面能显示当前活跃连接、空闲连接以及 SQL 执行统计。排查性能瓶颈时,我一般先看按耗时排序的 SQL 统计,再打开慢 SQL 日志:

spring: datasource: druid: filter: stat: log-slow-sql: true slow-sql-millis: 1000

slow-sql-millis 表示超过 1 秒即为慢 SQL。开启后查看日志中打印的完整 SQL,使用 explain 确认是否命中了有效索引。毕设答辩时主动指出这条排查链路,再结合服务监控的堆栈信息一起说明,比单纯点击页面演示要有说服力。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 2:02:05

Spring Boot vs Node.js 技术选型决策指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:01:41

Nuclei Templates 完整指南:5 分钟上手安全扫描与漏洞检测

Nuclei Templates 完整指南&#xff1a;5 分钟上手安全扫描与漏洞检测 【免费下载链接】nuclei-templates Community curated list of templates for the nuclei engine to find security vulnerabilities. 项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templat…

作者头像 李华
网站建设 2026/9/13 2:01:26

从 0 到 1 跑通 kohya_ss:AMD ROCm 训练环境实战手册

从 0 到 1 跑通 kohya_ss&#xff1a;AMD ROCm 训练环境实战手册 【免费下载链接】kohya_ss 项目地址: https://gitcode.com/GitHub_Trending/ko/kohya_ss 在 AMD 显卡机器上配置 kohya_ss 训练环境&#xff0c;最容易卡在 PyTorch 构建的选择上&#xff1a;装错 CUDA …

作者头像 李华
网站建设 2026/9/13 2:00:33

ESP32-P4 USB Host实战:从枚举到FatFs的U盘读写完整指南

1. 实验背景与整体方案设计1.1 为什么ESP32-P4的USB Host值得花一章来讲DNESP32P4开发板上市之后&#xff0c;我第一时间就拿它做了不少外设实验。说实话&#xff0c;串口、GPIO、I2C这些常规外设玩起来都挺顺手&#xff0c;但真正让我觉得这块板子“有内味”的&#xff0c;是它…

作者头像 李华
网站建设 2026/9/13 2:00:28

Android车机USB外设开发实战:从串口、CAN到HID设备的完整接入指南

车机调试台上经常摆着一堆 USB 外设&#xff1a;OBD 诊断盒子、USB-CAN 转换器、外接手柄、键盘、甚至还有临时接的串口传感器采集板。Android 车机和普通手机的 USB 开发有个非常大的区别——手机上的 USB 基本就是充电、传文件、连 ADB&#xff0c;而车机上 USB Host 是一个正…

作者头像 李华