news 2026/9/3 21:38:42

Vue 3与Spring Boot 3构建医院HR系统:架构设计与核心模块实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue 3与Spring Boot 3构建医院HR系统:架构设计与核心模块实现

简介:这是一套面向Java与前端开发者、高校计算机专业师生及医疗信息化项目实践者的医院人力资源管理系统完整源码,聚焦解决医院人事部门在招聘、考勤、薪酬、绩效、培训与离职等多环节的数字化管理需求。资源采用Vue3+SpringBoot3前后端分离架构,包含37个文件,涵盖10个核心Java后端业务类、4个CSS样式文件、4个JS交互逻辑脚本、2个YML配置及PDF/DOCX文档说明,压缩包仅2.87MB,轻量易部署。代码结构清晰,含标准Maven模块(pom.xml)、Vue工程目录与详细配置说明,便于快速理解分层设计与RESTful接口对接逻辑。已有37人学习下载,读者可直接运行调试,掌握Composition API应用、Spring Security权限控制、JPA数据建模及医疗场景下敏感信息处理等实战要点,是学习企业级HR系统开发的典型参考案例。

1. 项目概述与核心价值

最近在整理过往项目时,翻到了一个挺有意思的“医院人力资源管理系统”的源码包。这个项目采用了当前主流的前后端分离架构,前端基于 Vue 3,后端基于 Spring Boot 3,算是一个比较典型的现代化企业级应用案例。对于正在学习全栈开发,尤其是对医疗行业信息化感兴趣的朋友来说,这个项目源码就像一份“解剖样本”,能让你清晰地看到从技术选型到业务落地的完整链路。

这个系统本质上是一个为医院这类特殊组织量身定制的 HRM(Human Resource Management)系统。它解决的不仅仅是传统企业里员工档案、考勤、薪资这些基础问题,更要处理医院特有的复杂场景,比如医护人员的排班(涉及门诊、住院、手术、值班等多维度)、职称与执业资格管理、科室绩效核算等。所以,它不仅仅是技术的堆砌,更是业务逻辑深度融入技术实现的典范。如果你手头正好有这个源码包,或者想自己从头搭建一个类似系统,接下来的内容会带你深入其肌理,从设计思路到代码细节,再到那些只有踩过坑才知道的实操要点,希望能给你带来实实在在的参考价值。

2. 技术栈选型与架构设计解析

2.1 为什么是 Vue 3 + Spring Boot 3?

看到这个技术组合,很多人的第一反应可能是“流行”、“新”。但在这个项目里,选择它们有更深层的考量,而不仅仅是追新。

前端 Vue 3 的考量:医院人力资源系统的前端界面通常不会像电商那样有极其复杂的交互,但数据展示的维度多、表单复杂(如排班表、绩效核算表),且对实时性有一定要求(如消息通知、排班变更提示)。Vue 3 的 Composition API 在这里发挥了巨大优势。它允许我们将与“医护人员排班”相关的所有逻辑(如日期计算、规则校验、冲突检测)封装在一个独立的useSchedule组合式函数里,而不是像 Options API 那样分散在datamethodscomputed各个选项中。这使得代码在应对医院复杂的排班规则时,依然能保持极高的可读性和可维护性。另外,Vue 3 更小的打包体积和更好的性能,对于可能部署在医院内网、服务器资源相对有限的环境来说,也是一个加分项。

后端 Spring Boot 3 的考量:Spring Boot 3 基于 Spring Framework 6 和 Java 17+,它带来的不仅仅是版本号的提升。对于医院HR系统而言,安全性可维护性是生命线。Spring Boot 3 对 Jakarta EE 9+ 的全面支持(取代了旧的 javax),意味着更现代、更安全的基础依赖。其内置的更强大的 Actuator 端点,可以方便地监控系统健康状态、线程池、缓存等,这对于保障7x24小时运行的医院系统至关重要。此外,Spring Boot 3 对 GraalVM 原生镜像的更好支持,虽然在这个项目中可能不是首要目标,但为未来系统性能的极致优化预留了可能性。选择 Java 17+ 的 LTS(长期支持)版本,也确保了系统在未来的数年内能获得稳定的安全更新。

2.2 前后端分离架构与数据流设计

这个项目采用了经典的前后端分离架构。前端作为一个独立的 SPA(单页应用)部署在 Nginx 或 Apache 上,后端提供纯粹的 RESTful API。这种分离带来了清晰的职责划分和灵活的部署能力。

