拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Domino Java开发实战指南:环境搭建、代理编写与Web服务集成

Domino Java开发实战指南:环境搭建、代理编写与Web服务集成 简介《Domino开发指南精华》是一本面向企业级Java开发者的技术指南聚焦Lotus Domino平台的Java集成开发实践解决邮件处理、富文本操作、URL头信息获取、数据库交互、文档与视图管理及代理自动化等核心协作系统构建难题。资源为单文件PDF格式共1个文件大小3.82MB内容完整覆盖lotus.domino包的典型API调用与工程化应用适合具备Java基础、需快速落地Domino定制开发的中高级开发者。已有1930人学习下载表明其在遗留系统维护与协同办公平台二次开发领域具有持续参考价值。书中提供大量可直接复用的代码示例强调企业场景下的实操路径——如通过Notes API实现邮件自动归档、富文本字段动态渲染、视图数据分页加载及定时代理触发业务流程同时附有版权与使用规范说明便于合规引入生产环境。1. Domino开发指南精华不是Java框架而是Notes/Domino平台上的原生开发实战手册你手头有一套老系统——IBM Notes客户端Domino服务器架构的内部审批、文档协同或知识库系统现在要加一个新功能自动归档邮件到指定数据库、按关键词触发工作流、把Notes表单数据导出成Excel并带格式。这时候翻遍Maven仓库、Spring Boot Starter列表、甚至GitHub Trending都找不到“Domino Java API”的starter依赖——因为Domino开发根本不在现代Java生态里跑。它用的是自己的一套运行时Notes.jar NCSO.jar lotus.domino.* 包体系运行在Domino服务器JVM里调用的是C层Notes C API封装。这份《Domino开发指南精华》不是教你怎么用Spring整合Domino而是告诉你怎么在Notes Designer里写Java代理、怎么用LotusScript做前端逻辑、怎么用DXL导出/导入设计元素、怎么绕过Session对象线程安全陷阱、怎么让Java代理在服务器端真正拿到FullAdmin权限——全是血泪经验攒出来的硬核操作。适合正在维护/升级存量Domino应用的后端工程师、企业IT运维、以及被临时拉来救火的Java开发者。它不讲理论只讲“改完哪几行代码重启服务器后能立刻看到效果”。2. Domino开发环境搭建与核心API选型为什么必须用Notes 9.0.1 FP10 Domino 10.0.1而非最新版2.1 开发机环境Notes客户端 ≠ IDEDesigner才是真编辑器Domino开发不能靠IntelliJ或Eclipse写完Java再部署——所有Java代理Agent、Servlet、Web服务都必须在Notes Designer中编写、编译、保存到NSF数据库内。这意味着你的开发机必须装完整Notes客户端含Designer组件而非仅装Domino Administrator。常见错误是只装Admin Client结果打开.nsf文件时看不到“Agents”视图也点不了“Edit Agent”按钮。安装顺序严格如下先装IBM Notes 9.0.1 Fix Pack 10官方支持Java 8u181兼容性最稳再装Domino 10.0.1 Server注意不是11.x或12.x11版本对旧Java代理兼容性差且NCSO.jar签名机制变更导致Classloader报错最后配置Notes客户端连接本地Domino服务器Server Document中启用“Allow HTTP clients”和“Allow Java agents”。提示不要试图用Notes 12.x Domino 12.x组合。实测Java代理中调用session.getDatabase(, log.nsf)会返回null原因在于12.x默认禁用Legacy Java Security Manager而大量老代码依赖其权限校验逻辑。2.2 核心Jar包定位与classpath陷阱Domino Java开发依赖三个关键jar它们不在CLASSPATH环境变量里也不在项目lib目录下而是由Notes JVM在启动时动态加载Jar包名来源路径关键用途版本敏感点notes.jarC:\Program Files\IBM\Notes\jvm\lib\ext\notes.jar提供lotus.domino.*主类如Session、Database、Document必须与Notes客户端版本严格一致混用9.0.1客户端10.0.1服务器时优先取Notes客户端路径下的jarncso.jarC:\Program Files\IBM\Domino\jvm\lib\ext\ncso.jar提供com.ibm.domino.napi.*底层C API封装用于跨平台文件操作、DXL解析Domino服务器版本决定若代理需调用NAPI如读取NSF文件头必须用服务器对应版本domino.jarC:\Program Files\IBM\Domino\jvm\lib\ext\domino.jarDomino内置Servlet容器支持类用于开发HTTP Servlet仅在开发Web服务时需要但必须与httpstack配置匹配见4.2节验证是否加载成功在Java代理中写一行System.out.println(Loaded: Session.class.getPackage().getImplementationVersion());运行后查看Domino Console输出。若报NoClassDefFoundError: lotus/domino/Session90%是jar路径错了或Notes客户端未以管理员身份运行Windows UAC拦截了jvm.dll加载。2.3 Java vs LotusScript什么场景必须用Java什么场景死守LotusScript这不是语言优劣问题而是执行上下文决定的硬约束必须用Java的场景需调用外部HTTP API如调用企业微信机器人接口→ LotusScript的XMLHTTP对象不支持HTTPS证书校验Java可配SSLContext需处理大附件10MB→ LotusScript内存模型易OOMJava可用InputStream分块读取需集成JDBC如查SQL Server审计日志→ LotusScript无原生JDBC驱动Java可直接Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver)。必须用LotusScript的场景操作RichText字段如插入图片、设置段落样式→ Java API对RichTextItem的格式控制极弱appendText()后无法设字体而LotusScript的AppendRTItem()支持完整RTF指令前端表单事件如QuerySave、PostRecalc→ Notes客户端只识别LotusScriptJava无法挂载到表单事件链调用COM组件如Word转PDF→ Windows平台下LotusScript可CreateObject(Word.Application)Java需额外JNI桥接稳定性差。实操建议混合开发——前端表单用LotusScript做UI交互后台批处理用Java代理通过Command([ToolsRunMacro])或session.evaluate(Command(...)触发。3. Java代理开发全流程从创建到调试的六步闭环3.1 创建Java代理不是新建Java Class而是Designer里的特殊节点在Notes Designer中打开目标NSF → 左侧导航栏右键“Agents” → “New Agent” → 在弹窗中Name:ArchiveMailToDB命名规范动词名词避免空格和中文Shared: ✅ 勾选否则仅当前用户可见Target: 选“None”纯后台运行不绑定文档Trigger: 选“On event” → “After new mail has arrived”邮件归档场景Runtime: 选“Java”关键不是LotusScript点击OK后Designer自动打开Java编辑器初始模板已含import lotus.domino.*;和public class JavaAgent implements AgentBase结构——这是Domino强制约定不可删改。3.2 核心代码骨架Session复用、Database缓存、异常兜底三原则以下是最小可行代理代码已去业务逻辑保留Domino开发铁律import lotus.domino.*; public class ArchiveMailToDB extends AgentBase { private Session session; private Database targetDB; public void NotesMain() { try { // 【原则1】Session必须从AgentBase.getSession()获取禁止new Session() session getSession(); // 【原则2】Database对象必须缓存避免循环中反复openDatabase() targetDB session.getDatabase(, archive.nsf); if (!targetDB.isOpen()) { throw new RuntimeException(Target DB archive.nsf not found or closed); } // 主逻辑入口此处省略邮件扫描与归档代码 processIncomingMail(); } catch (Exception e) { // 【原则3】所有异常必须捕获并记录到Domino日志不能抛出 System.out.println(ERROR in ArchiveMailToDB: e.getMessage()); e.printStackTrace(); // 此行输出到Domino Console非Notes客户端日志 } } private void processIncomingMail() throws Exception { // 示例获取收件箱未读邮件 Database mailDB session.getDatabase(, mail\\username.nsf); View inbox mailDB.getView(($Inbox)); DocumentCollection unreads inbox.getAllUnreadEntries(); Document doc unreads.getFirstDocument(); while (doc ! null) { // 归档逻辑... doc unreads.getNextDocument(doc); } } }参数说明与逻辑说明getSession()返回的是当前代理执行上下文的Session对象它已预置了FullAdmin权限前提是代理属性中勾选“Run as Web user”并配置了有效ID比手动Session s new Session()安全得多session.getDatabase(, archive.nsf)中第一个参数为空字符串表示本地服务器若需远程库填服务器名如CNDomino01/OOrgunreads.getFirstDocument()返回的是Document对象但该对象生命周期绑定于DocumentCollection循环中必须用getNextDocument(doc)推进不能用for(Document d : collection)——后者在Domino Java API中不支持增强for循环System.out.println()输出到Domino服务器Consoleconsole.log命令可见而session.writeLog()才写入log.nsf后者性能开销大仅用于关键事务日志。3.3 调试Java代理Console日志 Domino Debug模式 远程JPDA三重验证Domino Java代理无法像普通Java程序那样F5调试必须用组合手段Console日志法最快在代理中插入System.out.println(STEP 1: Start processing);启动Domino服务器后在命令行输入tell http restart若代理为Web触发或load domino若为邮件触发实时监控Consoleshow log或tell amgr run ArchiveMailToDB手动触发观察输出。Domino Debug模式准确定位修改Domino服务器notes.ini添加JavaDebugPort8000 JavaDebugtrue重启Domino此时JVM启动时会监听8000端口在IntelliJ中配置Remote JVM DebugHostlocalhostPort8000无需附加任何jar直接Attach在Java代理代码中打断点如processIncomingMail()第一行触发代理后IDE会自动停住。远程JPDA验证生产环境兜底若服务器在Linux且无法直连用ssh -L 8000:localhost:8000 userdomino-server建立端口映射IntelliJ Debug配置中Host填localhostPort填8000即可远程调试。注意Debug模式下代理执行会变慢JVM字节码插桩切勿在生产环境长期开启JavaDebugtrue仅用于问题定位。4. 常见问题排查Java代理不执行、Session权限不足、DXL导入失败三大黑匣子4.1 现象Java代理在Designer中点击“Run”无反应Console无任何输出原因代理属性中未启用“Enabled”或“Shared Agent”权限未授权。排查步骤右键代理 → “Properties” → “Security”页签 → 确认“Enabled”复选框✅在“Runtime”页签 → 检查“Run on behalf of”是否设为“Server”非“User”打开Domino Administrator → 服务器文档 → “Security”页签 → “Sign and run unrestricted methods and operations”中确认代理签名者如CNDev/OOrg在“Signers”列表中。解决用服务器ID如server.id重新签名代理Designer中右键代理 → “Sign” → 选择服务器ID文件。4.2 现象session.getDatabase(, xxx.nsf)返回null但NSF明明存在原因NSF路径错误或数据库未在Domino目录注册。排查步骤在Domino Console执行show database确认xxx.nsf是否在列表中若不在检查NSF是否放在data\目录下非data\subdir\Domino默认只扫描data\一级若在子目录需在服务器文档“Basics”页签中添加路径到“Database directories”。解决将NSF移至data\根目录或修改服务器配置使其识别子目录。4.3 现象DXL导入时抛DOMException: Invalid character但XML文件用浏览器打开正常原因DXL文件含BOMByte Order Mark或编码声明与实际不符。排查步骤用Notepad打开DXL文件 → “编码”菜单 → 查看是否为UTF-8 with BOM检查DXL首行?xml version1.0 encodingUTF-8?中的encoding值是否与文件真实编码一致。解决Notepad中“编码” → “转为UTF-8无BOM格式”或用Java代码预处理String dxl Files.readString(Paths.get(form.dxl), StandardCharsets.UTF_8); dxl dxl.replaceFirst(^\\ufeff, ); // 移除BOM Database db session.getDatabase(, target.nsf); db.importDxl(dxl); // 此时不再报Invalid character4.4 现象Java代理中调用session.evaluate(DbLookup(...))返回空数组但Formula在Notes客户端中正常原因DbLookup在Java代理中运行于服务器上下文ThisDatabase指向代理所在NSF而非调用者NSF。解决显式指定数据库路径String[] result session.evaluate( DbLookup(\\; \server1!!app\\lookup.nsf\; \ViewName\; \key\; \Column\) );其中server1!!app\\lookup.nsf格式为服务器名!!数据库路径双反斜杠是Java字符串转义要求。5. Domino Web服务开发从Agent到Servlet的迁移路径与HTTP Header陷阱5.1 为什么Java Agent不够用当需要RESTful接口时Java Agent本质是定时/事件触发的批处理无法响应HTTP GET/POST请求。若需提供API给前端Vue应用调用必须转向Domino Servlet。但注意Domino 10.0.1默认Servlet容器是httpstack非Tomcat其Servlet API版本为2.5不支持WebServlet注解必须手动注册。5.2 创建Servletweb.xml Java类 Domino服务器配置三件套步骤1编写Servlet类必须继承javax.servlet.http.HttpServletpackage com.example.domino; import javax.servlet.http.*; import javax.servlet.*; import java.io.*; public class MailApiServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType(application/json;charsetUTF-8); PrintWriter out resp.getWriter(); out.print({\status\:\ok\,\count\:123}); out.flush(); } }步骤2配置web.xml放在NSF的WebContent\WEB-INF\web.xml?xml version1.0 encodingUTF-8? web-app xmlnshttp://java.sun.com/xml/ns/j2ee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd version2.4 servlet servlet-nameMailApi/servlet-name servlet-classcom.example.domino.MailApiServlet/servlet-class /servlet servlet-mapping servlet-nameMailApi/servlet-name url-pattern/api/mail/url-pattern /servlet-mapping /web-app步骤3Domino服务器启用HTTP Stack服务器文档 → “Internet Protocols” → “HTTP”页签 → 勾选“Enable HTTP protocol”在“Ports” → “Internet Ports”中确认HTTP端口默认80关键在notes.ini中添加HTTPEnableServlets1否则Servlet不加载。5.3 HTTP Header与CORSDomino默认禁用跨域前端拿不到响应Domino Servlet默认不返回Access-Control-Allow-Origin头Chrome会拦截响应。不能在Servlet中resp.setHeader(Access-Control-Allow-Origin, *)——httpstack会忽略。正确解法在NSF的WebConfig文档中配置创建一个Design Element → “Web Configuration”在“HTTP Response Headers”区域添加Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,POST,OPTIONS Access-Control-Allow-Headers: Content-Type保存后所有该NSF下的Servlet自动获得这些Header。提示生产环境请将*替换为具体域名如https://vue-app.example.com避免安全风险。6. 生产环境避坑清单权限、日志、升级三道生死线6.1 权限链断裂从代理签名到服务器ACL的七层校验Domino Java代理执行失败80%源于权限链断裂。这条链共7环缺一不可层级校验点失败现象检查命令/路径1. 代理签名代理属性中“Signer”字段是否为有效IDConsole报“Security exception”Designer中右键代理 → Properties → Security2. 签名者ACL签名者在目标NSF的ACL中权限≥Managersession.getDatabase()返回nullNSF右键 → Properties → Access Control → 查签名者权限3. 服务器ACL签名者在names.nsf中被授予“Server Access”代理完全不触发names.nsf→ “People”视图 → 找签名者 → 检查“Server Access”字段4. 服务器文档服务器文档中“Security”页签启用“Run unrestricted agents”Console报“Operation not allowed”Domino Administrator → 服务器文档 → Security页签5. notes.ininotes.ini中JAVA_POLICY_ENABLED1且JAVA_SECURITY_POLICY_FILE指向有效policy文件Java安全异常show config JAVA_POLICY_ENABLED6. JVM参数-Djava.security.manager未被意外启用代理启动即退出show config JavaOptions确认无-Djava.security.manager7. 操作系统Windows服务以“Local System”而非普通用户运行文件IO失败Windows服务管理器 → Domino服务 → “Log On”页签 → 确认为“Local System”血泪经验每次升级Domino后必须重走这7步。曾因第5步JAVA_POLICY_ENABLED被自动设为0导致所有Java代理静默失败排查耗时3天。6.2 日志黑洞Console、log.nsf、stdout三地日志的取舍策略Domino日志分散在三处新手常混淆Console日志show log实时、轻量、仅存内存重启即清空。只用于调试阶段快速验证逻辑通路log.nsf日志session.writeLog()持久化、带时间戳、可归档但I/O开销大。仅用于记录关键事务如“归档完成123封邮件”stdout重定向文件notes.ini中CONSOLE_LOG_FILEpath\console.log全量、无过滤、占磁盘。仅在疑难问题时开启日常关闭。我的习惯开发期System.out.println()打点 →show log盯屏上线前删掉所有System.out改用session.writeLog(INFO: Archive started)线上告警配置log.nsf的“Log Events”视图设置“Error”级别邮件通知。6.3 升级雷区Domino 10.0.1 → 11.0.1的四个不兼容点2023年有客户强行升级到11.0.1结果所有Java代理崩溃。实测四大不兼容问题点Domino 10.0.1行为Domino 11.0.1变化应对方案Session.createDateTime()返回DateTime对象timeValue方法正常返回DateTime但timeValue抛NullPointerException改用toJavaDate().getTime()Document.getItemValueString(Field)字段不存在时返回空字符串字段不存在时抛NoSuchElementException调用前先doc.hasItem(Field)Database.openByReplicaID()支持作为服务器名参数必须传真实服务器名被拒绝用session.getServerName()动态获取AgentBase.getSession()返回FullAdmin Session返回受限Session需显式session.asSigner()在代理开头加session session.asSigner()从那以后我每次升级Domino前都强制走一遍这四条兼容性测试用例哪怕只是小版本号变动。希望帮到你。本文还有配套的精品资源点击获取
返回列表