欢迎进入Wiki » FAQ » 如何开发短信接口?

如何开发短信接口?

在2015-08-08 15:24上被李小翔修改
评论 (0) · 附件 (2) · 记录 · 信息

供稿人:刘少林

现在的越来越多的项目都有发送短信的需求,FWK 中内置有短信发送的功能模块,开发中需要根据短信提供商的接口或短信网关接口,实现相应的短信服务即可。

首先,在应用中新建一个新的 ShortMessageService 服务类,并继承 bropen.framework.plugins.message.ShortMessageService,模板如下:

import bropen.framework.plugins.message.ShortMessage
import bropen.framework.plugins.message.MessageStatus

/**
 * XXX 短信服务
 */

class ShortMessageService extends bropen.framework.plugins.message.ShortMessageService {
   static aliasOverridingOrder = bropen.framework.plugins.message.ShortMessageService.aliasOverridingOrder + 1

   static bootStrapInit() {
       // 一些初始化配置可以放到这里
   }
   
   @java.lang.Override
   protected MessageStatus send(ShortMessage sms) {
       // 调用短信接口,发送短信,并且返回状态
       ...
       return MessageStatus.SENT
   }
   
   @java.lang.Override
   protected ShortMessage bind(Map msg) {
       // 将一个 Map 转换为 ShortMessage 对象
   }
   
}

上面的模板中,bootStrapInit 方法用于初始化一些系统参数,如系统参数:

  • bropen.framework.plugins.message.sms.enabled:是否启用短信,默认为否
  • bropen.framework.plugins.message.sms.http.url:第三方短信服务的地址
  • bropen.framework.plugins.message.sms.attempt.max:短信发送失败的最大重试次数,默认为 5
  • bropen.framework.plugins.message.sms.attempt.interval:短信发送失败的重试间隔,默认为 5 分钟

此外,还可以根据第三方短信服务的接口,自定义其他系统参数,如下例所示:

static bootStrapInit() {
   if ( !settingService.exists("bropen.framework.plugins.message.sms.http.sn") ) {
       // 短信服务地址
       settingService.createOrUpdate("bropen.framework.plugins.message.sms.http.url",
           "http://www.jianzhou.sh.cn/JianzhouSMSWSServer/services/BusinessService", "string").save()
       // 短信服务帐号
       settingService.createOrUpdate("bropen.framework.plugins.message.sms.http.sn",
           "sdk_foobar", "string").save()
       // 短信服务密码
       settingService.createOrUpdate("bropen.framework.plugins.message.sms.http.pwd",
           "1234567890", "passwd").save()
       // 短信服务开关
       settingService.createOrUpdate("bropen.framework.plugins.message.sms.enabled",
           "false", "boolean").save()
       // 短信服务帐号
       settingService.createOrUpdate("bropen.framework.plugins.message.sms.http.sig",
           "【Foobar】", "string").save()
   }
}

接口方法 send 是最重要的部分,该方法中,需要调用实际的第三方接口,将短信发送出去,如下例所示:

/**
 * 接口方法:通过短信网关发送短信,并返回状态。如果短信发送被禁用,则应直接返回 null。
 */

