新的短信服务集成到IDP中

最后更新:2021-12-01

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

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

  • 中国联通

  • 中国移动

  • 阿里短信平台

  • 253云通讯平台(新版)

  • 253云通讯平台(旧版)

推荐项目交付中使用已有的短信服务;若已有的不满足,才需要集成新的短信服务。集成后将会在设置的短信网关中增加你的短信网关。
image.png

2. 开始集成

2.1. 下载最新短信网关 Demo 工程源码

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

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

image.png
图1 使用 IDEA 打开 Demo 工程

2.3. 工程结构

工程使用 maven 进行管理,总体结构与 maven 标准项目相同,需要注意的是增加了一个 lib 目录,里面存放私有库 jar 包。

2.4. 代码开发

我们主要需要修改的点:

2.4.1. 项目名称

工程下载后名称为 notify-sms-engine-demo,复制代码目录为 notify-sms-engine-xxx,xxx为具体网关名,根据对接的短信网关真实名称确定,如 notify-sms-engine-aliyun、notify-sms-engine-cmcc、notify-sms-engine-253 等,我这里以对接 253 短信网关为例。
打开目录中 pom.xml,修改 artifactId 的值为你的目录名。
image.png
图2 修改项目名

2.4.2. 包名

使用 IDEA 打开改好项目名的项目,修改包名中 demo 为新的包名,如 aliyun、cmcc、i253 等。
image.png
图3 修改包名

2.4.3. Metadata 信息

主要需要修改 MINOR_TYPE、网关显示名称。
SMSEngine 类中 MINOR_TYPE 需要修改为 SMS_XXX 格式,如 SMS_ALIYUN、SMS_253,要求全大写,根据对接的网关名称确定。修改后修改 src/main/resources/metadata 中 SMS_DEMO.json 为 {MINOR_TYPE}.json,如 SMS_253.json。
网关显示名称修改为该短信网关真实的网关名称,如阿里短信平台、中国移动、中国联通、253等,修改 SMSEngine 类中 name 函数的返回值,返回真实网关名称即可。
image.png
图4 修改 Metadata

2.4.4. 需要用户填写的参数信息

