news 2026/10/21 15:24:16

Java电子病历管理系统源码实战:SSM部署、数据表拆解与事务改造

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java电子病历管理系统源码实战:SSM部署、数据表拆解与事务改造

简介:这是一套基于SpringBoot并整合SSM架构的医院病人电子病历管理系统Java Web源码,前端采用Vue与ElementUI,数据库使用MySQL5.7+,主要面向Java学习者和毕业设计、课程设计人群,帮助其快速掌握企业级Web管理系统的开发与部署流程。系统涵盖首页、医院公告、科室信息、出诊信息及后台管理模块,前后端数据交互完整,可作为同类医疗管理项目的参考基底。压缩包共1437个文件,以Java源码、JSP页面、JavaScript脚本、CSS样式、XML配置为主,同时包含SQL脚本、Word/PPT说明材料及大量前端图片素材,整体大小24.22MB,目录结构清晰,便于逐层阅读与二次开发。目前已有409人学习使用,适合需要一套可直接运行并附带说明文档的SpringBoot实战项目来提升开发能力的读者。

1. 医院病人电子病历管理系统:三个问题先想清楚再下载源码

“java-医院病人电子病历管理系统源码”这类项目,在所有 java 课程设计案例源码里出现频率极高,形态也很统一:一个基于 JSP/Servlet 或 SSM(Spring + SpringMVC + MyBatis)的 Web 应用,覆盖病人档案、门诊病历、处方录入、用户登录这几条核心链路,附数据库脚本和一份说明材料。很多 java 工程师第一次接触企业级 Web 项目就是从这里开始的,但能真正跑通并讲清楚的人不多。这篇内容不打算复述某个作者的原稿,而是把这类源码通用的拆解、部署、改坑路径说清楚——你拿到手之后,第一步不是看代码,而是先回答三个问题:技术栈是哪种、数据库怎么初始化、登录和病历这条主链路断在哪。回答完这三个问题,这套源码离“能跑”和“能讲”就不远了。适合正在做课程设计、准备毕业答辩,或者想把老项目改造成面试作品的人。

2. 拆源码先拆数据模型:电子病历系统的模块边界与四张核心表

2.1 拿到源码包先看顶层目录:技术栈从结构里一眼分辨

老项目不像 Spring Boot 那样有一个启动类可以点一下就跑,你得先花五分钟判断它属于哪一代技术栈。我一般会先解压源码,看一眼顶层目录和构建文件,判断它到底是 war 包结构还是 Maven 工程。

# 解压源码后,先看顶层有哪些目录,并确认是否存在 Maven 构建文件 find . -maxdepth 2 -type d | sort # 检查 pom.xml 是否存在,存在就说明是 Maven 工程 ls -la pom.xml build.gradle 2>/dev/null # 检查是否带 src/main/webapp,这是 JSP/Servlet 或 SSM 项目的特征 ls -l src/main/webapp/WEB-INF/web.xml 2>/dev/null

第一条命令把目录层级列出来,最多两层就够了,主要看有没有 src/main/java、src/main/resources、src/main/webapp 这样的标准结构;第二条命令确认有没有 Maven 配置文件;第三条命令看 web.xml 是否还在。老式 JSP+Servlet 项目经常没有 src/main 目录,而是直接把 .java 放在 src 下、jsp 放在 WebRoot 里;SSM 项目基本都有完整的 Maven 目录和 web.xml;如果一个项目里有启动类、有 application.yml,那就是 Spring Boot。拿到源码后先跑这三条命令,能避免你按错误的方式去配置环境,白折腾半小时。

2.2 三种技术栈快辨:JSP+Servlet、SSM、Spring Boot 的分辨表

确认技术栈是后续一切操作的前提。以我接过的电子病历类项目看,绝大多数是 SSM 结构,其次是 JSP+Servlet,少部分是 Spring Boot。分辨方式其实就围绕三个点:有没有 Spring 的 XML 配置、有没有 Mapper 接口和 XML、有没有启动类。

