ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

Vue 3与Spring Boot 3构建医院HR系统:架构设计与核心模块实现 简介这是一套面向Java与前端开发者、高校计算机专业师生及医疗信息化项目实践者的医院人力资源管理系统完整源码聚焦解决医院人事部门在招聘、考勤、薪酬、绩效、培训与离职等多环节的数字化管理需求。资源采用Vue3SpringBoot3前后端分离架构包含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算是一个比较典型的现代化企业级应用案例。对于正在学习全栈开发尤其是对医疗行业信息化感兴趣的朋友来说这个项目源码就像一份“解剖样本”能让你清晰地看到从技术选型到业务落地的完整链路。这个系统本质上是一个为医院这类特殊组织量身定制的 HRMHuman Resource Management系统。它解决的不仅仅是传统企业里员工档案、考勤、薪资这些基础问题更要处理医院特有的复杂场景比如医护人员的排班涉及门诊、住院、手术、值班等多维度、职称与执业资格管理、科室绩效核算等。所以它不仅仅是技术的堆砌更是业务逻辑深度融入技术实现的典范。如果你手头正好有这个源码包或者想自己从头搭建一个类似系统接下来的内容会带你深入其肌理从设计思路到代码细节再到那些只有踩过坑才知道的实操要点希望能给你带来实实在在的参考价值。2. 技术栈选型与架构设计解析2.1 为什么是 Vue 3 Spring Boot 3看到这个技术组合很多人的第一反应可能是“流行”、“新”。但在这个项目里选择它们有更深层的考量而不仅仅是追新。前端 Vue 3 的考量医院人力资源系统的前端界面通常不会像电商那样有极其复杂的交互但数据展示的维度多、表单复杂如排班表、绩效核算表且对实时性有一定要求如消息通知、排班变更提示。Vue 3 的 Composition API 在这里发挥了巨大优势。它允许我们将与“医护人员排班”相关的所有逻辑如日期计算、规则校验、冲突检测封装在一个独立的useSchedule组合式函数里而不是像 Options API 那样分散在data、methods、computed各个选项中。这使得代码在应对医院复杂的排班规则时依然能保持极高的可读性和可维护性。另外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。这种分离带来了清晰的职责划分和灵活的部署能力。核心数据流设计认证与授权流用户在前端登录前端将凭证用户名/密码发送至后端/api/auth/login接口。后端通过 Spring Security 进行校验成功后生成一个 JWTJSON Web Token返回给前端。前端将此 Token 存储在 localStorage 或更安全的 HttpOnly Cookie 中并在后续所有 API 请求的Authorization头部携带。后端通过一个JwtAuthenticationFilter拦截请求验证 Token 的有效性和权限。业务数据流以前端加载“科室人员列表”为例。前端 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: 科室IDschedule_date: 排班日期shift_type: 班次类型如“早班”、“中班”、“夜班”、“行政班”、“休息”work_type: 工作类型如“门诊”、“病房”、“手术”、“听班”location: 具体地点如“门诊三楼外科诊室1”、“住院部12楼东区”前端实现要点Vue 3 Element Plus视图层采用类似甘特图或日历的视图展示。可以使用专门的库如FullCalendar或V-Calendar但为了更深度定制医院业务规则如不同班次用不同颜色鼠标悬停显示详细信息本项目更可能采用Element Plus的Table组件进行横纵二维渲染横向为日期纵向为科室或人员。状态管理排班数据是典型的全局状态。虽然可以使用 Vuex 或 Pinia但对于中型系统合理组织的 Composables组合式函数配合 Provide/Inject 可能更轻量、更灵活。例如创建一个useScheduleStore的 composable内部管理当前的排班数据、选中的人员、视图模式等状态并提供loadSchedule、swapShift、publishSchedule等方法。交互逻辑核心是“拖拽排班”和“批量操作”。实现拖拽时要特别注意业务规则校验。例如一个医生在同一天不能同时被排门诊和手术除非有特殊说明夜班后必须有足够的休息时间。这些规则校验函数应放在后端的服务层但前端也需要进行实时预校验以提升用户体验。可以使用一个validateScheduleRule(scheduleData)函数在拖拽结束时立即调用给出友好提示。后端实现要点Spring Boot 3接口设计RESTful 风格是关键。GET /api/schedules: 获取排班列表支持复杂查询按科室、日期范围、人员、班次类型过滤。POST /api/schedules/batch: 批量创建或更新排班。这是排班的核心接口接收一个排班对象的数组。PUT /api/schedules/{id}: 调整单个排班。GET /api/schedules/rules: 获取当前医院的排班规则如最小休息时长、最大连续夜班数用于前端校验和后端最终校验。服务层逻辑在ScheduleService.batchCreateSchedules(ListScheduleDTO dtos)方法中必须包含以下步骤事务管理使用Transactional注解确保批量操作要么全部成功要么全部回滚。并发检查医院排班常涉及多人协作。可以使用乐观锁机制在schedule表中增加一个version字段或在更新时校验数据的“更新时间戳”防止多人同时修改导致的数据覆盖。规则引擎将排班规则业务规则抽象出来。可以创建一个ScheduleRuleEngine类里面包含checkRestTimeRule、checkShiftConflictRule等方法。服务层在保存数据前调用规则引擎进行校验不通过则抛出明确的业务异常如RestTimeNotEnoughException。数据持久化使用 MyBatis-Plus 或 Spring Data JPA。对于复杂的关联查询如查询某科室某月所有医生的排班及其个人信息要善于使用TableField注解或EntityGraph来优化避免 N1 查询问题。3.2 绩效与薪酬核算模块医院的绩效核算极其复杂通常与科室收入、成本、工作量如门诊人次、手术台次、医疗质量、患者满意度等多维度挂钩。核心计算模型系统需要定义一个灵活的绩效核算公式引擎。例如一个外科医生的月度绩效可能 (基础绩效点数 手术台次 × 点数系数 药占比控制奖励 - 病历扣罚点数) × 点单价。在数据库中这个公式可以被配置化存储。表结构设计思路performance_template绩效模板表定义核算周期月/季/年、适用科室/人员类型。performance_item绩效项目表如“门诊工作量”、“手术台次”、“病历质量扣罚”。每个项目有自己的计算规则SQL片段或脚本引用和权重。performance_record绩效记录表存储每个员工在每个周期的每一项得分和最终汇总结果。salary_record薪酬记录表关联绩效记录并结合基本工资、津贴、扣款等计算出应发工资。后端实现策略定时任务使用 Spring 的Scheduled注解或更强大的 Quartz Scheduler在每月初自动触发绩效核算任务。公式解析与计算不建议将复杂的计算公式硬编码在 Java 代码里。可以考虑引入轻量级的脚本引擎如AviatorScript或Janino将公式作为可配置的字符串存储。服务层从数据库读取公式和原始数据如从HIS系统接口获取的门诊量通过脚本引擎动态计算。这样当医院绩效政策调整时管理员可以在后台修改公式而无需重新发布代码。大数据量处理全院医护人员可能上千计算历史数据可能达百万级。核算任务必须是异步的。可以将核算请求放入消息队列如 RabbitMQ、RocketMQ由专门的消费者进行后台计算。计算过程中前端可以通过 WebSocket 或轮询一个任务状态接口向用户反馈进度。3.3 系统权限与数据安全设计医院HR数据高度敏感权限控制必须做到细粒度。基于角色的访问控制RBAC与数据权限结合角色权限RBAC定义角色如系统管理员、人力资源主任、科室主任、普通员工。每个角色关联一组菜单权限和操作权限如“增删改查排班”、“查看全院绩效”、“查看本科室工资”。数据权限这是关键。例如一个“内科主任”角色在拥有“查看员工档案”操作权限的基础上其数据权限应被限制为“只能查看内科所属的员工”。这在 Spring Security 中可以通过自定义PermissionEvaluator或在业务方法上使用注解如PreAuthorize(“hasDept(#deptId)”)来实现。在 SQL 查询层面需要在WHERE条件中动态追加数据过滤条件如AND department_id IN (用户可管理的科室ID列表)。审计日志所有对敏感数据的操作增、删、改尤其是薪资、绩效、人事变动入职、离职、调岗都必须记录完整的审计日志。日志表应包含操作人、操作时间、操作类型、操作的数据ID、数据变更前后的快照JSON格式存储等。这不仅是安全要求在出现争议时也是重要的追溯依据。4. 项目搭建与核心代码实操假设你已经拿到了源码包医院人力资源管理系统源码.zip我们来看看如何让它跑起来并理解其中的关键代码。4.1 环境准备与项目启动后端 (Spring Boot 3) 启动步骤解压与导入解压源码包使用 IntelliJ IDEA 或 Eclipse 打开后端项目文件夹通常包含pom.xml或build.gradle的目录。配置数据库在src/main/resources/application.yml或application.properties中找到数据库配置部分。你需要修改url、username、password以指向你自己的 MySQL 实例。通常源码会附带一个sql文件夹里面有数据库初始化脚本按顺序执行它们来创建表和初始化基础数据如菜单、角色。检查依赖与配置确保 Maven 或 Gradle 能正常下载依赖。检查是否有其他外部服务配置比如 Redis用于缓存或Session存储、邮件服务器等并根据你的环境进行相应配置或注释掉如果是演示。启动应用找到主启动类通常名为*Application带有SpringBootApplication注解直接运行它的main方法。观察控制台日志确保没有报错并看到类似 “Started Application in X seconds” 的信息。前端 (Vue 3) 启动步骤进入目录使用 VS Code 或 WebStorm 打开前端项目文件夹通常包含package.json和vite.config.js的目录。安装依赖在终端中执行npm install或yarn或pnpm install取决于项目使用的包管理器。配置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/, ) } } } })启动开发服务器运行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 3script setup片段展示了如何将排班相关的数据、状态和方法组织在一起。useScheduleStore是一个 Pinia Store 或类似的状态管理单元它集中管理了排班数据。computed属性根据当前选中的科室动态派生数据。所有的异步操作fetchDepartmentSchedule,swapSchedule和用户交互handleDrop都通过调用 Store 的方法来完成保持了组件逻辑的简洁和清晰。错误处理也统一在组件层面进行提供了良好的用户反馈。5. 部署上线与性能调优要点当开发调试完成准备将系统部署到医院的生产环境时有几个关键点需要特别注意。5.1 前后端部署策略后端部署打包使用mvn clean package -DskipTests生成可执行的 JAR 文件Spring Boot 内置了 Tomcat 等 Servlet 容器。环境配置生产环境的数据库密码、Redis地址、邮件服务器密钥等敏感信息绝对不能写在application.yml里提交到代码库。应该使用外部化配置方案A推荐使用application-prod.yml文件并通过启动参数--spring.profiles.activeprod激活。将此文件放在服务器上与代码分离。方案B使用环境变量。在服务器的启动脚本中设置JAVA_OPTS如-Dspring.datasource.password${DB_PASSWORD}。方案C使用配置中心如 Spring Cloud Config、Nacos、Apollo这在微服务架构中更常见。进程管理使用systemd或Supervisor来管理 Spring Boot 应用进程实现开机自启、故障自动重启、日志轮转等。一个简单的systemd服务单元文件示例[Unit] DescriptionHospital HRM Backend Service Afternetwork.target [Service] Typesimple Userappuser ExecStart/usr/bin/java -jar /opt/hrm-backend/app.jar --spring.profiles.activeprod Restarton-failure RestartSec10 [Install] WantedBymulti-user.target前端部署构建运行npm run build这会在dist目录下生成优化后的静态文件HTML, JS, CSS。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 数据库与缓存优化数据库优化索引策略排班表 (schedule) 的查询条件通常是department_id、schedule_date、staff_id。为这些字段建立复合索引能极大提升查询效率。例如INDEX idx_dept_date (department_id, schedule_date)。查询优化避免在循环中查询数据库。例如计算全院月度考勤汇总时应使用一条聚合SQL语句完成而不是为每个员工循环查询。分库分表对于超大型医院集团当单表数据量超过千万级时可以考虑按时间如每年一张表或按科室进行分表。缓存策略Redis应用会话缓存将用户的登录会话信息非敏感存入Redis比存在应用服务器内存更利于扩展。热点数据缓存医院的组织架构、科室列表、基础字典班次类型、职称等变化不频繁访问频繁非常适合缓存。使用Cacheable注解可以轻松实现。排班预览缓存生成全院或科室的月度排班视图是一个相对耗时的查询。可以将其结果缓存起来设置一个较短的过期时间如5分钟在排班正式发布前供快速预览。缓存更新当基础数据如科室信息被修改时必须同步清理或更新对应的缓存。可以使用 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 前端常见问题问题1Vue 3 组件更新了数据但视图不刷新。可能原因你直接修改了从 Pinia Store 或 Vuex 中获取的响应式对象的某个嵌套属性但这种方式可能“逃脱”了 Vue 的响应式追踪。解决方案对于Pinia确保你是在 Store 的 action 中修改状态。或者使用 Store 的$patch方法进行批量更新。对于Vuex通过commitmutation 来修改状态。通用方法对于对象或数组采用返回新引用的方式。例如scheduleList.value [...scheduleList.value, newItem]或obj.value { ...obj.value, newKey: newValue }。问题2Element Plus 表格或表单组件在动态数据下表现异常。可能原因Element Plus 的某些组件如ElTable在动态改变column时ElForm在动态增减表单项时需要唯一的key来正确触发其内部更新。解决方案为动态生成的列表项或组件添加唯一的:key绑定。例如在循环渲染ElTableColumn时给每个 column 加上:keycolumn.prop。问题3开发环境跨域CORS问题。表现前端控制台报错Access-Control-Allow-Origin。解决方案开发阶段如前所述使用 Vite 或 Webpack 的代理功能是最佳实践。生产环境确保后端 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 后端常见问题问题1Spring Boot 应用启动时报数据库连接失败。排查步骤检查application.yml中的数据库连接字符串、用户名、密码是否正确。确认数据库服务是否已启动systemctl status mysql。检查服务器防火墙是否开放了数据库端口默认3306。如果是云服务器检查安全组规则。尝试用命令行工具如mysql -h host -u user -p手动连接验证网络和凭证。问题2MyBatis-Plus 查询结果映射不到实体类属性。可能原因数据库字段名下划线风格user_name和实体类属性名驼峰风格userName没有正确映射。解决方案在application.yml中开启 MyBatis-Plus 的驼峰映射配置mybatis-plus: configuration: map-underscore-to-camel-case: true或者在实体类字段上使用TableField(value “user_name”)注解显式指定映射。问题3事务Transactional不生效。常见原因方法不是public的。Spring AOP 代理默认只对 public 方法生效。异常类型不对。默认只对RuntimeException和Error回滚。如果方法抛出了Exception需要在注解中指定Transactional(rollbackFor Exception.class)。在同一个类中一个非事务方法调用了另一个事务方法。由于 Spring AOP 是基于代理的这种自调用会绕过代理导致事务失效。解决方法是注入自身的代理对象或者将事务方法放到另一个 Service 中。6.3 联调与部署问题问题前端能访问但所有API请求都返回404或500。排查清单网络连通性在服务器上用curl http://localhost:8080/api/health测试后端服务本身是否正常。Nginx代理配置检查 Nginx 配置文件中location /api的proxy_pass地址是否正确以及后端服务是否在监听该地址和端口。后端上下文路径检查 Spring Boot 的server.servlet.context-path配置。如果后端设置了context-path: /hrm-api那么前端代理或请求的地址就需要是/hrm-api/xxx而不是/api/xxx。防火墙与安全组再次确认服务器和云平台的安全组规则是否允许了前端服务器IP访问后端应用的端口。查看日志这是最直接的排错方式。分别查看前端浏览器开发者工具的网络Network和控制器Console标签页以及后端应用的日志文件通常在logs目录下或通过journalctl -u your-service-name查看错误信息通常一目了然。这个项目从技术栈选型到业务模块设计再到部署上线涵盖了一个现代Web应用开发的完整生命周期。最大的体会是技术是为业务服务的。在开发类似医院HR系统这样业务逻辑极其复杂的系统时前期花在领域建模和数据库设计上的时间远比后期写代码的时间更重要。一个清晰、可扩展的数据模型是应对未来业务频繁变更的基石。另外在团队协作中前后端定义清晰、稳定的API契约可以使用Swagger/OpenAPI生成文档并建立完善的错误处理和信息反馈机制能极大提升开发效率和联调体验。最后安全无小事尤其是涉及大量个人敏感信息的系统必须将安全思维贯穿于设计、开发、测试、部署的每一个环节。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进