Ecology短信接入通用方案:中间表解耦供应商,实现灵活切换

发布时间:2026/10/17 1:35:32
Ecology短信接入通用方案:中间表解耦供应商,实现灵活切换
简介Ecology通用短信接口实现是一份面向泛微Ecology系统开发者的接口集成说明文档重点讲解基于中间表模式的短信发送方案。该方案由Ecology仅负责将待发送的短信写入中间表短信设备供应商或客户自行从中间表取数发送从而避免与不同厂商逐一对接。文档详细列出了sms.xml中的关键配置项包括数据库类型、服务器IP、端口、数据库名、账号密码及插入中间表的SQL语句并对SQL Server与Oracle的差异、必填字段等注意事项作出提示。资源为单份doc文档压缩包大小38KB内容精炼适合需要快速实现短信集成的Ecology实施或二次开发人员参考。目前已有436人学习下载文档还附带了建表SQL脚本示例与配置文件修改方法可帮助读者直接落地中间表结构并完成接口启用减少集成过程中的踩坑成本也便于在现有项目中进行扩展和二次定制。1. 用中间表解耦短信供应商Ecology 短信接入的通用做法Ecology 短信接入做得多了就会发现短信发不出去通常不是通道问题而是对接方式的问题。每家短信设备供应商的接口协议都不一样有的给 HTTP 推送地址、有的只认数据库中间表、还有的必须走专用 SDK如果每接一家都要写一套集成代码项目周期根本扛不住。这份方案给的是一个更务实的设计Ecology 只负责把短信内容和接收人写进一张中间表后续的发送动作由短信设备供应商或客户自己完成。只要数据库能连上、表里有接收人手机号和短信内容两个字段就能把流程短信发出去。适合正在给 OA 系统做短信提醒、又不想被某一家供应商绑死的实施和开发人员。2. 中间表机制Ecology 为什么只“写”短信不“发”短信2.1 三种短信接入方式的对比与选型依据实际做 OA 短信集成时绕不开三种路径。第一种是直连供应商接口Ecology 通过 HTTP 或 WebService 把短信内容推给供应商平台实时性最好但问题也很明显每家供应商的协议格式、鉴权方式、返回码都不一样代码里每对接一家就要写一套适配层换供应商意味着重写一遍。第二种是中间表方案Ecology 把短信数据写入数据库的某张表供应商的程序定时扫描这张表把数据读走后调用短信网关发送。第三种是自研发送类开发人员实现系统提供的短信发送接口完全自己控制发送逻辑。这三种方式各有适用场景对照下来会清晰很多接入方式实时性与供应商耦合度技术门槛适用场景直连供应商接口高高需要按供应商协议开发适配层长期绑定一家供应商且接口稳定数据库中间表中低会写 SQL、能改配置文件即可供应商多、设备杂、可能频繁更换自研发送类高极高必须 Java 开发并部署到系统有专职开发有特殊发送或回执需求选中间表方案本质上是买一个“后悔药”。今天这家供应商报价高明天那家通道不稳定如果代码里写死了调用逻辑每一次切换都是一次开发周期。中间表的好处是 Ecology 侧完全不感知对方是谁只要数据落进表里剩下的由供应商扫表解决。我接触过的大多数短信设备供应商确实都已经实现了中间表发送方式这也是这套接口能通用起来的现实基础。2.2 中间表方案的完整数据流与两个硬性前提这套机制跑起来之后数据流是这样的流程节点触发短信动作Ecology 读取 sms.xml 里配置的插入 SQL通过 JDBC 把接收人、短信内容等参数写入中间表供应商的定时程序扫描到新数据后调用短信网关发送完成后在表里回写状态如果供应商做了这个功能。整个链路里Ecology 只参与“写中间表”这一步发送成功与否、失败重推多少次都不归系统管这是中间表方案和直连接口最本质的区别。提示中间表方案的实时性取决于供应商扫表的频率。扫表间隔 30 秒和扫表间隔 5 分钟用户体验完全是两回事。选型前先问清楚供应商的轮询周期免得上线后短信延迟被业务方追着问。但这份方案有两个硬性前提原文里写得很明确。第一中间表所在数据库必须用 SQL Server 或 Oracle其他数据库暂时不支持。原因是 sms.xml 里 type 属性只有 sqlserver 和 oracle 两个取值JDBC 驱动和 SQL 方言都是按这两个库适配的换 MySQL 或 PostgreSQL 需要额外改类实现。第二中间表至少要有两个字段一个存接收人手机号一个存短信内容。至于发送时间、紧急程度、是否中文、发送人这些字段可以通过 SQL 写死也可以由数据库函数生成不是必备项。理解了这两个前提再看配置和建表脚本就不会觉得有什么玄学成分了。3. sms.xml 七参数配置SQL Server 与 Oracle 两套改法3.1 配置文件位置与七参数逐项拆解配置文件位于 ecology/WEB-INF/service/sms.xml。这个文件决定了 Ecology 把短信写到哪个库、哪张表、用什么样的 SQL 插入。默认内容是一个完整的模块声明核心在 construct 这一段module idsms version1.0.0 service-point idsmssender interfaceweaver.sms.SmsService invoke-factory construct classweaver.sms.JdbcSmsService set propertytype valuesqlserver/ set propertyhost value192.168.0.204/ set propertyport value1433/ set propertydbname valueecology3802/ set propertyusername valuesa/ set propertypassword value123/ set propertysql valueinsert into OutBox(ReceiverMobileNo,Msg,SendTime,IsChinese,ExpressLevel,Sender) values(?,?,getDate(),1,1,1)/ /construct /invoke-factory /service-point /moduleconstruct 的 class 是 weaver.sms.JdbcSmsService这也就是“通用接口”的默认实现它负责把配置里的数据库连接参数拼成 JDBC 连接把 sql 属性里的语句拿出来执行再把运行时传入的手机号和短信内容填进占位符。七个 set property 就是全部需要关心的参数逐一拆解如下属性作用SQL Server 示例Oracle 示例type中间表所在数据库类型sqlserveroraclehost数据库服务器 IP192.168.0.204192.168.0.204port数据库端口14331521dbname数据库名ecology3802weaver1username数据库账号saecology40002password数据库密码123ecologysql往中间表插入数据的语句insert into OutBox...insert into OutBox...前六个参数和 weaver.properties 里的数据库配置逻辑一致照着中间表所在库的实际信息填就行这里不展开。3.2 插入 SQL 里占位符与写死值的关系sql 属性是整个配置里最需要理解的部分。看这条语句insert into OutBox(ReceiverMobileNo,Msg,SendTime,IsChinese,ExpressLevel,Sender) values(?,?,getDate(),1,1,1)。ReceiverMobileNo 是接收人手机号Msg 是短信内容这两个字段的值不是配置文件里写死的而是由接口运行时从 Ecology 流程数据里取出来填充的所以用问号做占位符。注意占位符的顺序第一个问号对应接收人第二个问号对应短信内容不能颠倒否则短信会发给一串数字、内容变成手机号。SendTime 用 SQL Server 自带的 getDate() 函数取系统当前时间IsChinese 置 1 表示短信内容是中文ExpressLevel 置 1 表示普通优先级Sender 写 1 是发送人编号。后三个字段的值系统并不关心供应商通常也不会按这些字段做逻辑判断写死 1 完全够用。从这套设计里能提炼出一个通用规律中间表里真正有意义的只有“接收人”和“短信内容”两个字段其他字段要么是数据库自动生成要么是给供应商程序做扩展用的。如果你的供应商要求必须填某个特定字段比如需要填业务类型或签名编号只需要在 sql 语句里把对应的写死值改成供应商要求的固定值即可。3.3 切换短信通道关闭 RTX 通道的一行配置配置完 sms.xml 还不够还要处理短信通道的切换。Ecology 默认走 RTX 通道也就是内部即时通讯工具的短信能力如果用默认配置短信根本不会进中间表。打开 ecology/WEB-INF/prop/weaver_rtx.properties找到 CurSmsServer 这一行#config file #Fri Aug 13 11:30:56 CST 2004 IsInitRTXOrgtrue IsDownLineNotifytrue #CurSmsServerrtx CurSmsServerIsValidtrue RTXServerPort8036 RTXServerIP RTXServerOutIP只要把CurSmsServerrtx用 # 注释掉系统就会跳过 RTX 通道把短信请求转给 sms.xml 里配置的 JdbcSmsService 处理也就是走中间表方案。IsInitRTXOrg 和 IsDownLineNotify 是组织架构同步和下线通知的开关和短信通道无关保持原样即可。RTXServerPort、RTXServerIP 这些参数也可以不动因为它们只在 RTX 通道启用时才会被读取。4. 建中间表的两份脚本从表结构到主键生成4.1 SQL Server 版 outbox 建表脚本原文给了一份可直接落地的 SQL Server 建表脚本适用于大部分客户的中间表场景CREATE TABLE outbox ( ID int IDENTITY (1, 1), ExpressLevel int, Sender varchar (50), ReceiverMobileNo varchar (50), Msg varchar (500), SendTime datetime, IsChinese bit )表名 outbox字段含义按顺序解释ID 是自增主键IDENTITY(1,1) 表示从 1 开始每次加 1不需要手动维护主键值ExpressLevel 是紧急程度int 类型Sender 是发送人编号varchar(50)ReceiverMobileNo 是接收人手机号varchar(50)Msg 是短信内容varchar(500)SendTime 是发送时间datetime 类型IsChinese 用 bit 类型表示是否中文1 为中文0 为非中文。这个表设计里有个容易被忽略的点发送时间字段。它使用的是 SQL Server 的 datetime 类型而客户端插入时用的是 getDate() 函数两者是匹配的。如果你要在字段上加默认约束也可以写成SendTime datetime default getdate()效果类似但 sms.xml 里的 SQL 已经显式写入了 SendTime 的值所以表结构上不加默认约束也不影响运行。ReceiverMobileNo 设成 varchar(50) 看起来空间浪费实际是给国际号码和带区号的号码留了余地不建议收紧到 11 位。4.2 Oracle 版建表脚本序列与触发器缺一不可Oracle 和 SQL Server 在自增主键的处理上差别很大Oracle 没有 IDENTITY 自增列主键值要靠序列加触发器配合生成。对应的建表脚本要分三段看create table OUTBOX( ID NUMBER not null, EXPRESSLEVEL NUMBER, SENDER VARCHAR2(50), RECEIVERMOBILENO VARCHAR2(50) not null, MSG VARCHAR2(500), SENDTIME DATE not null, ISCHINESE NUMBER not null ); create sequence OUTBOX_ID_SEQ minvalue 1 maxvalue 999999999 start with 141 increment by 1 cache 20; CREATE OR REPLACE TRIGGER SET_OUTBOX_ID BEFORE INSERT ON OUTBOX FOR EACH ROW DECLARE NEXT_OUTBOX_ID NUMBER; BEGIN SELECT OUTBOX_ID_SEQ.NEXTVAL INTO NEXT_OUTBOX_ID FROM DUAL; :NEW.ID : NEXT_OUTBOX_ID; END;表结构部分是常规的 Oracle 建表语法唯一要注意的是 ISCHINESE 和 EXPRESSLEVEL 用了 NUMBER 而不是像 SQL Server 那样的 bit。序列段的 start with 141 是给已有历史数据准备的如果之前的表里已经插到 ID 140序列要从 141 开始避免主键冲突。触发器是整段脚本的关键它在每次 INSERT 前执行从序列取下一个值赋给 :NEW.ID这样 insert 语句里就不需要显式写 ID 字段了。Oracle 下对应的 sms.xml 配置也要跟着变主要是端口和 SQL 方言module idsms version1.0.0 service-point idsmssender interfaceweaver.sms.SmsService invoke-factory construct classweaver.sms.JdbcSmsService set propertytype valueoracle/ set propertyhost value192.168.0.204/ set propertyport value1521/ set propertydbname valueweaver1/ set propertyusername valueecology40002/ set propertypassword valueecology/ set propertysql valueinsert into OutBox(ReceiverMobileNo,Msg,SendTime,IsChinese,ExpressLevel,Sender) values(?,?,(select sysdate from dual),1,1,1)/ /construct /invoke-factory /service-point /moduletype 改成 oracle端口从 1433 改成 1521。SQL 语句里最典型的变化是取当前时间的方式SQL Server 用 getDate()Oracle 用(select sysdate from dual)这是两个数据库方言在日期处理上的核心差异。另外注意 Sender 的值从 1 变成了 1因为 Oracle 对隐式类型转换更严格字符串字段的赋值最好显式加引号防止类型转换报错。4.3 中间表字段设计的几个容易被忽略的细节建表的时候有三个细节建议提前想清楚。第一Msg 字段的 500 长度看起来够用但如果业务方要求短信内容里拼接审批链接或表单摘要500 字符在极端情况下是不够的建议直接给 varchar(1000) 或更大反正中间表只做暂存不会长期占用空间。第二如果客户希望短信内容前自动带签名比如“【XX公司】”不要把签名拼进 Ecology 流程里的短信模板直接在插入 SQL 里拼接字符串更稳妥因为模板是配置在流程节点的改动会影响所有流程而 SQL 只影响短信发送这一个环节。第三Oracle 的 OUTBOX 表建议把 RECEIVERMOBILENO 和 SENDTIME 设成 not null原因不是业务必须而是供应商扫表程序如果读到空手机号或空时间的记录容易直接报错退出影响后面的正常数据发送。5. 避坑指南短信没发出去的五个常见原因中间表方案上线后出的问题绝大多数不是接口本身的逻辑而是配置和数据库层面的细节。我按实际排查频率整理了五个最容易翻车的点每条按现象、原因、解决的顺序写清楚。5.1 配好 sms.xml 后短信根本没进中间表现象流程审批完了短信没发出去打开中间表一看一条记录都没有。日志里也看不到任何短信发送相关的报错。原因weaver_rtx.properties 里的CurSmsServerrtx没有注释掉。系统仍然认为短信通道是 RTX请求根本不会到达 JdbcSmsService中间表自然没有数据。这是先例最多的一种情况因为很多人只改了 sms.xml忽略了第二个配置文件。解决打开 ecology/WEB-INF/prop/weaver_rtx.properties在 CurSmsServer 行前面加 # 注释保存后重启 OA 服务。重启后确认 CurSmsServerIsValidtrue再用测试流程发一条短信看中间表是否有数据。5.2 Oracle 下插入报错SQL 方言没切换干净现象type 和 port 都改成 Oracle 了但发短信时系统日志报 SQL 执行异常错误码通常是 ORA-00904 或 ORA-00933。原因sql 属性还是 SQL Server 的写法常见的有两种一是用 getDate()Oracle 不认二是用 1 给 Sender 字段赋值而 Sender 是 varchar2 类型Oracle 隐式转换失败。解决把 SQL 改成values(?,?,(select sysdate from dual),1,1,1)Sender 字段的 1 加引号时间函数换成sysdate from dual。改完先拿数据库客户端手工执行一遍这条 insert确认能插入成功再重启服务。5.3 主键冲突中间表数据写不进去现象中间表里已经有数据但新短信记录插不进去日志报主键重复或唯一约束被违反。原因Oracle 表建好了但序列和触发器没有执行或者序列的起始值小于表里已有数据的最大 ID。比如表里最大 ID 已经是 150序列却 start with 141下次取到的值就是 141直接撞上已有记录。解决重新执行序列脚本把 start with 改成当前表最大 ID 加 1可以用select max(id)1 from OUTBOX查出来再改。触发器也要确认存在可以用select trigger_name from user_triggers where table_nameOUTBOX检查。SQL Server 那边因为用的是 IDENTITY 自增基本不存在这个问题。5.4 修改 sms.xml 后新配置不生效现象改了 sql 语句甚至把表名和字段名都换成客户的新中间表了但实际发送时系统还在往旧表里插数据。原因服务没有重启配置被缓存在运行内存中。sms.xml 属于 service 配置很多版本的 Ecology 不会热加载这类文件必须重启进程才能重新解析。解决改完 sms.xml 后完整重启 OA 应用服务而不是只刷新浏览器页面。另外确认改的是正确的文件路径ecology/WEB-INF/service/sms.xml注意是 service 目录不是 services这两个目录拼写接近容易找错。5.5 中文短信变乱码供应商收到的是乱字符现象中间表里查记录Msg 显示中文完全正常但手机上收到的短信内容是一串乱码。原因IsChinese 字段被置成了 0。供应商的扫表程序通常按这个字段决定短信编码方式1 按中文编码发送0 按纯英文或 ASCII 编码发送。中文内容走了英文字符集就会在网关侧编码错乱。解决确认插入 SQL 里 IsChinese 对应的位置写的是 1。同时检查中间表数据库的字符集Oracle 推荐用 AL32UTF8SQL Server 用 Chinese_PRC_CI_AS 这类中文排序规则字符集不匹配也会导致写入后乱码。还有一个隐蔽点有些扫表程序不看 IsChinese而是自动检测内容里有没有中文字符这种情况下 Msg 字段的 varchar2 类型如果长度按字节算500 字节可能存不下 500 个汉字需要按字符算或加大长度。6. 进阶玩法自研发送类与实时性验证6.1 实现 SmsService 接口并用 sms.xml 完成切换中间表方案的短板是实时性供应商定时扫表短信发送时间取决于扫描频率。如果客户对实时性要求高或者中间表方案压根不适合现场网络环境还有另一条路自己写一个 Java 发送类实现系统开放的短信接口。接口定义很简单只有一个方法public interface SmsService { public boolean sendSMS(String smsId, String number, String msg); }smsId 是系统内部生成的短信标识number 是接收人手机号msg 是短信内容。实现这个接口后Ecology 发送短信时会直接调用这个方法不再经过数据库中间表。一个最简实现public class TestService implements SmsService { public boolean sendSMS(String smsId, String number, String msg) { System.out.println(接受人 number); System.out.println(测试短信 msg); return true; } }这个方法把接收人和短信内容打印到控制台直接返回 true 表示发送成功。实际项目中这里应该换成调用供应商 HTTP 接口的逻辑或者接入某个短信网关的 SDK。部署时把编译好的 class 文件放到 ecology/WEB-INF/classes 目录如果带包名就按包路径放然后把 sms.xml 改成引用这个类module idsms version1.0.0 service-point idsmssender interfaceweaver.sms.SmsService invoke-factory construct classTestService /construct /invoke-factory /service-point /module注意这里 construct class 从 weaver.sms.JdbcSmsService 换成了自己的 TestService这行改动表示系统将绕过 JDBC 中间表逻辑直接调用自定义发送逻辑。6.2 验证接口生效的两种做法自研类部署完验证是否生效有个很实用的技巧先不要接真实短信网关用一个只写日志的测试类跑一遍。第一种做法是上面这个控制台打印版本但要注意如果服务不是前台启动System.out.println 的输出会被重定向到日志文件查的时候要找对文件。第二种做法更稳妥在 sendSMS 方法里把参数写进一张调试表public boolean sendSMS(String smsId, String number, String msg) { Connection conn DriverManager.getConnection(url, user, password); PreparedStatement ps conn.prepareStatement(insert into sms_debug(sms_id, mobile, msg) values(?,?,?)); ps.setString(1, smsId); ps.setString(2, number); ps.setString(3, msg); ps.executeUpdate(); return true; }然后去系统里随便找一个有短信通知的流程走一遍提交动作看调试表里有没有数据。有数据说明接口已被正确调用没数据检查 sms.xml 的 class 名是否写错、类是否在 classpath 里、以及 RTX 通道有没有被注释掉。我以前接过一个客户项目中间表建了、供应商扫表也正常手机就是收不到短信最后查出来扫表程序把 IsChinese 读成了 0中文内容全被当成英文去编码整个排查过程绕了一大圈。从那以后我每次配通用短信接口都强制先走一遍“注释 RTX 通道——确认中间表字段——发测试短信——查发送日志”四步流程不跳步不靠猜。这套流程能帮你把最耗时的“通道问题”和“编码问题”拦在早期希望帮到你。本文还有配套的精品资源点击获取