技术栈判断点配置在哪部署方式
JSP + Servlet只有 .java 和 .jsp,无 pom.xml,无 Spring XMLweb.xml 里配 servlet-mapping打 war 放进 Tomcat webapps
SSM(Spring+SpringMVC+MyBatis)有 pom.xml、applicationContext.xml、mapper 接口与 mapper.xmlresources 下的 spring-*.xmlMaven 打包 war,Tomcat 部署
Spring Boot有启动类、application.yml / application.properties单配置文件,无需 web.xmljava -jar 或 mvn spring-boot:run

判断口诀很简单:看到 XML 堆在 resources 里,十有八九是 SSM;看到 Java 类直接继承 HttpServlet,是原生的 Servlet;看到启动类,才是 Spring Boot。这套判断方法不只适用于电子病历项目,任何 java Web 源码都能这么开局。值得注意的是,如果源码包里的说明材料里写“JDK 1.8 + Tomcat 8 运行”,那一般就是 Servlet 或 SSM 老项目,别非要用 Spring Boot 的思维去理解它。

2.3 核心表拆解:病人、病历、处方、用户四张表怎么关联

电子病历系统的业务主链路是:用户登录 → 选择/登记病人 → 医生录入病历 → 开处方 → 查询归档。这条链路落到数据库里,通常就是四张核心表。下面是这四张表的典型职责和关键字段,你可以拿它和手头源码里的 SQL 脚本对照:

表名业务角色关键字段关联关系
sys_user医生/护士/管理员登录账号id、username、password、role、real_name医生在病历表和处方表里作为操作人
patient病人基本信息id、name、gender、birth_date、phone病历表通过 patient_id 指向它
medical_record门诊/住院病历主表id、patient_id、doctor_id、visit_date、diagnosis、status一条病人可有多条病历
prescription处方明细id、record_id、drug_name、dosage、quantity一张病历对应多条处方

这四张表基本决定了一个电子病历系统的完整度。新手最容易忽略的是 medical_record 表里的 status 字段,它表示病历是“暂存”还是“已提交”。很多源码里这个字段默认是 0,录入时如果没有显式赋值,查询列表就可能什么都查不到。另一个容易看走眼的地方是外键:老项目为了省事很少建物理外键,表之间的关系全靠 Java 代码里的查询条件维持,一旦有人删了病人没删病历,数据就变成孤儿记录。这个坑知道的人不少,主动处理的人不多。

2.4 实体类与建表 SQL:让 MyBatis 映射不报错的几条约定

拿到数据库脚本之后,先别急着跑代码,先把建表 SQL 和实体类对照一遍。SSM 项目里最常翻车的不是 SQL 语法,而是 MyBatis 的映射规则:数据库字段是下划线风格(比如 patient_id),Java 实体类属性是驼峰风格(这样写 patientId)。如果你的 mybatis-config.xml 里没开驼峰映射,查询结果里 patientId 永远为 null。

<settings> <!-- 开启自动驼峰命名规则映射,数据库 patient_id 才能映射到实体类 patientId --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

这个配置在 MyBatis 全局配置文件或 Spring 整合配置里都能看到。开了之后,你还要注意实体类的属性名和表字段要按约定对应,比如主键字段叫 id,逻辑删除字段叫 deleted,创建时间叫 create_time。很多源码的说明材料里会有一句“请先导入 database/emr.sql”,这个脚本里一般兼着建库、建表和初始账号数据三件事。

以病历主表为例,常见建表语句是下面这个样子:

CREATE TABLE medical_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '病历主键', patient_id BIGINT NOT NULL COMMENT '病人ID', doctor_id BIGINT NOT NULL COMMENT '接诊医生ID', visit_date DATETIME NOT NULL COMMENT '就诊时间', chief_complaint VARCHAR(500) COMMENT '主诉', present_illness TEXT COMMENT '现病史', diagnosis TEXT COMMENT '诊断意见', status TINYINT DEFAULT 0 COMMENT '0暂存 1已提交' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门诊病历表';

这里四个字段值得注意:visit_date 用 DATETIME 不用 TIMESTAMP,是为了避开时区换算的老问题;chief_complaint 定 500 个字符,是给主诉留的合理空间,太少不够填;status 默认 0 意味着新插入的记录是“暂存”状态,后面查询列表时要记得加条件;ENGINE 和 CHARSET 必须显式指定,不然在部分 MySQL 默认配置下建出来的是 MyISAM,事务和行级锁都没有。如果你拿到手的源码是 MyBatis Plus 版本,还会遇到“根据实体类生成建表 SQL”这类工具操作——但我建议你把它当成草稿参考,重点还是改这份手工 DDL,保证字段注释和业务对齐。

