当前位置: 首页 > news >正文

处方签的模板填充+PDF签名——一次医疗场景的打印设计

处方签的模板填充+PDF签名——一次医疗场景的打印设计

文章目录

  • 处方签的模板填充+PDF签名——一次医疗场景的打印设计
    • 一、处方签不是普通的打印页面
    • 二、模板填充:用$占位符替代硬编码
    • 三、合并单元格的边框陷阱
    • 四、签名的位置:不是"居中"那么简单
    • 五、模板驱动的完整链路
    • 六、为什么不做HTML转PDF
    • 七、结语

一、处方签不是普通的打印页面

医疗系统里有一种特殊的东西叫"处方签"。它不是普通的表格打印——首先,它有法律效力。一张处方签上必须有医师签名和药师签名,缺一个就是废纸。其次,它格式固定。药监局规定了处方签的版式和必填字段,不能随便改。

所以,处方签的打印流程不是"在屏幕上画几个框",而是三步:

① XLS模板 → ② 填入患者+药品数据 → ③ 签上医师和药师的名字 → PDF输出

这个流程的每一步都有坑。我们一步步说。

二、模板填充:用$占位符替代硬编码

处方签的格式是固定的,但内容每次不同——患者姓名、药品名、用法用量。我们的做法是做一个Excel模板文件,里面放占位符。比如$xm代表姓名,$xb代表性别:

处方签模板.xls 内容: ┌──────────────────────────────┐ │ 患者姓名:$xm │ │ 性别:$xb │ │ 诊断:$zd │ │ 药品:$m1 | 用法:$u1 │ │ 药品:$m2 | 用法:$u2 │ └──────────────────────────────┘

代码里的print()方法遍历Excel的每个单元格,遇到以$开头的就去Map里找对应的值:

