forked from fanruan/demo-third-sms-v2
Roger.Chen
3 years ago
commit
2e3c918958
27 changed files with 881 additions and 0 deletions
@ -0,0 +1,5 @@
|
||||
*.iml |
||||
.idea/ |
||||
lib/report/*.jar |
||||
target/ |
||||
.DS_Store |
@ -0,0 +1,122 @@
|
||||
|
||||
apply plugin: 'java' |
||||
|
||||
|
||||
ext { |
||||
/** |
||||
* 项目中依赖的jar的路径 |
||||
* 1.如果依赖的jar需要打包到zip中,放置在lib根目录下 |
||||
* 2.如果依赖的jar仅仅是编译时需要,防止在lib下子目录下即可 |
||||
*/ |
||||
libPath = "$projectDir/../webroot/WEB-INF/lib" |
||||
|
||||
/** |
||||
* 是否对插件的class进行加密保护,防止反编译 |
||||
*/ |
||||
guard = false |
||||
|
||||
def pluginInfo = getPluginInfo() |
||||
pluginPre = "fine-plugin" |
||||
pluginName = pluginInfo.id |
||||
pluginVersion = pluginInfo.version |
||||
|
||||
outputPath = "$projectDir/../webroot/WEB-INF/plugins/plugin-" + pluginName + "-1.0/classes" |
||||
} |
||||
|
||||
group = 'com.fr.plugin' |
||||
version = '10.0' |
||||
sourceCompatibility = '8' |
||||
|
||||
sourceSets { |
||||
main { |
||||
java.outputDir = file(outputPath) |
||||
output.resourcesDir = file(outputPath) |
||||
} |
||||
} |
||||
|
||||
ant.importBuild("encrypt.xml") |
||||
//定义ant变量 |
||||
ant.projectDir = projectDir |
||||
ant.references["compile.classpath"] = ant.path { |
||||
fileset(dir: libPath, includes: '**/*.jar') |
||||
fileset(dir: ".",includes:"**/*.jar" ) |
||||
} |
||||
|
||||
classes.dependsOn('clean') |
||||
|
||||
task copyFiles(type: Copy,dependsOn: 'classes'){ |
||||
from outputPath |
||||
into "$projectDir/classes" |
||||
} |
||||
|
||||
task preJar(type:Copy,dependsOn: guard ? 'compile_encrypt_javas' : 'compile_plain_javas'){ |
||||
from "$projectDir/classes" |
||||
into "$projectDir/transform-classes" |
||||
include "**/*.*" |
||||
} |
||||
jar.dependsOn("preJar") |
||||
|
||||
task makeJar(type: Jar,dependsOn: preJar){ |
||||
from fileTree(dir: "$projectDir/transform-classes") |
||||
baseName pluginPre |
||||
appendix pluginName |
||||
version pluginVersion |
||||
destinationDir = file("$buildDir/libs") |
||||
|
||||
doLast(){ |
||||
delete file("$projectDir/classes") |
||||
delete file("$projectDir/transform-classes") |
||||
} |
||||
} |
||||
|
||||
task copyFile(type: Copy,dependsOn: ["makeJar"]){ |
||||
from "$buildDir/libs" |
||||
from("$projectDir/lib") { |
||||
include "*.jar" |
||||
} |
||||
from "$projectDir/plugin.xml" |
||||
into file("$buildDir/temp/plugin") |
||||
} |
||||
|
||||
task zip(type:Zip,dependsOn:["copyFile"]){ |
||||
from "$buildDir/temp/plugin" |
||||
destinationDir file("$buildDir/install") |
||||
baseName pluginPre |
||||
appendix pluginName |
||||
version pluginVersion |
||||
} |
||||
|
||||
//控制build时包含哪些文件,排除哪些文件 |
||||
processResources { |
||||
// exclude everything |
||||
// 用*.css没效果 |
||||
// exclude '**/*.css' |
||||
// except this file |
||||
// include 'xx.xml' |
||||
} |
||||
|
||||
/*读取plugin.xml中的version*/ |
||||
def getPluginInfo(){ |
||||
def xmlFile = file("plugin.xml") |
||||
if (!xmlFile.exists()) { |
||||
return ["id":"none", "version":"1.0.0"] |
||||
} |
||||
def plugin = new XmlParser().parse(xmlFile) |
||||
def version = plugin.version[0].text() |
||||
def id = plugin.id[0].text() |
||||
return ["id":id,"version":version] |
||||
} |
||||
|
||||
repositories { |
||||
mavenLocal() |
||||
maven { |
||||
url = uri('http://mvn.finedevelop.com/repository/maven-public/') |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
//使用本地jar |
||||
implementation fileTree(dir: 'lib', include: ['**/*.jar']) |
||||
implementation fileTree(dir: libPath, include: ['**/*.jar']) |
||||
} |
||||
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<project> |
||||
<target name="compile_encrypt_javas" depends="copyFiles"> |
||||
<echo message="加密文件"/> |
||||
<echo message="${projectDir}"/> |
||||
<taskdef name="pretreatment" classname="com.fr.plugin.pack.PluginPretreatmentTask"> |
||||
<classpath refid="compile.classpath"/> |
||||
</taskdef> |
||||
<pretreatment baseDir="${projectDir}"/> |
||||
</target> |
||||
<target name="compile_plain_javas" depends="copyFiles"> |
||||
</target> |
||||
</project> |
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<plugin> |
||||
<id>com.fr.plugin.decision.third.sms.v11</id> |
||||
<name><![CDATA[新第三方短信插件]]></name> |
||||
<active>yes</active> |
||||
<version>1.0</version> |
||||
<env-version>11.0</env-version> |
||||
<jartime>2019-11-06</jartime> |
||||
<vendor>Lanlan</vendor> |
||||
<description><![CDATA[新第三方短信插件]]></description> |
||||
<extra-core> |
||||
<SMSServiceProvider class="com.fr.plugin.decision.third.sms.ThirdSmsServiceProvider"/> |
||||
<LocaleFinder class="com.fr.plugin.decision.third.sms.ThirdSmsLocaleFinder"/> |
||||
</extra-core> |
||||
<extra-decision> |
||||
<ControllerRegisterProvider class="com.fr.plugin.decision.third.sms.ThirdSmsControllerProvider"/> |
||||
<WebResourceProvider class="com.fr.plugin.decision.third.sms.ThirdSmsWebResourceProvider"/> |
||||
</extra-decision> |
||||
<function-recorder class="com.fr.plugin.decision.third.sms.ThirdSmsServiceProvider"/> |
||||
</plugin> |
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>plugin</artifactId> |
||||
<groupId>com.fr.maven</groupId> |
||||
<version>10.0</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>fine-decision-sms-new-demo</artifactId> |
||||
|
||||
<build> |
||||
<!---如果要更改调试插件,改这里的配置就可以了--> |
||||
<outputDirectory> |
||||
${web-inf-path}/plugins/plugin-com.fr.plugin.decision.third.sms.v11-2.0/classes |
||||
</outputDirectory> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-compiler-plugin</artifactId> |
||||
<configuration> |
||||
<source>8</source> |
||||
<target>8</target> |
||||
</configuration> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.fr.core</groupId> |
||||
<artifactId>core-plugin-interface</artifactId> |
||||
<version>10.0</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fr.core</groupId> |
||||
<artifactId>core-project-plugin-interface</artifactId> |
||||
<version>10.0</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
</project> |
@ -0,0 +1,28 @@
|
||||
# 第三方短信平台插件 |
||||
|
||||
## 开启短信 |
||||
|
||||
使用该插件可以不使用帆软内置的短信平台,只需要在购买短信功能点后,通过插件使用自己的短信平台即可,为了方便展示客户自己的账号信息,可以自己在插件中提供短信配置信息的接口,如下图所示: |
||||
![open](screenshots/open.png) |
||||
|
||||
给管理员绑定手机号: |
||||
![open2](screenshots/open2.png) |
||||
|
||||
绑定好后如图: |
||||
![open3](screenshots/open3.png) |
||||
|
||||
开启短信验证密码: |
||||
![open4](screenshots/open4.png) |
||||
|
||||
## 测试方式 |
||||
|
||||
可以在登录决策平台后,访问管理系统->系统管理->短信,点击信息测试处的发送测试短信。 |
||||
|
||||
## 测试时获取验证码 |
||||
|
||||
可以直接在日志中看到要短信发送的内容。 |
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 242 KiB |
@ -0,0 +1,16 @@
|
||||
package com.fr.plugin.decision.third.sms; |
||||
|
||||
import com.fr.web.struct.Component; |
||||
import com.fr.web.struct.browser.RequestClient; |
||||
import com.fr.web.struct.category.ParserType; |
||||
import com.fr.web.struct.category.ScriptPath; |
||||
|
||||
public class ThirdSmsComponent extends Component { |
||||
|
||||
public static final ThirdSmsComponent KEY = new ThirdSmsComponent(); |
||||
|
||||
@Override |
||||
public ScriptPath script(RequestClient req) { |
||||
return ScriptPath.build("com/fr/plugin/decision/third/sms/web/sms.js", ParserType.PLAIN); |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
package com.fr.plugin.decision.third.sms; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractControllerRegisterProvider; |
||||
import com.fr.plugin.decision.third.sms.controller.ThirdSmsController; |
||||
|
||||
public class ThirdSmsControllerProvider extends AbstractControllerRegisterProvider { |
||||
@Override |
||||
public Class<?>[] getControllers() { |
||||
return new Class[] { |
||||
ThirdSmsController.class |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
package com.fr.plugin.decision.third.sms; |
||||
|
||||
import com.fr.stable.fun.impl.AbstractLocaleFinder; |
||||
|
||||
public class ThirdSmsLocaleFinder extends AbstractLocaleFinder { |
||||
|
||||
@Override |
||||
public String find() { |
||||
return "com/fr/plugin/decision/third/sms/locale/sms"; |
||||
} |
||||
} |
@ -0,0 +1,131 @@
|
||||
package com.fr.plugin.decision.third.sms; |
||||
|
||||
import com.fr.base.sms.SMSContext; |
||||
import com.fr.json.JSONArray; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.decision.third.sms.fun.SMSXmlReader; |
||||
import com.fr.plugin.decision.third.sms.fun.SmsClient; |
||||
import com.fr.plugin.transform.ExecuteFunctionRecord; |
||||
import com.fr.plugin.transform.FunctionRecorder; |
||||
import com.fr.stable.fun.impl.AbstractSMSServiceProvider; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
@FunctionRecorder |
||||
public class ThirdSmsServiceProvider extends AbstractSMSServiceProvider { |
||||
|
||||
private static final String SMS_PUBLIC_MODEL = "public-model"; |
||||
private static final String SMS_PRIVATE_MODEL = "private-model"; |
||||
|
||||
public ThirdSmsServiceProvider() { |
||||
startListener(); |
||||
} |
||||
|
||||
@Override |
||||
public String sign() { |
||||
return SmsClient.getInstance().getSign(); |
||||
} |
||||
|
||||
/** |
||||
* 必须大于1,且跟js文件中的优先级保持一致 |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public int priority() { |
||||
return 20; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isSMSAvailable() { |
||||
//根据具体情况看短信服务是否可用
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 这里解析sms_template.xml文件中的模板返回,实际获取短信服务的模板 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public Map<String, List<SMSTemplateBean>> getSMSTemplate() { |
||||
Map<String, List<SMSTemplateBean>> result = new HashMap<>(); |
||||
Map<String, Map<String, Object>> smsTemplates = SmsClient.getInstance().getSMSTemplate(); |
||||
result.put("publicModel", convertSMSTemplateBeanList(smsTemplates.get(SMS_PUBLIC_MODEL))); |
||||
result.put("privateModel", convertSMSTemplateBeanList(smsTemplates.get(SMS_PRIVATE_MODEL))); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 读取sms_template_mapping.xml配置文件中的映射规则 |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public Map<String, String> mapping() { |
||||
Map<String, String> map = new HashMap<>(); |
||||
Map<String, Object> templateMappings = SMSXmlReader.getSMSTemplateMappings(); |
||||
for (Map.Entry<String, Object> entry : templateMappings.entrySet()) { |
||||
JSONObject jsonObject = JSONObject.mapFrom(entry.getValue()); |
||||
if (jsonObject == null) { |
||||
continue; |
||||
} |
||||
map.put(entry.getKey(), jsonObject.getString("content")); |
||||
} |
||||
return map; |
||||
} |
||||
|
||||
@Override |
||||
public Response sendTest(String mobile) { |
||||
SmsClient.getInstance().send(mobile); |
||||
return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送测试短信成功", JSONObject.create()); |
||||
} |
||||
|
||||
@Override |
||||
@ExecuteFunctionRecord |
||||
public Response send(String template, String mobile, JSONObject para, String receiver) throws Exception { |
||||
SmsClient.getInstance().send(template, mobile, para, receiver); |
||||
FineLoggerFactory.getLogger().info("短信模板:{}, 手机号:{},参数:{}", template, mobile, para); |
||||
return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送普通短信成功", JSONObject.create()); |
||||
} |
||||
|
||||
@Override |
||||
public Response batchSendSMS(String template, List<String> mobiles, JSONArray params, List<String> receivers) throws Exception { |
||||
SmsClient.getInstance().batchSend(template, mobiles, params, receivers); |
||||
return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送批量短信成功", JSONObject.create()); |
||||
} |
||||
|
||||
/** |
||||
* 启动发送短信的监听器 |
||||
*/ |
||||
private void startListener() { |
||||
SMSContext.addSmsListener(new Listener() { |
||||
|
||||
@Override |
||||
public void beforeSend(String text, List<String> mobiles, JSONArray params, List<String> receivers) { |
||||
System.out.println("发送短信前监听事件"); |
||||
FineLoggerFactory.getLogger().info("发送短信前监听事件"); |
||||
} |
||||
|
||||
@Override |
||||
public void afterSend(String text, List<String> mobiles, JSONArray params, List<String> receivers, Response response) { |
||||
System.out.println("发送短信后监听事件"); |
||||
FineLoggerFactory.getLogger().info("发送短信后监听事件"); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private List<SMSTemplateBean> convertSMSTemplateBeanList(Map<String, Object> map) { |
||||
List<SMSTemplateBean> beanList = new ArrayList<>(); |
||||
for (Object data : map.values()) { |
||||
JSONObject json = JSONObject.mapFrom(data); |
||||
if (json == null) { |
||||
continue; |
||||
} |
||||
beanList.add(SMSTemplateBean.create(json.getString("id"), json.getString("content"), json.getString("language"))); |
||||
} |
||||
return beanList; |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.plugin.decision.third.sms; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractWebResourceProvider; |
||||
import com.fr.decision.web.MainComponent; |
||||
import com.fr.web.struct.Atom; |
||||
|
||||
public class ThirdSmsWebResourceProvider extends AbstractWebResourceProvider { |
||||
@Override |
||||
public Atom attach() { |
||||
return MainComponent.KEY; |
||||
} |
||||
|
||||
@Override |
||||
public Atom client() { |
||||
return ThirdSmsComponent.KEY; |
||||
} |
||||
} |
@ -0,0 +1,29 @@
|
||||
package com.fr.plugin.decision.third.sms.controller; |
||||
|
||||
import com.fr.decision.webservice.Response; |
||||
import com.fr.decision.webservice.annotation.VisitRefer; |
||||
import com.fr.plugin.decision.third.sms.fun.SmsClient; |
||||
import com.fr.third.springframework.stereotype.Controller; |
||||
import com.fr.third.springframework.web.bind.annotation.PathVariable; |
||||
import com.fr.third.springframework.web.bind.annotation.RequestMapping; |
||||
import com.fr.third.springframework.web.bind.annotation.RequestMethod; |
||||
import com.fr.third.springframework.web.bind.annotation.ResponseBody; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
@Controller |
||||
@RequestMapping("/{version}/third/sms") |
||||
public class ThirdSmsController { |
||||
|
||||
@RequestMapping(method = RequestMethod.GET) |
||||
@ResponseBody |
||||
@VisitRefer(required = false) |
||||
public Response getSMSConfig(HttpServletRequest req, |
||||
HttpServletResponse res, |
||||
@PathVariable("version") String version) throws Exception { |
||||
|
||||
return Response.ok(SmsClient.getInstance().getSmsConfig()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,73 @@
|
||||
package com.fr.plugin.decision.third.sms.fun; |
||||
|
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import org.w3c.dom.Document; |
||||
import org.w3c.dom.Node; |
||||
import org.w3c.dom.NodeList; |
||||
|
||||
import javax.xml.parsers.DocumentBuilder; |
||||
import javax.xml.parsers.DocumentBuilderFactory; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
public class SMSXmlReader { |
||||
|
||||
private static final Map<String, Map<String, Object>> SMS_TEMPLATES_MAP = new ConcurrentHashMap<>(); |
||||
private static final String SMS_PUBLIC_MODEL = "public-model"; |
||||
private static final String SMS_PRIVATE_MODEL = "private-model"; |
||||
|
||||
private static final String SMS_TEMPLATE_XML = "sms_template.xml"; |
||||
private static final String SMS_TEMPLATE_MAPPING_XML = "sms_template_mapping.xml"; |
||||
|
||||
public static Map<String, Object> getPublicSMSTemplates() { |
||||
return getSMSTemplates(SMS_TEMPLATE_XML, SMS_PUBLIC_MODEL); |
||||
} |
||||
|
||||
public static Map<String, Object> getPrivateSMSTemplates() { |
||||
return getSMSTemplates(SMS_TEMPLATE_XML, SMS_PRIVATE_MODEL); |
||||
} |
||||
|
||||
public static Map<String, Object> getSMSTemplateMappings() { |
||||
return getSMSTemplates(SMS_TEMPLATE_MAPPING_XML, SMS_PUBLIC_MODEL); |
||||
} |
||||
|
||||
public static Map<String, Object> getSMSTemplates(String xmlPath, String type) { |
||||
if (!SMS_TEMPLATES_MAP.containsKey(type)) { |
||||
synchronized (com.fr.base.sms.SMSXmlReader.class) { |
||||
Map<String, Object> map = new ConcurrentHashMap<>(); |
||||
readXML(map, xmlPath, type); |
||||
if (!map.isEmpty()) { |
||||
SMS_TEMPLATES_MAP.put(type, map); |
||||
} |
||||
} |
||||
} |
||||
return SMS_TEMPLATES_MAP.get(type); |
||||
} |
||||
|
||||
private static void readXML(Map<String, Object> map, String xmlFile, String nodeName) { |
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
||||
String xmlPath = "com/fr/plugin/decision/third/sms/xml/".concat(xmlFile); |
||||
try { |
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); |
||||
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); |
||||
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); |
||||
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); |
||||
dbf.setXIncludeAware(false); |
||||
DocumentBuilder db = dbf.newDocumentBuilder(); |
||||
Document document = db.parse(SMSXmlReader.class.getClassLoader().getResourceAsStream(xmlPath)); |
||||
NodeList bookList = document.getElementsByTagName(nodeName); |
||||
for (int i = 0; i < bookList.getLength(); i++) { |
||||
Node node = bookList.item(i); |
||||
String id = node.getAttributes().getNamedItem("id").getTextContent(); |
||||
JSONObject jsonObject = JSONObject.create(); |
||||
jsonObject.put("id", id); |
||||
jsonObject.put("content", node.getAttributes().getNamedItem("content").getTextContent()); |
||||
jsonObject.put("language", node.getAttributes().getNamedItem("language").getTextContent()); |
||||
map.put(id, jsonObject); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,106 @@
|
||||
package com.fr.plugin.decision.third.sms.fun; |
||||
|
||||
import com.fr.base.sms.SMSTemplateType; |
||||
import com.fr.json.JSONArray; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.fun.SMSServiceProvider; |
||||
import org.w3c.dom.Document; |
||||
import org.w3c.dom.Node; |
||||
import org.w3c.dom.NodeList; |
||||
|
||||
import javax.xml.parsers.DocumentBuilder; |
||||
import javax.xml.parsers.DocumentBuilderFactory; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/11/8 |
||||
* 这个是短信发送的客户端,调用各家实际短信发送平台,这里只通过输出日志的方式提供一个示例 |
||||
*/ |
||||
public class SmsClient { |
||||
|
||||
private static final SmsClient instance = new SmsClient(); |
||||
private static final String SMS_PUBLIC_MODEL = "public-model"; |
||||
private static final String SMS_PRIVATE_MODEL = "private-model"; |
||||
|
||||
public static SmsClient getInstance() { |
||||
return instance; |
||||
} |
||||
|
||||
public String getSign() { |
||||
return "第三方短信"; |
||||
} |
||||
|
||||
/** |
||||
* 获取短信配置信息 |
||||
* |
||||
* @return 短信配置信息 |
||||
*/ |
||||
public Map<String, Object> getSmsConfig() { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
result.put("username", "优先级20"); |
||||
result.put("balance", 102.20); |
||||
result.put("isSmsAvailable", true); |
||||
result.put("accountType", 1); |
||||
result.put("publicModel", JSONArray.create(SMSXmlReader.getPublicSMSTemplates())); |
||||
result.put("privateModel", JSONArray.create(SMSXmlReader.getPrivateSMSTemplates())); |
||||
result.put("sign", getSign()); |
||||
|
||||
initSmsModels(result, "publicModel"); |
||||
initSmsModels(result, "privateModel"); |
||||
return result; |
||||
} |
||||
|
||||
public boolean send(String mobile) { |
||||
System.out.println("新插件(20)发送测试短信成功"); |
||||
FineLoggerFactory.getLogger().info("新插件(20)发送测试短信成功"); |
||||
return true; |
||||
} |
||||
|
||||
public boolean send(String template, String mobile, JSONObject para, String receiver) { |
||||
System.out.println("新插件(20)发送普通短信成功"); |
||||
FineLoggerFactory.getLogger().info("新插件(20)发送普通短信成功"); |
||||
return true; |
||||
} |
||||
|
||||
public boolean batchSend(String template, List<String> mobiles, JSONArray params, List<String> receivers) { |
||||
System.out.println("新插件(20)发送批量短信成功"); |
||||
FineLoggerFactory.getLogger().info("新插件(20)发送批量短信成功"); |
||||
return true; |
||||
} |
||||
|
||||
private void initSmsModels(Map<String, Object> result, String key) { |
||||
if (result.containsKey(key)) { |
||||
List<Map<String, Object>> smsModels = new ArrayList<Map<String, Object>>(); |
||||
JSONArray ja = (JSONArray) result.get(key); |
||||
for (int i = 0; i < ja.length(); i++) { |
||||
JSONObject jo = ja.optJSONObject(i); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
String language = jo.optString("language"); |
||||
if (StringUtils.isNotEmpty(language) && StringUtils.equals(key, "publicModel") && !StringUtils.equals(language, SMSTemplateType.MAINLAND_SMS_TEMPLATE.getLanguage())) { |
||||
continue; |
||||
} |
||||
map.put("id", jo.optString("id")); |
||||
map.put("content", jo.optString("content")); |
||||
map.put("language", language); |
||||
smsModels.add(map); |
||||
} |
||||
result.put(key, smsModels); |
||||
} |
||||
} |
||||
|
||||
public Map<String, Map<String, Object>> getSMSTemplate() { |
||||
Map<String, Map<String, Object>> result = new HashMap<>(); |
||||
result.put(SMS_PUBLIC_MODEL, SMSXmlReader.getPublicSMSTemplates()); |
||||
result.put(SMS_PRIVATE_MODEL, SMSXmlReader.getPrivateSMSTemplates()); |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,236 @@
|
||||
// 邮箱配置组件的注册过程一共分为4步:
|
||||
|
||||
// 1.基础配置
|
||||
var PRIORITY = 20; // 优先级(需要跟ThirdSmsServiceProvider#priority方法返回值一致),必须大于1,当有多个组件注册时,只有优先级最高的组件才会起作用
|
||||
var WIDGET_TYPE = 'demo.system.sms.config'; // 组件名称
|
||||
var MODEL_TYPE = 'demo.model.system.sms.config'; // 模型名称
|
||||
|
||||
// 2.定义组件
|
||||
var LAYOUT = { |
||||
ITEM_HEIGHT: 24, |
||||
ITEM_GAP: 15, |
||||
LABEL_WIDTH: 120, |
||||
}; |
||||
var Widget = BI.inherit(BI.Pane, { |
||||
props: { |
||||
baseCls: 'demo-system-sms-config', |
||||
}, |
||||
|
||||
_store: function () { |
||||
return BI.Models.getModel(MODEL_TYPE); |
||||
}, |
||||
|
||||
watch: { |
||||
'config.balance': function (value) { |
||||
this.balanceLabel.setText(config.balance + BI.i18nText('Dec-Basic_RMB')); |
||||
this.testButton.setEnable(value > 0); |
||||
}, |
||||
}, |
||||
|
||||
beforeRender: function (callback) { |
||||
var self = this; |
||||
self.loading(); |
||||
this.store.requestGetConfig(function () { |
||||
callback(); |
||||
self.loaded(); |
||||
}); |
||||
}, |
||||
|
||||
render: function () { |
||||
var self = this; |
||||
var config = self.model.config; |
||||
|
||||
return { |
||||
type: 'bi.vertical', |
||||
bgap: LAYOUT.ITEM_GAP, |
||||
items: [ |
||||
// 账号绑定
|
||||
{ |
||||
type: 'bi.vertical_adapt', |
||||
height: LAYOUT.ITEM_HEIGHT, |
||||
items: [ |
||||
{ |
||||
type: 'bi.label', |
||||
cls: 'dec-font-weight-bold', |
||||
width: LAYOUT.LABEL_WIDTH, |
||||
text: BI.i18nText('Dec-System_SMS_Account_Bind'), |
||||
textAlign: 'left', |
||||
title: BI.i18nText('Dec-System_SMS_Account_Bind'), |
||||
}, |
||||
{ |
||||
type: 'bi.label', |
||||
text: config.username, |
||||
textAlign: 'left', |
||||
}, |
||||
], |
||||
}, |
||||
// 账号余额
|
||||
{ |
||||
type: 'bi.vertical_adapt', |
||||
height: LAYOUT.ITEM_HEIGHT, |
||||
items: [ |
||||
{ |
||||
type: 'bi.label', |
||||
cls: 'dec-font-weight-bold', |
||||
width: LAYOUT.LABEL_WIDTH, |
||||
text: BI.i18nText('Dec-System_SMS_Account_Balance'), |
||||
textAlign: 'left', |
||||
title: BI.i18nText('Dec-System_SMS_Account_Balance'), |
||||
}, |
||||
{ |
||||
type: 'bi.label', |
||||
ref: function (_ref) { |
||||
self.balanceLabel = _ref; |
||||
}, |
||||
text: config.balance + BI.i18nText('Dec-Basic_RMB'), |
||||
textAlign: 'left', |
||||
}, |
||||
], |
||||
}, |
||||
// 短信签名
|
||||
{ |
||||
type: 'bi.vertical_adapt', |
||||
height: LAYOUT.ITEM_HEIGHT, |
||||
items: [ |
||||
{ |
||||
type: 'bi.label', |
||||
cls: 'dec-font-weight-bold', |
||||
width: LAYOUT.LABEL_WIDTH, |
||||
text: BI.i18nText('Dec-System_SMS_Signatures'), |
||||
textAlign: 'left', |
||||
title: BI.i18nText('Dec-System_SMS_Signatures'), |
||||
}, |
||||
{ |
||||
type: 'bi.label', |
||||
text: config.sign, |
||||
textAlign: 'left', |
||||
}, |
||||
], |
||||
}, |
||||
// 信息测试
|
||||
{ |
||||
type: 'bi.vertical_adapt', |
||||
height: LAYOUT.ITEM_HEIGHT, |
||||
items: [ |
||||
{ |
||||
type: 'bi.label', |
||||
cls: 'dec-font-weight-bold', |
||||
width: LAYOUT.LABEL_WIDTH, |
||||
text: BI.i18nText('Dec-System_SMS_Test'), |
||||
textAlign: 'left', |
||||
title: BI.i18nText('Dec-System_SMS_Test'), |
||||
}, |
||||
{ |
||||
type: 'bi.button', |
||||
ref: function (_ref) { |
||||
self.testButton = _ref; |
||||
}, |
||||
text: BI.i18nText('Dec-System_Send_Test_SMS'), |
||||
textAlign: 'left', |
||||
clear: true, |
||||
disabled: config.balance <= 0, |
||||
handler: function () { |
||||
self._sendTestMessage(); |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}; |
||||
}, |
||||
|
||||
/** |
||||
* 发送测试短信 |
||||
*/ |
||||
_sendTestMessage: function () { |
||||
var self = this; |
||||
var popoverName = BI.UUID(); |
||||
BI.Popovers.create(popoverName, { |
||||
type: 'bi.popover', |
||||
width: 450, |
||||
height: 220, |
||||
header: BI.i18nText('Dec-System_Send_Test_Sms'), |
||||
body: { |
||||
type: 'dec.send.test.msg.dialog', |
||||
listeners: [ |
||||
{ |
||||
eventName: BI.Popover.EVENT_CONFIRM, |
||||
action: function (phone) { |
||||
self.store.requsetSendTestMessage(phone); |
||||
}, |
||||
}, |
||||
{ |
||||
eventName: BI.Popover.EVENT_CLOSE, |
||||
action: function () { |
||||
BI.Popovers.remove(popoverName); |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
}); |
||||
BI.Popovers.show(popoverName); |
||||
}, |
||||
}); |
||||
|
||||
// 3.定义模型
|
||||
var Model = BI.inherit(Fix.Model, { |
||||
state: function () { |
||||
return { |
||||
config: { |
||||
isSmsAvailable: true, |
||||
accountType: 1, |
||||
username: '', |
||||
balance: 0, |
||||
sign: '', |
||||
publicModel: [], |
||||
privateModel: [], |
||||
}, |
||||
}; |
||||
}, |
||||
|
||||
actions: { |
||||
/** |
||||
* 获取邮箱配置 |
||||
* @param {Function} callback beforeRender的回调 |
||||
*/ |
||||
requestGetConfig: function (callback) { |
||||
var self = this; |
||||
// 发送请求,获取配置
|
||||
Dec.reqGetHandle('/v10/third/sms', '', function (data) { |
||||
self.model.config = data; |
||||
BI.isFunction(callback) && callback(); |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* 发送测试邮件 |
||||
* @param {string} phone 收件人号码 |
||||
*/ |
||||
requsetSendTestMessage: function (phone) { |
||||
var self = this; |
||||
Dec.reqPost( |
||||
'/v10/config/sms/test', |
||||
{ |
||||
mobile: phone, |
||||
}, |
||||
function (result) { |
||||
if (result && result.data && result.data.code === 'success') { |
||||
BI.Msg.toast(BI.i18nText('Dec-Send_Success'), { level: 'success' }); |
||||
} else { |
||||
BI.Msg.toast(BI.i18nText('Dec-System_SMS_Send_Fail'), { |
||||
level: 'error', |
||||
}); |
||||
} |
||||
self.requestGetConfig(); |
||||
} |
||||
); |
||||
}, |
||||
}, |
||||
}); |
||||
|
||||
// 4.注册组件
|
||||
BI.shortcut(WIDGET_TYPE, Widget); // 注册组件
|
||||
BI.model(MODEL_TYPE, Model); // 注册模型
|
||||
BI.config('dec.provider.system', function (provider) { |
||||
provider.registerSmsConfigWidget(WIDGET_TYPE, PRIORITY); // 注册邮箱配置组件
|
||||
}); |
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<sms-template> |
||||
<public-model id="10" content="【信息平台】尊敬的管理员,#taskname#于#time#运行失败,请知晓。" language="zh_CN"/> |
||||
<public-model id="306" content="【信息平台】尊敬的管理員,#taskname#於#time#運行失敗,請知曉。" language="zh_TW"/> |
||||
<public-model id="329" content="【信息平台】Dear administrator, #taskname# failed to run at #time#." language="en_US"/> |
||||
<public-model id="1005" content="【信息平台】Dear administrator" language="en_US"/> |
||||
|
||||
<private-model id="101" content="【第三方短信】私人短信" language="zh_CN"/> |
||||
<private-model id="102" content="【第三方短信】私人短信2" language="zh_CN"/> |
||||
</sms-template> |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<sms-template> |
||||
<public-model id="10" content="【我的短信映射】尊敬的管理员,#taskname#于#time#运行失败,请知晓。" language="zh_CN"/> |
||||
<public-model id="306" content="【我的短信映射】尊敬的管理員,#taskname#於#time#運行失敗,請知曉。" language="zh_TW"/> |
||||
<public-model id="329" content="【我的短信映射】Dear administrator, #taskname# failed to run at #time#." language="en_US"/> |
||||
</sms-template> |
Loading…
Reference in new issue