3. 本地跑通最小闭环:JDK、MySQL、Tomcat 三步启动源码

3.1 环境版本清单:为什么是 JDK 1.8 + MySQL 5.7 + Tomcat 8.5

很多人在环境配置上翻车,不是不会装,而是版本组合不对。电子病历系统这类老 Java Web 项目,最稳的组合是老三样:JDK 1.8、MySQL 5.7、Tomcat 8.5。它们不是最新的,却是兼容面最宽的。JDK 11 以上对老 SSM 项目的 CGLIB 代理和 JSP 编译偶尔会出问题;MySQL 8.0 的驱动类名改了,如果源码里的 jdbc.properties 还写着 com.mysql.jdbc.Driver,连数据库这一步就会直接报错。

组件推荐版本说明
JDK1.8老项目编译和运行最稳,IDEA 里把 Project SDK 指到 1.8
MySQL5.7驱动用 com.mysql.jdbc.Driver,不需要 serverTimezone 参数也能容忍
Tomcat8.5支持 Servlet 3.1,SSM 和 JSP 项目都能良好运行
Maven3.6.x解析老项目依赖足够,不要用太新的版本

如果项目说明材料里明确写的是 Spring Boot,那 MySQL 8.0 + 驱动 com.mysql.cj.jdbc.Driver 也是常见组合,区别只在配置文件。判断依据还是第 2 章的结论:SSM/老项目用 5.7,Spring Boot 新工程用 8.0 没毛病。安装顺手程度排序:先装 JDK 配 JAVA_HOME,再装 MySQL 并记住 root 密码,最后解压 Tomcat 就好,Windows 和 macOS 都建议直接用 IDEA 里的 Tomcat 集成,少踩环境变量路径的坑。

3.2 初始化数据库:执行 sql 脚本与修改连接配置

跑通源码前一定要先把数据库准备好,不然一启动就报 NullPointerException 之类的问题,排查起来方向都是错的。常见做法是先用客户端连接到 MySQL,手工建一个库,再把源码里的 sql 脚本导进去,最后改 jdbc.properties 里的账号密码。

# 1. 登录 MySQL 控制台,创建电子病历系统使用的数据库 mysql -uroot -p # 2. 在 mysql> 提示符下执行建库语句,字符集用 utf8mb4 CREATE DATABASE IF NOT EXISTS emr DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 3. 退出后用命令行导入 sql 脚本,路径换成你自己解压后的实际路径 mysql -uroot -p123456 emr < D:/emr/sql/emr.sql

这里的关键点是建库时就把字符集钉死在 utf8mb4,而不是用 MySQL 默认的 latin1,否则后面 JSP 页面显示中文全是问号。导入脚本后,用show tables;确认四张核心表都建出来了,再手工查一下 sys_user 表里有没有初始账号。

接下来改连接配置,SSM 项目通常在 resources 下的 jdbc.properties 里:

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/emr?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false jdbc.username=root jdbc.password=123456

driver 这一行,MySQL 5.7 用 com.mysql.jdbc.Driver,MySQL 8.0 要改成 com.mysql.cj.jdbc.Driver,两个类名只差一个 c,复制错了必报 ClassNotFoundException。URL 里的 characterEncoding 参数负责告诉驱动“往数据库写数据时用 UTF-8 编码”,serverTimezone 是给 MySQL 8.0 用的,MySQL 5.7 也能兼容。username 和 password 要改成你自己的,别用源码自带的那组——很多源码的默认密码是 root,如果跟你的环境不一致,连数据库这一步就过不去。

3.3 用命令行和 IDEA 两种方式部署:跑出登录页才算赢

数据库就绪后,部署到 Tomcat 有两条路径。想快速验证项目能不能跑,直接用命令行 Maven 打 war 包丢进 Tomcat webapps;想改代码调试,建议在 IDEA 里配置 Tomcat。两条路都走一遍,你对项目的理解会更完整。

