泛微Ecology短信接口中间表配置:从SQL Server到Oracle的落地指南
简介面向泛微Ecology系统的开发与实施人员提供一份关于通用短信接口实现方式及使用说明的doc文档。接口设计基于中间表理念由Ecology只负责把待发送短信数据写入中间表再由短信设备供应商或客户自行读取发送从而免去与每家短信设备厂商逐一对接集成。文档围绕sms.xml配置展开逐一说明数据库类型、服务器IP、端口、数据库名、账号密码以及往中间表插入数据的SQL语句等参数的设置方法并强调目前只支持sqlserver与oracle两种数据库中间表至少需包含短信内容和接收人字段同时说明了如何通过注释weaver_rtx.properties中的CurSmsServer参数切换短信发送设备。资源共1个文件格式为doc压缩包大小38KB小巧易用。已有436人学习浏览适合需要为Ecology快速接入短信发送能力的开发者参考文档还提供了sqlserver与oracle建表脚本示例可直接参照落地显著降低集成复杂度、提升系统可靠性。1. 中间表这个思路把短信设备对接变成一条 SQL 的事第一次接 OA 短信集成的人十个里有九个先去找短信供应商要 SDK 和开发文档签完协议等对方排期。Ecology 的通用短信接口完全不走这条路它把「发短信」简化成往数据库中间表插一行数据短信设备供应商定时扫这张表把消息发出去Ecology 这边只需要保证 INSERT 语句正确。这套思路在 Ecology 配套资料里很早就有了原理到现在也没变但对新人来说坑不少数据库类型不支持 MySQL、表字段对不上、SQL Server 和 Oracle 的函数混用短信可能一条都发不出去系统日志却毫无异常。这篇笔记按「先看清环境、再改配置、最后验证」的顺序把 Ecology 通用短信接口的落地步骤拆开讲适合正在做 OA 短信对接的部署工程师照着一路敲完。2. 装之前先看清环境Ecology 短信接口只认 SQL Server 和 Oracle2.1 数据库只认 SQL Server 和 Oracle别在 MySQL 上浪费时间Ecology 通用短信接口的第一个硬性前提写在最前面中间表所在的数据库必须是 SQL Server 或 Oracle其他数据库暂时不支持。这句话来自原接口说明的第一条注意事项很多现场踩的第一个坑就在这——手头只有一套 MySQL想着把表建进去让接口跑起来结果 JdbcSmsService 的数据库方言都对不上连接阶段就失败。我一般会先确认现场数据库类型再看中间表打算建在哪个库建在 Ecology 自己的业务库里最省事不用新开数据库实例要求隔离时也可以单独建一个短信中转库只要把 IP、端口、库名配到 sms.xml 里就行。为什么这条限制这么死看配置就明白了sms.xml 里的 type 字段只有两个可选值sqlserver 和 oracle。接口往中间表插入数据用的 SQL 里发送时间是由数据库函数生成的SQL Server 用 getDate()Oracle 用 sysdate这两个函数不能互换。也就是说接口根本不关心发短信的设备长什么样但它依赖的数据库方言是固定的。确认类型的办法很简单看 ecology 的 weaver.properties 数据库连接配置或者直接问 DBA 要一个权限最小的账号。注意别上来就用 sa 和默认口令跑生产原文档示例里的 sa/123 只适合本地开发演示正式环境一定要先改掉。提示中间表也可以不建在 Ecology 业务库里单独建一个短信中转库会更干净前提是 sms.xml 里的 host、port、dbname 指向那个库。2.2 中间表最少有两个字段接收人手机号和短信内容原文档对中间表结构提了两点要求必须存放短信内容、必须存放短信接收人。除此之外表名、字段名、字段数量统统不限制因为往中间表插数据的 SQL 是写在配置里的表叫 OutBox 还是 someTable 都行接收人字段叫 ReceiverMobileNo 还是 MobileNo 也无所谓。示例里的 OutBox 表一共有六个字段ReceiverMobileNo 接收人、Msg 短信内容、SendTime 发送时间、IsChinese 是否中文、ExpressLevel 紧急程度、Sender 发送人。真正被接口用到的只有前两个其余字段可以由 SQL 写死固定值。有一个细节值得先说清楚接口要求中间表「必须有字段」但字段类型也是自己定的。接收人字段建议 varchar(20) 起步短信内容字段至少要能放下一条完整短信示例里用的 varchar(500) 很宽裕。如果你拿到的是供应商建好的表字段名和示例不一样也没关系只要改配置里的 INSERT SQL 去匹配对方的字段名即可。怕的是两种表混着抄表按 OutBox 建了SQL 却写的 someTable那结果就是插不进去日志里连个正经报错都没有。那为什么接口只认这两个字段因为短信对接的差异全在设备侧有的设备走 HTTP 调用有的走 socket有的只认数据库。Ecology 把差异全部抹平只保留「发给谁、发什么」这两个公共要素剩下的交给供应商去扫表。这个设计也让后续维护变得简单换短信供应商不用改 ecology 代码只要改 sms.xml 里的连接参数表结构兼容的情况下连 SQL 都不用动。2.3 先找到 sms.xml配置文件的位置和备份配置入口是 ecology/WEB-INF/service/sms.xml。注意目录名别搞错是 WEB-INF 下的 service 目录不是 WEB-INF/classes我见过有人在这上面找了一下午。Windows 服务器直接进 ecology 安装目录找Linux 上不确定路径时用 find 搜一下。cd /opt/ecology/WEB-INF/service ls -l sms.xml cp sms.xml sms.xml.bak.$(date %Y%m%d)备份文件带日期改坏了能快速还原。改任何 Spring service 配置之前先备份是我个人的习惯sms.xml 这种文件一旦改错短信模块可能直接拒绝加载重启后比不重启更难排查。另外如果服务器上部署了多个 ecology 实例改配置前先用 find / -name sms.xml 把每个实例的路径都列出来确认改的是当前在跑的那一个。顺手把 weaver_rtx.properties 也一起备份这两个文件经常要联动修改恢复的时候也能成对还原。3. 配置 sms.xml七个数据库参数和一段插入 SQL 怎么填3.1 七个 set 参数逐一拆解type、host、port、dbname、username、password、sqlsms.xml 的结构很简洁一个 module 包着一个 service-point再往下一层是 construct。只要把 construct 指定为 weaver.sms.JdbcSmsService并给它配上一组数据库属性和一条 SQL中间表方案就算是激活了。先把 SQL Server 版本的完整配置贴出来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 /moduletype 指定数据库类型只写 sqlserver 或 oracle写成其他值 JdbcSmsService 不会认。host 是中间表所在数据库服务器的 IP注意填的是数据库地址不是短信设备地址很多人第一次配会填反。port 默认也很固定SQL Server 是 1433Oracle 是 1521如果 DBA 改了实例端口照实际填。dbname 是数据库名SQL Server 里对应库名Oracle 里对应服务名或 SID和 weaver.properties 里的库参数含义差不多抄过去基本不会错。username 和 password 就是连接中间表库用的账号密码原文档给的 sa/123 是演示值。生产配置我一般会单独建一个账号只授权 INSERT防止短信模块被注入后拿到过大的数据库权限。密码如果包含特殊字符注意 XML 转义 要写成 小于号要写成 。后面那条 sql 属性是整个文件最长的字符串它被双引号包起来内部不能再出现双引号SQL 里的字符串字面量统一用单引号。注意sql 属性里的整条 INSERT 是在 XML 属性中语句内部不能再用双引号否则 XML 解析直接失败重启时容器会报错。3.2 插入 SQL 的 ? 占位规则只有接收人和内容是系统填的sql 属性是这套接口的核心原文档里的示例是insert into OutBox(ReceiverMobileNo,Msg,SendTime,IsChinese,ExpressLevel,Sender) values(?,?,getDate(),1,1,1)里面两个问号分别代表接收人手机号和短信内容。Ecology 每次要发短信时会调 JdbcSmsService 把这两个值按顺序填到问号里然后执行这条 SQL。也就是说问号的位置就等于字段的位置第一个问号进 ReceiverMobileNo第二个进 Msg。如果把 SQL 写成 values(?,?,...) 但表里第一列是 Msg、第二列是手机号短信内容就被塞进手机号字段供应商扫描出去就是一条垃圾短信而且数据库不报错。这类错最隐蔽我排查过不止一次。其他字段的处理策略很简单不关心的全部写死。IsChinese 写 1 表示中文内容ExpressLevel 写 1 表示普通优先级Sender 写 1 表示一个发送人编号。不同供应商对这几个字段的语义要求不一样接收人、内容必须来自接口其余按供应商要求调整即可。原文档特意强调最简单的中间表可以只有 MobileNo 和 messageBody 两列那 SQL 就短了insert into someTable(MobileNo, messageBody) values(?,?)这种极简结构也完全能跑因为接口不关心表里有没有其他列只要 INSERT 语句和表结构匹配就行。3.3 SQL Server 与 Oracle 的 SQL 写法差异如果中间表在 Oracle 里整个 sms.xml 的配置基本不变只有三处要动type 改成 oracle、port 改成 1521、SQL 里的 getDate() 改成 (select sysdate from dual)。注意不是直接写 sysdate 就完事Oracle 里从函数取值需要带 dual 表所以完整的写法是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 /module注意 Sender 的取值从 1 变成了带有单引号的 1因为原文档给出的 Oracle 表里 SENDER 是 VARCHAR2(50)字符串类型必须引起来。SQL Server 表里 Sender 是 varchar(50)写成 1 会被隐式转换两种写法都能跑但两条 SQL 放到一起看差异就很明显项目SQL ServerOracletype 值sqlserveroracle默认端口14331521发送时间函数getDate()(select sysdate from dual)IsChinese 类型bitnumber主键方案IDENTITY 自增序列 触发器切换数据库时最容易翻车的就是只改 type 忘了改 SQLgetDate() 直接丢到 Oracle 里执行数据库会报函数不存在。这类错好在会报错比静默失败好排查但也会耗费你十分钟去对照两个版本的区别提前把这张表存下来能省不少事。4. 建中间表与切换通道SQL Server 和 Oracle 两套脚本对照4.1 SQL Server 建表脚本IDENTITY 自增方案原文档直接给了两个建表脚本省得自己设计字段。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 );ID 列用 IDENTITY(1,1) 自增接口插入时不写 ID数据库自动分配省掉主键取值逻辑。ReceiverMobileNo 是接收人手机号给 varchar(50) 很够用Msg 是短信内容varchar(500) 对单条短信来说很宽裕供应商如果支持长短信拼接这个长度可以再调。SendTime 是 datetime配合配置里的 getDate() 使用。IsChinese 是 bit 类型写 1 表示中文。这套表结构参考原文档实际用的时候也可以加自己的字段。比如加一个 STATUS 字段标记短信发送状态供应商每发一条就 update 一下便于对账——这不在接口要求里但很多现场会自己补。需要注意的是接口 SQL 是显式列出字段名的所以表里字段物理顺序无所谓但如果有人图省事写 values(?,?) 不写字段名列表那就会依赖物理顺序建表时字段顺序就变重要了。4.2 Oracle 建表、序列、触发器没有自增就自己造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;为什么必须三件套一起建因为 OUTBOX 表的 ID 是 NOT NULL接口的 INSERT 语句又没有写 ID 列所以必须有一个默认值来源序列负责生成递增数字触发器负责在每次 INSERT 前把序列值塞进 :NEW.ID。缺了哪个插入都会因为 ID 为空报错。序列 START WITH 141 是原文档按客户现场已有数据定的起点新环境建表可以直接 START WITH 1或者从大于当前 MAX(ID) 的值开始否则主键会冲突。触发器和序列最好用有建表权限的账号执行执行完可以手动插入一条测试数据验证自增逻辑。如果触发器建失败检查一下有没有同名的触发器已经存在Oracle 里同名触发器会直接报错。4.3 切换短信通道注释掉 CurSmsServerrtxsms.xml 配好只是第一步还要看一下 ecology/WEB-INF/prop/weaver_rtx.properties。这个文件原本可能打开了 RTX 短信通道如果不关Ecology 在发短信时可能优先走 RTX 逻辑导致中间表方式没生效。原文档给的改法只有一步把 CurSmsServerrtx 注释掉。#config file IsInitRTXOrgtrue IsDownLineNotifytrue #CurSmsServerrtx CurSmsServerIsValidtrue RTXServerPort8036 RTXServerIP RTXServerOutIPCurSmsServer 参数用来指定当前短信发送设备注释掉之后短信服务就不再绑定 RTX 通道转而走 sms.xml 里配置的 JdbcSmsService。其余配置保持原样RTXServerIP 本来就是空值不用填。有两个点容易踩一是有人顺手把 CurSmsServerIsValidtrue 改成 false想用这种办法禁用 RTX结果反而触发服务有效性校验失败二是 properties 文件只认 # 注释不认 //写错的话整个文件解析都可能出问题。改完这个文件不需要重启数据库但必须重启应用服务器让配置重新加载。5. 常见问题与排查短信没发出去时先查这四样5.1 配置都改了短信一条不发日志还没报错现象sms.xml 和 weaver_rtx.properties 都按文档改了重启也做了OA 里触发短信提醒结果供应商那边一条没收到ecology 日志里也找不到异常。原因中间表里可能压根没有新数据或者数据插到了别的库。接口用 JdbcSmsService 执行 INSERT如果连接到了错误的数据库实例、错误的库名插入自然落空。还有一种常见情况多个 ecology 实例部署在同一台机器上你改的 sms.xml 不是当前在跑的那个。解决先把 sms.xml 里的 host、port、dbname 拿到数据库客户端手动连一遍确认库存在、账号能登录再用后面的 SELECT 查中间表有数据说明接口到表这段通没数据就去查应用日志里有没有 SQLException。用数据库客户端连的时候记得用配置里同一个账号测不要把 sa 的权限当成业务账号的权限。5.2 报 SQL 语法错误或者 ORA-00900现象重启后第一次发短信应用日志直接抛 SQL 语法错误Oracle 下常见 ORA-00900一看就知道数据库不认识这条 SQL。原因数据库是 Oracle但 sms.xml 里 SQL 还写着 getDate()或者 type 还是 sqlserverJdbcSmsService 用了错误的方言处理参数。SQL Server 的函数和 Oracle 的函数本来就是两套混用必报错。解决把 getDate() 改成 (select sysdate from dual)把 type 改成 oracle端口同步改成 1521。自查时可以先把配置里的 SQL 语句原样在数据库客户端里跑一遍参数 ? 用真实值替换能执行通过再放回配置。这一步能过滤掉绝大多数 SQL 层面的低级错误。5.3 短信发出去了但内容是一串乱码现象供应商收到了短信中文全部变成问号或乱码英文和数字正常。原因通常是 IsChinese 字段没有按中文置 1或者中间表所在数据库的字符集与内容编码对不上。IsChinese 是 bit/number 类型原文档在 SQL 里写死 1代表短信内容是中文如果配置里写的是 0部分供应商会把内容按纯 ASCII 处理中文自然坏掉。解决确认 SQL 里 IsChinese 的写死值是 1再检查数据库字符集Oracle 如果建库时用的不是 AL32UTF8建议把 Msg 字段的字符集也统一一下。SQL Server 端则要注意表字段的排序规则中文乱码大多数时候是字段字符集和接口写入的编码不一致导致的。5.4 短信能发但延迟到了分钟级现象中间表里有数据供应商也收到了但发送时间总是比触发时间晚好几分钟甚至更久。原因中间表方案的缺点就是这个——供应商通常定时扫描中间表扫描频度决定了发送延迟和 ecology 这边没关系。这是写死在供应商客户端里的逻辑不是改几个参数就能解决的。解决和供应商确认扫描间隔能否调短现场如果对实时性要求高可以看 5.5 节绕开中间表直接实现发送方法。做方案选型的时候就要想清楚中间表方式适合对实时性要求不高的业务比如流程到达通知、待办提醒不适合验证码、告警这类分钟级敏感的场景。5.5 实时性不能满足自己写 Java 实现 SmsService 接口原文档留了第二条路不通过中间表直接实现 weaver.sms.SmsService 接口Ecology 发短信时直接调用你的方法。接口只有一条方法public interface SmsService { public boolean sendSMS(String smsId, String number, String msg); }实现类怎么写原文档给了一个测试实现作用是把接收人和短信内容打到控制台public class TestService implements SmsService { public boolean sendSMS(String smsId, String number, String msg) { System.out.println(接受人 number); System.out.println(测试短信 msg); return true; } }编译成 class 文件后我一般放到 ecology/WEB-INF/classes 下确保它在应用 classpath 里然后把 sms.xml 的 construct 改成你自己的实现类module idsms version1.0.0 service-point idsmssender interfaceweaver.sms.SmsService invoke-factory construct classTestService /construct /invoke-factory /service-point /module这里有几个细节class 必须能提供无参构造器Spring 才会实例化方法签名要和接口完全一致包名、类名要写全限定名返回布尔值true 表示发送成功。这条路的实时性完全由自己控制代价是需要 Java 开发介入比配置中间表复杂不少适合短信供应商支持 HTTP 接口、或者你自己有发送通道的场景。如果只是临时模拟发送TestService 这种方式拿来验证链路非常方便。6. 装完怎么验证跑通查表、看日志、找供应商确认6.1 重启应用服务器是前提改完 sms.xml 和 weaver_rtx.properties配置不会热生效。sms.xml 属于 Spring service 配置文件必须重启应用服务器让 JdbcSmsService 重新加载。我一般会在重启前先检查一遍 XML 格式标签有没有闭合、property 有没有双引号格式错了容器启动时直接报解析异常这时候别急着查短信先把启动日志看完。6.2 从 OA 里触发一次真实发送重启完成后找一个绑定了短信提醒的流程节点或者测试功能发起一条真实的短信动作。注意别用数据库里手动执行 INSERT 代替那样只能验证表结构验证不了接口链路。触发后等一两分钟查中间表。SQL Server 用SELECT TOP 5 ID, ReceiverMobileNo, Msg, SendTime FROM OutBox ORDER BY ID DESC;Oracle 用SELECT ID, RECEIVERMOBILENO, MSG, SENDTIME FROM OUTBOX WHERE SENDTIME SYSDATE - 1 ORDER BY ID DESC;如果表里出现一条新记录且 Msg 内容跟你触发的内容一致说明「OA 到中间表」这一段是通的。接下来把这条 Msg 的接收号码发给短信供应商让他们确认是否收到。如果表里没数据去 ecology 的日志文件里搜 JdbcSmsService 或 SmsService 关键词多半能翻到具体的异常栈。6.3 验证完记得保留备份整个链路确认通了之后把配置改动前备份的 sms.xml.bak 保留一段时间再删。原因很现实短信通道线上跑一天没问题不代表后续没问题万一供应商调整对端表结构你还能对比最初的配置。从那以后我每次改 sms.xml 都强制走一遍「备份、重启、查表」三连改完不急着下班先确认中间表真的多了一行再让供应商确认收到短信。这套流程看起来多花十分钟但能挡住绝大多数「配置完没生效」的返工希望帮到你。本文还有配套的精品资源点击获取