新的短信服务集成到IDP中

最后更新:2024-07-31

1、IDP中已经集成的短信服务

截止当前版本,IDP中已经集成的短信服务有:

  • IDaaS安全认证短信

  • 阿里短信平台

推荐项目交付中使用已有的短信服务,如果已有插件不满足需求,再去集成新的短信服务,集成后再去添加短信网关。 image.png

2、插件集成

2.1.下载demo

运行命令 git clone https://github.com/aliyun-idaas/notify-sms-engine-demo.git

2.2.使用IDEA打开Demo工程,可查看代码

image.png图2.1

图2.1使用 IDEA 打开 Demo 工程

2.3.工程结构

工程使用 maven 进行管理,总体结构与 maven 标准项目相同,需要注意的是增加了一个 lib 目录,里面存放私有库 jar 包,maven仓库无法下载,主要是二方包(如idp相关包)。

2.4.代码开发

主要修改点:

2.4.1.修改项目名称

工程下载后名称为 notify-sms-plugin-demo,复制代码目录为 notify-sms-plugin-xxx,xxx为具体网关名,根据对接的短信网关真实名称确定,如 notify-sms-plugin-aliyun、notify-sms-plugin-cmcc等,我这里以对接 i253云通讯平台(i235)为例。

  • 项目名称修改为notify-sms-plugin-i235

  • 打开目录中 pom.xml,修改 artifactId 的值为你的目录名

    image.png
    图2.2

2.4.2.修改包名

使用 IDEA 打开改好项目名的项目,修改包名中 demo 为新的包名,如 aliyun、cmcc、i253 等,我这里是对接i253云通讯平台(i235)短信,包名由demo改为 i235 image.png
图2.3

2.4.3.修改类名

修改类名格式:XxxSmsEngine、XxxSmsSender 或者 SmsXxxEngine、SmsXxxSender样式 修改SMSEngine和SMSSender类名分别为SmsI253Engine、SmsI253Sendeimage.png
图2.4

2.4.4.修改METADATA信息

主要需要修改 MINOR_TYPE、name方法(网关显示名称)、以及metadata文件夹下SMS_DEMO.json 文件名

  • 修改XxxSmsEngine 类中 MINOR_TYPE 需要修改为 SMS_XXX 格式,如 SMS_ALIYUN、SMS_235、SMS_ESB

要求全大写,根据对接的网关名称确定。

  • 修改后修改 src/main/resources/metadata 中 SMS_DEMO.json 为 {MINOR_TYPE}.json,如 SMS_ESB.json。

  • 网关显示名称修改为该短信网关真实的网关名称,如阿里短信平台、中国移动、中国联通、ESB、253等,修改 XxxSmsEngine 类中 name 方法的返回值,返回网关名称,以i253云通讯平台(i235)为例:
    image.png
    图2.5

2.4.5.填写参数信息

修改前端映射文件