@java.lang.Override
protected MessageStatus send(ShortMessage sms) {
   if ( !isEnabled() ) return null // 如果没有启用短信服务,则直接返回null
   
    String url = settingService.get("bropen.framework.plugins.message.sms.http.url")        // 服务地址
   String account = settingService.get("bropen.framework.plugins.message.sms.http.sn")     // 企业账户
   String pwd = settingService.get("bropen.framework.plugins.message.sms.http.pwd")        // 密码
   String sig = settingService.get("bropen.framework.plugins.message.sms.http.sig") ?: ""  // 短信后缀

   // 收件人
   List<String> phones = []
   for ( String to in sms.to ) {
       if ( to.indexOf("<") )
            phones += to.replaceAll("^[^<]*<", "").replaceAll(">.*\$", "")
   }
   // 拼消息实体:接收人、短信内容
   String phone = phones.join(";")
    String message = sms.text + (sms.signature ? ("\n"+ sms.signature) : "")
    message += sig
   
   // 发送 (开发和测试环境不发短信)
   String resp = null
   if ( grails.util.Environment.current == grails.util.Environment.PRODUCTION ) {
        Client c = new Client(url,account, pwd)
        resp = c.sendBatchMessage(phone, message)
        log.debug("sms.id=" + sms.id + ", resp=" + resp)
        resp = resp.replaceAll(/,.+/, "")
   } else {
        resp = '999999999'
        log.debug("sms.id=" + sms.id + ", resp=" + resp + ", phone=" + phone + ", message=" + message)
   }
   
   // 检查返回值(服务反馈的状态码),并设置 sms 对象的 statusCode、statusMessage,以便审计和查找发送失败原因
   sms.statusCode = resp
   switch ( sms.statusCode ) {
       case "-1" : sms.statusMessage="余额不足"; break
       case "-2" : sms.statusMessage="帐号或密码错误"; break
       ...
       case "-19" : sms.statusMessage="必须为POST提交"; break
       case "-20" : sms.statusMessage="超速提交(一般为每秒一次提交)"; break
       default: sms.statusMessage = sms.statusCode
   }
   // 返回状态
   return sms.statusCode.toLong() > 0 ? MessageStatus.SENT : MessageStatus.ERROR
}

/**
 * 从第三方接口的 demo 代码中拷贝出来的短信客户端
 */

public static class Client {
   ....
}

上面的例子中,注意:

  • 第一行判断是否启用了短信,否则直接返回 null
  • 调用短信客户端类发送完成后,可以设置 sms 对象的 statusCode、statusMessage 属性,以便审计和查找发送失败原因

此外,上面的例子中有一个内部类 Client,一般可以从短信服务商提供的 java 例子中找到,简单修改即可,如:

public static class Client {
   
   // webservice服务器定义
   private String serviceURL = null;        // 入口地址:http://www.jianzhou.sh.cn/JianzhouSMSWSServer/http/sendBatchMessage
   private String account    = null;        // 账户
   private String pwd        = null;        // 密码
   
   /*
     * 构造函数
     */

   public Client(String url, String account, String pwd) throws UnsupportedEncodingException {
       this.serviceURL = url;
       this.account = account;
       this.pwd = pwd;
   }
   
   /*
     * 方法名称:sendBatchMessage
     * 功    能:发送个性短信
     * 参    数:mobile,content(手机号,内容)
     * 返 回 值:唯一标识,如果不填写rrid将返回系统生成的
     */

   public String sendBatchMessage(String mobile, String content) {
       ....
   }
   
}

接口方法 bind 用来将 Map 对象转换成一个 ShortMessage 对象,默认情况下,Map 中包含下列数据(其中 from、to、text 不能为空):

  • from:发送人名称/员工或用户对象
  • to:逗号或分号分隔的手机号、或手机号列表、员工列表
  • text:消息正文
  • signature:签名
  • sentDateSche:计划发送时间,空则立即发送

如有其他需求,可以覆盖 bind 方法实现自己的转换逻辑。

最后,接口开发完成后,可以调用 ShortMessageService 的 sendMessage 方法发送短信,如:

ctx.shortMessageService.flush = true    // 如果在 console 中执行,必须加上这句;否则不需要

// 发送一条新的短信
ctx.shortMessageService.sendMessage( [from:"abc", to:"13312345678", text:"test text"] )

// 重试一条老的短信
def sms = bropen.framework.plugins.message.ShortMessage.get(xxxx)
ctx.shortMessageService.sendMessage( sms )

如上例所示,sendMessage 方法有两个版本,一个版本的参数是 Map、一个版本的参数是 ShortMessage 对象,通常情况下我们使用 Map 来传递参数(新建一条短信并发送),而 Map 中的数据规范参见上文中 bind 方法的默认情况。

此外,启用短信配置、并实现短信接口后,用管理员登录到后台,可以查看短信发送情况,并进行重发、或直接发送短信。

图片1.png图片2.png

标签: BroFramework
在2015-08-08 15:22上被李小翔创建

Copyright © 2013 北京博瑞开源软件有限公司
京ICP备12048974号