# 项目根目录下执行,跳过测试并打 war 包 mvn clean package -DskipTests # 把打出的 war 复制到 Tomcat 的 webapps 目录,文件名决定访问路径 cp target/emr.war $CATALINA_HOME/webapps/ # 执行启动脚本(Windows 用户用 startup.bat) $CATALINA_HOME/bin/startup.sh

启动日志看到Deployment of web application archive [emr.war] has finished后,访问http://localhost:8080/emr/login.jsp,能看到登录页,说明部署成功。如果没有显示登录页而是 404,最常见原因是上下文路径不对。Tomcat 会以 war 文件名作为上下文路径,比如 emr.war 就是/emr。如果你访问的是http://localhost:8080/login.jsp,那必然 404。

IDEA 里部署的步骤也顺一下:File → Project Structure → Artifacts,先把 Web Application Archive 的配置改成 war exploded,再到 Run/Debug Configurations 里新增 Tomcat Server Local,Deployment 选项卡里把 artifact 加进去,Application context 填/emr,启动后 IDEA 会自动弹出浏览器。这套操作看起来繁琐,但只配一次,后续调试按个 Shift+F10 就能热更新页面,比手工复制 war 包省事得多。

3.4 登录入口验证:管理员、医生、护士三条权限路径

部署成功后,先用初始账号登录一次,确认账号角色和权限结构。老源码的 sys_user 表里通常预置了三个账号:管理员 admin、医生 doctor、护士 nurse,初始密码一般和账号同名或干脆是 123456,经过 MD5 后存进数据库。你可以在表里直接查:

SELECT user_id, username, role, real_name FROM sys_user;

查出来的 role 字段决定了登录后的页面入口。常见设计是:admin 进系统管理页,管理医生账号和字典数据;doctor 进工作台,能看病人列表、写病历、开处方;nurse 只做挂号登记和查询病历。这些权限多半不是通过 Spring Security 实现的,而是登录后把用户对象塞进 session,在每个 jsp 页面里用 if 判断 role 渲染菜单。这套做法的优点是简单、源码容易看懂,缺点是你直接请求一个没有菜单链接的 URL,比如/record/edit.jsp,后端不拦截的话照样能打开。第 5 章会专门展开这个拦截怎么补。

4. 部署避坑:五个让病历系统当场翻车的配置细节

4.1 现象:启动报 ClassNotFoundException: com.mysql.jdbc.Driver

原因:项目里根本没引入 MySQL 驱动 jar,或者引的是 MySQL 8.0 驱动,而配置类名还是 5.x 的写法。

解决:先看 pom.xml 里有没有 mysql-connector-java 依赖:

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>

如果源码是非 Maven 工程,去 WEB-INF/lib 目录看有没有 mysql-connector-java.jar。没有的话,从本地 Maven 仓库或者 IDE 的依赖管理里拷一份进去。注意版本:MySQL 5.7 环境配 5.1.x 驱动正好,MySQL 8.0 环境必须用 8.0.x 以上的驱动并同步改 jdbc.properties 里的 driver 类名。

4.2 现象:Access denied for user 'root'@'localhost'

原因:基本不是权限问题,而是 jdbc.properties 里的密码和你本地 MySQL 不一致。还有一种隐蔽情况:密码末尾多了一个空格,或者 properties 文件里jdbc.password=123456后面带着看不见的空白字符。

解决:用 MySQL 客户端手工连一次,确认密码没问题后,再打开 jdbc.properties 检查。不要直接在记事本里改,建议用 IDEA 打开,右下角能看到文件编码和行尾格式。改完记得重启 Tomcat,只点“重新编译”不会重新加载配置文件。

4.3 现象:病历页面上中文全部变成问号

原因:三层编码没对齐。JSP 页面本身的 pageEncoding、MySQL 表结构的 charset、JDBC 连接的 characterEncoding,任何一层不是 UTF-8,中文就乱。

解决:页面统一改成:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

web.xml 里加一个编码过滤器,强制请求和响应都走 UTF-8:

<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter>

forceEncoding 设为 true 很关键,它会同时覆盖 request 和 response 的编码,比只在页面头声明可靠得多。数据库那层,第 3 章建库时已经用了 utf8mb4,这里也就不会出问题。三层对不齐是这类 Java Web 源码里最常遇到的乱码原因,没有捷径,逐层查。