先确定需要对接的短信网关中需要传递的参数有哪些,其中又有哪些参数是固定的,哪些是需要用户填写的。如根据 235短信网关接口文档(https://zz.253.com/api_doc/guo-nei-duan-xin/dan-fa-qun-fa-jie-kou.html)通过 SMS_235.json 文件配置下面变量:
1、name:网关名称,用户填写(必填);
2、description:网关描述,用户填写(非必填);
3、smsUrl:SMS URL,用户填写(必填);
4、apiUsername:API账户,用户填写(必填);
5、apiPassword:API密码,用户填写(必填);
6、title:短信标题,用户填写(必填);
7、extCode:Api扩展字段,用户填写(非必填);
我们需要修改 src/resources/metadata 文件夹下面的SMS_DEMO.json 文件这里修改文件夹名称为插件SMS_235 为短信网关 minorType名称
SMS_235.json:前端会按照该 json 信息渲染界面,和上面字段一一对应。

示例:
image.png
图2.6

image.png
图2.7

如何定义UI Schema文件中的内容请参考’UI Schema规范’章节内容。

2.4.6.SmsEngine类编写

build方法组装SmsSender

核心方法通过实现SmsMsgEngineMetadatabuild方法组装SmsSender,以i253为例,build方法的json字段就是前端传入的值,通过 doValidate(json) 方法解析和验证json,解析json后需要在修改下图 图2.11 红框处的代码,改成上面自己业务定义的json字段,通过 config.optString(“apiUsername”) 获取前端传的值,然后再通过set方法 传入到Sender类,这样我们的SmsMsgSender就构造好了。
image.png
图2.11

修改验证参数KEYS

在Engine类 找到KEYS数组字段(这里字段均为上面json中定义的字段中的key值,如SMS_235.json ),通过添加或者修改自己需要验证的字段如 图2.12,如没有需要验证非空字段KEYS设置为空数组即可
image.png
图2.12

修改加密字段 ENCRYPT_FIELDS

在Engine类 找到ENCRYPT_FIELDS数组字段(这里字段均为上面json中定义的字段中的key值,如SMS_235.json ),通过添加或者修改自己需要加密的字段如 图2.13,如没有字段加密,ENCRYPT_FIELDS设置为空数组即可
image.png
图2.13

Sms253Engine示例:

package com.idsmanager.idp.notify.sms.i253;

import com.idsmanager.idp.notify.infrastructure.InvalidConfigException;
import com.idsmanager.idp.notify.sms.infrastructure.SMS;
import com.idsmanager.idp.notify.sms.infrastructure.SmsMsgEngineMetadata;
import com.idsmanager.idp.notify.sms.infrastructure.SmsMsgSender;
import com.idsmanager.idp.notify.util.JsonFiledSecurityUtils;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;

@SMS
public class Sms253Engine extends SmsMsgEngineMetadata {

    private static final String SMS_253 = "SMS_253";
    private static final String[] ENCRYPT_FIELDS = {"apiPassword"};

    private static final String[] KEYS = new String[]{"apiUsername", "apiPassword", "title"};


    @Override
    public String name() {
        return "i253云通讯平台";
    }

    @Override
    public final String minorType() {
        return SMS_253;
    }

    @Override
    public String[] encryptFields() {
        return ENCRYPT_FIELDS;
    }

    @Override
    public void validate(String json) throws InvalidConfigException {
        doValidate(json);
    }

    @Override
    public SmsMsgSender build(String json) throws InvalidConfigException {
        JSONObject config = doValidate(json);
        JsonFiledSecurityUtils.decryptField(config, encryptFields());
        Sms253Sender sender = new Sms253Sender();
        sender.setName(config.optString("name"));
        sender.setDescription(config.optString("description"));
        sender.setSmsUrl(config.optString("smsUrl"));
        sender.setApiUsername(config.optString("apiUsername"));
        sender.setApiPassword(config.optString("apiPassword"));
        sender.setTitle(config.optString("title"));
        sender.setExtCode(config.optString("extCode"));
        sender.setInternatMsg(config.optBoolean("isInternatMsg"));
        String url = config.optString("url");
        url = StringUtils.isBlank(url) ? "https://sms.253.com/m"
        + "sg/send" : url;
        sender.setSmsUrl(url);
        return sender;
    }

    private JSONObject doValidate(String json) throws InvalidConfigException {
        JSONObject config = null;
        try {
            config = JSONObject.fromObject(json);
        } catch (Throwable e) {
            throw new InvalidConfigException("解析配置失败,无效JSON字符串", e);
        }
        for (String key : KEYS) {
            ensureParamNotNull(key, config.optString(key));
        }
        return config;
    }

}

2.4.7.编写Sender的发送逻辑

根据 253 短信网关短信发送文档(https://zz.253.com/api_doc/guo-nei-duan-xin/dan-fa-qun-fa-jie-kou.html); 253 短信网关使用 http 接口发送信息,请求、响应值均为 json 格式。所以我们在发送类通过 IDP 传递给 Notify 的短信接收者、短信内容组装235请求信息,调用235 发送接口调用发送短信。 修改 SMSSender 类中 sendMessage (具体发送逻辑)方法,该方法参数 message 的值为具体要发送的短信内容,如“尊敬的用户xxx,您本次的验证码是:133554, 2分钟内有效。如非本人操作,请忽略本短信并联系管理员。”; 根据 253接口文档,需要在这个内容的最前面拼接上 title;参数 phoneNumbers 为短信接收手机号,该参数为数组类型,截止文档编写时,该参数均只会传递一个值,需要注意该手机号为带有国际区号的手机号,需要根据对接的短信网关决定是否删掉该区号,内容示例“86-18888888888”。短信发送成功,函数要求返回 ApiResult.SUCCESS,失败要求返回 ApiResult.FAILURE 或 new ApiResult(NotifyErrorCode.SEND_UNKNOWN_ERROR, “具体的失败原因”); 其他短信网关具体的逻辑参考对应厂商文档来。 235发送示例:

/*
 * Copyright (c) 2016 BeiJing JZYT Technology Co. Ltd
 * www.idsmanager.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * BeiJing JZYT Technology Co. Ltd ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement you
 * entered into with BeiJing JZYT Technology Co. Ltd.
 */
package com.idsmanager.idp.notify.sms.i253;

import com.google.common.collect.ImmutableMap;
import com.idsmanager.idp.notify.commons.infrastructure.ApiResult;
import com.idsmanager.idp.notify.commons.infrastructure.dto.msg.RContentBasedMsgSendReq;
import com.idsmanager.idp.notify.commons.infrastructure.dto.msg.TemplateBasedMsgSendReq;
import com.idsmanager.idp.notify.logger.NotifyPluginLogger;
import com.idsmanager.idp.notify.sms.domain.SmsMsgTemplate;
import com.idsmanager.idp.notify.sms.infrastructure.SmsMsgSender;
import com.idsmanager.micro.commons.utils.httpclient.HttpClientExecutor;
import com.idsmanager.micro.commons.utils.httpclient.HttpClientPostExecutor;
import com.idsmanager.micro.commons.utils.httpclient.IDSHttpResponse;
import org.apache.commons.lang.StringUtils;

import static com.idsmanager.idp.notify.commons.NotifyErrorCode.SEND_UNKNOWN_ERROR;

/**
 * 2017/2/28
 * <p/>
 * <p/>
 * 使用 www.253.com 的短信发送
 *
 * @author Shengzhao Li
 */
public class Sms253Sender extends SmsMsgSender {

    /**
     * 253 发送短信的 URL, 固定
     */
    public static final String DEFAULT_SMS_URL = "https://sms.253.com/msg/send";

    /**
     * 逗号
     */
    private static final String COMMA = ",";

    /**
     * 国内手机号码区号前缀,使用短信微服务的标准前缀
     */
    private static final String CN_PHONE_REGION_CODE = "86-";

    /**
     * 标识符 "-"
     */
    private static final String RUNG = "-";

    /**
     * 发送 短信的 URL, 使用默认值即可
     */
    private String name = "";
    private String description = "";
    /**
     * 发送 短信的 URL, 使用默认值即可
     */
    private String smsUrl = DEFAULT_SMS_URL;

    /**
     * API 调用 的账号
     */
    private String apiUsername = "";

    /**
     * API 调用的 密码
     */
    private String apiPassword = "";

    /**
     * 发送消息时的标题,如: 【IDP2】
     * 在 253中定义 ,  可选
     */
    private String title = "【云IDaaS平台】";
    /**
     * API调用时的扩展码(ex), 可选
     */
    private String extCode;

    /**
     * 网关是否支持国际化
     */
    private boolean internatMsg = false;





    /**
     * 发送超时时间
     */
    private int maxConnectionSeconds;

    public Sms253Sender() {
    }

    public String getSmsUrl() {
        return smsUrl;
    }

    public void setSmsUrl(String smsUrl) {
        this.smsUrl = smsUrl;
    }

    public String getApiUsername() {
        return apiUsername;
    }

    public void setApiUsername(String apiUsername) {
        this.apiUsername = apiUsername;
    }

    public String getApiPassword() {
        return apiPassword;
    }

    public void setApiPassword(String apiPassword) {
        this.apiPassword = apiPassword;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getMaxConnectionSeconds() {
        return maxConnectionSeconds;
    }

    public void setMaxConnectionSeconds(int maxConnectionSeconds) {
        this.maxConnectionSeconds = maxConnectionSeconds;
    }

    public String getExtCode() {
        return extCode;
    }

    public void setExtCode(String extCode) {
        this.extCode = extCode;
    }

    public boolean isInternatMsg() {
        return internatMsg;
    }

    public void setInternatMsg(boolean internatMsg) {
        this.internatMsg = internatMsg;
    }

    public String getName() {
        return name;
    }

    public Sms253Sender setName(String name) {
        this.name = name;
        return this;
    }

    public String getDescription() {
        return description;
    }

    public Sms253Sender setDescription(String description) {
        this.description = description;
        return this;
    }

    @Override
    public ApiResult sendMsgByTemplate(TemplateBasedMsgSendReq req, String content, SmsMsgTemplate template) {
        return sendMessage(content, req.getReceiver().getRecipients());
    }

    @Override
    public ApiResult sendMsgByRContent(RContentBasedMsgSendReq req) {
        return sendMessage(req.getContent(), req.getReceiver().getRecipients());
    }

    /**
     * 参见API文档: https://www.253.com/api-docs-1.html
     *
     * @param message      SMS content
     * @param phoneNumbers Phone numbers
     * @return SMSResult
     */
    public ApiResult sendMessage(String message, String... phoneNumbers) {
        if (StringUtils.isEmpty(message) || phoneNumbers == null) {
            NotifyPluginLogger.debug("Param checking failed, message: {}, phoneNumbers: {}", message, phoneNumbers);
            return new ApiResult(0x0000, "message is empty or phoneNumber is null");
        }

        StringBuilder builder = convertPhoneNumbers(phoneNumbers);

        HttpClientExecutor clientExecutor = createHttpClientExecutor(builder, message);

        return clientExecutor.execute(this::responseToResult);

    }

    protected ApiResult responseToResult(IDSHttpResponse response) {
        ApiResult result;
        if (response.isResponse200()) {
            final String responseText = response.responseAsString();
            final String code = checkingResponseSuccessful(responseText);
            if (Sms253ErrorEnum.SMS253NEW_SUCCESS.getErrorCode().equals(code)
                || (code != null && code.startsWith("0\n"))) {
                NotifyPluginLogger.debug("Send sms success response code [200] response text [{}]", responseText);
                result = ApiResult.SUCCESS;
            } else {
                NotifyPluginLogger.info("Send sms failed response code [200] response text [{}]", responseText);
                result = new ApiResult(SEND_UNKNOWN_ERROR, "253云通讯平台发送短信失败,响应码:【" + code + "】," +
                                       "错误信息:【" + Sms253ErrorEnum.load(code).getErrorMsg() + "】", ImmutableMap.of("responseText", responseText));
            }
        } else {
            int httpStatus = response.httpResponse().getStatusLine().getStatusCode();
            try {
                NotifyPluginLogger.info("Send sms failed response code [{}] response text [{}]", response.httpResponse().getStatusLine().getStatusCode(),
                                        response.responseAsString());
            } catch (IllegalStateException e) {
                NotifyPluginLogger.info("Send sms failed response code [{}]", httpStatus, e);
            }
            result = new ApiResult(SEND_UNKNOWN_ERROR, "发送短信失败,调用253服务时HTTP状态码错误[" + httpStatus + "]");
        }
        return result;
    }

    protected HttpClientExecutor createHttpClientExecutor(StringBuilder sb, String message) {
        HttpClientExecutor executor = new HttpClientPostExecutor(this.smsUrl);
        executor.addRequestParam("un", this.apiUsername)
        .addRequestParam("pw", this.apiPassword)
        .addRequestParam("phone", sb.toString())
        .addRequestParam("ex", this.extCode)
        .addRequestParam("msg", getFullMessage(message))
        .addRequestParam("rd", "1");
        executor.maxConnectionSeconds(maxConnectionSeconds);
        return executor;
    }

    /*
     * 获取完成的 发送消息, 检查是否有标题(subject)
     * */
    protected String getFullMessage(String message) {
        if (StringUtils.isNotEmpty(this.title)) {
            return this.title + message;
        }
        return message;
    }

    /*
     * 判断第二个响应的数据是否为 0
     *
     * "响应状态为0 表明那个成功提交到服务器"
     * 详细参见 https://www.253.com/api-docs.html
     * */
    protected String checkingResponseSuccessful(String responseText) {
        String[] split = responseText.split(COMMA);
        return split.length > 1 ? split[1] : "-1";
    }

    /*
     * 将 手机号转化为 用 逗号,   分隔
     *
     */
    protected StringBuilder convertPhoneNumbers(String[] phoneNumbers) {
        final int length = phoneNumbers.length;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(appendPhoneNumber(phoneNumbers[i]));
            if (i + 1 < length) {
                sb.append(COMMA);
            }
        }
        return sb;
    }

    private String appendPhoneNumber(String phoneNumbers) {
        if (!this.internatMsg) {
            phoneNumbers = phoneNumbers.contains(RUNG) ? phoneNumbers.replace(newStr(phoneNumbers), "") : phoneNumbers;
        } else {
            phoneNumbers = phoneNumbers.contains(RUNG) ? phoneNumbers.replace(RUNG, "") : phoneNumbers;
        }
        return phoneNumbers;
    }

    private String newStr(String phoneNumber) {
        return phoneNumber.substring(0, phoneNumber.indexOf(RUNG) + 1);
    }

}

2.4.8.插件审计日志和日志打印

日志打印

日志打印,Notify提供日志打印工具类 NotifyPluginLogger,可以通过此类打印日志,打印的日志会记录到: /data/applications/idp4-microservice/notify/logs/时间/idaas-notifyPlugin-log-0.log; 如:我们发送调用第三方短信服务商 发送短信时,通过NotifyPluginLogger.error打印对应返回的响应信息sendReq,如下: NotifyPluginLogger.error("[{}] Send mas fail response  response text [{}]", RIDHolder.id(), JSON.toJSONString(sendReq)); 调用发送短信,显示发送失败:

image.png

连上服务器,打开idaas-notifyPlugin-log-0.log 日志文件排查问题,打开日志文件通过发送时间定位到具体日志信息找到问题:
image.png
以上就可以查看Notify插件打印的具体日志信息;

切记:

  • 一定要用NotifyPluginLogger 工具类打印日志,这样日志文件才会在idaas-notifyPlugin-log-0.log 输出,不然会打印到idaas-notify-log-0.log 文件,不方便排查问题;

  • 日志方法如果是错误的地方使用 NotifyPluginLogger.error 方法打印,调试的日志使用NotifyPluginLogger.info打印;

  • 打印对象一定要通过JSON.toJSONString(sendReq) 转换一下,否则日志展示出来的就是对象地址信息

审计日志

审计日志打印,可以使用工具类 ApiResultHelper返回,比如

#发送短信成功
return ApiResultHelper.success(NotifyErrorCode.SUCCESS, "发送短信成功");
#发送短信失败,把获取到的第三方错误返回
String result = sendPost(smsUrl, phoneNumbers);
SmsResponse sendReq = JSON.parseObject(result, SmsResponse.class);
if (!sendReq.isSuccess()){
    return ApiResultHelper.error(FAILURE, sendReq);
}

上述sendReq 是调用第三方短信服务商短信接口获取的响应,我们通过: return ApiResultHelper.error(FAILURE, sendReq); 传入响应的对象信息:sendReq,当发送短信失败,就可以通过审计日志中查看问题; 发送短信失败:
image.png 打开“审计”->“操作日志”->“管理日志”
image.png 展开日志信息,再展开详细信息,即可看到第三方短信服务商,响应的错误信息:
image.png
以上日志工具类在插件demo都有使用,可以结合文档使用;

2.5.插件新增依赖包

由于 Notify 没有实现类隔离,需要注意在插件开发过程中如果需要引入新的 maven 依赖,请先检查引入的依赖是否在下列列表中,如果在列表中,请使用列表中的版本,并将 scope 修改为 provided。如果有新增依赖包插件打包的时候需要打开assembly配置,实际参考** 2.6.2.有第三方lib依赖**

antlr:antlr:2.7.7
ch.qos.logback:logback-classic:1.2.12
ch.qos.logback:logback-core:1.2.12
cn.jpush.api:jpush-client:3.2.9
com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.6.0
com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2021.0.6.0
com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.6.0
com.alibaba.nacos:nacos-auth-plugin:2.2.0
com.alibaba.nacos:nacos-client:2.2.0
com.alibaba.nacos:nacos-encryption-plugin:2.2.0
com.alibaba.security:typesafe-config-shade:1.3.3-jdk7
com.alibaba.spring:spring-context-support:1.0.11
com.alibaba:fastjson:1.2.83
com.aliyun.rapt.commons:rapt-utils:0.4.4
com.aliyun.security:rapt-circuitbreaker:1.0.4.4
com.aliyun.security:rapt-logger:1.0.4.4
com.aliyun.security:rapt-support:1.0.4.4
com.aliyun.securitysdk:rass-api:2.7
com.aliyun.securitysdk:rass-core:2.7.0
com.aliyun.securitysdk:rass-lite:2.7.0
com.aliyun.securitysdk:rass-resource:2.3.4.0-apsara
com.aliyun.securitysdk:rass-spring-context:2.7.0
com.aliyun:aliyun-java-sdk-core:4.4.3
com.aliyun:aliyun-java-sdk-idaas-doraemon:1.2.4
com.beust:jcommander:1.82
com.fasterxml.jackson.core:jackson-annotations:2.13.5
com.fasterxml.jackson.core:jackson-core:2.13.5
com.fasterxml.jackson.core:jackson-databind:2.13.5
com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.13.5
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.5
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.5
com.fasterxml.jackson.module:jackson-module-afterburner:2.13.5
com.fasterxml.jackson.module:jackson-module-jsonSchema:2.6.5
com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.5
com.fasterxml:classmate:1.5.1
com.github.jai-imageio:jai-imageio-core:1.4.0
com.github.ua-parser:uap-java:1.5.2
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.9.1
com.google.errorprone:error_prone_annotations:2.11.0
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:31.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.zxing:core:3.5.0
com.google.zxing:javase:3.5.0
com.idsmanager.boot:micro-commons:1.3.0
com.idsmanager.notify:notify-api:4.21.3
com.idsmanager.notify:notify-autoconfiguration:4.21.3
com.idsmanager.notify:notify-core:4.21.3
com.idsmanager.notify:notify-email-api:4.21.3
com.idsmanager.notify:notify-email-local:4.21.3
com.idsmanager.notify:notify-email-remote:4.21.3
com.idsmanager.notify:notify-email-web:4.21.3
com.idsmanager.notify:notify-mobile-api:4.21.3
com.idsmanager.notify:notify-mobile-engine-jpush:4.21.3
com.idsmanager.notify:notify-mobile-local:4.21.3
com.idsmanager.notify:notify-mobile-web:4.21.3
com.idsmanager.notify:notify-rocket-mq:4.21.3
com.idsmanager.notify:notify-sms-api:4.21.3
com.idsmanager.notify:notify-sms-engine-253:4.21.3
com.idsmanager.notify:notify-sms-engine-253-new:4.21.3
com.idsmanager.notify:notify-sms-engine-aliyun:4.21.3
com.idsmanager.notify:notify-sms-engine-cmcc:4.21.3
com.idsmanager.notify:notify-sms-engine-cmcc-ws:1.0
com.idsmanager.notify:notify-sms-engine-unicom:4.21.3
com.idsmanager.notify:notify-sms-local:4.21.3
com.idsmanager.notify:notify-sms-remote:4.21.3
com.idsmanager.notify:notify-sms-web:4.21.3
com.idsmanager.notify:notify-website-api:4.21.3
com.idsmanager.notify:notify-website-local:4.21.3
com.idsmanager.notify:notify-website-web:4.21.3
com.idsmanager:idp-commons:1.0-SNAPSHOT
com.jayway.jsonpath:json-path:2.7.0
com.mysql:mysql-connector-j:8.0.33
com.net.sxt:jxtWS:1.0
com.sun.activation:jakarta.activation:1.2.2
com.sun.istack:istack-commons-runtime:3.0.12
com.vaadin.external.google:android-json:0.0.20131108.vaadin1
com.zaxxer:HikariCP:4.0.3
commons-beanutils:commons-beanutils:1.8.0
commons-beanutils:commons-beanutils:1.9.4
commons-codec:commons-codec:1.15
commons-collections:commons-collections:3.2.2
commons-discovery:commons-discovery:0.2
commons-io:commons-io:2.11.0
commons-lang:commons-lang:2.5
commons-lang:commons-lang:2.6
commons-logging:commons-logging:1.1.1
commons-logging:commons-logging:1.2
commons-net:commons-net:3.8.0
io.github.classgraph:classgraph:4.8.149
io.micrometer:micrometer-core:1.9.17
io.prometheus:simpleclient:0.15.0
io.prometheus:simpleclient_tracer_common:0.15.0
io.prometheus:simpleclient_tracer_otel:0.15.0
io.prometheus:simpleclient_tracer_otel_agent:0.15.0
io.springfox:springfox-bean-validators:2.4.0
io.springfox:springfox-core:2.4.0
io.springfox:springfox-spi:2.4.0
io.swagger.core.v3:swagger-annotations:2.2.8
io.swagger.core.v3:swagger-core:2.2.8
io.swagger.core.v3:swagger-models:2.2.8
io.swagger:swagger-annotations:1.5.6
jakarta.activation:jakarta.activation-api:1.2.2
jakarta.annotation:jakarta.annotation-api:1.3.5
jakarta.persistence:jakarta.persistence-api:2.2.3
jakarta.transaction:jakarta.transaction-api:1.3.3
jakarta.validation:jakarta.validation-api:2.0.2
jakarta.xml.bind:jakarta.xml.bind-api:2.3.3
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
javax.mail:mail:1.4.7
javax.persistence:javax.persistence-api:2.2
javax.validation:validation-api:2.0.1.Final
javax.xml.bind:jaxb-api:2.3.1
jaxen:jaxen:1.2.0
net.bytebuddy:byte-buddy:1.12.23
net.bytebuddy:byte-buddy-agent:1.12.23
net.logstash.logback:logstash-logback-encoder:4.5.1
net.minidev:accessors-smart:2.4.11
net.minidev:json-smart:2.4.11
net.sf.ezmorph:ezmorph:1.0.6
net.sf.json-lib:json-lib:jdk15:2.4
org.apache.axis:axis:1.4
org.apache.axis:axis-jaxrpc:1.4
org.apache.axis:axis-saaj:1.4
org.apache.commons:commons-collections4:4.4
org.apache.commons:commons-lang3:3.12.0
org.apache.httpcomponents:httpasyncclient:4.1.5
org.apache.httpcomponents:httpclient:4.5.14
org.apache.httpcomponents:httpcore:4.4.16
org.apache.httpcomponents:httpcore-nio:4.4.16
org.apache.logging.log4j:log4j-api:2.17.2
org.apache.logging.log4j:log4j-to-slf4j:2.17.2
org.apache.skywalking:apm-toolkit-logback-1.x:8.14.0
org.apache.skywalking:apm-toolkit-trace:8.14.0
org.apache.tomcat.embed:tomcat-embed-core:9.0.83
org.apache.tomcat.embed:tomcat-embed-el:9.0.83
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.83
org.apiguardian:apiguardian-api:1.1.2
org.aspectj:aspectjweaver:1.9.7
org.assertj:assertj-core:3.22.0
org.bouncycastle:bcmail-jdk15:1.46
org.bouncycastle:bcpkix-jdk18on:1.73
org.bouncycastle:bcprov-jdk15:1.46
org.bouncycastle:bcprov-jdk15on:1.70
org.bouncycastle:bcprov-jdk18on:1.73
org.bouncycastle:bcutil-jdk18on:1.73
org.checkerframework:checker-qual:3.12.0
org.codehaus.groovy:groovy-all:2.4.21
org.dom4j:dom4j:2.1.3
org.glassfish.jaxb:jaxb-runtime:2.3.9
org.glassfish.jaxb:txw2:2.3.9
org.hamcrest:hamcrest:2.2
org.hdrhistogram:HdrHistogram:2.1.12
org.hibernate.common:hibernate-commons-annotations:5.1.2.Final
org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final
org.hibernate.validator:hibernate-validator:6.2.5.Final
org.hibernate:hibernate-core:5.6.15.Final
org.ini4j:ini4j:0.5.4
org.jacoco:org.jacoco.agent:runtime:0.8.3
org.jboss.logging:jboss-logging:3.4.3.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.4.2.Final
org.junit.jupiter:junit-jupiter:5.8.2
org.junit.jupiter:junit-jupiter-api:5.8.2
org.junit.jupiter:junit-jupiter-engine:5.8.2
org.junit.jupiter:junit-jupiter-params:5.8.2
org.junit.platform:junit-platform-commons:1.8.2
org.junit.platform:junit-platform-engine:1.8.2
org.latencyutils:LatencyUtils:2.0.3
org.mockito:mockito-core:4.5.1
org.mockito:mockito-junit-jupiter:4.5.1
org.objenesis:objenesis:3.2
org.opentest4j:opentest4j:1.2.0
org.ow2.asm:asm:9.3
org.skyscreamer:jsonassert:1.5.1
org.slf4j:jul-to-slf4j:1.7.36
org.slf4j:slf4j-api:1.7.36
org.springdoc:springdoc-openapi-common:1.6.15
org.springdoc:springdoc-openapi-ui:1.6.15
org.springdoc:springdoc-openapi-webmvc-core:1.6.15
org.springframework.boot:spring-boot:2.7.18
org.springframework.boot:spring-boot-actuator:2.7.18
org.springframework.boot:spring-boot-actuator-autoconfigure:2.7.18
org.springframework.boot:spring-boot-autoconfigure:2.7.18
org.springframework.boot:spring-boot-starter:2.7.18
org.springframework.boot:spring-boot-starter-actuator:2.7.18
org.springframework.boot:spring-boot-starter-aop:2.7.18
org.springframework.boot:spring-boot-starter-data-jpa:2.7.18
org.springframework.boot:spring-boot-starter-jdbc:2.7.18
org.springframework.boot:spring-boot-starter-json:2.7.18
org.springframework.boot:spring-boot-starter-logging:2.7.18
org.springframework.boot:spring-boot-starter-test:2.7.18
org.springframework.boot:spring-boot-starter-tomcat:2.7.18
org.springframework.boot:spring-boot-starter-validation:2.7.18
org.springframework.boot:spring-boot-starter-web:2.7.18
org.springframework.boot:spring-boot-test:2.7.18
org.springframework.boot:spring-boot-test-autoconfigure:2.7.18
org.springframework.cloud:spring-cloud-commons:3.1.8
org.springframework.cloud:spring-cloud-context:3.1.8
org.springframework.cloud:spring-cloud-starter:3.1.8
org.springframework.cloud:spring-cloud-starter-bootstrap:3.1.8
org.springframework.data:spring-data-commons:2.7.18
org.springframework.data:spring-data-jpa:2.7.18
org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE
org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE
org.springframework.security:spring-security-crypto:5.7.11
org.springframework.security:spring-security-rsa:1.0.12.RELEASE
org.springframework:spring-aop:5.3.34
org.springframework:spring-aspects:5.3.34
org.springframework:spring-beans:5.3.34
org.springframework:spring-context:5.3.34
org.springframework:spring-core:5.3.34
org.springframework:spring-expression:5.3.34
org.springframework:spring-jcl:5.3.34
org.springframework:spring-jdbc:5.3.34
org.springframework:spring-orm:5.3.34
org.springframework:spring-test:5.3.34
org.springframework:spring-tx:5.3.34
org.springframework:spring-web:5.3.34
org.springframework:spring-webmvc:5.3.34
org.webjars:swagger-ui:4.17.1
org.webjars:webjars-locator-core:0.50
org.xmlunit:xmlunit-core:2.9.1
org.yaml:snakeyaml:1.30
wsdl4j:wsdl4j:1.6.3

2.6.插件打包

DEMO插件工程使用Maven进行管理,在开发插件后,需要使用Maven命令来进行打包生成应用插件jar, 在工程的pom.xml文件所在目录,使用Maven 命令:

mvn clean package

运行成功后在target目录有以notify-sms-plugin-xxx-{version}-jar-with-plugin.jar的文件生成即是插件jar。 考虑到Notify插件开发时有可能依赖其他第三方lib来完成插件开发(即在pom.xml中会加入第三方依赖dependency),在打包时需要分两种情况来处理,具体如下:

2.6.1.无任务第三方lib依赖

若无任何第三方lib依赖,直接如上所说使用Maven命令运行,使用生成的notify-sms-plugin-xxx-{version}-jar-with-plugin.jar文件即可, 以i235为例打包后插件为:notify-sms-plugin-i235-1.0.0-jar-with-plugin.jar。

2.6.2.有第三方lib依赖

对于有第三方lib依赖的Notify插件,需要配置使用Maven的assembly插件来将指定的lib一起打包到一个jar中。 假设我们需要依赖一个叫 jjwt的第三方lib库, 首先在 pom.xml中加入依赖,如下图:
image.png
再在src/mian/assembly目录增加assembly-plugin.xml 插件配置(在DEMO工程中已经有此插件配置,注释取消即可),如下图:
image.png
标签中的内容格式为:{groupId}:{artifactId}。 最后再使用Maven的打包命令生成对应的插件jar文件即可,如下图:
image.png

**注意:**此时生成的插件完整jar文件为:notify-sms-plugin-xxx-{version}-jar-with-plugin.jar,即图中的notify-sms-plugin-demo-1.0.0-jar-with-plugin.jar文件(此时的notify-sms-plugin-demo-1.0.0.jar只包含工程本身代码,在没有额外第三方依赖,也就是只依赖了Notify核心包,这个插件包也是可以使用的)。

2.7.插件上传

使用ssh文件上传工具,这里我使用的xftp,登录到服务器上,到Notify插件目录(插件目录是Notify工作目录下的plugins文件夹下${workdir}/plugins),假如Notify的工作目录为:/data/applications/idp4-microservice/notify 对应的Notify插件目录:/data/applications/idp4-microservice/notify/plugins,这里对应上传notify-sms-plugin-demo-1.0.0-jar-with-plugin.jar插件到对应目录。
image.png

注意:若已经有相同的插件存在,需要移除之前的插件,若版本号升级,没有删除之前相同的插件,可能导致新上传的插件不可用。 如以下notify-sms-engine-esb-v2-1.0.0.jarnotify-sms-engine-esb-v2-2.0.0.jar两个插件,如果同时存在可能导致新版本插件无法加载。
image.png

2.8.运行调试

可以采用java的远程调试功能来调试插件;

3.UI Schema规范

具体请查看 IDaaS插件前端集成文档