简介:OpenMRS 2.3.1 独立版是一份面向医疗机构、医疗信息化开发者及运维人员的开源电子病历系统部署包。它旨在帮助用户在资源有限的环境中快速搭建可定制的病历管理平台,涵盖患者登记、病史记录、诊断报告、处方与实验室结果管理等核心功能。压缩包内共15个文件,以properties与xml配置文件、jar/war程序包、sh启动脚本及zip格式的演示/空数据库为主,整体大小约394.68MB;独立运行版免去了复杂服务器配置,附带的README与启动脚本可引导完成基础配置,webapps与Tomcat目录则提供了可直接运行的完整环境。空数据库与演示数据库便于初始化测试,政策文件和配置模板可辅助理解系统默认策略,模块化设计与多语言界面也有助于在不同规模和区域的机构中灵活部署。已有588人学习下载,适合需要评估、部署或二次开发OpenMRS的团队参考。
1. 拿到 openmrs-standalone-2.3.1 这个 zip,别急着解压:先搞清楚它能救什么急
OpenMRS standalone 2.3.1 的 zip 包,本质上是一个自带运行时、解压即用的开源企业电子病历系统,适合需要离线演示、快速搭测试环境或在一台没有外网的内网机器上起病历系统的场景。很多团队第一次接触它,是把 OpenMRS 当作一套“能直接跑起来的开源 HIS 前端”来评估——它确实做到了:一个 zip 里同时打包了 Tomcat 中间件、H2 数据库和 OpenMRS 平台本体,省去手工配 servlet 容器的过程。这篇笔记从解压开始,讲到换 MySQL、做备份和排障,读完你能把这个 zip 变成一台能长期服务的实例,也能知道 2.3.1 的边界在哪、什么时候不该硬上。
2. Standalone 发行版与源码包的根本差异:为什么要用 zip 起 OpenMRS
2.1 Standalone 不是简化版,而是“被预先组装好的生产候选”
OpenMRS 官方除了提供 war 包和源码仓库,还会发布 standalone 发行版。常见做法是把 OpenMRS Core、参考应用模块和必要的依赖模块一起打进一个可执行 jar,再配上一个 Tomcat 的内嵌版本。2.3.1 这个版本号对应的是 OpenMRS Platform 2.3.x 时期的 standalone 构建,它和源码包的最大区别是:源码包要你自己装 Maven、MySQL、Tomcat,再编译模块;standalone 则把这些步骤全部提前做完,你拿到的是一个“黑匣子”——至少第一次启动前,你不需要知道它的模块装配细节。
这个设计目的很直接:让医院信息科的同事、没有 Java 背景的实施人员也能把系统拉起来。zip 里那个 openmrs-standalone.jar 是入口,它负责启动内嵌 Tomcat、初始化 H2 连接池、加载模块目录里的所有 omod 模块。如果你把它理解成“一个可以取代 Tomcat + MySQL + OpenMRS 部署目录三件套的组装体”,后续调参就有方向了。
2.2 压成 zip 的原因:跨平台分发和离线安装
2.3.1 时代的 standalone 构建没有用安装向导,而是选择打 zip,这有几个实际好处。第一,zip 在 Windows 和 Linux 下都能解压,不需要管理员权限,解压到用户目录就能跑;第二,zip 天然适合离线分发,医院内网环境经常不允许访问 Maven 中央仓库,zip 包内已经带了核心模块,不需要联网下载依赖;第三,zip 方便做版本管理——你想回退到 2.3.0,解压另一个包、改一下数据目录就可以切换。
要注意的是,这个 zip 起到的只是“运输容器”作用,它内部的 openmrs-standalone.jar 才是真正的程序。解压后你会看到 conf、modules、webapp 几个目录:conf 里放 runtime.properties 等配置文件;modules 里是 omod 模块包;webapp 是解包后的前端静态资源。第一次启动后,home 目录下会多出一个 openmrs 数据目录,H2 的库文件和 runtime 日志都写在那里。
2.3 2.3.1 能做什么、不能做什么:评估边界
OpenMRS 2.3.1 是 2.x 系列中相对成熟的一个小版本,支持患者登记、临床就诊记录、处方、报表和用户权限管理,参考应用界面也能正常使用。但 standalone 默认用的是 H2 数据库,H2 适合单机、演示和测试,不适合多科室并发写入;而且 standalone 的模块加载方式和源码部署略有不同,如果你要引入第三方 omod,需要验证它和 2.3.1 的 API 兼容性。我对它的定位是:评估期、开发环境和培训环境的最佳选择,生产环境务必换成 MySQL,见第 4 章。
提示:2.3.1 的 standalone 包对 Java 版本有硬性要求,Java 8 是安全区间。不要看到是 2.x 就觉得 Java 11 也能跑,遇到过几次因为默认 JDK 版本太高导致启动失败的案例,具体原因放在第 5 章排查。
3. 在 Windows 和 Linux 上跑通 OpenMRS Standalone:最小可执行清单
3.1 环境准备:先过 Java 和端口两道关
部署前最容易被忽略的是 Java 环境。OpenMRS 2.3.1 依赖 Java 8,超过这个版本,内嵌 Tomcat 的类加载器可能抛 NoClassDefFoundError 或 UnsupportedClassVersionError。我一般会在命令行先确认版本,然后检查 8080 端口是否被占用:
java -version # 期望输出包含 1.8 或 8u,例如 java version "1.8.0_202" # 检查端口占用(Linux) ss -tlnp | grep 8080 # 检查端口占用(Windows PowerShell) netstat -ano | findstr 8080这里只看两件事:一是 java 命令是否指向 JDK 8;二是 8080 是否空闲。如果你机器上装了多个 JDK,建议显式设置 JAVA_HOME,让它指向 JDK 8 的安装路径。standalone 的启动脚本会优先读取 JAVA_HOME,其次才在 PATH 里找 java。端口如果被其他服务占用,OpenMRS 的 Tomcat 会启动失败,但日志可能只显示“Port busy”,不会提示是谁占用。
3.2 解压 zip 并启动:Windows 双击与 Linux 命令行
拿到 openmrs-standalone-2.3.1 zip 后,先解压到不含中文和空格路径的目录,避免 Tomcat 的资源路径解析出问题。Windows 下常见的做法是解压到 D:\openmrs-standalone-2.3.1,然后双击 openmrs-standalone.bat。Linux 下这样启动:
cd /opt/openmrs-standalone-2.3.1 chmod +x openmrs-standalone.sh ./openmrs-standalone.sh脚本会启动内嵌 Tomcat,打开浏览器访问http://localhost:8080/openmrs,进入初始化向导。首次启动时间比较长,main 方法里会创建 H2 数据库、加载所有模块并初始化核心数据,这个过程在三到五分钟内都算正常,不要中途关掉终端。完成之后浏览器会自动跳转到管理员创建页面,输入用户名、密码、姓名,系统才会真正进入可用状态。
3.3 Windows 下后台静默启动:避免关了终端就断
双击 bat 启动的进程会绑定在终端窗口上,窗口一关服务就停。Windows 上想让 OpenMRS 一直跑,有几种做法。第一,写一个简单的 vbs 脚本,用隐藏窗口的方式调用 bat;第二,用 WinSW 这类工具把 standalone 包装成 Windows 服务;第三种是我用得比较多的方式——直接把启动脚本塞进计划任务的“用户登录时”触发器,再把程序设为开机自动登录。对于评估环境来说,第三种最简单,也方便手动停止。
Linux 服务器上更推荐用 systemd 托管,下面是我常用的服务单元配置,注意替换实际路径和用户:
sudo tee /etc/systemd/system/openmrs.service > /dev/null <<EOF [Unit] Description=OpenMRS Standalone 2.3.1 After=network.target [Service] Type=simple User=openmrs WorkingDirectory=/opt/openmrs-standalone-2.3.1 ExecStart=/usr/bin/java -jar /opt/openmrs-standalone-2.3.1/openmrs-standalone.jar Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now openmrs这里的 Type=simple 适合 standalone jar 直接前台运行的场景。ExecStart 里没有写 -Xmx 之类的 JVM 参数,是因为 standalone 的启动脚本里默认有内存设置,如果你用 systemd 直启 jar,内存参数要自己加,建议写成-Xms512m -Xmx2g,避免容器因为内存限制被杀掉。Restart=on-failure 能在程序抛异常退出时自动拉起,但如果是端口被占或者数据库文件损坏导致的退出,无限重启只会刷日志,排查时记得先journalctl -u openmrs -n 100看真实原因。
3.4 初始化数据库和第一个管理员账号
访问初始化向导后,系统会让你选择安装方式,常见选择是“安装参考应用”,这是 OpenMRS 2.3.1 时期默认推荐的界面。接下来填写数据库配置,如果只是本地评估,保留 H2 的默认选项即可;如果要接 MySQL,这一步就要动手改参数,具体见第 4 章。数据库初始化完成后,创建超级管理员账号,账号名建议用 admin 而不是 doctor 之类,因为后续装模块、管理权限都需要管理员角色。
整个初始化过程在 H2 模式下很快,MySQL 模式下取决于网络和磁盘,但一般不超过十分钟。完成后登录,系统会进入 OpenMRS 的仪表盘,到这里最小可执行集就算跑通了。接下来要做的不是急着录患者,而是先确认日志里的关键信息:数据目录在哪、运行模式是 H2 还是 MySQL、模块加载是否全部 success。
4. 从演示到生产:把 Standalone 的 H2 换成 MySQL,并做好备份
4.1 为什么必须换 MySQL:H2 的边界与并发问题
H2 是 OpenMRS standalone 内置的嵌入式数据库,零配置、单文件存储,对演示和开发极其友好。但它的并发写能力有限,多科室同时录入患者、开处方时,H2 的行锁竞争会导致界面卡顿;而且 H2 的数据文件依赖文件锁,进程异常退出后可能留下锁文件,导致下次启动失败。生产级 OpenMRS 需要 MySQL 或 MariaDB 承载核心数据,这也是官方文档明确建议的走向。
换库不是把 zip 删了再装一遍,standalone 通过 conf/runtime.properties 里的连接参数来决定连哪个库。把 H2 切换成 MySQL 的常见做法是:先准备好一个 MySQL 实例和空库,再修改 runtime.properties,把连接 URL、用户名、密码指向 MySQL。注意:这个切换不会自动迁移已有 H2 数据,如果 H2 里已经有测试数据,需要先用导出工具把数据倒出来,再导入 MySQL。
4.2 配置 MySQL 连接参数与建立数据库
先在 MySQL 里建库和账号,再给 OpenMRS 足够的权限。我习惯单独建一个账号,不用 root:
CREATE DATABASE openmrs CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'openmrs'@'localhost' IDENTIFIED BY 'StrongPassword'; GRANT ALL PRIVILEGES ON openmrs.* TO 'openmrs'@'localhost'; FLUSH PRIVILEGES;字符集选 utf8mb4 是必要的,OpenMRS 里会存多语言文本和患者姓名,utf8mb4 能覆盖表情符号和生僻字,避免写入报错。如果 MySQL 版本比较老,没有 utf8mb4,也可以用 utf8;但 MySQL 8 环境下建议直接用 utf8mb4。
接下来修改 runtime.properties,文件位置在解压目录的 conf 文件夹里。没有这个文件的话,第一次启动后会自动生成。关键行如下:
# OpenMRS runtime properties connection.url=jdbc:mysql://localhost:3306/openmrs?useSSL=false&characterEncoding=UTF-8 connection.username=openmrs connection.password=StrongPassword connection.driver_class=com.mysql.jdbc.Driver改完保存,重启 OpenMRS。standalone 检测到连接配置变了,会认为是新部署,重新执行数据库初始化脚本——所以这一步要在 H2 数据还没积累出重要内容时做。初始化完成后,登录系统验证几个基础页面:患者登记、搜索、仪表盘报表。如果页面能正常打开但录入患者保存不了,重点看 MySQL 的字符集和 SQL 模式,特别是 ONLY_FULL_GROUP_BY 可能导致一些统计查询失败。
4.3 固化配置:把 runtime.properties 纳入版本管理
runtime.properties 是整个 standalone 实例最核心的配置文件,里面不仅有数据库连接,还有模块路径、数据目录、scheduler 是否启用等开关。多实例部署时,我一般会把 conf 目录复制一份作为模板,修改连接参数后分发给各台机器,避免每台机器靠记忆手工改。注意以下几点:一是数据目录和模块目录的路径使用绝对路径;二是不要把密码写死到公开仓库;三是 Windows 路径和 Linux 路径的写法不要混用。
application_data_directory=/var/lib/openmrs module.repository_folder=/opt/openmrs-standalone-2.3.1/modulesapplication_data_directory 控制着 H2 数据文件或一些本地文件的落盘位置。如果你的机器有独立数据盘,把这个目录挂过去,后续备份就只需要打这一个目录的包,非常省事。很多实施团队容易忽略这个字段,导致数据散落在 home 目录下,备份时漏掉。
4.4 备份与恢复:最便宜的安全网是定时压缩数据目录
OpenMRS 生产实例的备份逃不开两件事:数据库备份和数据目录备份。MySQL 备份用 mysqldump,注意加上单事务参数,避免锁表;数据目录备份则直接打包 application_data_directory 指向的目录,里面包含上传的图片、文档等附件。备份命令如下:
# 数据库备份 mysqldump -u openmrs -pStrongPassword --single-transaction --routines --triggers openmrs > openmrs_$(date +%Y%m%d).sql # 数据目录备份 tar -czf openmrs_data_$(date +%Y%m%d).tar.gz /var/lib/openmrs恢复时先停服务,再倒库:登录 MySQL 执行 source 导入备份的 SQL,然后解压数据目录到原位置,最后启动 OpenMRS。这个流程里有几个容易翻车的点:如果 source 导入时遇到外键顺序问题,可以在备份时加上--no-create-db用默认库导入;如果数据目录压缩时文件正在被写入,会导致附件损坏,备份前要保证服务停止或者文件处于一致状态。定时备份可以交给 cron 或计划任务,保留七天轮换足够。
4.5 用反向代理补上 HTTPS 和域名访问
standalone 默认只监听 8080 的 HTTP,生产环境不可能直接暴露。常见做法是前面挂 Nginx 做 TLS 终止,把 /openmrs 路径反代到本地 8080。这个配置需要注意 cookie 的 Secure 属性,否则 HTTPS 下登录会掉会话。我的最小配置长这样:
server { listen 443 ssl; server_name emr.example.com; ssl_certificate /etc/nginx/ssl/emr.crt; ssl_certificate_key /etc/nginx/ssl/emr.key; location /openmrs { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_cookie_path /openmrs /openmrs; } }proxy_cookie_path 这一行很容易漏掉,不写的话 OpenMRS 设置 JSESSIONID 时只认原始路径,浏览器存了 cookie 也发不出来,表现为“能打开登录页,登录后立刻回到登录页”。这属于典型的部署层次问题,不是 OpenMRS 本身 bug,排查时第一时间看浏览器开发者工具里的 cookie 路径。
5. 避坑指南:OpenMRS Standalone 2.3.1 最常见的 5 个翻车点
5.1 启动闪退,日志只有一行报错:Java 版本不匹配
现象:双击 bat 或执行 sh 后进程立刻退出,终端里只剩一行UnsupportedClassVersionError或者干脆没有输出。原因:系统默认 Java 版本高于 8,2.3.1 的内嵌 Tomcat 编译字节码版本是 JDK 8。解决:显式设置 JAVA_HOME 指向 JDK 8,再启动。
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH ./openmrs-standalone.sh如果机器上确实没有 JDK 8,装一个不会影响其他应用,standalone 进程是独立 JVM,不修改全局配置也行。这个坑是最常见的,八成启动失败都源于此。线上排查顺序我建议是:先 java -version,再看日志,最后才怀疑代码包本身。
5.2 端口被占用导致 Tomcat 启动中止:把监听地址改成 127.0.0.1
现象:日志显示Port 8080 already in use,服务起不来。原因:本机已有应用占用 8080,或者 OpenMRS 被系统当作单实例重复启动了。解决:要么停掉占用的进程,要么改 OpenMRS 的端口。修改方式是在 runtime.properties 里增加一行server.port=8081,重启即可。注意:如果改用 8081,访问路径变成http://localhost:8081/openmrs,Nginx 反代配置也要跟着改。
5.3 解压 zip 时文件损坏或路径过长:先用压缩软件测试完整性
现象:解压 openmrs-standalone-2.3.1.zip 时提示 CRC 校验错误,或者解压到一半报文件路径太长。原因:下载过程丢包导致 zip 损坏;Windows 解压到深层次目录时,路径字段超过限制。解决:先用 7-Zip 打开看看能否正常列出内容,再解压;路径重命名成一个短目录,例如 D:\openmrs。看热词里提到 zip 伪加密和 zip 解压问题,记住一个原则:zip 不是可靠的长期存储介质,下载完第一件事是做完整性校验,哪怕是核对文件大小也好过解压到一半才报错。
5.4 H2 残留锁文件导致重启失败:删除 .lock.db 文件
现象:服务被 kill 后,再次启动报Database may be already in use。原因:H2 在数据目录里生成了带 lock 的文件,进程异常退出没有释放。解决:停掉所有 java 进程,删除数据目录里的.lock.db文件,再启动。这个方法只对 H2 有效,MySQL 模式不会出现这问题。如果你已经把数据切到了 MySQL,这段直接跳过。
5.5 登录后立即登出:反向代理的 cookie 与 HTTPS 设置
现象:在 HTTPS 地址下输入用户名密码,浏览器转一圈又回到登录页,没有任何报错。原因:Nginx 反代没设置 proxy_cookie_path,或者没有传 X-Forwarded-Proto 导致 OpenMRS 的会话 cookie 被视为不安全。解决:按 4.5 的配置补上 proxy_cookie_path;如果还不行,检查浏览器 Application 面板里 cookie 的 Secure 标记是否被正确移除。这个问题在 standalone 直连时不会出现,只在加了反代之后冒出来,所以遇到时要第一时间怀疑是中间层,而不是 OpenMRS 本体。
提示:遇到 5.5 类似的情况,别急着重启服务,先开浏览器开发者工具看请求和 cookie,能省一半时间。
6. 进阶用法:用多实例配置与自动化健康检查提高部署交付效率
部署 OpenMRS 到第二台机器时,你会发现自己手动点初始化向导其实是在浪费时间。我现在的做法是:把 runtime.properties 做成一式两份,一份是 H2 演示模板,一份是 MySQL 生产模板,里面把 application_data_directory、模块路径、连接池大小都提前写好,新环境只要改 IP 和密码就能拉起来。这是整个 standalone 工作流里最值得投入的一步,能显著减少实施交付的重复劳动。
验证部署是否健康有个很朴素的方法:写一个脚本,定时请求http://localhost:8080/openmrs/ms/emrapi/patient这个接口(带管理员 Basic Auth),检查 HTTP 200 和响应体长度。返回 200 且内容非空,说明 Tomcat 和模块都活着;如果返回 503,说明基本上下文没起来,再去看日志找模块加载失败点。下面是一个最小健康检查脚本:
#!/bin/bash AUTH=$(echo -n "admin:yourpassword" | base64) STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Basic $AUTH" \ http://localhost:8080/openmrs/ms/emrapi/patient) if [ "$STATUS" == "200" ]; then echo "OpenMRS healthy" else echo "OpenMRS down, status=$STATUS" fi这个 bash 脚本可以放进 cron,每分钟跑一次,配合告警可以达到最基本的可用性监控。如果你不想用管理员密码在脚本里做 Basic Auth,也可以给监控单独开一个低权限账号,只开放查看权限,更安全。我的习惯是监控账号和日常账号分开,防止脚本泄露密码后波及整个系统。
最后一个技巧:升级 standalone 版本前,一定先把 conf 目录和 application_data_directory 整个备份下来。OpenMRS 的模块机制很灵活,但灵活的另一面是有可能不向后兼容,升级后旧模块和新平台版本冲突而加载失败。留着旧版本压缩包和数据备份,就是给自己留一张后悔药,回退时解压旧包、替换 conf、启动,十分钟内恢复原状。这句话不是空话,是我在 2.x 系列上真实花费过一晚上的教训。希望这些边界和细节,能帮你在自己的 OpenMRS 部署上少走一段弯路。
本文还有配套的精品资源,点击获取