4.4 现象:新增病历后,列表里的时间比本地时间早了 8 个小时或晚了几小时

原因:JDBC URL 没指定时区,MySQL 驱动按服务器默认时区(通常是 UTC 或美国时区)解析了 DATETIME 字段。老 MySQL 5.7 驱动不强制要求 serverTimezone,换成 8.0 驱动后这个参数成了必填项。

解决:在 jdbc.properties 的 URL 末尾加参数:

jdbc.url=jdbc:mysql://localhost:3306/emr?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false

改完重启服务,再看新增数据的时间就是东八区了。如果项目里还用了 FastJson 或者 Jackson 做 JSON 序列化,Java 侧的new Date()本身不带时区,前端格式化时也要统一指定时区,否则页面显示和数据库存储仍然各说各话。

4.5 现象:Tomcat 启动失败,日志提示 Port 8080 required by Tomcat v8.5 Server is already in use

原因:本地已经跑着一个 Tomcat,或者 IDEA 上次调试的进程没杀干净,8080 端口被占。

解决:先确认占用者是谁:

# Windows netstat -ano | findstr :8080 # macOS / Linux lsof -i:8080

查到进程 PID 后,要么杀掉,要么改 Tomcat 的端口。改端口在 Tomcat conf/server.xml 里,找到<Connector port="8080"改成 8081,然后启动,访问路径也要跟着换成 8081。IDEA 里配置 Tomcat 时,HTTP port 和 JMX port 要一起检查,只改一个还会冲突。

5. 病历核心业务实现:从登录鉴权到病历读写的事务链路

5.1 登录鉴权:用 Filter 拦截请求,别只靠 JSP 页面的 if 判断

很多老源码的权限控制停留在“登录后把用户存在 session,页面上根据角色显示不同菜单”。这种做法的最大漏洞是:直接请求内部 URL 照样能访问。我一般会在拿到源码后第一时间补一个登录过滤器,把未登录跳转到后端接口的路堵死。

public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; HttpSession session = request.getSession(false); String uri = request.getRequestURI(); // 登录页、登录接口、静态资源放行,其余请求必须携带登录态 if (uri.endsWith("login.jsp") || uri.endsWith("/login") || uri.contains("/static/") || uri.contains("/css/")) { chain.doFilter(request, response); return; } // 没有 session 或 session 里没有用户对象,直接重定向回登录页 if (session == null || session.getAttribute("loginUser") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(request, response); } }

这段代码有四个要点:一是getSession(false)表示不主动创建 session,否则所有请求都会产生一个会话对象,浪费内存;二是放行列表要覆盖登录接口本身,不然用户提交登录表单时连账号密码都送不到后端;三是重定向必须带request.getContextPath(),否则在/emr上下文下会把用户引到不存在的路径;四是静态资源放行后,CSS、JS、图片这些才能正常加载,不然登录页样式全丢。

配套的注册方式有两种:老项目在 web.xml 里加 filter 和 filter-mapping,注解风格的项目直接在类上写@WebFilter(urlPatterns = "/*")。注意如果你用了 Spring MVC,Spring 自带的 CharacterEncodingFilter 要先执行,登录过滤器放在它后面,避免编码还没设置就做了重定向。

5.2 病历新增与状态流转:暂存和提交是两条逻辑

病历录入是整个系统里业务属性最强的模块。医生填写时经常写一半去接诊下一个病人,所以源码里通常有“暂存”和“提交”两个按钮,对应 medical_record 表的 status 字段。提交后的病历才进入正式列表,暂存的只有医生本人能看到。

