diff --git a/JSD-9185-需求确认书V1.docx b/JSD-9185-需求确认书V1.docx
new file mode 100644
index 0000000..3640b80
Binary files /dev/null and b/JSD-9185-需求确认书V1.docx differ
diff --git a/README.md b/README.md
index 4fd9462..4ff6f75 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-9185
-JSD-9185 基于服务调用客户消息接口
\ No newline at end of file
+JSD-9185 基于服务调用客户消息接口\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/lib/finekit-10.0.jar b/lib/finekit-10.0.jar
new file mode 100644
index 0000000..611c8f5
Binary files /dev/null and b/lib/finekit-10.0.jar differ
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..235ce64
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,18 @@
+
+
+ com.fr.plugin.third.party.jsdjbif
+
+ yes
+ 0.2
+ 10.0
+ 2019-01-01
+ fr.open
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/Utils.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/Utils.java
new file mode 100644
index 0000000..27f0e71
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/Utils.java
@@ -0,0 +1,156 @@
+package com.fr.plugin.third.party.jsdjbif;
+
+import com.fanruan.api.log.LogKit;
+import com.fanruan.api.util.StringKit;
+import com.fr.general.IOUtils;
+import com.fr.third.org.apache.http.HttpEntity;
+import com.fr.third.org.apache.http.HttpStatus;
+import com.fr.third.org.apache.http.client.config.RequestConfig;
+import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse;
+import com.fr.third.org.apache.http.client.methods.HttpGet;
+import com.fr.third.org.apache.http.client.methods.HttpPost;
+import com.fr.third.org.apache.http.conn.ssl.NoopHostnameVerifier;
+import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import com.fr.third.org.apache.http.entity.StringEntity;
+import com.fr.third.org.apache.http.impl.client.CloseableHttpClient;
+import com.fr.third.org.apache.http.impl.client.HttpClients;
+import com.fr.third.org.apache.http.ssl.SSLContextBuilder;
+import com.fr.third.org.apache.http.ssl.TrustStrategy;
+import com.fr.third.org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+public class Utils {
+ public static String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36";
+ public static RequestConfig REQUEST_CONFIG = RequestConfig.custom()
+ .setConnectionRequestTimeout(30000)
+ .setSocketTimeout(30000) // 服务端相应超时
+ .setConnectTimeout(30000) // 建立socket链接超时时间
+ .build();
+
+ public static CloseableHttpClient createSSLClientDefault() {
+ try {
+ SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+
+ @Override
+ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ return true;
+ }
+ }).build();
+ HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
+ return HttpClients.custom().setSSLSocketFactory(sslsf).build();
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ }
+ return HttpClients.createDefault();
+ }
+
+ public static synchronized CloseableHttpClient createHttpClient(String url) {
+ CloseableHttpClient httpClient = null;
+ if (StringKit.isEmpty(url)) {
+ httpClient = HttpClients.createDefault();
+ return httpClient;
+ }
+
+ if (url.startsWith("https://")) {
+ httpClient = createSSLClientDefault();
+ return httpClient;
+ }
+ httpClient = HttpClients.createDefault();
+ return httpClient;
+ }
+
+ public static synchronized String createHttpGetContent(CloseableHttpClient httpClient, String url) throws IOException {
+ if ((httpClient == null) || (StringKit.isEmpty(url))) {
+ return "";
+ }
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT);
+ httpGet.setConfig(Utils.REQUEST_CONFIG);
+ CloseableHttpResponse response = httpClient.execute(httpGet);
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != HttpStatus.SC_OK) {
+ response.close();
+ LogKit.info("http请求出错,http status:" + statusCode);
+ return "";
+ }
+
+ HttpEntity httpEntity = response.getEntity();
+ if (httpEntity == null) {
+ response.close();
+ LogKit.info("http请求出错,http响应内容为空");
+ return "";
+ }
+ String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
+ response.close();
+ if (StringKit.isEmpty(responseContent)) {
+ LogKit.info("http请求出错,http响应内容为空1");
+ return "";
+ }
+ return responseContent;
+ }
+
+ public static synchronized String createHttpPostContent(CloseableHttpClient httpClient, String url, String bodyContent) throws IOException {
+ if ((httpClient == null) || (StringKit.isEmpty(url)) || (StringKit.isEmpty(bodyContent))) {
+ return "";
+ }
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT);
+ httpPost.setConfig(Utils.REQUEST_CONFIG);
+ StringEntity bodyEntity = new StringEntity(bodyContent, "UTF-8");
+ httpPost.setEntity(bodyEntity);
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != HttpStatus.SC_OK) {
+ response.close();
+ LogKit.info("http请求出错,http status:" + statusCode);
+ return "";
+ }
+
+ HttpEntity httpEntity = response.getEntity();
+ if (httpEntity == null) {
+ response.close();
+ LogKit.info("http请求出错,http响应内容为空");
+ return "";
+ }
+ String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
+ response.close();
+ if (StringKit.isEmpty(responseContent)) {
+ LogKit.info("http请求出错,http响应内容为空1");
+ return "";
+ }
+ return responseContent;
+ }
+
+ /**
+ * 获取请求主体内容
+ * @param req
+ * @return
+ * @throws IOException
+ */
+ public static String getHttpRequestBody(HttpServletRequest req) throws IOException {
+ if (req == null) {
+ return "";
+ }
+ ServletInputStream inputStream = req.getInputStream();
+ if (inputStream == null) {
+ return "";
+ }
+ String content = IOUtils.inputStream2String(inputStream);
+ if (StringKit.isEmpty(content)) {
+ return "";
+ }
+ return content;
+ }
+
+
+}
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/config/CustomDataConfig.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/config/CustomDataConfig.java
new file mode 100644
index 0000000..e04f31d
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/config/CustomDataConfig.java
@@ -0,0 +1,103 @@
+package com.fr.plugin.third.party.jsdjbif.config;
+
+
+import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+
+/**
+ * 配置数据保存
+ */
+@Visualization(category = "发送消息")
+public class CustomDataConfig extends DefaultConfiguration {
+ public String getNameSpace() {
+ return this.getClass().getName();
+ }
+
+ private static volatile CustomDataConfig config = null;
+
+ public static CustomDataConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(CustomDataConfig.class);
+ }
+ return config;
+ }
+
+ @Identifier(value = "msgUrl", name = "消息地址", description = "", status = Status.SHOW)
+ private Conf msgUrl = Holders.simple("http://xxxx/ImMessageService.asmx");
+
+ @Identifier(value = "nSenderPlatID", name = "平台标识(nSenderPlatID)", description = "", status = Status.SHOW)
+ private Conf nSenderPlatID = Holders.simple("");
+
+ @Identifier(value = "nOnlineOnly", name = "是否只支持在线发送(nOnlineOnly)", description = "0:否;1:是", status = Status.SHOW)
+ private Conf nOnlineOnly = Holders.simple("0");
+
+ @Identifier(value = "nReserveDays", name = "保留天数(nReserveDays)", description = "", status = Status.SHOW)
+ private Conf nReserveDays = Holders.simple(2);
+
+ @Identifier(value = "strFromApp", name = "来源(strFromApp)", description = "", status = Status.SHOW)
+ private Conf strFromApp = Holders.simple("xxxx");
+
+ @Identifier(value = "strAppCode", name = "协同应用代码(strAppCode)", description = "", status = Status.SHOW)
+ private Conf strAppCode = Holders.simple("");
+
+ public String getMsgUrl() {
+ return msgUrl.get();
+ }
+
+ public void setMsgUrl(String msgUrl) {
+ this.msgUrl.set(msgUrl);
+ }
+
+ public String getnSenderPlatID() {
+ return nSenderPlatID.get();
+ }
+
+ public void setnSenderPlatID(String nSenderPlatID) {
+ this.nSenderPlatID.set(nSenderPlatID);
+ }
+
+ public String getnOnlineOnly() {
+ return nOnlineOnly.get();
+ }
+
+ public void setnOnlineOnly(String nOnlineOnly) {
+ this.nOnlineOnly.set(nOnlineOnly);
+ }
+
+ public Integer getnReserveDays() {
+ return nReserveDays.get();
+ }
+
+ public void setnReserveDays(Integer nReserveDays) {
+ this.nReserveDays.set(nReserveDays);
+ }
+
+ public String getStrFromApp() {
+ return strFromApp.get();
+ }
+
+ public void setStrFromApp(String strFromApp) {
+ this.strFromApp.set(strFromApp);
+ }
+
+ public String getStrAppCode() {
+ return strAppCode.get();
+ }
+
+ public void setStrAppCode(String strAppCode) {
+ this.strAppCode.set(strAppCode);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ CustomDataConfig cloned = (CustomDataConfig) super.clone();
+ cloned.msgUrl = (Conf) msgUrl.clone();
+ cloned.nSenderPlatID = (Conf) nSenderPlatID.clone();
+ cloned.nOnlineOnly = (Conf) nOnlineOnly.clone();
+ cloned.nReserveDays = (Conf) nReserveDays.clone();
+ cloned.strFromApp = (Conf) strFromApp.clone();
+ cloned.strAppCode = (Conf) strAppCode.clone();
+ return cloned;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/config/DataConfigInitializeMonitor.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/config/DataConfigInitializeMonitor.java
new file mode 100644
index 0000000..a09e0c6
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/config/DataConfigInitializeMonitor.java
@@ -0,0 +1,24 @@
+package com.fr.plugin.third.party.jsdjbif.config;
+
+import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+import com.fr.record.analyzer.EnableMetrics;
+
+/**
+ * 配置信息初始化
+ */
+@EnableMetrics
+public class DataConfigInitializeMonitor extends AbstractPluginLifecycleMonitor {
+ @Override
+ @Focus(id = "com.fr.plugin.third.party.jsdjbif", text = "plugin-jsdjbif", source = Original.PLUGIN)
+ public void afterRun(PluginContext pluginContext) {
+ CustomDataConfig.getInstance();
+ }
+
+ @Override
+ public void beforeStop(PluginContext pluginContext) {
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomHttpHandlerProvider.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomHttpHandlerProvider.java
new file mode 100644
index 0000000..eed95c4
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomHttpHandlerProvider.java
@@ -0,0 +1,15 @@
+package com.fr.plugin.third.party.jsdjbif.http;
+
+import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.stable.fun.Authorize;
+
+@Authorize(callSignKey = "com.fr.plugin.third.party.jsdjbif")
+public class CustomHttpHandlerProvider extends AbstractHttpHandlerProvider {
+ @Override
+ public BaseHttpHandler[] registerHandlers() {
+ return new BaseHttpHandler[]{
+ new SendMsgHttpHandler(),
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomURLAliasProvider.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomURLAliasProvider.java
new file mode 100644
index 0000000..9e9f8c0
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/CustomURLAliasProvider.java
@@ -0,0 +1,14 @@
+package com.fr.plugin.third.party.jsdjbif.http;
+
+import com.fr.decision.fun.impl.AbstractURLAliasProvider;
+import com.fr.decision.webservice.url.alias.URLAlias;
+import com.fr.decision.webservice.url.alias.URLAliasFactory;
+
+public class CustomURLAliasProvider extends AbstractURLAliasProvider {
+ @Override
+ public URLAlias[] registerAlias() {
+ return new URLAlias[]{
+ URLAliasFactory.createPluginAlias("/jsdjbif/SendCommonMessageByUserCode", "/jsdjbif/SendCommonMessageByUserCode", true),
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/third/party/jsdjbif/http/SendMsgHttpHandler.java b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/SendMsgHttpHandler.java
new file mode 100644
index 0000000..260f94a
--- /dev/null
+++ b/src/main/java/com/fr/plugin/third/party/jsdjbif/http/SendMsgHttpHandler.java
@@ -0,0 +1,191 @@
+package com.fr.plugin.third.party.jsdjbif.http;
+
+import com.fanruan.api.log.LogKit;
+import com.fanruan.api.util.StringKit;
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.json.JSONObject;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.third.party.jsdjbif.Utils;
+import com.fr.plugin.third.party.jsdjbif.config.CustomDataConfig;
+import com.fr.third.org.apache.http.HttpEntity;
+import com.fr.third.org.apache.http.HttpStatus;
+import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse;
+import com.fr.third.org.apache.http.client.methods.HttpPost;
+import com.fr.third.org.apache.http.entity.StringEntity;
+import com.fr.third.org.apache.http.impl.client.CloseableHttpClient;
+import com.fr.third.org.apache.http.util.EntityUtils;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ *
+ */
+public class SendMsgHttpHandler extends BaseHttpHandler {
+
+ @Override
+ public RequestMethod getMethod() {
+ return RequestMethod.POST;
+ }
+
+ @Override
+ public String getPath() {
+ return "/jsdjbif/SendCommonMessageByUserCode";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+ @Override
+ public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception {
+ res.setContentType("application/json; charset=utf-8");
+
+ //添加认证
+ if (!PluginContexts.currentContext().isAvailable()) {
+ LogKit.error("发送消息件试用过期, 请购买许可证");
+ WebUtils.printAsJSON(res, getResultJson("0", "发送消息件试用过期, 请购买许可证"));
+ return;
+ }
+
+ String reqContent = Utils.getHttpRequestBody(req);
+ if (StringKit.isEmpty(reqContent)) {
+ WebUtils.printAsJSON(res, getResultJson("0", "无内容传递"));
+ return;
+ }
+
+ JSONObject json = new JSONObject(reqContent);
+ String nSenderUserCode = json.getString("nSenderUserCode");
+ nSenderUserCode = StringKit.trim(nSenderUserCode);
+ if (StringKit.isEmpty(nSenderUserCode)) {
+ WebUtils.printAsJSON(res, getResultJson("0", "发送者用户账号为空"));
+ return;
+ }
+ String sReceiverPlatUserIds = json.getString("sReceiverPlatUserIds");
+ sReceiverPlatUserIds = StringKit.trim(sReceiverPlatUserIds);
+ if (StringKit.isEmpty(sReceiverPlatUserIds)) {
+ WebUtils.printAsJSON(res, getResultJson("0", "接受消息者为空"));
+ return;
+ }
+
+ String strContent = json.getString("strContent");
+ strContent = StringKit.trim(strContent);
+ if (StringKit.isEmpty(strContent)) {
+ WebUtils.printAsJSON(res, getResultJson("0", "内容为空"));
+ return;
+ }
+
+ try {
+ String msg = sendMsg(nSenderUserCode, sReceiverPlatUserIds, strContent);
+ if (StringKit.isNotEmpty(msg)) {
+ WebUtils.printAsJSON(res, getResultJson("0", msg));
+ return;
+ }
+ } catch (Exception e) {
+ WebUtils.printAsJSON(res, getResultJson("0", "发送出错"));
+ return;
+ }
+ WebUtils.printAsJSON(res, getResultJson("1", ""));
+ }
+
+ private JSONObject getResultJson(String code, String message) {
+ JSONObject json = new JSONObject();
+ json.put("message", message);
+ json.put("code", code);
+ return json;
+ }
+
+
+ /**
+ * 发送消息
+ *
+ * @param nSenderUserCode 发送者用户账号
+ * @param sReceiverPlatUserIds 接受消息者
+ * @param strContent strContent
+ * @return
+ */
+ private synchronized String sendMsg(String nSenderUserCode, String sReceiverPlatUserIds, String strContent) throws IOException {
+ String msgUrl = CustomDataConfig.getInstance().getMsgUrl();
+ HttpPost httpPost = new HttpPost(msgUrl);
+ httpPost.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT);
+ String receiverContent = createReceiver(sReceiverPlatUserIds);
+ if (StringKit.isEmpty(receiverContent)) {
+ return "接受者为空";
+ }
+ String bodyContent = "\n" +
+ "\n" +
+ " \n" +
+ " \n" +
+ " " + CustomDataConfig.getInstance().getnSenderPlatID() + "\n" +
+ " " + nSenderUserCode + "\n" +
+ " \n" +
+ " \n" +
+ " " + CustomDataConfig.getInstance().getnOnlineOnly() + "\n" +
+ " " + CustomDataConfig.getInstance().getnReserveDays() + "\n" +
+ " " + CustomDataConfig.getInstance().getStrFromApp() + "\n" +
+ " " + CustomDataConfig.getInstance().getStrAppCode() + "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+ LogKit.info("发送消息,http url:" + msgUrl);
+ LogKit.info("发送消息,http body:\n" + bodyContent);
+ httpPost.setEntity(new StringEntity(bodyContent, "UTF-8"));
+ httpPost.setHeader("Content-type", "application/soap+xml; charset=utf-8");
+ httpPost.setConfig(Utils.REQUEST_CONFIG);
+ CloseableHttpClient httpClient = Utils.createHttpClient(msgUrl);
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != HttpStatus.SC_OK) {
+ response.close();
+ httpClient.close();
+ LogKit.info("发送消息出错,http status:" + statusCode);
+ return "发送消息出错,http status:" + statusCode;
+ }
+
+ HttpEntity httpEntity = response.getEntity();
+ if (httpEntity == null) {
+ response.close();
+ httpClient.close();
+ LogKit.info("发送消息出错,http响应内容为空");
+ return "发送消息出错,http响应内容为空";
+ }
+ String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
+ response.close();
+ httpClient.close();
+ LogKit.info("发送消息,http响应内容\n" + responseContent);
+ return "";
+ }
+
+ private String createReceiver(String receiverContent) {
+ if (StringKit.isEmpty(receiverContent)) {
+ return "";
+ }
+ String[] receivers = receiverContent.split(",");
+ if ((receivers == null) || (receivers.length <= 0)) {
+ return "";
+ }
+ String senderPlatID = CustomDataConfig.getInstance().getnSenderPlatID();
+ String receiver, tempReceiver;
+ int count = 0;
+ String content = "";
+ for (int i = 0, max = receivers.length - 1; i <= max; i++) {
+ receiver = StringKit.trim(receivers[i]);
+ if (StringKit.isEmpty(receiver)) {
+ continue;
+ }
+ tempReceiver = senderPlatID + "@" + receiver;
+ if (count >= 1) {
+ content = content + ",";
+ }
+ content = content + tempReceiver;
+ count++;
+ }
+ return content;
+ }
+}