if("$".equals(firstChar)){colName=temp.substring(1);colValue=String.valueOf(map.get(colName));// 替换单元格内容label=newLabel(j,x,colValue,...);}

这个设计的巧妙之处在于:处方签格式变了,改Excel模板就行,一行代码不用动。药监局改了处方签版式?把模板重新排版,代码零改动。

三、合并单元格的边框陷阱

Excel模板里经常有合并单元格——比如"药品"那栏,名称和用法两大列上面有个大标题"处方明细"。从Excel转到PDF时,合并单元格的边框处理是最容易出错的地方。

问题在哪?Excel的合并单元格只有一个"视觉上"的大格子。实际上,内部每个被合并的单元格都还有自己的格式。边框不会被自动"继承"——合并后的大格子,下边框和右边框可能需要从被合并的最远单元格上取。

for(Rangeobj:mergedCells){intrs=obj.getTopLeft().getRow();intre=obj.getBottomRight().getRow();intcs=obj.getTopLeft().getColumn();intce=obj.getBottomRight().getColumn();if(当前单元格是合并格的左上角){if(rs<re){// 下边线要从最下面那行的同事格取}if(cs<ce){// 右边线要从最右边那列的同事格取}}}

然后是一个长长的 if-else 链条,逐个组合判断哪条边该显示、哪条该隐藏——disableBorderSide(15)隐藏全部四边,disableBorderSide(2)只隐藏下边……一共15种组合。

这段代码看起来像是机器生成的。不是。它就是手工一行行写的——因为当初被合并单元格的边框问题折腾了无数次,每个组合都是在实际打印中碰到的真实错误。

四、签名的位置:不是"居中"那么简单

处方签上需要两个签名:医师在右下角,药师在左下角

这不是CSS里"float:right"能搞定的事。iText的PDF操作是基于坐标的——你得告诉它签名图片精确的 (x, y) 坐标。

// 先加医师签名——右下角addWaterMarkIncludeWords(filename1,filename2,fileqm1,385,240);// 再加药师签名——左下角addWaterMarkIncludeWords(filename2,filename,fileqm2,110,240);

addWaterMarkIncludeWords做三件事:

  1. 打开已有PDF(PdfReader
  2. 创建PdfStamper(往已有PDF上盖内容)
  3. 把签名图片放在每一页的指定位置
  4. 删掉原文件——这是关键,签名后的PDF覆盖原PDF,不留无签名版本
PdfReaderreader=newPdfReader(inputFile);PdfStamperstamper=newPdfStamper(reader,newFileOutputStream(outputFile));Imageimage=Image.getInstance(imageFilePath);image.setAbsolutePosition(width,height);image.scalePercent(20f);for(inti=1;i<total;i++){under=stamper.getUnderContent(i);under.addImage(image);}stamper.close();newFile(inputFile).delete();// 删除未签名版本

为什么签名必须放在UnderContent(内容之下)而不是OverContent(内容之上)?因为处方签的文字不能被签名图片遮挡。放下面,签名像是印在纸上的底纹——能看清签名,也能看清上面的处方内容。

五、模板驱动的完整链路

一条完整的处方签打印链路是这样的:

getfile(map, 医师签名.jpg, 药师签名.jpg) ├── print(map, "处方单.xls") → 填充模板,生成ByteArrayOutputStream ├── Workbook(流) → JXL读回内存 ├── xlsToPDF(workbook, "v", f1) → 转PDF(纵向) ├── addWaterMark(医师签名) → 盖医师签名 ├── addWaterMark(药师签名) → 盖药师签名 └── 返回pdf文件路径

模板是Excel,数据是Map,签名是图片,输出是PDF。每层都是独立步骤,改签名位置不需要动模板,改模板格式不需要动数据,改数据字段不需要动签名。

六、为什么不做HTML转PDF

很多人会问:用HTML画处方签,然后转PDF不是更灵活吗?

两个原因。第一,在医院里,Excel就是行业语言。药房的人、医保中心的人、药监局的检查员——他们用Excel排版处方签比用HTML熟练得多。第二,Excel转PDF能保住原始格式——字体、边框、对齐、合并单元格——一行一行地从JXL的CellFormat里抠出来,再用iText还原回去。HTML转PDF看似方便,但CSS的渲染结果在不同浏览器之间天差地别,兼容性问题更多。

选择Excel作为模板格式,本质上是一个**“让业务人员自己能维护”**的决策——改处方签版式不用找开发,自己调Excel就行。

七、结语

处方签的打印功能,代码不到700行。但它是医疗信息化里极少数**“不容忍任何格式错误”**的功能——边框差一条线,被药监局退回来;签名位置歪了3毫米,处方作废;字体大小不对,药品名称看不清,发药发错。

这套模板+填充+签名的三段式设计,核心是隔离变化:版式变化改Excel,数据变化改代码,签名变化改坐标。三个维度各自独立,互不干扰。

在今天看来这套方案没什么特别——模板引擎+PDF生成,任何一个报表引擎都能做。但在没有模板引擎、没有报表工具的2010年代,自己把JXL和iText串起来,就是一个完整的打印系统。

http://www.jsqmd.com/news/1097455/

相关文章:

  • 深入理解QEMU架构:模拟器与虚拟化器的完美结合
  • 三阶段 DEA Performance 完整实操教程|剔除环境与随机干扰、效率校正全过程操作与论文分析思路
  • OpenEuler Infrastructure核心功能揭秘:从Ansible到CI/CD的完整工具链
  • libucc与XSched内核的协同工作:完整调度框架解析
  • 元容沙箱SDK API完全参考:动态代码运行与文件操作接口使用手册
  • 世界模型火了,可你的AI连无人机翻转都算不准——缺的不是数据而是这条公理
  • 基于知识图谱的设备物资配置优化实战指南
  • ANNC社区贡献指南:从问题反馈到代码提交的完整流程
  • openEuler高可用与集群部署终极指南:构建企业级HA架构与Kubernetes集群管理
  • 元容沙箱SDK开发者指南:贡献代码与扩展自定义隔离策略的最佳实践
  • PilotGo-plugin-llmops架构详解:Agent、Server与Web三大模块协同工作原理
  • QEMU性能优化:5个关键技巧提升虚拟机运行效率
  • 如何快速上手gala-gopher?5分钟搭建你的第一个eBPF性能监控环境
  • 别再写 @CustomDialog 了,我把它从雷达鸭代码里全删了重写
  • sysSentry系统巡检框架:10分钟快速搭建企业级硬件故障监控平台
  • Autodesk Inventor 2027 下载安装教程 专业三维机械设计工程仿真软件下载安装步骤
  • 电子管功放入门介绍:工作原理、结构、优缺点和使用注意
  • 终极指南:iTrustee_tzdriver与iTrustee OS通信机制详解
  • 如何实现浏览器直连桌面?WebRTC远程屏幕共享技术深度解析
  • OpenEuler Infrastructure部署指南:从0到1搭建社区管理平台
  • sysHAX性能优化秘籍:提升LLM推理吞吐量的7个关键技巧
  • openEuler/libummu高级特性:原子操作与令牌管理深度解析
  • UnifiedBus性能优化:如何调优异构硬件通信效率
  • 如何快速部署safeguard?5分钟入门Linux内核安全监控工具
  • 66_Python多线程与并发
  • Vue-Giant-Tree:10,000+节点海量数据树形组件的终极解决方案
  • DXVK:让Linux游戏体验媲美Windows的Vulkan转换层技术
  • 三步掌握XUnity.AutoTranslator:新手也能轻松上手的Unity游戏翻译完整指南
  • euler-copilot-shell日志管理技巧:轻松追踪和解决问题
  • safeguard挂载限制实战:防止未授权文件系统挂载的终极方案