@Controller @RequestMapping("/record") public class RecordController { @Autowired private MedicalRecordService recordService; @PostMapping("/save") public String save(MedicalRecord record, @RequestParam(value = "status", defaultValue = "0") Integer status) { // status 由前端按钮控制:暂存传 0,提交传 1 record.setStatus(status); recordService.save(record); return "redirect:/record/list"; } }

Controller 层只做参数接收和状态赋值,真正的业务在 service 层。status 这个参数值得注意:前端是两个按钮共用同一个 save 接口,通过提交不同的 status 值区分行为;defaultValue = "0" 保证了如果请求里没有 status 字段,不会因为参数缺失而报 400。这是老项目最常见的写法,比新建两个接口更简洁,但代价是医生得在页面端自己保证点击“提交”时把状态值改成 1。检查源码时重点看页面 JS 里有没有这段赋值逻辑,如果没有,病历永远只会以暂存状态落库。

5.3 组合查询:按姓名、科室、日期查病历,动态 SQL 怎么拼才安全

病历列表页一般都有查询条件:病人姓名、就诊科室、就诊日期。最直接的做法是用字符串拼接 SQL,但病人姓名里如果有单引号,SQL 就崩了。MyBatis 的<where>和<if>正是为这种场景设计的。

<select id="listByCondition" resultType="com.emr.pojo.MedicalRecord"> SELECT * FROM medical_record <where> <if test="patientName != null and patientName != ''"> AND patient_name LIKE CONCAT('%', #{patientName}, '%') </if> <if test="deptId != null"> AND dept_id = #{deptId} </if> <if test="visitDate != null and visitDate != ''"> AND visit_date = #{visitDate} </if> </where> ORDER BY visit_date DESC, id DESC </select>

这段 mapper 有几个细节需要解释。<where>标签会自动去掉第一个多余的 AND,比手工写where 1=1干净,也避免了条件为空时生成where 1=1这种无效扫描。patient_name LIKE CONCAT('%', #{patientName}, '%')用了预编译参数占位符,能防止 SQL 注入;如果用${patientName},用户输入任何内容都会直接拼进 SQL,这是 java 开发里最不该犯的错误。visit_date = #{visitDate}是精确匹配,适合按某一天查病历;如果要查一个时间区间,需要两个参数startDate和endDate,用BETWEEN或>=和<=两个条件。最后按就诊时间倒序排列,保证最新病历排在最上面,符合医生看列表的习惯。

5.4 事务边界:病历和处方必须同生共死

电子病历系统里最经典的事务场景是“写病历 + 开处方”一起提交。病历保存成功、处方保存失败,或者反过来,都会造成病人有诊断结果但没药方,或者有药方但对不上病历。解决思路是让 service 层方法整体加入事务。

@Service public class RecordServiceImpl implements MedicalRecordService { @Autowired private MedicalRecordMapper recordMapper; @Autowired private PrescriptionMapper prescriptionMapper; @Override @Transactional(rollbackFor = Exception.class) public void saveRecordWithPrescription(MedicalRecord record, List<PrescriptionItem> items) { // 先插入病历主表,得到自增主键 recordMapper.insert(record); for (PrescriptionItem item : items) { // 每条处方明细都挂到刚生成的病历 ID 下 item.setRecordId(record.getId()); prescriptionMapper.insert(item); } } }

这个方法的三个关键点:一是@Transactional加在 service 实现类上而不是 controller 上,因为 controller 里一个请求往往要调多个 service,事务粒度太大会把无关操作也卷进来;二是rollbackFor = Exception.class必写,Spring 默认只对 RuntimeException 回滚,如果 mapper 抛的是受检异常,不加这个参数就静默提交了;三是record.getId()能拿到自增主键的前提是 MyBatis 的 useGeneratedKeys 配置正确,通常在 mapper 的 insert 语句里配useGeneratedKeys="true" keyProperty="id"。很多源码没有事务,你要自己补上,这也是后面面试时能拿出来讲的实打实的点。

6. 把这套源码变成面试谈资:三个低成本改造方向

6.1 从 SSM 迁移到 Spring Boot + MyBatis Plus

老项目的通病是配置繁琐,面试官也腻了。花三四天把 SSM 改造成 Spring Boot 版本,直接去掉 web.xml、spring-*.xml 那一堆配置,用 application.yml 统一管理数据源和 MyBatis 映射。MyBatis Plus 根据实体类生成建表 SQL 的功能可以当草稿用,但真正建表还是以手写 DDL 为准,因为有注释、能控制索引。改造完成后,mvn spring-boot:run一下就能起服务,部署门槛大幅下降。

6.2 把硬编码 role 改成 RBAC 权限模型

原项目的 sys_user.role 字段只支持三种固定角色,新增一个“科室主任”角色就得改代码。低成本升级方案是拆三张表:sys_user、sys_role、sys_user_role,用户挂在角色下,角色控制菜单和接口访问。工作量不大,但权限边界一下清晰了,病历的查看和修改权限可以按角色细分到操作级别。

6.3 电子病历系统的高频面试追问对照表

这套源码改完,面试或被答辩提问时,回答思路可以直接参考这张对照表:

面试官常问建议回答思路对应改动点
病历和处方的一致性问题怎么解决用 @Transactional 管理事务边界,保证要么都成功要么都回滚第 5.4 节代码
动态查询怎么防 SQL 注入MyBatis 的 #{} 预编译 +<where>标签条件拼接第 5.3 节 mapper 代码
权限控制是怎么做的登录过滤器拦截未登录请求,再按 RBAC 模型拆分角色权限第 5.1 节代码 + 6.2 节改造

我自己的做法是接到这类源码后,先把数据库脚本跑通,再补登录过滤器,最后给 service 层加上事务和重构查询。这三个改动做完,这个项目就不再是“从网上抄的”,而是你能讲清来龙去脉的作品。项目小不要紧,把事务一致性、动态查询和权限演进想清楚,面试官基本不会问倒你。希望帮到你。

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

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

接口测试效率低?优测把用例生成、Mock、压测、CI串联成流水线

2026年了&#xff0c;接口测试这件看似基础的事&#xff0c;反而是很多团队最头疼的环节。接口数量翻了几倍&#xff0c;业务链路越拉越长&#xff0c;以前用调试工具单个请求点一遍就算完事的做法&#xff0c;已经撑不起交付节奏了。优测这款接口测试工具&#xff0c;我在实际…

作者头像 李华
网站建设 2026/10/19 6:11:18

深入浅出JVM底层:垃圾回收、内存分配与线上调优实战

搞JVM底层这块&#xff0c;很多人第一反应就是啃那本大部头的经典书&#xff0c;但说实话&#xff0c;真没几个人能坚持从头翻到尾。尤其到了工作三五年这个阶段&#xff0c;业务代码写了无数&#xff0c;一到线上出现内存暴涨、CPU飙高、频繁Full GC的时候就抓瞎&#xff0c;回…

作者头像 李华
网站建设 2026/10/15 14:06:08

多智能体协作系统agency-agents:架构设计与工程落地实践

项目标题: agency-agents做智能体协作类项目有一段时间了&#xff0c;踩过不少坑&#xff0c;也重构过好几轮。今天把“agency-agents”这个项目从设计初衷到落地实现完整拆开聊一聊。这个项目的核心不是再做一个单一对话机器人&#xff0c;而是把多个具备不同专长的AI代理组合…

作者头像 李华
网站建设 2026/10/20 15:34:55

马士HHH刷屏背后:热词传播机制与内容创作避坑指南

大半夜的&#xff0c;我刚准备关电脑睡觉&#xff0c;群里突然炸出来一张截图。配文就四个字母&#xff1a;HHH。底下跟了上百条回复&#xff0c;全是清一色的“马士HHH”。我盯着屏幕看了几秒&#xff0c;职业病就上来了——这又是一个典型的热词苗子&#xff0c;而且八成又要…

作者头像 李华
网站建设 2026/10/15 10:22:07

DSec学习资料汇总:DeepSeek本地部署与Agent沙盒架构实战指南

1. 从一份资料汇总说起&#xff1a;DSec到底在解决什么问题第一次看到“DSec学习资料汇总”这个标题&#xff0c;很多人会以为这只是一份普通的链接集合。但真正翻过一遍内容的人会发现&#xff0c;它其实是一张围绕DeepSeek 生态、Agent 开发、沙盒隔离与系统架构铺开的知识地…

作者头像 李华
网站建设 2026/10/16 12:54:25

AI工作流失败后如何续跑?检查点机制与人工接管设计指南

1. 自动化跑完最后一公里&#xff0c;人反而更忙了你有没有遇到过这种场景&#xff1a;凌晨两点&#xff0c;你盯着屏幕上那个跑了三个小时的自动化工作流&#xff0c;进度条卡在87%不动了。日志里最后一行写着“等待元素超时”&#xff0c;然后就是一片死寂。你心里清楚&#…

作者头像 李华