核心数据流设计:

  1. 认证与授权流:用户在前端登录,前端将凭证(用户名/密码)发送至后端/api/auth/login接口。后端通过 Spring Security 进行校验,成功后生成一个 JWT(JSON Web Token)返回给前端。前端将此 Token 存储在 localStorage 或更安全的 HttpOnly Cookie 中,并在后续所有 API 请求的Authorization头部携带。后端通过一个JwtAuthenticationFilter拦截请求,验证 Token 的有效性和权限。
  2. 业务数据流:以前端加载“科室人员列表”为例。前端 Vue 组件在onMounted生命周期中,调用封装好的departmentService.getStaffList(deptId)方法。该方法使用 Axios 发起 GET 请求到后端/api/department/{deptId}/staff。后端控制器 (DepartmentController) 接收到请求,调用服务层 (DepartmentService) 进行业务逻辑处理(可能涉及多表关联查询),服务层再调用数据访问层 (DepartmentMapper) 从 MySQL 数据库中获取数据,最终将结构化的 JSON 数据沿原路返回给前端。前端收到数据后,利用 Vue 的响应式系统更新组件状态,驱动视图渲染。

注意:在实际医院环境中,涉及员工敏感信息(如薪资、家庭住址)的 API,务必使用 HTTPS 进行全程加密传输。JWT 虽然方便,但其本身的内容是可解码的,因此切勿在 JWT 的 payload 中存放任何敏感信息,如密码、身份证号全文等。通常只存放用户ID、角色等非敏感标识。

3. 核心业务模块深度剖析

一个医院HR系统的核心,在于如何将医院特有的、纷繁复杂的业务流程,抽象成清晰、可扩展的软件模块。下面我们拆解几个关键模块。

3.1 医护人员排班管理模块

这是医院HR系统中最复杂、最具挑战性的模块。它远不止是一个日历视图那么简单。

数据结构设计:排班的核心是“谁”、“在什么时间”、“在什么地点”、“做什么事”。在数据库设计中,通常会有一张核心的schedule表,其关键字段可能包括:

  • id: 主键
  • staff_id: 医护人员ID,关联员工表
  • department_id: 科室ID
  • schedule_date: 排班日期
  • shift_type: 班次类型(如“早班”、“中班”、“夜班”、“行政班”、“休息”)
  • work_type: 工作类型(如“门诊”、“病房”、“手术”、“听班”)
  • location: 具体地点(如“门诊三楼外科诊室1”、“住院部12楼东区”)

前端实现要点(Vue 3 + Element Plus):

  1. 视图层:采用类似甘特图或日历的视图展示。可以使用专门的库如FullCalendarV-Calendar,但为了更深度定制医院业务规则(如不同班次用不同颜色,鼠标悬停显示详细信息),本项目更可能采用Element PlusTable组件进行横纵二维渲染(横向为日期,纵向为科室或人员)。
  2. 状态管理:排班数据是典型的全局状态。虽然可以使用 Vuex 或 Pinia,但对于中型系统,合理组织的 Composables(组合式函数)配合 Provide/Inject 可能更轻量、更灵活。例如,创建一个useScheduleStore的 composable,内部管理当前的排班数据、选中的人员、视图模式等状态,并提供loadScheduleswapShiftpublishSchedule等方法。
  3. 交互逻辑:核心是“拖拽排班”和“批量操作”。实现拖拽时,要特别注意业务规则校验。例如,一个医生在同一天不能同时被排门诊和手术(除非有特殊说明),夜班后必须有足够的休息时间。这些规则校验函数应放在后端的服务层,但前端也需要进行实时预校验以提升用户体验。可以使用一个validateScheduleRule(scheduleData)函数,在拖拽结束时立即调用,给出友好提示。