先确定需要对接的短信网关中需要传递的参数有哪些,其中又有哪些参数是固定的,哪些是需要用户填写的。如根据 253 短信网关接口文档(https://zz.253.com/api_doc/guo-nei-duan-xin/dan-fa-qun-fa-jie-kou.html)可得知,变量有:1、接口地址,该地址应由用户填写;2、account,用户填写;3、password,用户填写;4、msg,短信内容;5、phone,手机号。实际调试后得知短信内容中需要有固定标题,因此这里可定义为一个由用户填写的变量。需要用户填写的有4个值,分别为:接口地址、account、password、title。
修改 SMS_253.json,前端会按照该 json 信息渲染界面。
image.png
图5 添加短信网关前端界面
按照下列 json 格式示例添加描述信息可增加一行输入框到前端界面中。

    {
      "key": "smsUrl",
      "name": {
        "zh": "SMS URL",
        "en": "SMS URL"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写SMS URL",
        "en": "Please input SMS Gateway URL"
      },
      "description": {
        "zh": "SMS URL",
        "en": "SMS URL"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写SMS URL",
          "en": "Please input SMS Gateway URL"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    }

需要修改 key、name.zh、name.en、placeholder.zh、placeholder.en、description.zh、description.en、rules.required、rules.message.zh、rules.message.en、type 的值,分别为,后端获取参数用的唯一标识(这个标识名字可以定义任意值,前后端一致即可)、中文名称、英文名称、中文占位提示信息、英文占位提示信息、中文描述、英文描述、是否必填、未填写时中文提示消息、未填写时英文提示消息、输入框类型(input为文本、password为密码)。我们的前端渲染 json 可定义单行输入框、多行文本框、下拉选项框、单选按钮、复选按钮等(见文末示例),需要了解更多的参数信息,可查看 IDaaS插件前端集成文档 或联系 IDaaS 前端团队同学。
修改好的 SMS_253.json 内容为

{
  "formData": [
    {
      "key": "name",
      "name": {
        "zh": "网关名称",
        "en": "Gateway Name"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写短信网关名称",
        "en": "Please input SMS Gateway Name"
      },
      "description": {
        "zh": "短信网关名称",
        "en": "SMS Gateway Name"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写短信网关名称",
          "en": "Please input SMS Gateway name"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "smsUrl",
      "name": {
        "zh": "SMS URL",
        "en": "SMS URL"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写SMS URL",
        "en": "Please input SMS Gateway URL"
      },
      "description": {
        "zh": "SMS URL",
        "en": "SMS URL"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写SMS URL",
          "en": "Please input SMS Gateway URL"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "account",
      "name": {
        "zh": "253 账户",
        "en": "253 account"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写 253 账户",
        "en": "Please input SMS Gateway 253 account"
      },
      "description": {
        "zh": "253 账户",
        "en": "253 account"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写 253 账户",
          "en": "Please input SMS Gateway 253 account"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "password",
      "name": {
        "zh": "253 密码",
        "en": "253 password"
      },
      "type": "password",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写 253 密码",
        "en": "Please input SMS Gateway 253 password"
      },
      "description": {
        "zh": "253 密码",
        "en": "253 password"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写 253 密码",
          "en": "Please input SMS Gateway 253 password"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "title",
      "name": {
        "zh": "标题",
        "en": "title"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写标题",
        "en": "Please input SMS Gateway title"
      },
      "description": {
        "zh": "标题",
        "en": "title"
      },
      "rules": {
        "required": true,
        "message": {
          "zh": "请填写标题",
          "en": "Please input SMS Gateway title"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "description",
      "name": {
        "zh": "网关描述",
        "en": "Gateway description"
      },
      "type": "input",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "请填写短信网关描述",
        "en": "Please input SMS Gateway Name"
      },
      "description": {
        "zh": "短信网关描述",
        "en": "SMS Gateway description"
      },
      "rules": {
        "required": false,
        "message": {
          "zh": "请填写短信网关描述",
          "en": "Please input SMS Gateway description"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    },
    {
      "key": "enabled",
      "name": {
        "zh": "启用短信网关",
        "en": "Enable SMS Gateway"
      },
      "type": "switch",
      "readonly": false,
      "disabled": false,
      "placeholder": {
        "zh": "启用后可以对短信模板进行内容自定义",
        "en": "After enabling, you can customize the content of the SMS template"
      },
      "description": {
        "zh": "启用短信网关",
        "en": "Enable SMS Gateway"
      },
      "rules": {
        "required": false,
        "message": {
          "zh": "启用后可以对短信模板进行内容自定义",
          "en": "After enabling, you can customize the content of the SMS template"
        },
        "trigger": "blur"
      },
      "show": true,
      "send": true,
      "number": null
    }
  ]
}

里面的网关名称(上面 json 中key为name)、网关描述(上面 json 中key为description)、启用短信网关(上面 json 中key为enabled)为固定需要的值,请勿修改。

在 SMSSender 类中添加表单中变量对应的字段,并生成对应的setter,如上面 json 中 key 为 smsUrl,代表253短信网关发送地址,则在下图中增加了 smsUrl 这个字段,并生成了对应的 setter 方法。
image.png图6 SMSSender 类中添加字段

修改 SMSEngine 类中对应校验方法和生成Sender方法中的字段名,需要注意 config.optString(“account”) 中 key 需要和 SMS_253.json 中的 key 一致,另外需要注意传过来的数据只有用户填写的数据,不会传默认值,如开关类型,默认关闭状态,用户没进行过修改,则不会传该参数,需要自己在插件中处理默认值。
image.png
图7 修改 SMSEngine 类中对应校验方法和生成Sender方法中的字段名

2.4.5. 编写具体发送逻辑

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

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

import com.google.gson.Gson;
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.sms.domain.SmsMsgTemplate;
import com.idsmanager.idp.notify.sms.i253.dto.SmsMsgRequestDto;
import com.idsmanager.idp.notify.sms.i253.dto.SmsMsgResponseDto;
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 com.idsmanager.micro.commons.web.filter.RIDHolder;
import org.apache.http.entity.StringEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;

/**
 * 2021/3/8
 *
 * @author lanyu
 */
public class SMSSender extends SmsMsgSender {

    private static final Logger LOG = LoggerFactory.getLogger(SMSSender.class);

    private final Gson gson = new Gson();

    private String smsUrl;

    private String account;

    private String password;

    private String title;

    public ApiResult sendMessage(String message, String... phoneNumbers) {
        final String phoneNumber = phoneNumbers[0];
        final String msg = this.title + message;

        final SmsMsgRequestDto smsMsgRequestDto = new SmsMsgRequestDto();
        smsMsgRequestDto.setPhone(phoneNumber);
        smsMsgRequestDto.setMsg(msg);
        smsMsgRequestDto.setAccount(this.account);
        smsMsgRequestDto.setPassword(this.password);
        final String requestBody = gson.toJson(smsMsgRequestDto);

        HttpClientExecutor executor = new HttpClientPostExecutor(this.smsUrl);
        executor.httpEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
        final String responseBody;
        try {
            responseBody = executor.executeWithException(IDSHttpResponse::responseAsString);
        } catch (Exception e) {
            LOG.error("[" + RIDHolder.id() + "]- request [" + this.smsUrl + "] failed", e);
            return ApiResult.FAILURE;
        }
        final SmsMsgResponseDto smsMsgResponseDto = gson.fromJson(responseBody, SmsMsgResponseDto.class);

        if (smsMsgResponseDto == null || !"0".equals(smsMsgResponseDto.getCode())) {
            LOG.info("[{}]- send sms failed [{}] [{}]", RIDHolder.id(), requestBody, responseBody);
            return ApiResult.FAILURE;
        }
        return ApiResult.SUCCESS;
    }

    /**
     * 根据模板发送消息 (暂时没有地方会用到)
     *
     * @param req
     * @param content
     * @param template
     * @return
     */
    @Override
    public ApiResult sendMsgByTemplate(TemplateBasedMsgSendReq req, String content, SmsMsgTemplate template) {
        return sendMessage(content, req.getReceiver().getRecipients());
    }

    /**
     * 直接发送原生消息
     *
     * @param req example: {"subject":"","content":"尊敬的用户wceshi,您本次的验证码是:133554, 2分钟内有效。如非本人操作,请忽略本短信并联系管理员。","mimeType":"text","receiver":{"userUniqueId":"86-18888888888","userDisplayName":"86-18888888888","recipients":["86-18888888888"],"params":{"code":"133554","minutes":2,"username":"wceshi"}},"options":{"instanceId":"wceshi","businessId":"general_sms_code","externalId":"general_sms_code"},"defaultTenantId":"0000000000000000","systemId":"0000000000000000","tenantId":"c43bd59e4a03351d527cda65023dbca7wpnnBYyqcfd"}
     * @return
     */
    @Override
    public ApiResult sendMsgByRContent(RContentBasedMsgSendReq req) {
        return sendMessage(req.getContent(), req.getReceiver().getRecipients());
    }

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

    public void setAccount(String account) {
        this.account = account;
    }

    public void setPassword(String password) {
        this.password = password;
    }

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



/*
 * 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.dto;

import java.io.Serializable;

/**
 * 2021/3/9
 *
 * @author ilanyu
 */
public class SmsMsgRequestDto implements Serializable {

    private static final long serialVersionUID = -136360816850746394L;

    private String account;

    private String password;

    private String msg;

    private String phone;

    public SmsMsgRequestDto() {
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "SmsMsgRequestDto{" +
                "account='" + account + '\'' +
                ", password='" + password + '\'' +
                ", msg='" + msg + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

/*
 * 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.dto;

import java.io.Serializable;

/**
 * 2021/3/9
 *
 * @author ilanyu
 */
public class SmsMsgResponseDto implements Serializable {

    private static final long serialVersionUID = 1609515899231267341L;

    private String code;

    private String msgId;

    private String time;

    private String errorMsg;

    public SmsMsgResponseDto() {
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsgId() {
        return msgId;
    }

    public void setMsgId(String msgId) {
        this.msgId = msgId;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    @Override
    public String toString() {
        return "SmsMsgResponseDto{" +
                "code='" + code + '\'' +
                ", msgId='" + msgId + '\'' +
                ", time='" + time + '\'' +
                ", errorMsg='" + errorMsg + '\'' +
                '}';
    }
}

由于 Notify 没有实现类隔离,需要注意在插件开发过程中如果需要引入新的 maven 依赖,请先检查引入的依赖是否在下列列表中,如果在列表中,请使用列表中的版本,并将 scope 修改为 provided。

antlr:antlr:2.7.7
ch.qos.logback:logback-classic:1.2.3
ch.qos.logback:logback-core:1.2.3
cn.jpush.api:jpush-client:3.2.9
com.alibaba:fastjson:1.2.68.noneautotype
com.aliyun:aliyun-java-sdk-core:4.0.6
com.beust:jcommander:1.48
com.fasterxml:classmate:1.3.0
com.fasterxml:classmate:1.3.4
com.fasterxml.jackson.core:jackson-annotations:2.9.0
com.fasterxml.jackson.core:jackson-annotations:2.9.8
com.fasterxml.jackson.core:jackson-core:2.9.6
com.fasterxml.jackson.core:jackson-databind:2.9.6
com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.6.5
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.6
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.6
com.fasterxml.jackson.module:jackson-module-afterburner:2.6.5
com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.6
com.google.code.findbugs:jsr305:1.3.9
com.google.code.gson:gson:2.3
com.google.code.gson:gson:2.8.2
com.google.code.gson:gson:2.8.5
com.google.code.gson:gson:2.8.6
com.google.errorprone:error_prone_annotations:2.0.18
com.google.guava:guava:18.0
com.google.guava:guava:23.0
com.google.j2objc:j2objc-annotations:1.1
com.google.zxing:core:3.2.1
com.google.zxing:javase:3.2.1
com.idsmanager.boot:micro-commons:1.1.2
com.idsmanager.notify:notify-api:4.11.0
com.idsmanager.notify:notify-autoconfiguration:4.11.0
com.idsmanager.notify:notify-core:4.11.0
com.idsmanager.notify:notify-email-api:4.11.0
com.idsmanager.notify:notify-email-local:4.11.0
com.idsmanager.notify:notify-email-remote:4.11.0
com.idsmanager.notify:notify-email-web:4.11.0
com.idsmanager.notify:notify-mobile-api:4.11.0
com.idsmanager.notify:notify-mobile-engine-jpush:4.11.0
com.idsmanager.notify:notify-mobile-local:4.11.0
com.idsmanager.notify:notify-mobile-web:4.11.0
com.idsmanager.notify:notify-rocket-mq:4.11.0
com.idsmanager.notify:notify-sms-api:4.11.0
com.idsmanager.notify:notify-sms-engine-253:4.11.0
com.idsmanager.notify:notify-sms-engine-253-new:4.11.0
com.idsmanager.notify:notify-sms-engine-aliyun:4.11.0
com.idsmanager.notify:notify-sms-engine-cmcc:4.11.0
com.idsmanager.notify:notify-sms-engine-cmcc-ws:1.0
com.idsmanager.notify:notify-sms-engine-unicom:4.11.0
com.idsmanager.notify:notify-sms-local:4.11.0
com.idsmanager.notify:notify-sms-remote:4.11.0
com.idsmanager.notify:notify-sms-web:4.11.0
com.idsmanager.notify:notify-website-api:4.11.0
com.idsmanager.notify:notify-website-local:4.11.0
com.idsmanager.notify:notify-website-web:4.11.0
commons-beanutils:commons-beanutils:1.8.0
commons-beanutils:commons-beanutils:1.9.3
commons-codec:commons-codec:1.10
commons-codec:commons-codec:1.11
commons-collections:commons-collections:3.2.1
commons-collections:commons-collections:3.2.2
commons-discovery:commons-discovery:0.2
commons-io:commons-io:2.4
commons-lang:commons-lang:2.3
commons-lang:commons-lang:2.4
commons-lang:commons-lang:2.6
commons-logging:commons-logging:1.1.1
commons-logging:commons-logging:1.2
commons-net:commons-net:3.6
com.net.sxt:jxtWS:1.0
com.sun.xml.bind:jaxb-core:2.1.14
com.sun.xml.bind:jaxb-impl:2.1
com.zaxxer:HikariCP:2.7.9
dom4j:dom4j:1.6.1
net.sf.json-lib:json-lib:jar:jdk15:2.3
io.netty:netty-all:4.0.42.Final
io.netty:netty-all:4.1.29.Final
io.netty:netty-tcnative-boringssl-static:1.1.33.Fork26
io.springfox:springfox-core:2.7.0
io.springfox:springfox-schema:2.7.0
io.springfox:springfox-spi:2.7.0
io.springfox:springfox-spring-web:2.7.0
io.springfox:springfox-swagger2:2.7.0
io.springfox:springfox-swagger-common:2.7.0
io.springfox:springfox-swagger-ui:2.7.0
io.swagger:swagger-annotations:1.5.6
io.swagger:swagger-models:1.5.13
javax.activation:activation:1.1
javax.activation:activation:1.1.1
javax.activation:javax.activation-api:1.2.0
javax.annotation:javax.annotation-api:1.3.2
javax.mail:mail:1.4.1
javax.persistence:javax.persistence-api:2.2
javax.transaction:javax.transaction-api:1.2
javax.validation:validation-api:2.0.1.Final
javax.xml.bind:jaxb-api:2.1
javax.xml.bind:jaxb-api:2.3.0
javax.xml.stream:stax-api:1.0-2
mysql:mysql-connector-java:5.1.35
net.bytebuddy:byte-buddy:1.7.11
net.bytebuddy:byte-buddy:1.8.15
net.logstash.logback:logstash-logback-encoder:4.5.1
net.sf.ezmorph:ezmorph:1.0.6
org.apache.axis:axis:1.4
org.apache.axis:axis-jaxrpc:1.4
org.apache.axis:axis-saaj:1.4
org.apache.commons:commons-lang3:3.4
org.apache.commons:commons-lang3:3.7
org.apache.httpcomponents:httpclient:4.5.5
org.apache.httpcomponents:httpclient:4.5.6
org.apache.httpcomponents:httpcore:4.4.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.rocketmq:rocketmq-client:4.4.0
org.apache.rocketmq:rocketmq-common:4.4.0
org.apache.rocketmq:rocketmq-logging:4.4.0
org.apache.rocketmq:rocketmq-remoting:4.4.0
org.apache.tomcat.embed:tomcat-embed-core:8.5.34
org.apache.tomcat.embed:tomcat-embed-el:8.5.34
org.apache.tomcat.embed:tomcat-embed-websocket:8.5.34
org.aspectj:aspectjrt:1.8.13
org.aspectj:aspectjweaver:1.8.13
org.bouncycastle:bcmail-jdk15:1.46
org.bouncycastle:bcprov-jdk15:1.46
org.codehaus.groovy:groovy-all:2.4.15
org.codehaus.groovy:groovy-all:2.4.6
org.codehaus.mojo:animal-sniffer-annotations:1.14
org.hibernate.common:hibernate-commons-annotations:5.0.1.Final
org.hibernate.common:hibernate-commons-annotations:5.0.4.Final
org.hibernate:hibernate-core:5.2.17.Final
org.hibernate:hibernate-core:5.3.4.Final
org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final
org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final
org.hibernate.validator:hibernate-validator:6.0.12.Final
org.javassist:javassist:3.22.0-GA
org.javassist:javassist:3.23.1-GA
org.jboss:jandex:2.0.3.Final
org.jboss:jandex:2.0.5.Final
org.jboss.logging:jboss-logging:3.3.1.Final
org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.0.1.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.mapstruct:mapstruct:1.1.0.Final
org.reflections:reflections:0.9.11
org.slf4j:jul-to-slf4j:1.7.25
org.slf4j:slf4j-api:1.7.25
org.slf4j:slf4j-api:1.7.7
org.springframework.boot:spring-boot:2.0.5.RELEASE
org.springframework.boot:spring-boot-autoconfigure:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-aop:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-data-jpa:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-jdbc:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-json:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-logging:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-tomcat:2.0.5.RELEASE
org.springframework.boot:spring-boot-starter-web:2.0.5.RELEASE
org.springframework.data:spring-data-commons:2.0.10.RELEASE
org.springframework.data:spring-data-jpa:2.0.10.RELEASE
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-core:5.0.8.RELEASE
org.springframework.security:spring-security-core:5.0.9.RELEASE
org.springframework:spring-aop:5.0.9.RELEASE
org.springframework:spring-aspects:5.0.9.RELEASE
org.springframework:spring-beans:5.0.9.RELEASE
org.springframework:spring-context:5.0.9.RELEASE
org.springframework:spring-core:5.0.9.RELEASE
org.springframework:spring-expression:5.0.9.RELEASE
org.springframework:spring-jcl:5.0.9.RELEASE
org.springframework:spring-jdbc:5.0.9.RELEASE
org.springframework:spring-orm:5.0.9.RELEASE
org.springframework:spring-tx:5.0.9.RELEASE
org.springframework:spring-web:5.0.9.RELEASE
org.springframework:spring-webmvc:5.0.9.RELEASE
wsdl4j:wsdl4j:1.6.3

2.5. 打包用户目录UD

使用命令 mvn package 即可打包。

2.6. 运行调试

1、若有 Notify 源码
先 install 开发的插件,再在 notify-application 模块的 pom.xml 中引入该插件,即可运行或调试。
2、若无 Notify 源码
需要先有一套完整的 Notify 运行环境,文件列表如图所示。
image.png
图8 Notify 运行环境
修改 application.properties 中 spring.datasource.url、spring.datasource.username、spring.datasource.password 为正确的 jdbc 连接信息、MySQL 用户名、MySQL 密码,创建好 idp4_testV1_2 数据库。
修改 startup.sh 中 JAVA_HOME 为正确的地址。
将打包好的插件的 jar 包,以及用到的依赖包的 jar 包,压缩到 notify-application-1.0.war 中的 WEB-INF/lib 目录中,压缩时注意压缩算法需要使用仅存储。
在 Linux 环境中给 startup.sh 增加可执行权限后使用 ./startup.sh 即可运行。
或在 Windows 环境中直接双击 run.bat 即可运行。

若需要调试,则需要在 IDEA 运行配置中添加远程 JVM 调试配置,主机设置为运行 Notify 的服务器IP,如 11.164.60.12,端口设置为一个可以通过防火墙的,没有其他程序使用的端口,如 5005。复制给出的远程 JVM 命令行参数,将其添加到 startup.sh 或 run.bat 的 Java 参数中,启动Notify后,再在IDEA中进行远程 Debug 即可进行调试。
image.png
图9 添加远程 JVM 调试

image.png
图10 使用远程 JVM 调试
在开发过程中,若反复压缩 notify-application-1.0.war 不方便,可将 notify-application-1.0.war 解压,然后将打包的插件放到解压后的目录中的 WEB-INF/lib 目录中,然后使用命令 java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -DServer.name=NotifyServer org.springframework.boot.loader.WarLauncher –spring.config.location=application.properties -server 启动,同样可以进行远程调试。若在 Notify 启动时就需要断点进行调试,可将 agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 中的 suspend=n 修改为 suspend=y,即可在启动时等待 IDEA 进行远程调试,开启调试后,再继续运行。

3. 前端JSON示例

可直接格式复制去使用,注意使用时修改key为具有含义的值,name、placeholder、description、options 等为能让用户看明白的值。

3.1. 单行输入框

{
  "key": "name",
  "name": { "zh": "名称", "en": "Name" },
  "type": "input",
  "readonly": false,
  "disabled": false,
  "placeholder": { "zh": "请填写名称", "en": "Please enter the Name" },
  "description": { "zh": "名称", "en": "Source name" },
  "rules": { "required": true, "message": "此项不能为空", "trigger": "blur" },
  "maxlength":255,
  "show": true,
  "send": true
}

3.2. 多行文本框

{
  "key": "description",
  "name": { "zh": "描述", "en": "Description" },
  "type": "textarea",
  "disabled": false,
  "readonly": false,
  "placeholder": { "zh": "请输入描述", "en": "Please enter the Description" },
  "description": { "zh": "", "en": "" },
  "rules": { "required": false, "message": "此项不能为空", "trigger": "blur" },
  "maxlength":255,
  "show": true,
  "send": true
}

3.3. 下拉选项框

{
  "key": "name",
  "name": { "zh": "名称", "en": "Name" },
  "type": "select",
  "options": [
    { "label": "Name1", "value": { "zh": "名称1", "en": "name 1" }, "disabled": false }, 
    { "label": "Name2", "value": { "zh": "名称2", "en": "name 2" }, "disabled": false }
  ],
  "disabled": false,
  "placeholder": { "zh": "", "en": "" },
  "description": { "zh": "名称的描述", "en": "name description" },
  "rules": { "required": false, "message": "此项不能为空", "trigger": "change" },
  "show": true,
  "send": true
}

3.4. 单选按钮框

{
  "key": "log",
  "name": { "zh": "是否记录日志", "en": "record log" },
  "type": "radio",
  "options": [
    { "label": "true", "value": { "zh": "是", "en": "Yes" }, "disabled": false }, 
    { "label": "false", "value": { "zh": "否", "en": "No" }, "disabled": false }
  ],
  "description": { "zh": "是否记录日志", "en": "Choose whether to record log." },
  "rules": { "required": false, "message": "此项不能为空", "trigger": "change" },
  "show": true,
  "send": true,
}

3.5. 复选按钮框

{
  "key": "names",
  "name": { "zh": "名称", "en": "name" },
  "type": "checkbox",
  "options": [
    { "label": "name1", "value": { "zh": "名称1", "en": "name 1" }, "disabled": false }, 
    { "label": "name1", "value": { "zh": "名称2", "en": "name 2" }, "disabled": false }
  ],
  "description": { "zh": "名称的描述" },
  "rules": { "required": true, "message": "此项不能为空", "trigger": "change", "type": "array" },
  "show": true,
  "send": true
}