后端实现要点(Spring Boot 3):

  1. 接口设计:RESTful 风格是关键。
    • GET /api/schedules: 获取排班列表,支持复杂查询(按科室、日期范围、人员、班次类型过滤)。
    • POST /api/schedules/batch: 批量创建或更新排班。这是排班的核心接口,接收一个排班对象的数组。
    • PUT /api/schedules/{id}: 调整单个排班。
    • GET /api/schedules/rules: 获取当前医院的排班规则(如最小休息时长、最大连续夜班数),用于前端校验和后端最终校验。
  2. 服务层逻辑:在ScheduleService.batchCreateSchedules(List<ScheduleDTO> dtos)方法中,必须包含以下步骤:
    • 事务管理:使用@Transactional注解,确保批量操作要么全部成功,要么全部回滚。
    • 并发检查:医院排班常涉及多人协作。可以使用乐观锁机制,在schedule表中增加一个version字段,或在更新时校验数据的“更新时间戳”,防止多人同时修改导致的数据覆盖。
    • 规则引擎:将排班规则(业务规则)抽象出来。可以创建一个ScheduleRuleEngine类,里面包含checkRestTimeRulecheckShiftConflictRule等方法。服务层在保存数据前,调用规则引擎进行校验,不通过则抛出明确的业务异常(如RestTimeNotEnoughException)。
  3. 数据持久化:使用 MyBatis-Plus 或 Spring Data JPA。对于复杂的关联查询(如查询某科室某月所有医生的排班及其个人信息),要善于使用@TableField注解或@EntityGraph来优化,避免 N+1 查询问题。

3.2 绩效与薪酬核算模块

医院的绩效核算极其复杂,通常与科室收入、成本、工作量(如门诊人次、手术台次)、医疗质量、患者满意度等多维度挂钩。

核心计算模型:系统需要定义一个灵活的绩效核算公式引擎。例如,一个外科医生的月度绩效可能 = (基础绩效点数 + 手术台次 × 点数系数 + 药占比控制奖励 - 病历扣罚点数) × 点单价。在数据库中,这个公式可以被配置化存储。

表结构设计思路:

  • performance_template:绩效模板表,定义核算周期(月/季/年)、适用科室/人员类型。
  • performance_item:绩效项目表,如“门诊工作量”、“手术台次”、“病历质量扣罚”。每个项目有自己的计算规则(SQL片段或脚本引用)和权重
  • performance_record:绩效记录表,存储每个员工在每个周期的每一项得分和最终汇总结果。
  • salary_record:薪酬记录表,关联绩效记录,并结合基本工资、津贴、扣款等,计算出应发工资。

后端实现策略:

  1. 定时任务:使用 Spring 的@Scheduled注解或更强大的 Quartz Scheduler,在每月初自动触发绩效核算任务。
  2. 公式解析与计算:不建议将复杂的计算公式硬编码在 Java 代码里。可以考虑引入轻量级的脚本引擎,如AviatorScriptJanino,将公式作为可配置的字符串存储。服务层从数据库读取公式和原始数据(如从HIS系统接口获取的门诊量),通过脚本引擎动态计算。这样,当医院绩效政策调整时,管理员可以在后台修改公式,而无需重新发布代码。
  3. 大数据量处理:全院医护人员可能上千,计算历史数据可能达百万级。核算任务必须是异步的。可以将核算请求放入消息队列(如 RabbitMQ、RocketMQ),由专门的消费者进行后台计算。计算过程中,前端可以通过 WebSocket 或轮询一个任务状态接口,向用户反馈进度。

3.3 系统权限与数据安全设计

医院HR数据高度敏感,权限控制必须做到细粒度。

基于角色的访问控制(RBAC)与数据权限结合:

  1. 角色权限(RBAC):定义角色如系统管理员人力资源主任科室主任普通员工。每个角色关联一组菜单权限和操作权限(如“增删改查排班”、“查看全院绩效”、“查看本科室工资”)。
  2. 数据权限:这是关键。例如,一个“内科主任”角色,在拥有“查看员工档案”操作权限的基础上,其数据权限应被限制为“只能查看内科所属的员工”。这在 Spring Security 中可以通过自定义PermissionEvaluator或在业务方法上使用注解(如@PreAuthorize(“hasDept(#deptId)”))来实现。在 SQL 查询层面,需要在WHERE条件中动态追加数据过滤条件(如AND department_id IN (用户可管理的科室ID列表))。

审计日志:所有对敏感数据的操作(增、删、改),尤其是薪资、绩效、人事变动(入职、离职、调岗),都必须记录完整的审计日志。日志表应包含操作人、操作时间、操作类型、操作的数据ID、数据变更前后的快照(JSON格式存储)等。这不仅是安全要求,在出现争议时也是重要的追溯依据。

4. 项目搭建与核心代码实操

假设你已经拿到了源码包医院人力资源管理系统源码.zip,我们来看看如何让它跑起来,并理解其中的关键代码。

4.1 环境准备与项目启动

后端 (Spring Boot 3) 启动步骤:

  1. 解压与导入:解压源码包,使用 IntelliJ IDEA 或 Eclipse 打开后端项目文件夹(通常包含pom.xmlbuild.gradle的目录)。
  2. 配置数据库:在src/main/resources/application.ymlapplication.properties中,找到数据库配置部分。你需要修改urlusernamepassword以指向你自己的 MySQL 实例。通常源码会附带一个sql文件夹,里面有数据库初始化脚本,按顺序执行它们来创建表和初始化基础数据(如菜单、角色)。
  3. 检查依赖与配置:确保 Maven 或 Gradle 能正常下载依赖。检查是否有其他外部服务配置,比如 Redis(用于缓存或Session存储)、邮件服务器等,并根据你的环境进行相应配置或注释掉(如果是演示)。
  4. 启动应用:找到主启动类(通常名为*Application,带有@SpringBootApplication注解),直接运行它的main方法。观察控制台日志,确保没有报错,并看到类似 “Started Application in X seconds” 的信息。

前端 (Vue 3) 启动步骤:

  1. 进入目录:使用 VS Code 或 WebStorm 打开前端项目文件夹(通常包含package.jsonvite.config.js的目录)。
  2. 安装依赖:在终端中执行npm installyarnpnpm install(取决于项目使用的包管理器)。
  3. 配置API代理:开发环境下,前端需要调用后端API。在vite.config.js或单独的代理配置文件中,需要设置代理,将/api前缀的请求转发到后端服务器地址(如http://localhost:8080)。这是解决跨域问题的常用方式。
    // vite.config.js 示例 export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } })
  4. 启动开发服务器:运行npm run dev。控制台会输出本地访问地址,通常是http://localhost:5173。用浏览器打开它。

4.2 关键代码片段解析

后端:JWT认证过滤器核心逻辑

@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtTokenProvider tokenProvider; // 自定义的Token工具类 @Autowired private UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { // 1. 从请求头中提取JWT String jwt = getJwtFromRequest(request); if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { // 2. 从JWT中解析出用户名 String username = tokenProvider.getUsernameFromJWT(jwt); // 3. 从数据库加载用户详细信息(包含权限) UserDetails userDetails = userDetailsService.loadUserByUsername(username); // 4. 构建Authentication对象并设置到Security上下文中 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception ex) { logger.error("无法设置用户认证上下文", ex); } // 5. 继续执行后续过滤器链 filterChain.doFilter(request, response); } private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }

这段代码是系统安全的门户。它拦截每一个请求,检查是否携带了合法的JWT令牌。如果合法,就根据令牌中的用户名从数据库加载用户信息和权限,并存入SecurityContextHolder。这样,在后续的控制器 (Controller) 中,你就可以通过@AuthenticationPrincipal注解轻松获取当前登录用户的信息。

前端:使用Composition API封装排班相关逻辑

<script setup> import { ref, computed, onMounted } from 'vue'; import { useScheduleStore } from '@/stores/schedule'; import { ElMessage, ElMessageBox } from 'element-plus'; const scheduleStore = useScheduleStore(); const currentDeptId = ref(null); const scheduleData = computed(() => scheduleStore.getScheduleByDept(currentDeptId.value)); // 加载排班数据 const loadSchedule = async (month) => { try { await scheduleStore.fetchDepartmentSchedule({ departmentId: currentDeptId.value, month: month }); } catch (error) { ElMessage.error(`加载排班失败: ${error.message}`); } }; // 拖拽调整排班 const handleDrop = async (event, targetDate, targetShift) => { const staffId = event.dataTransfer.getData('staffId'); const originalScheduleId = event.dataTransfer.getData('scheduleId'); try { // 调用Store中的action来更新数据 await scheduleStore.swapSchedule({ staffId, targetDate, targetShift, originalScheduleId }); ElMessage.success('排班调整成功'); } catch (error) { // 这里捕获的可能是前端预校验错误,也可能是后端API返回的业务错误 ElMessageBox.alert(`调整失败: ${error.message}`, '提示'); } }; // 初始化加载第一个科室的排班 onMounted(() => { if (someDeptList.value.length > 0) { currentDeptId.value = someDeptList.value[0].id; loadSchedule(currentMonth.value); } }); </script>

这个Vue 3<script setup>片段展示了如何将排班相关的数据、状态和方法组织在一起。useScheduleStore是一个 Pinia Store 或类似的状态管理单元,它集中管理了排班数据。computed属性根据当前选中的科室动态派生数据。所有的异步操作(fetchDepartmentSchedule,swapSchedule)和用户交互(handleDrop)都通过调用 Store 的方法来完成,保持了组件逻辑的简洁和清晰。错误处理也统一在组件层面进行,提供了良好的用户反馈。

5. 部署上线与性能调优要点

当开发调试完成,准备将系统部署到医院的生产环境时,有几个关键点需要特别注意。

5.1 前后端部署策略

后端部署:

  1. 打包:使用mvn clean package -DskipTests生成可执行的 JAR 文件(Spring Boot 内置了 Tomcat 等 Servlet 容器)。
  2. 环境配置:生产环境的数据库密码、Redis地址、邮件服务器密钥等敏感信息,绝对不能写在application.yml里提交到代码库。应该使用外部化配置:
    • 方案A(推荐):使用application-prod.yml文件,并通过启动参数--spring.profiles.active=prod激活。将此文件放在服务器上,与代码分离。
    • 方案B:使用环境变量。在服务器的启动脚本中设置JAVA_OPTS,如-Dspring.datasource.password=${DB_PASSWORD}
    • 方案C:使用配置中心,如 Spring Cloud Config、Nacos、Apollo,这在微服务架构中更常见。
  3. 进程管理:使用systemdSupervisor来管理 Spring Boot 应用进程,实现开机自启、故障自动重启、日志轮转等。一个简单的systemd服务单元文件示例:
    [Unit] Description=Hospital HRM Backend Service After=network.target [Service] Type=simple User=appuser ExecStart=/usr/bin/java -jar /opt/hrm-backend/app.jar --spring.profiles.active=prod Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target

前端部署:

  1. 构建:运行npm run build,这会在dist目录下生成优化后的静态文件(HTML, JS, CSS)。
  2. Web服务器配置:将dist目录下的所有文件上传到 Nginx 或 Apache 的网站根目录。关键是要配置路由重写,因为 Vue 是 SPA。
    # Nginx 配置示例 server { listen 80; server_name hrm.your-hospital.com; root /var/www/hrm-frontend/dist; index index.html; location / { try_files $uri $uri/ /index.html; # 支持前端路由 } location /api { proxy_pass http://localhost:8080; # 将API请求代理到后端 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
    这个配置将所有/api开头的请求转发给后端Spring Boot应用,其他所有请求都返回index.html,由前端路由接管。

5.2 数据库与缓存优化

数据库优化:

  1. 索引策略:排班表 (schedule) 的查询条件通常是department_idschedule_datestaff_id。为这些字段建立复合索引能极大提升查询效率。例如:INDEX idx_dept_date (department_id, schedule_date)
  2. 查询优化:避免在循环中查询数据库。例如,计算全院月度考勤汇总时,应使用一条聚合SQL语句完成,而不是为每个员工循环查询。
  3. 分库分表:对于超大型医院集团,当单表数据量超过千万级时,可以考虑按时间(如每年一张表)或按科室进行分表。

缓存策略:

  1. Redis应用
    • 会话缓存:将用户的登录会话信息(非敏感)存入Redis,比存在应用服务器内存更利于扩展。
    • 热点数据缓存:医院的组织架构、科室列表、基础字典(班次类型、职称等)变化不频繁,访问频繁,非常适合缓存。使用@Cacheable注解可以轻松实现。
    • 排班预览缓存:生成全院或科室的月度排班视图是一个相对耗时的查询。可以将其结果缓存起来,设置一个较短的过期时间(如5分钟),在排班正式发布前供快速预览。
  2. 缓存更新:当基础数据(如科室信息)被修改时,必须同步清理或更新对应的缓存。可以使用 Spring 的@CacheEvict注解。

5.3 安全加固 Checklist

在系统上线前,务必完成以下安全检查:

  • [ ]HTTPS:为生产环境域名配置有效的 SSL/TLS 证书,强制所有流量走 HTTPS。
  • [ ]密码策略:后端强制要求用户密码复杂度(大小写字母、数字、特殊字符组合,长度至少8位),并定期提醒更换。
  • [ ]SQL注入防护:坚持使用 MyBatis 的#{}预编译占位符,或 JPA 的参数化查询,绝对禁止字符串拼接 SQL。
  • [ ]XSS 防护:后端在输出用户提交的内容到 HTML 前,进行转义或过滤。Vue 和 React 等现代框架默认提供了一定的 XSS 防护,但对于富文本编辑器内容,仍需在后端进行安全处理(如使用 Jsoup 进行过滤)。
  • [ ]CSRF 防护:Spring Security 默认启用了 CSRF 防护。确保前端在发起状态修改请求(POST, PUT, DELETE)时,携带正确的 CSRF Token(通常由框架自动处理)。
  • [ ]接口限流与防刷:对登录、短信验证码等接口实施限流(如使用 Guava RateLimiter 或 Sentinel),防止暴力破解和短信轰炸。
  • [ ]文件上传安全:限制上传文件的类型、大小,并对文件进行病毒扫描。上传的文件不要存储在 Web 应用可执行的目录下,且通过独立的域名或路径提供访问,避免被恶意执行。

6. 常见问题排查与调试技巧

在实际开发和运维中,你肯定会遇到各种问题。这里记录几个典型场景和解决思路。

6.1 前端常见问题

问题1:Vue 3 组件更新了数据,但视图不刷新。

  • 可能原因:你直接修改了从 Pinia Store 或 Vuex 中获取的响应式对象的某个嵌套属性,但这种方式可能“逃脱”了 Vue 的响应式追踪。
  • 解决方案
    1. 对于Pinia:确保你是在 Store 的 action 中修改状态。或者,使用 Store 的$patch方法进行批量更新。
    2. 对于Vuex:通过commitmutation 来修改状态。
    3. 通用方法:对于对象或数组,采用返回新引用的方式。例如,scheduleList.value = [...scheduleList.value, newItem]obj.value = { ...obj.value, newKey: newValue }

问题2:Element Plus 表格或表单组件在动态数据下表现异常。

  • 可能原因:Element Plus 的某些组件(如ElTable在动态改变column时,ElForm在动态增减表单项时)需要唯一的key来正确触发其内部更新。
  • 解决方案:为动态生成的列表项或组件添加唯一的:key绑定。例如,在循环渲染ElTableColumn时,给每个 column 加上:key="column.prop"

问题3:开发环境跨域(CORS)问题。

  • 表现:前端控制台报错Access-Control-Allow-Origin
  • 解决方案
    1. 开发阶段:如前所述,使用 Vite 或 Webpack 的代理功能是最佳实践。
    2. 生产环境:确保后端 Spring Boot 应用正确配置了 CORS。可以在配置类中添加一个WebMvcConfigurerBean。
      @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") // 针对的路径 .allowedOriginPatterns("https://hrm.your-hospital.com") // 允许的前端域名,生产环境要写具体 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) // 如果前端请求带cookie,需要为true .maxAge(3600); } }

6.2 后端常见问题

问题1:Spring Boot 应用启动时报数据库连接失败。

  • 排查步骤
    1. 检查application.yml中的数据库连接字符串、用户名、密码是否正确。
    2. 确认数据库服务是否已启动(systemctl status mysql)。
    3. 检查服务器防火墙是否开放了数据库端口(默认3306)。
    4. 如果是云服务器,检查安全组规则。
    5. 尝试用命令行工具(如mysql -h host -u user -p)手动连接,验证网络和凭证。

问题2:MyBatis-Plus 查询结果映射不到实体类属性。

  • 可能原因:数据库字段名(下划线风格user_name)和实体类属性名(驼峰风格userName)没有正确映射。
  • 解决方案
    1. application.yml中开启 MyBatis-Plus 的驼峰映射配置:
      mybatis-plus: configuration: map-underscore-to-camel-case: true
    2. 或者在实体类字段上使用@TableField(value = “user_name”)注解显式指定映射。

问题3:事务(@Transactional)不生效。

  • 常见原因
    1. 方法不是public的。Spring AOP 代理默认只对 public 方法生效。
    2. 异常类型不对。默认只对RuntimeExceptionError回滚。如果方法抛出了Exception,需要在注解中指定@Transactional(rollbackFor = Exception.class)
    3. 在同一个类中,一个非事务方法调用了另一个事务方法。由于 Spring AOP 是基于代理的,这种自调用会绕过代理,导致事务失效。解决方法是注入自身的代理对象,或者将事务方法放到另一个 Service 中。

6.3 联调与部署问题

问题:前端能访问,但所有API请求都返回404或500。

  • 排查清单
    1. 网络连通性:在服务器上,用curl http://localhost:8080/api/health测试后端服务本身是否正常。
    2. Nginx代理配置:检查 Nginx 配置文件中location /apiproxy_pass地址是否正确,以及后端服务是否在监听该地址和端口。
    3. 后端上下文路径:检查 Spring Boot 的server.servlet.context-path配置。如果后端设置了context-path: /hrm-api,那么前端代理或请求的地址就需要是/hrm-api/xxx,而不是/api/xxx
    4. 防火墙与安全组:再次确认服务器和云平台的安全组规则,是否允许了前端服务器IP访问后端应用的端口。
    5. 查看日志:这是最直接的排错方式。分别查看前端浏览器开发者工具的网络(Network)和控制器(Console)标签页,以及后端应用的日志文件(通常在logs目录下或通过journalctl -u your-service-name查看),错误信息通常一目了然。

这个项目从技术栈选型到业务模块设计,再到部署上线,涵盖了一个现代Web应用开发的完整生命周期。最大的体会是,技术是为业务服务的。在开发类似医院HR系统这样业务逻辑极其复杂的系统时,前期花在领域建模和数据库设计上的时间,远比后期写代码的时间更重要。一个清晰、可扩展的数据模型,是应对未来业务频繁变更的基石。另外,在团队协作中,前后端定义清晰、稳定的API契约(可以使用Swagger/OpenAPI生成文档),并建立完善的错误处理和信息反馈机制,能极大提升开发效率和联调体验。最后,安全无小事,尤其是涉及大量个人敏感信息的系统,必须将安全思维贯穿于设计、开发、测试、部署的每一个环节。

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

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

STM32F103驱动HC-SR04超声波测距:从硬件原理到软件滤波的实战优化

简介&#xff1a;本资源是基于STM32F103RCT6微控制器与HC-SR04超声波传感器实现高精度实时测距的完整嵌入式项目&#xff0c;面向嵌入式初学者、课程设计学生及智能硬件开发者&#xff0c;解决非接触式距离检测在机器人避障、智能家居与自动化场景中的基础应用问题。压缩包共77…

作者头像 李华
网站建设 2026/9/4 14:37:22

基于vn.py的量化策略二次开发:机器学习选股与回测实战指南

简介&#xff1a;这是一套面向计算机及相关专业&#xff08;如人工智能、自动化、电子信息等&#xff09;在校学生与初学者的量化交易实战项目资源&#xff0c;基于vn.py框架深度二次开发&#xff0c;完整覆盖选股策略设计、多因子回测验证与机器学习模型集成三大核心环节&…

作者头像 李华
网站建设 2026/9/4 15:30:58

ESP32多功能手表DIY:从硬件选型到功耗优化的完整复刻指南

1. 先搞清楚这个“多功能手表”到底能做什么&#xff0c;以及复刻需要什么如果你对ESP32开发板感兴趣&#xff0c;并且想做一个能戴在手上、功能比普通电子表更丰富的玩意儿&#xff0c;那么这个“ESP32多功能手表”项目就值得一看。它本质上是一个基于ESP32芯片的DIY可穿戴设备…

作者头像 李华
网站建设 2026/9/2 9:54:05

多节点无线通信中差分放大转发技术性能仿真教程

在多节点无线通信中&#xff0c;中继协作是提升传输可靠性和覆盖范围的重要手段。放大转发&#xff08;Amplify-and-Forward, AF&#xff09;协议因为实现简单、时延低&#xff0c;成为协作通信中最常见的中继模式之一。但传统 AF 方案大多依赖信道状态信息&#xff08;Channel…

作者头像 李华
网站建设 2026/9/4 8:22:30

Tabby 自托管AI编程助手:私有化代码补全与代码问答的完整落地指南

Tabby 自托管AI编程助手:私有化代码补全与代码问答的完整落地指南 【免费下载链接】tabby Self-hosted AI coding assistant 项目地址: https://gitcode.com/GitHub_Trending/tab/tabby Tabby 是一款自托管的 AI 编程助手&#xff0c;用开源、可私有部署的方式替代 GitH…

作者头像 李华
网站建设 2026/9/3 15:39:46

SpringBoot图书馆管理系统实战:从架构设计到性能优化

简介&#xff1a;这是一套面向Java初学者与课程设计实践者的SpringBoot图书馆管理系统完整源码&#xff0c;适用于高校Java程序设计、Web开发或软件工程类课程实训项目。系统采用前后端分离架构&#xff0c;涵盖用户管理、图书借阅、库存统计、管理员后台及数据可视化等核心功能…

作者头像 李华