rsp) throws Exception;
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-task/pom.xml b/jframe-pay/jframe-pay-plugin/jframe-pay-task/pom.xml
index 2832f38..7af129f 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-task/pom.xml
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-task/pom.xml
@@ -1,9 +1,10 @@
-
- 4.0.0
-
- cn
- jframe-pay-plugin
- 1.0.0
-
- jframe-pay-task
+
+ 4.0.0
+
+ io.github.dzh
+ jframe-pay-plugin
+ 2.0.0-SNAPSHOT
+
+ jframe-pay-task
\ No newline at end of file
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/pom.xml b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/pom.xml
index d0ebf6f..319b805 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/pom.xml
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/pom.xml
@@ -1,68 +1,65 @@
- 4.0.0
-
- cn
- jframe-pay-plugin
- 1.0.0
-
- jframe-pay-upmp
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ io.github.dzh
+ jframe-pay-plugin
+ 2.0.0-SNAPSHOT
+
+ jframe-pay-upmp
-
-
- com.alibaba
- fastjson
- 1.1.41
-
-
- cn
- jframe-pay-dao
- 1.0.0
- plugin
-
-
- cn
- jframe-httpclient
- 1.0.0
- plugin
-
+
+
+ com.alibaba
+ fastjson
+
-
- com
- upacp_sdk
- 1.0.0
- system
- ${project.basedir}/compile/upacp_sdk-1.0.0-20150703140550.jar
-
-
- org.bouncycastle
- bcprov-jdk16
- 1.46
-
-
- commons-codec
- commons-codec
- 1.10
-
-
- commons-io
- commons-io
- 2.4
-
-
- commons-lang
- commons-lang
- 2.6
-
-
- log4j
- log4j
- 1.2.17
-
-
- org.slf4j
- slf4j-log4j12
- 1.7.13
-
-
+
+ com
+ upacp_sdk
+ 1.0.0
+ system
+ ${project.basedir}/compile/upacp_sdk-1.0.0-20150703140550.jar
+
+
+ org.bouncycastle
+ bcprov-jdk16
+ 1.46
+
+
+ commons-codec
+ commons-codec
+
+
+ commons-io
+ commons-io
+ 2.4
+
+
+ commons-lang
+ commons-lang
+ 2.6
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.13
+
+
+
+ io.github.dzh
+ jframe-pay-dao
+ plugin
+
+
+ io.github.dzh
+ jframe-httpclient
+ plugin
+
+
\ No newline at end of file
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/domain/UpmpConfig.java b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/domain/UpmpConfig.java
index 2323417..512b733 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/domain/UpmpConfig.java
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/domain/UpmpConfig.java
@@ -1,17 +1,16 @@
/**
- *
+ *
*/
package jframe.pay.upmp.domain;
+import jframe.core.util.PropsConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import jframe.ext.util.PropertiesConfig;
-
/**
*
*
- *
+ *
* @author dzh
* @date Nov 25, 2015 3:05:10 PM
* @since 1.0
@@ -37,7 +36,7 @@ public class UpmpConfig {
static final Logger LOG = LoggerFactory.getLogger(UpmpConfig.class);
- public static PropertiesConfig config = new PropertiesConfig();
+ public static PropsConf config = new PropsConf();
public static void init(String file) throws Exception {
config.init(file);
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/service/UpmppayServiceImpl.java b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/service/UpmppayServiceImpl.java
index f2c3ab6..ce09746 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/service/UpmppayServiceImpl.java
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-upmp/src/main/java/jframe/pay/upmp/service/UpmppayServiceImpl.java
@@ -1,27 +1,12 @@
/**
- *
+ *
*/
package jframe.pay.upmp.service;
-import java.net.URL;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.unionpay.acp.sdk.SDKConfig;
-
import jframe.core.conf.VarHandler;
-import jframe.core.plugin.annotation.InjectPlugin;
-import jframe.core.plugin.annotation.InjectService;
-import jframe.core.plugin.annotation.Injector;
-import jframe.core.plugin.annotation.Start;
-import jframe.core.plugin.annotation.Stop;
-import jframe.ext.util.PropertiesConfig;
+import jframe.core.plugin.annotation.*;
+import jframe.core.util.PropsConf;
import jframe.httpclient.service.HttpClientService;
import jframe.memcached.client.MemcachedService;
import jframe.pay.dao.service.PayDaoService;
@@ -37,6 +22,15 @@
import jframe.pay.upmp.domain.UpmpConfig;
import jframe.pay.upmp.domain.UpmpFields;
import jframe.pay.upmp.req.ConsumeReq;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* @author dzh
@@ -74,7 +68,7 @@ void start() {
VarHandler vh = new VarHandler(Plugin.getContext().getConfig());
UpmpConfig.config.replace(vh);
- PropertiesConfig acpSDK = new PropertiesConfig();
+ PropsConf acpSDK = new PropsConf();
acpSDK.init(UpmpConfig.getConf(UpmpConfig.KEY_ACP_SDK));
acpSDK.replace(vh);
SDKConfig.getConfig().loadProperties(acpSDK.clone2Properties());
@@ -102,7 +96,7 @@ public void pay(Map req, Map rsp) throws Excepti
return;
}
- rsp.put(F_filter, JsonUtil.createPropertyFilter(new String[] { F_rspCode, F_rspDesc, F_tn }));
+ rsp.put(F_filter, JsonUtil.createPropertyFilter(new String[]{F_rspCode, F_rspDesc, F_tn}));
if (ConsumeReq.consume(req, rsp)) {
OrderUpmp od = PayDao.selectOrderUpmp(req.get(F_payNo));
@@ -226,24 +220,22 @@ public void postBack(OrderUpmp od) {
URL url = new URL(od.backUrl);
int port = url.getPort() == -1 ? 80 : url.getPort();
- if (LOG.isDebugEnabled())
- LOG.debug("postBack -> {}, {},{}", url.toString(), new Date(), map);
- Long packtime = System.currentTimeMillis();
+ LOG.info("postBack -> {},{},{}", url, new Date(), map);
+ Long backtime = System.currentTimeMillis();
Map paras = new HashMap<>(HTTP_PARAS);
paras.put("ip", url.getHost());
paras.put("port", String.valueOf(port));
- Map rsp = HttpClient.> send("payback", url.getPath(),
+ String rsp = HttpClient.send("payback", url.getPath(),
HttpUtil.format(map, "utf-8"), null, paras);
Long packTime = System.currentTimeMillis();
- if (LOG.isDebugEnabled())
- LOG.debug("orderNo=" + od.orderNo + " postBack" + new Date() + " use time=" + (packTime - packtime)
- + " rsp=" + rsp);
- if (RspCode.SUCCESS.code.equals(rsp.get(F_rspCode))) {
- succ = true;
- } else {
- LOG.error("payNo=" + od.payNo + "rsp=" + rsp);
- }
+ LOG.info("postback orderNo={}, postBack->{}, use time->{}, rsp->{}", od.orderNo, url.getPath(),
+ (System.currentTimeMillis() - backtime), rsp);
+// if (RspCode.SUCCESS.code.equals(rsp.get(F_rspCode))) {
+// succ = true;
+// } else {
+// LOG.error("payNo=" + od.payNo + "rsp=" + rsp);
+// }
} catch (Exception e) {
succ = false;
LOG.error(e.getMessage());
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/pom.xml b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/pom.xml
index 0f45575..fb189db 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/pom.xml
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/pom.xml
@@ -1,45 +1,43 @@
- 4.0.0
-
- cn
- jframe-pay-plugin
- 1.0.0
-
- jframe-pay-wx
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ io.github.dzh
+ jframe-pay-plugin
+ 2.0.0-SNAPSHOT
+
+ jframe-pay-wx
-
-
- commons-dbutils
- commons-dbutils
- 1.6
-
-
- org.jdom
- jdom
- 2.0.2
-
-
- org.json
- json
- 20140107
-
-
- com.alibaba
- fastjson
- 1.1.41
-
-
- cn
- jframe-pay-dao
- 1.0.0
- plugin
-
-
- cn
- jframe-httpclient
- 1.0.0
- plugin
-
-
+
+
+ commons-dbutils
+ commons-dbutils
+ 1.6
+
+
+ org.jdom
+ jdom
+ 2.0.2
+
+
+ org.json
+ json
+ 20140107
+
+
+ com.alibaba
+ fastjson
+
+
+
+ io.github.dzh
+ jframe-pay-dao
+ plugin
+
+
+ io.github.dzh
+ jframe-httpclient
+ plugin
+
+
\ No newline at end of file
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/domain/WxConfig.java b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/domain/WxConfig.java
index 64dd8c6..3ab6677 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/domain/WxConfig.java
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/domain/WxConfig.java
@@ -1,13 +1,12 @@
/**
- *
+ *
*/
package jframe.pay.wx.domain;
+import jframe.core.util.PropsConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import jframe.ext.util.PropertiesConfig;
-
/**
* @author dzh
* @date Sep 25, 2014 1:49:56 PM
@@ -39,7 +38,7 @@ public class WxConfig {
static Logger LOG = LoggerFactory.getLogger(WxConfig.class);
- public static PropertiesConfig config = new PropertiesConfig();
+ public static PropsConf config = new PropsConf();
public static void init(String file) throws Exception {
config.init(file);
diff --git a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/service/WxpayServiceImpl.java b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/service/WxpayServiceImpl.java
index 5074c6c..7c209c8 100644
--- a/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/service/WxpayServiceImpl.java
+++ b/jframe-pay/jframe-pay-plugin/jframe-pay-wx/src/main/java/jframe/pay/wx/service/WxpayServiceImpl.java
@@ -1,20 +1,6 @@
package jframe.pay.wx.service;
-import java.net.URL;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import jframe.core.plugin.annotation.InjectPlugin;
-import jframe.core.plugin.annotation.InjectService;
-import jframe.core.plugin.annotation.Injector;
-import jframe.core.plugin.annotation.Start;
-import jframe.core.plugin.annotation.Stop;
+import jframe.core.plugin.annotation.*;
import jframe.httpclient.service.HttpClientService;
import jframe.memcached.client.MemcachedService;
import jframe.pay.dao.service.PayDaoService;
@@ -30,6 +16,15 @@
import jframe.pay.wx.domain.WxConfig;
import jframe.pay.wx.domain.WxFields;
import jframe.pay.wx.http.client.WxServiceNew;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
@Injector
public class WxpayServiceImpl implements WxpayService, WxFields {
@@ -178,7 +173,7 @@ public void payBack(Map req, Map rsp) throws Exc
/**
* TODO BitSet
- *
+ *
* @param req
* @return
*/
@@ -324,10 +319,8 @@ public void wxPayBack(Map req, Map rsp) throws E
/**
* 通知租车后台
- *
- * @param conn
+ *
* @param od
- * @param orderStatus
*/
public void postBack(OrderWx od) {
Map map = new HashMap(2, 1);
@@ -339,26 +332,23 @@ public void postBack(OrderWx od) {
URL url = new URL(od.backUrl);
int port = url.getPort() == -1 ? 80 : url.getPort();
- if (LOG.isDebugEnabled())
- LOG.debug("postBack -> {}, {},{}", url.toString(), new Date(), map);
- Long packtime = System.currentTimeMillis();
+ LOG.info("postBack -> {},{},{}", url, new Date(), map);
+ Long backtime = System.currentTimeMillis();
Map paras = new HashMap<>(HTTP_PARAS);
paras.put("ip", url.getHost());
paras.put("port", String.valueOf(port));
- Map rsp = HttpClient.> send("payback", url.getPath(),
+ String rsp = HttpClient.send("payback", url.getPath(),
HttpUtil.format(map, "utf-8"), null, paras);
Long packTime = System.currentTimeMillis();
- if (LOG.isDebugEnabled())
- LOG.debug("orderNo=" + od.orderNo + " postBack" + new Date() + " use time=" + (packTime - packtime)
- + " rsp=" + rsp);
- if (RspCode.SUCCESS.code.equals(rsp.get(F_rspCode))) {
- succ = true;
- } else {
- LOG.error("payNo=" + od.payNo + "rsp=" + rsp);
- }
+ LOG.info("postback orderNo={}, postBack->{}, use time->{}, rsp->{}", od.orderNo, url.getPath(),
+ (System.currentTimeMillis() - backtime), rsp);
+// if (RspCode.SUCCESS.code.equals(rsp.get(F_rspCode))) {
+// succ = true;
+// } else {
+// LOG.error("payNo=" + od.payNo + "rsp=" + rsp);
+// }
} catch (Exception e) {
- succ = false;
LOG.error(e.getMessage());
}
diff --git a/jframe-pay/jframe-pay-plugin/pom.xml b/jframe-pay/jframe-pay-plugin/pom.xml
index 0eabf0d..81bce4c 100644
--- a/jframe-pay/jframe-pay-plugin/pom.xml
+++ b/jframe-pay/jframe-pay-plugin/pom.xml
@@ -1,45 +1,45 @@
- 4.0.0
-
- cn
- jframe-pay
- 1.0.0
-
- jframe-pay-plugin
- pom
-
- jframe-pay-alipay
- jframe-pay-wx
- jframe-pay-http
- jframe-pay-dao
- jframe-pay-task
- jframe-pay-upmp
-
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ io.github.dzh
+ jframe-pay
+ 2.0.0-SNAPSHOT
+
+ jframe-pay-plugin
+ pom
+
+ jframe-pay-alipay
+ jframe-pay-wx
+ jframe-pay-http
+ jframe-pay-dao
+ jframe-pay-task
+ jframe-pay-upmp
+ jframe-pay-client
+
-
-
-
- maven-jar-plugin
- 2.4
-
- plugin
-
-
-
-
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+ plugin
+
+
+
+
-
-
- jframe-pay-domain
- cn
- 1.0.0
-
-
- cn
- jframe-memcached-client
- 1.0.0
- plugin
-
-
+
+
+ io.github.dzh
+ jframe-pay-domain
+
+
+
+ io.github.dzh
+ jframe-memcached-client
+ plugin
+
+
\ No newline at end of file
diff --git a/jframe-pay/release/jframe-pay/bin/jframe.sh b/jframe-pay/jframe-pay-release/bin/jframe.sh
similarity index 100%
rename from jframe-pay/release/jframe-pay/bin/jframe.sh
rename to jframe-pay/jframe-pay-release/bin/jframe.sh
diff --git a/jframe-pay/jframe-pay-release/filter.properties.example b/jframe-pay/jframe-pay-release/filter.properties.example
new file mode 100644
index 0000000..e69de29
diff --git a/jframe-pay/release/jframe-pay/conf/acp_sdk_dev.properties b/jframe-pay/jframe-pay-release/filter/acp_sdk_dev.properties
similarity index 98%
rename from jframe-pay/release/jframe-pay/conf/acp_sdk_dev.properties
rename to jframe-pay/jframe-pay-release/filter/acp_sdk_dev.properties
index aac64e1..090f453 100644
--- a/jframe-pay/release/jframe-pay/conf/acp_sdk_dev.properties
+++ b/jframe-pay/jframe-pay-release/filter/acp_sdk_dev.properties
@@ -1,5 +1,4 @@
###### SDK \u914d\u7f6e\u6587\u4ef6 \u914d\u7f6e\u6587\u4ef6\u4e2d\u65e5\u5fd7\u548c\u8bc1\u4e66\u7684\u5b58\u653e\u8def\u5f84\u6839\u636e\u5b9e\u9645\u60c5\u51b5\u914d\u7f6e\uff0c\u4ea4\u6613\u5730\u5740\u548c\u8bc1\u4e66\u6839\u636ePM\u73af\u5883\u3001\u751f\u4ea7\u73af\u5883\u914d\u5957\u914d\u7f6e#####
-
##########################\u4ea4\u6613\u53d1\u9001\u5730\u5740\u914d\u7f6e#############################
######(\u4ee5\u4e0b\u914d\u7f6e\u4e3aPM\u73af\u5883\uff1a\u5165\u7f51\u6d4b\u8bd5\u73af\u5883\u7528\uff0c\u751f\u4ea7\u73af\u5883\u914d\u7f6e\u89c1\u6587\u6863\u8bf4\u660e)#######
##\u524d\u53f0\u4ea4\u6613\u8bf7\u6c42\u5730\u5740
@@ -16,9 +15,6 @@ acpsdk.batchTransUrl=https://101.231.204.80:5000/gateway/api/batchTransReq.do
acpsdk.fileTransUrl=https://101.231.204.80:9080/
## app \u4EA4\u6613\u8BF7\u6C42\u5730\u5740
acpsdk.appTransUrl=https://101.231.204.80:5000/gateway/api/appTransReq.do
-
-
-
#########################\u7b7e\u540d\u8bc1\u4e66\u914d\u7f6e ################################
######(\u4ee5\u4e0b\u914d\u7f6e\u4e3aPM\u73af\u5883\uff1a\u5165\u7f51\u6d4b\u8bd5\u73af\u5883\u7528\uff0c\u751f\u4ea7\u73af\u5883\u914d\u7f6e\u89c1\u6587\u6863\u8bf4\u660e)#######
##\u7b7e\u540d\u8bc1\u4e66\u8def\u5f84
@@ -27,8 +23,6 @@ acpsdk.signCert.path=D:\\certs\\PM_700000000000001_acp.pfx
acpsdk.signCert.pwd=000000
##\u7b7e\u540d\u8bc1\u4e66\u7c7b\u578b
acpsdk.signCert.type=PKCS12
-
-
##########################\u9a8c\u7b7e\u8bc1\u4e66\u914d\u7f6e################################
##\u9a8c\u8bc1\u7b7e\u540d\u8bc1\u4e66\u76ee\u5f55
acpsdk.validateCert.dir=D:\\certs\\
diff --git a/jframe-pay/release/jframe-pay/conf/acp_sdk_run.properties b/jframe-pay/jframe-pay-release/filter/acp_sdk_run.properties
similarity index 98%
rename from jframe-pay/release/jframe-pay/conf/acp_sdk_run.properties
rename to jframe-pay/jframe-pay-release/filter/acp_sdk_run.properties
index aac64e1..090f453 100644
--- a/jframe-pay/release/jframe-pay/conf/acp_sdk_run.properties
+++ b/jframe-pay/jframe-pay-release/filter/acp_sdk_run.properties
@@ -1,5 +1,4 @@
###### SDK \u914d\u7f6e\u6587\u4ef6 \u914d\u7f6e\u6587\u4ef6\u4e2d\u65e5\u5fd7\u548c\u8bc1\u4e66\u7684\u5b58\u653e\u8def\u5f84\u6839\u636e\u5b9e\u9645\u60c5\u51b5\u914d\u7f6e\uff0c\u4ea4\u6613\u5730\u5740\u548c\u8bc1\u4e66\u6839\u636ePM\u73af\u5883\u3001\u751f\u4ea7\u73af\u5883\u914d\u5957\u914d\u7f6e#####
-
##########################\u4ea4\u6613\u53d1\u9001\u5730\u5740\u914d\u7f6e#############################
######(\u4ee5\u4e0b\u914d\u7f6e\u4e3aPM\u73af\u5883\uff1a\u5165\u7f51\u6d4b\u8bd5\u73af\u5883\u7528\uff0c\u751f\u4ea7\u73af\u5883\u914d\u7f6e\u89c1\u6587\u6863\u8bf4\u660e)#######
##\u524d\u53f0\u4ea4\u6613\u8bf7\u6c42\u5730\u5740
@@ -16,9 +15,6 @@ acpsdk.batchTransUrl=https://101.231.204.80:5000/gateway/api/batchTransReq.do
acpsdk.fileTransUrl=https://101.231.204.80:9080/
## app \u4EA4\u6613\u8BF7\u6C42\u5730\u5740
acpsdk.appTransUrl=https://101.231.204.80:5000/gateway/api/appTransReq.do
-
-
-
#########################\u7b7e\u540d\u8bc1\u4e66\u914d\u7f6e ################################
######(\u4ee5\u4e0b\u914d\u7f6e\u4e3aPM\u73af\u5883\uff1a\u5165\u7f51\u6d4b\u8bd5\u73af\u5883\u7528\uff0c\u751f\u4ea7\u73af\u5883\u914d\u7f6e\u89c1\u6587\u6863\u8bf4\u660e)#######
##\u7b7e\u540d\u8bc1\u4e66\u8def\u5f84
@@ -27,8 +23,6 @@ acpsdk.signCert.path=D:\\certs\\PM_700000000000001_acp.pfx
acpsdk.signCert.pwd=000000
##\u7b7e\u540d\u8bc1\u4e66\u7c7b\u578b
acpsdk.signCert.type=PKCS12
-
-
##########################\u9a8c\u7b7e\u8bc1\u4e66\u914d\u7f6e################################
##\u9a8c\u8bc1\u7b7e\u540d\u8bc1\u4e66\u76ee\u5f55
acpsdk.validateCert.dir=D:\\certs\\
diff --git a/jframe-pay/release/jframe-pay/conf/activemq.properties b/jframe-pay/jframe-pay-release/filter/activemq.properties
similarity index 55%
rename from jframe-pay/release/jframe-pay/conf/activemq.properties
rename to jframe-pay/jframe-pay-release/filter/activemq.properties
index 79c467a..91832d9 100644
--- a/jframe-pay/release/jframe-pay/conf/activemq.properties
+++ b/jframe-pay/jframe-pay-release/filter/activemq.properties
@@ -1,10 +1,8 @@
# def conf
-mq.url = tcp://192.168.1.123:61616
-mq.queue.pay = pay-queue
-
-# producer mq
+mq.url=tcp://192.168.1.123:61616
+mq.queue.pay=pay-queue
+# producer mq
#p.url = tcp://192.168.1.123:61616
-
# consumer mq
#c.url = tcp://192.168.1.123:61616
diff --git a/jframe-pay/jframe-pay-release/filter/alipay.properties b/jframe-pay/jframe-pay-release/filter/alipay.properties
new file mode 100644
index 0000000..d30fdac
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/alipay.properties
@@ -0,0 +1,20 @@
+group.id=test
+notify_url=http://ip:port/pay/ord/aliback
+#
+@test.partner=208********202
+@test.seller.id=*****@***.com
+@test.subject=**\u79df\u8f66
+@test.app.id=****
+@test.private.key=
+@test.public.key =
+@test.ali_public_key=
+service = mobile.securitypay.pay
+payment_type=1
+input_charset=UTF-8
+it_b_pay=1h
+# return_url
+# paymethod
+# algo
+sign.type=RSA
+default_charset=UTF-8
+sign.algorithms=SHA1WithRSA
diff --git a/jframe-pay/release/jframe-pay/conf/config.properties b/jframe-pay/jframe-pay-release/filter/config.properties
similarity index 61%
rename from jframe-pay/release/jframe-pay/conf/config.properties
rename to jframe-pay/jframe-pay-release/filter/config.properties
index c1269c6..5e842ed 100755
--- a/jframe-pay/release/jframe-pay/conf/config.properties
+++ b/jframe-pay/jframe-pay-release/filter/config.properties
@@ -1,90 +1,78 @@
#application directory
-app.conf = ${app.home}/conf
-app.lib = ${app.home}/lib
-app.plugin = ${app.home}/plugin
+app.conf=${app.home}/conf
+app.lib=${app.home}/lib
+app.plugin=${app.home}/plugin
# upgrade file store directory
-app.update = ${app.home}/update
+app.update=${app.home}/update
# plug-in cache directory
-app.cache = ${app.home}/conf/cache
+app.cache=${app.home}/conf/cache
# plug-in temporary directory
-app.temp = ${app.home}/temp
-
+app.temp=${app.home}/temp
#configuration files
#file.units = ${app.home}/conf/units.xml
#file.signals = ${app.home}/conf/signals.def
-clean = true
+clean=true
#application's name,every app should has it's own name
-app.name = jframe.pay
+app.name=jframe.pay
#frame
-app.frame = jframe.core.DefFrame
-app.launcher = jframe.core.FrameLauncher
-
+app.frame=jframe.core.DefFrame
+app.launcher=jframe.core.FrameLauncher
#jvm's configuration file
-vmargs = ${app.home}/conf/vmargs
+vmargs=${app.home}/conf/vmargs
#if system is windows,use vmargs-win
#vmargs=${app.home}/conf/vmargs-win
-
#application's pid file
-app.pid = ${app.home}/temp/app.pid
+app.pid=${app.home}/temp/app.pid
#daemon process's pid file
-daemon.pid = ${app.home}/temp/daemon.pid
+daemon.pid=${app.home}/temp/daemon.pid
#launcher = jframe.launcher.FrameMain
#mode=daemon or normal,launch with daemon mode, otherwise launching normally
-launch.mode = daemon
+launch.mode=daemon
#context
#default dispatcher is jframe.core.dispatch.DefDispatcher
#context.dispatcher = jframe.ext.msg.pool.MsgPoolDispatcher
#context.dispatcher = jframe.ext.dispatch.ActivemqDispatcher
#file.dispatcher.mq = ${app.home}/conf/d-activemq.properties
-
-# plugins won't be started when starting
+# plugins won't be started when starting
#plugin.forbid = jframe.example.plugin.ExamplePlugin
-
# datasource
#multi.datasource=masterdb slavedb
#file.masterdb = ${app.home}/conf/mysql.properties
#file.slavedb = ${app.home}/conf/mysql_ro1.properties
#file.datasource = ${app.home}/conf/datasource.properties
-
# mybatis
-file.mybatis = ${app.home}/conf/mybatis-config.xml
-mybatis.id = run run_ro1
-file.mybatis.charset = utf-8
-
-
-file.upmp = ${app.home}/conf/upmp.properties
+file.mybatis=${app.home}/conf/mybatis-config.xml
+mybatis.id=run run_ro1
+file.mybatis.charset=utf-8
+file.upmp=${app.home}/conf/upmp.properties
#file.upmp = ${app.home}/conf/upmp_p.properties
-file.alipay = ${app.home}/conf/alipay.properties
-file.wx = ${app.home}/conf/wxpay.properties
+file.alipay=${app.home}/conf/alipay.properties
+file.wx=${app.home}/conf/wxpay.properties
#file.wx.pfx = ${app.home}/conf/1219114301_20140516113900.pfx
#alipay.properties
-groupid.alipay = test
+groupid.alipay=test
#wx.properties
-groupid.wxpay = test
+groupid.wxpay=test
#upmp.properties
-groupid.upmppay = test
-
-# http
-http.port = 8028
-https.enabled = false
-
+groupid.upmppay=test
+# http
+http.port=8028
+https.enabled=false
#redis conf file
#redis.conf = ${app.home}/conf/redis.properties
#file.getui = ${app.home}/conf/getui.properties
#file.pushy = ${app.home}/conf/pushy.properties
# task
-file.task = ${app.home}/conf/task.properties
+file.task=${app.home}/conf/task.properties
# activemq
#file.activemq = ${app.home}/conf/activemq.properties
-file.memcached = ${app.home}/conf/memcached.properties
+file.memcached=${app.home}/conf/memcached.properties
#file.emayclient = ${app.home}/conf/emayclient.properties
#file.yunpian = ${app.home}/conf/yunpian.properties
-file.httpclient = ${app.home}/conf/httpclient.properties
-
+file.httpclient=${app.home}/conf/httpclient.properties
#file.payclient = ${app.home}/conf/payclient.properties
#upmp.back.url = http://localhost:8018/pay/back/upmp
#file.qiniu = ${app.home}/conf/qiniu.properties
#file.mongoclient = ${app.home}/conf/mongoclient.properties
-
-token.disable = true
-jframe.debug = true
+token.disable=true
+jframe.debug=true
diff --git a/jframe-pay/release/jframe-pay/conf/d-activemq.properties b/jframe-pay/jframe-pay-release/filter/d-activemq.properties
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/d-activemq.properties
rename to jframe-pay/jframe-pay-release/filter/d-activemq.properties
diff --git a/jframe-pay/release/jframe-pay/conf/datasource.properties b/jframe-pay/jframe-pay-release/filter/datasource.properties
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/datasource.properties
rename to jframe-pay/jframe-pay-release/filter/datasource.properties
diff --git a/jframe-pay/release/jframe-pay/conf/http.properties b/jframe-pay/jframe-pay-release/filter/http.properties
similarity index 94%
rename from jframe-pay/release/jframe-pay/conf/http.properties
rename to jframe-pay/jframe-pay-release/filter/http.properties
index 04427c6..ac4bd45 100644
--- a/jframe-pay/release/jframe-pay/conf/http.properties
+++ b/jframe-pay/jframe-pay-release/filter/http.properties
@@ -1,14 +1,11 @@
# 连接超时
http.connection.timeout=15000
-
# 应答超时
http.so.timeout=30000
-
# 网络参数
http.stale.check.enabled=true
http.tcp.no.delay=true
http.default.max.connections.per.host=100
http.max.total.connections=1000
-
# 字符集
http.content.encoding=utf-8
\ No newline at end of file
diff --git a/jframe-pay/jframe-pay-release/filter/httpclient.properties b/jframe-pay/jframe-pay-release/filter/httpclient.properties
new file mode 100755
index 0000000..66e674f
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/httpclient.properties
@@ -0,0 +1,16 @@
+group.id=payback
+#@indexHost.http.method = post
+#@indexHost.http.max.conn.route = 200
+#@indexHost.http.keep-alive = 5
+#@payback.ip = 127.0.0.1
+#@payback.port = 80
+@payback.group=jframe.pay
+http.method=post
+http.max.conn=100
+http.max.conn.route=200
+http.keep-alive=5
+#second
+http.idle.conn.close=30
+http.charset=utf-8
+http.so.timeout=2000
+http.conn.timeout=2000
diff --git a/jframe-pay/release/jframe-pay/conf/jmxremote.access b/jframe-pay/jframe-pay-release/filter/jmxremote.access
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/jmxremote.access
rename to jframe-pay/jframe-pay-release/filter/jmxremote.access
diff --git a/jframe-pay/release/jframe-pay/conf/jmxremote.password b/jframe-pay/jframe-pay-release/filter/jmxremote.password
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/jmxremote.password
rename to jframe-pay/jframe-pay-release/filter/jmxremote.password
diff --git a/jframe-pay/jframe-pay-release/filter/logback-daemon.xml b/jframe-pay/jframe-pay-release/filter/logback-daemon.xml
new file mode 100644
index 0000000..c21f188
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/logback-daemon.xml
@@ -0,0 +1,45 @@
+
+
+ Application Daemon
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+ ${LOG_HOME}/jfd-%d{yyyy-MM-dd}.log
+
+ 10
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jframe-pay/jframe-pay-release/filter/logback.xml b/jframe-pay/jframe-pay-release/filter/logback.xml
new file mode 100644
index 0000000..ddf31d4
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/logback.xml
@@ -0,0 +1,39 @@
+
+
+ Application
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+ ${LOG_HOME}/jf-%d{yyyy-MM-dd}.log
+
+ 10
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jframe-pay/release/jframe-pay/conf/management.properties b/jframe-pay/jframe-pay-release/filter/management.properties
similarity index 99%
rename from jframe-pay/release/jframe-pay/conf/management.properties
rename to jframe-pay/jframe-pay-release/filter/management.properties
index db08b78..48aad26 100644
--- a/jframe-pay/release/jframe-pay/conf/management.properties
+++ b/jframe-pay/jframe-pay-release/filter/management.properties
@@ -28,7 +28,6 @@
#
# For setting the SNMP agent port use the following line
# com.sun.management.snmp.port=
-
#####################################################################
# Optional Instrumentation
#####################################################################
@@ -45,10 +44,8 @@
# Refer to the specification for the java.lang.management.ThreadMBean
# interface - see isThreadContentionMonitoringSupported() method.
#
-
# To enable thread contention monitoring, uncomment the following line
# com.sun.management.enableThreadContentionMonitoring
-
#####################################################################
# SNMP Management Properties
#####################################################################
@@ -63,7 +60,6 @@
# Later changes to the above system property (e.g. via setProperty method), this
# config file, or the ACL file has no effect to the running SNMP agent.
#
-
#
# ##################### SNMP Trap Port #########################
#
@@ -73,10 +69,8 @@
# the SNMP agent will send traps at :
# Default for this property is 162.
#
-
# To set port for sending traps to a different port use the following line
# com.sun.management.snmp.trap=
-
#
# ################ SNMP listen interface #########################
#
@@ -90,10 +84,8 @@
# The format of the value for that property is any string accepted
# by java.net.InetAddress.getByName(String).
#
-
# For restricting the port on which SNMP agent listens use the following line
# com.sun.management.snmp.interface=
-
#
# #################### SNMP ACL file #########################
#
@@ -102,10 +94,8 @@
# If this property is specified as false then the ACL file
# is not checked: all manager hosts are allowed all access.
#
-
# For SNMP without checking ACL file uncomment the following line
# com.sun.management.snmp.acl=false
-
#
# com.sun.management.snmp.acl.file=filepath
# Specifies location for ACL file
@@ -121,10 +111,8 @@
# Modification to the ACL file has no effect to any running SNMP
# agents which read that ACL file at startup.
#
-
# For a non-default acl file location use the following line
# com.sun.management.snmp.acl.file=filepath
-
#####################################################################
# RMI Management Properties
#####################################################################
@@ -142,7 +130,6 @@
# this config file, the password file, or the access file have no effect to the
# running MBean server, the connector, or the registry.
#
-
#
# ########## RMI connector settings for local management ##########
#
@@ -158,11 +145,9 @@
# For remote management the remote JMX RMI connector server should
# be used instead with authentication and SSL/TLS encryption enabled.
#
-
# For allowing the local management agent accept local
# and remote connection requests use the following line
# com.sun.management.jmxremote.local.only=false
-
#
# ###################### RMI SSL #############################
#
@@ -170,10 +155,8 @@
# Default for this property is true. (Case for true/false ignored)
# If this property is specified as false then SSL is not used.
#
-
# For RMI monitoring without SSL use the following line
# com.sun.management.jmxremote.ssl=false
-
# com.sun.management.jmxremote.ssl.config.file=filepath
# Specifies the location of the SSL configuration file. A properties
# file can be used to supply the keystore and truststore location and
@@ -194,10 +177,8 @@
# If the property "com.sun.management.jmxremote.ssl" is set to false,
# then this property is ignored.
#
-
# For supplying the keystore settings in a file use the following line
# com.sun.management.jmxremote.ssl.config.file=filepath
-
# com.sun.management.jmxremote.ssl.enabled.cipher.suites=
# The value of this property is a string that is a comma-separated list
# of SSL/TLS cipher suites to enable. This property can be specified in
@@ -207,7 +188,6 @@
# the SSL/TLS RMI Server Socket Factory uses the SSL/TLS cipher suites that
# are enabled by default.
#
-
# com.sun.management.jmxremote.ssl.enabled.protocols=
# The value of this property is a string that is a comma-separated list
# of SSL/TLS protocol versions to enable. This property can be specified in
@@ -217,17 +197,14 @@
# specified then the SSL/TLS RMI Server Socket Factory uses the SSL/TLS
# protocol versions that are enabled by default.
#
-
# com.sun.management.jmxremote.ssl.need.client.auth=true|false
# Default for this property is false. (Case for true/false ignored)
# If this property is specified as true in conjunction with the previous
# property "com.sun.management.jmxremote.ssl" then the SSL/TLS RMI Server
# Socket Factory will require client authentication.
#
-
# For RMI monitoring with SSL client authentication use the following line
# com.sun.management.jmxremote.ssl.need.client.auth=true
-
# com.sun.management.jmxremote.registry.ssl=true|false
# Default for this property is false. (Case for true/false ignored)
# If this property is specified as true then the RMI registry used
@@ -243,10 +220,8 @@
# then the RMIServer remote object and the RMI registry are
# both exported with the same SSL/TLS RMI Socket Factories.
#
-
# For using an SSL/TLS protected RMI registry use the following line
# com.sun.management.jmxremote.registry.ssl=true
-
#
# ################ RMI User authentication ################
#
@@ -255,10 +230,8 @@
# If this property is specified as false then no authentication is
# performed and all users are allowed all access.
#
-
# For RMI monitoring without any checking use the following line
# com.sun.management.jmxremote.authenticate=false
-
#
# ################ RMI Login configuration ###################
#
@@ -279,10 +252,8 @@
# If the property "com.sun.management.jmxremote.authenticate" is set to
# false, then this property and the password & access files are ignored.
#
-
# For a non-default login configuration use the following line
# com.sun.management.jmxremote.login.config=
-
#
# ################ RMI Password file location ##################
#
@@ -296,10 +267,8 @@
# Otherwise the password file must exist and be in the valid format.
# If the password file is empty or non-existent then no access is allowed.
#
-
# For a non-default password file location use the following line
# com.sun.management.jmxremote.password.file=filepath
-
#
# ################ RMI Access file location #####################
#
@@ -313,6 +282,5 @@
# Otherwise, the access file must exist and be in the valid format.
# If the access file is empty or non-existent then no access is allowed.
#
-
# For a non-default password file location use the following line
# com.sun.management.jmxremote.access.file=filepath
diff --git a/jframe-pay/jframe-pay-release/filter/memcached.properties b/jframe-pay/jframe-pay-release/filter/memcached.properties
new file mode 100755
index 0000000..f940159
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/memcached.properties
@@ -0,0 +1,20 @@
+mem.name=mem
+mem.servers=s1 s2
+#mem.servers = local
+mem.server.local.host=127.0.0.1
+mem.server.local.port=11211
+mem.server.local.weight=1
+mem.server.s1.host=10.4.8.151
+mem.server.s1.port=11211
+mem.server.s1.weight=1
+mem.server.s2.host=10.4.8.213
+mem.server.s2.port=11211
+mem.server.s2.weight=1
+# memcached parameters
+mem.initconn=10
+mem.minconn=5
+mem.maxconn=250
+# seconds
+mem.maxidle=3600000
+mem.timeout.read=3000
+mem.timeout.conn=3000
\ No newline at end of file
diff --git a/jframe-pay/release/jframe-pay/conf/mybatis-config.xml b/jframe-pay/jframe-pay-release/filter/mybatis-config.xml
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/mybatis-config.xml
rename to jframe-pay/jframe-pay-release/filter/mybatis-config.xml
diff --git a/jframe-pay/jframe-pay-release/filter/payclient.properties b/jframe-pay/jframe-pay-release/filter/payclient.properties
new file mode 100755
index 0000000..0820d55
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/payclient.properties
@@ -0,0 +1,14 @@
+# http,https,ws,dono
+pay.connection=http
+pay.version=1.0.0
+pay.charset=utf-8
+# http
+http.ip=192.168.1.123
+http.port=8028
+http.pay.path=/pay
+http.usr.path=/usr
+# ws
+# ws.ip =
+#
+ch.timeout=5000
+ch.thread.count=1
diff --git a/jframe-pay/jframe-pay-release/filter/task.properties b/jframe-pay/jframe-pay-release/filter/task.properties
new file mode 100755
index 0000000..8146121
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/task.properties
@@ -0,0 +1,15 @@
+#true or false ,default is true
+task.start=true
+# p,c,pc
+task.mode=p
+# default
+task.timeout=120
+task.count=30
+# TaskType
+task.types=1,100
+# task 1 back url
+task.1.timeout=120
+task.1.count=30
+# task 100 upmp query order
+task.100.timeout=180
+task.100.count=20
diff --git a/jframe-pay/jframe-pay-release/filter/upmp.properties b/jframe-pay/jframe-pay-release/filter/upmp.properties
new file mode 100644
index 0000000..716c9e2
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/upmp.properties
@@ -0,0 +1,18 @@
+#group
+group.id=test run
+# test
+@test.mer.id=***********
+@test.back.url=http://ip:port/pay/back/upmpback
+#@test.front.url= http://183.129.161.72:8018/pay/back/upmp
+@test.acp.sdk=${app.home}/conf/acp_sdk_dev.properties
+# run
+@run.mer.id=************
+@run.back.url=http://ip:port/pay/back/upmpback
+#@test.front.url= http://183.129.161.72:8018/pay/back/upmp
+@run.acp.sdk=${app.home}/conf/acp_sdk_run.properties
+# 01-Debit Card 02-Credit Card
+# mer.reserved={cardType=02}
+# message info
+version=5.0.0
+charset=UTF-8
+
diff --git a/jframe-pay/release/jframe-pay/conf/vmargs b/jframe-pay/jframe-pay-release/filter/vmargs
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/vmargs
rename to jframe-pay/jframe-pay-release/filter/vmargs
diff --git a/jframe-pay/release/jframe-pay/conf/vmargs-win b/jframe-pay/jframe-pay-release/filter/vmargs-win
similarity index 100%
rename from jframe-pay/release/jframe-pay/conf/vmargs-win
rename to jframe-pay/jframe-pay-release/filter/vmargs-win
diff --git a/jframe-pay/jframe-pay-release/filter/wxpay.properties b/jframe-pay/jframe-pay-release/filter/wxpay.properties
new file mode 100644
index 0000000..8eff0e2
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/filter/wxpay.properties
@@ -0,0 +1,20 @@
+group.id=test
+# partner
+@test.partner=******1212
+#@test.partner.key = *********22276e34a
+# app
+@test.app.id=
+@test.app.secret=
+@test.app.key =
+# message info
+version=1.0.0
+charset=UTF-8
+sign.method=sha1
+grant.type=client_credential
+# url
+token.url=https://api.weixin.qq.com/cgi-bin/token
+#gate.url = https://api.weixin.qq.com/pay/genprepay?access_token=
+gate.url=https://api.weixin.qq.com/pay/genprepay
+notify.url=http://ip:port/pay/ord/wxback
+# default is http
+use.https=false
\ No newline at end of file
diff --git a/jframe-pay/jframe-pay-release/pom.xml b/jframe-pay/jframe-pay-release/pom.xml
new file mode 100644
index 0000000..8eb39d5
--- /dev/null
+++ b/jframe-pay/jframe-pay-release/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+ io.github.dzh
+ jframe-pay
+ 2.0.0-SNAPSHOT
+
+ jframe-pay-release
+ pom
+
+
+
+ ${project.basedir}/filter.properties
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ compile
+
+
+ copy-resources
+ validate
+
+ copy-resources
+
+
+ ${project.basedir}/conf
+
+
+ ${project.basedir}/filter
+ true
+
+
+
+
+
+
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-plugin
+ package
+
+ copy-dependencies
+
+
+ ${project.basedir}/plugin/
+ true
+ true
+ false
+ compile
+ plugin
+
+
+
+ copy-lib
+ package
+
+ copy-dependencies
+
+
+ ${project.basedir}/lib/
+ true
+ true
+ false
+ compile
+ plugin
+
+
+
+
+
+
+
+
+
+ io.github.dzh
+ jframe-launcher
+
+
+
+ io.github.dzh
+ jframe-pay-http
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-dao
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-alipay
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-upmp
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-wx
+ plugin
+
+
+
\ No newline at end of file
diff --git a/jframe-pay/pom.xml b/jframe-pay/pom.xml
index 3323af8..f1131bb 100644
--- a/jframe-pay/pom.xml
+++ b/jframe-pay/pom.xml
@@ -1,111 +1,229 @@
- 4.0.0
- cn
- jframe-pay
- 1.0.0
- pom
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ io.github.dzh
+ jframe-pay
+ 2.0.0-SNAPSHOT
+ pom
-
- UTF-8
- 1.2.1
-
+
+ UTF-8
+ 2.0.0-SNAPSHOT
+ 1.7.26
+
-
-
-
- src/main/java
-
- **/*.properties
- **/*.xml
-
-
-
- src/main/resources
-
- **/*.properties
- **/*.xml
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.0
-
- 1.8
- 1.8
- ${project.build.sourceEncoding}
-
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- 3.1.0
-
-
- compile
-
-
-
- ${project.build.sourceEncoding}
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M2
-
- true
-
-
-
-
+
+
+
+ src/main/java
+
+ **/*.properties
+ **/*.xml
+
+
+
+ src/main/resources
+
+ **/*.properties
+ **/*.xml
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.1.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 1.8
+ 1.8
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.1.0
+
+
+ compile
+
+
+
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M2
+
+ true
+
+
+
+
-
- jframe-pay-lib
- jframe-pay-plugin
- jframe-pay-client
- release
-
-
-
- junit
- junit
- 4.12
- test
-
-
- org.slf4j
- slf4j-api
- 1.7.12
-
-
- org.slf4j
- slf4j-simple
- 1.7.12
- test
-
-
- cn
- jframe-core
- ${jframe.version}
-
-
- cn
- jframe-ext
- ${jframe.version}
-
-
- org.apache.httpcomponents
- httpcore
- 4.4
-
-
- org.apache.httpcomponents
- httpclient
- 4.4
-
-
+
+ jframe-pay-lib
+ jframe-pay-plugin
+ jframe-pay-release
+
+
+
+
+
+
+ io.github.dzh
+ jframe-launcher
+ ${jframe.version}
+
+
+ io.github.dzh
+ jframe-core
+ ${jframe.version}
+
+
+ io.github.dzh
+ jframe-ext
+ ${jframe.version}
+
+
+
+
+ io.github.dzh
+ jframe-memcached-client
+ ${jframe.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-httpclient
+ ${jframe.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-mybatis
+ ${jframe.version}
+ plugin
+
+
+
+
+ io.github.dzh
+ jframe-pay-domain
+ ${project.version}
+
+
+ org.dom4j
+ dom4j
+ 2.1.1
+
+
+ jaxen
+ jaxen
+ 1.2.0
+
+
+ com.alibaba
+ fastjson
+ 1.2.58
+
+
+ com.google.code.gson
+ gson
+ 2.8.5
+
+
+ commons-codec
+ commons-codec
+ 1.12
+
+
+ org.apache.httpcomponents
+ httpcore
+ 4.4.11
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.9
+
+
+
+
+ io.github.dzh
+ jframe-pay-alipay
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-dao
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-http
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-task
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-upmp
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-wx
+ ${project.version}
+ plugin
+
+
+ io.github.dzh
+ jframe-pay-client
+ ${project.version}
+ plugin
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+ test
+
+
\ No newline at end of file
diff --git a/jframe-pay/release/jframe-pay/conf/alipay.properties b/jframe-pay/release/jframe-pay/conf/alipay.properties
deleted file mode 100644
index 73a296a..0000000
--- a/jframe-pay/release/jframe-pay/conf/alipay.properties
+++ /dev/null
@@ -1,24 +0,0 @@
-group.id = test
-
-notify_url = http://ip:port/pay/ord/aliback
-
-#
-@test.partner = 208********202
-@test.seller.id = *****@***.com
-@test.subject = **\u79df\u8f66
-@test.app.id = ****
-@test.private.key =
-@test.public.key =
-@test.ali_public_key =
-
-service = mobile.securitypay.pay
-payment_type = 1
-input_charset = UTF-8
-it_b_pay = 1h
-# return_url
-# paymethod
-
-# algo
-sign.type = RSA
-default_charset = UTF-8
-sign.algorithms = SHA1WithRSA
diff --git a/jframe-pay/release/jframe-pay/conf/httpclient.properties b/jframe-pay/release/jframe-pay/conf/httpclient.properties
deleted file mode 100755
index da4a097..0000000
--- a/jframe-pay/release/jframe-pay/conf/httpclient.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-group.id = payback
-
-#@indexHost.http.method = post
-#@indexHost.http.max.conn.route = 200
-#@indexHost.http.keep-alive = 5
-
-#@payback.ip = 127.0.0.1
-#@payback.port = 80
-@payback.group = jframe.pay
-
-http.method = post
-http.max.conn = 100
-http.max.conn.route = 200
-http.keep-alive = 5
-#second
-http.idle.conn.close = 30
-http.charset = utf-8
-
-http.so.timeout = 2000
-http.conn.timeout = 2000
diff --git a/jframe-pay/release/jframe-pay/conf/logback-daemon.xml b/jframe-pay/release/jframe-pay/conf/logback-daemon.xml
deleted file mode 100644
index c5cf1ae..0000000
--- a/jframe-pay/release/jframe-pay/conf/logback-daemon.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
- Application Daemon
-
-
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
-
- ${LOG_HOME}/jfd-%d{yyyy-MM-dd}.log
-
- 10
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/jframe-pay/release/jframe-pay/conf/logback.xml b/jframe-pay/release/jframe-pay/conf/logback.xml
deleted file mode 100644
index 1d02fee..0000000
--- a/jframe-pay/release/jframe-pay/conf/logback.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
- Application
-
-
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
-
- ${LOG_HOME}/jf-%d{yyyy-MM-dd}.log
-
- 10
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/jframe-pay/release/jframe-pay/conf/memcached.properties b/jframe-pay/release/jframe-pay/conf/memcached.properties
deleted file mode 100755
index 075815b..0000000
--- a/jframe-pay/release/jframe-pay/conf/memcached.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-mem.name = mem
-
-mem.servers = s1 s2
-#mem.servers = local
-
-mem.server.local.host = 127.0.0.1
-mem.server.local.port = 11211
-mem.server.local.weight = 1
-
-mem.server.s1.host = 10.4.8.151
-mem.server.s1.port = 11211
-mem.server.s1.weight = 1
-
-mem.server.s2.host = 10.4.8.213
-mem.server.s2.port = 11211
-mem.server.s2.weight = 1
-
-
-# memcached parameters
-mem.initconn = 10
-mem.minconn = 5
-mem.maxconn = 250
-# seconds
-mem.maxidle = 3600000
-mem.timeout.read = 3000
-mem.timeout.conn = 3000
\ No newline at end of file
diff --git a/jframe-pay/release/jframe-pay/conf/payclient.properties b/jframe-pay/release/jframe-pay/conf/payclient.properties
deleted file mode 100755
index 284fd87..0000000
--- a/jframe-pay/release/jframe-pay/conf/payclient.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-# http,https,ws,dono
-pay.connection = http
-pay.version = 1.0.0
-pay.charset = utf-8
-
-# http
-http.ip = 192.168.1.123
-http.port = 8028
-
-http.pay.path = /pay
-http.usr.path = /usr
-
-# ws
-# ws.ip =
-
-#
-ch.timeout = 5000
-ch.thread.count = 1
diff --git a/jframe-pay/release/jframe-pay/conf/task.properties b/jframe-pay/release/jframe-pay/conf/task.properties
deleted file mode 100755
index 9eb5acf..0000000
--- a/jframe-pay/release/jframe-pay/conf/task.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-#true or false ,default is true
-task.start = true
-# p,c,pc
-task.mode = p
-
-# default
-task.timeout = 120
-task.count = 30
-
-# TaskType
-task.types = 1,100
-
-# task 1 back url
-task.1.timeout = 120
-task.1.count = 30
-
-# task 100 upmp query order
-task.100.timeout = 180
-task.100.count = 20
diff --git a/jframe-pay/release/jframe-pay/conf/upmp.properties b/jframe-pay/release/jframe-pay/conf/upmp.properties
deleted file mode 100644
index cf633b1..0000000
--- a/jframe-pay/release/jframe-pay/conf/upmp.properties
+++ /dev/null
@@ -1,22 +0,0 @@
-#group
-group.id = test run
-
-
-# test
-@test.mer.id = ***********
-@test.back.url = http://ip:port/pay/back/upmpback
-#@test.front.url= http://183.129.161.72:8018/pay/back/upmp
-@test.acp.sdk = ${app.home}/conf/acp_sdk_dev.properties
-
-# run
-@run.mer.id = ************
-@run.back.url = http://ip:port/pay/back/upmpback
-#@test.front.url= http://183.129.161.72:8018/pay/back/upmp
-@run.acp.sdk = ${app.home}/conf/acp_sdk_run.properties
-# 01-Debit Card 02-Credit Card
-# mer.reserved={cardType=02}
-
-# message info
-version=5.0.0
-charset=UTF-8
-
diff --git a/jframe-pay/release/jframe-pay/conf/wxpay.properties b/jframe-pay/release/jframe-pay/conf/wxpay.properties
deleted file mode 100644
index 12b46c1..0000000
--- a/jframe-pay/release/jframe-pay/conf/wxpay.properties
+++ /dev/null
@@ -1,27 +0,0 @@
-group.id = test
-
-# partner
-@test.partner = ******1212
-#@test.partner.key = *********22276e34a
-# app
-@test.app.id =
-@test.app.secret =
-@test.app.key =
-# message info
-version=1.0.0
-charset=UTF-8
-sign.method=sha1
-
-grant.type = client_credential
-
-# url
-token.url = https://api.weixin.qq.com/cgi-bin/token
-
-
-#gate.url = https://api.weixin.qq.com/pay/genprepay?access_token=
-gate.url = https://api.weixin.qq.com/pay/genprepay
-
-notify.url = http://ip:port/pay/ord/wxback
-
-# default is http
-use.https=false
\ No newline at end of file
diff --git a/jframe-pay/release/pom.xml b/jframe-pay/release/pom.xml
deleted file mode 100644
index 6acbd2d..0000000
--- a/jframe-pay/release/pom.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-
- 4.0.0
-
- cn
- jframe-pay
- 1.0.0
-
- release
- pom
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
- 2.10
-
-
- copy-lib
- package
-
- copy-dependencies
-
-
- ${project.basedir}/jframe-pay/lib/
- true
- true
- false
- compile
- plugin
-
-
-
- copy-plugin
- package
-
- copy-dependencies
-
-
- ${project.basedir}/jframe-pay/plugin/
- true
- true
- false
- compile
- plugin
-
-
-
-
-
-
-
-
- org.eclipse.m2e
- lifecycle-mapping
- 1.0.0
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
- [2.8,)
-
- copy-dependencies
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- cn
- jframe-launcher
- ${jframe.version}
-
-
- cn
- jframe-pay-http
- 1.0.0
- plugin
-
-
- cn
- jframe-pay-dao
- 1.0.0
- plugin
-
-
- cn
- jframe-pay-alipay
- 1.0.0
- plugin
-
-
- cn
- jframe-pay-upmp
- 1.0.0
- plugin
-
-
- cn
- jframe-pay-wx
- 1.0.0
- plugin
-
-
-
\ No newline at end of file
diff --git a/jframe-plugin/jframe-activemq/pom.xml b/jframe-plugin/jframe-activemq/pom.xml
index 623bfa5..1e6a069 100644
--- a/jframe-plugin/jframe-activemq/pom.xml
+++ b/jframe-plugin/jframe-activemq/pom.xml
@@ -12,7 +12,7 @@
org.apache.activemq
activemq-client
- 5.11.1
+ 6.0.1
\ No newline at end of file
diff --git a/jframe-plugin/jframe-alipay/pom.xml b/jframe-plugin/jframe-alipay/pom.xml
new file mode 100644
index 0000000..1167b47
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ jframe-plugin
+ io.github.dzh
+ 2.0.0-SNAPSHOT
+
+ 4.0.0
+
+ jframe-alipay
+
+
+
+ com.alipay.sdk
+ alipay-sdk-java
+ 4.31.72.ALL
+
+
+
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/AlipayPlugin.java b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/AlipayPlugin.java
new file mode 100644
index 0000000..e58270e
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/AlipayPlugin.java
@@ -0,0 +1,10 @@
+package jframe.alipay;
+
+import jframe.core.plugin.DefPlugin;
+
+/**
+ * @author dzh
+ * @date 2019-07-22 14:55
+ */
+public class AlipayPlugin extends DefPlugin {
+}
diff --git a/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayService.java b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayService.java
new file mode 100644
index 0000000..dc96b79
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayService.java
@@ -0,0 +1,59 @@
+package jframe.alipay.service;
+
+import com.alipay.api.AlipayClient;
+import jframe.core.plugin.annotation.Service;
+
+import java.util.Map;
+
+/**
+ * https://docs.open.alipay.com/204 App支付
+ * https://docs.open.alipay.com/291/105971 密钥配置
+ * https://opendocs.alipay.com/open/203/105286 支付Notify说明
+ *
+ * https://docs.open.alipay.com/270/105899/
+ * https://docs.open.alipay.com/api_1/alipay.trade.page.pay/
+ *
+ * https://openhome.alipay.com/platform/demoManage.htm#/alipay.trade.page.pay
+ * https://openhome.alipay.com/platform/appDaily.htm?tab=info
+ * https://sandbox.alipaydev.com/user/accountDetails.htm?currentBar=1
+ *
+ * @author dzh
+ * @date 2019-07-22 14:56
+ */
+@Service(clazz = "jframe.alipay.service.AlipayServiceImpl", id = AlipayService.ID)
+public interface AlipayService {
+
+ String ID = "jframe.service.alipay";
+
+ String F_URL = "url";
+ String F_APP_ID = "app.id";
+ String F_PRIVATE_KEY = "private.key";
+ String F_PUBLIC_KEY = "public.key";
+ String F_FORMAT = "format";
+ String F_CHARSET = "charset";
+ String F_SIGN_TYPE = "sign.type";
+ String F_ENCRYPT_KEY = "encrypt.key";
+ String F_ENCRYPT_TYPE = "encrypt.type";
+ String F_RETURN_URL = "return.url";
+ String F_NOTIFY_URL = "notify.url";
+
+ String TRADE_STATUS_WAIT = "WAIT_BUYER_PAY"; //交易创建,等待买家付款
+ String TRADE_STATUS_CLOSED = "TRADE_CLOSED"; //未付款交易超时关闭,或支付完成后全额退款
+ String TRADE_STATUS_SUCC = "TRADE_SUCCESS"; //交易支付成功
+ String TRADE_STATUS_FINISHED = "TRADE_FINISHED"; //交易结束,不可退款
+
+ //https://opendocs.alipay.com/support/01raw4
+ String TRADE_NOTIFY_RES_SUCC = "success";//接收成功
+ String TRADE_NOTIFY_RES_FAIL = "fail"; //接收失败,重新发送通知
+
+ AlipayClient getClient(String id);
+
+ /**
+ * @param id
+ * @param param 异步返回参数
+ * @return
+ */
+ boolean checkAsyncReturn(String id, Map param);
+
+ String getConf(String id, String key);
+}
diff --git a/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayServiceImpl.java b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayServiceImpl.java
new file mode 100644
index 0000000..723b01d
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/main/java/jframe/alipay/service/AlipayServiceImpl.java
@@ -0,0 +1,134 @@
+package jframe.alipay.service;
+
+import com.alipay.api.*;
+import com.alipay.api.internal.util.AlipaySignature;
+import jframe.alipay.AlipayPlugin;
+import jframe.core.conf.Config;
+import jframe.core.plugin.annotation.InjectPlugin;
+import jframe.core.plugin.annotation.Injector;
+import jframe.core.plugin.annotation.Start;
+import jframe.core.plugin.annotation.Stop;
+import jframe.core.util.PropsConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author dzh
+ * @date 2019-07-22 14:58
+ */
+@Injector
+class AlipayServiceImpl implements AlipayService {
+ static Logger LOG = LoggerFactory.getLogger(AlipayServiceImpl.class);
+
+ @InjectPlugin
+ static AlipayPlugin plugin;
+
+ static String FILE_ALIPAY = "file.alipay";
+
+ //group id -> AlipayClient
+ private Map clients = new HashMap<>();
+
+ private PropsConf alipayConf;
+
+ @Start
+ void start() {
+ LOG.info("Start AlipayService");
+ try {
+ String file = plugin.getConfig(FILE_ALIPAY, plugin.getConfig(Config.APP_CONF) + "/alipay.properties");
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
+ alipayConf = new PropsConf();
+ alipayConf.init(file);
+ for (String id : alipayConf.getGroupIds()) {
+ AlipayClient client = createAlipayClient(alipayConf, id);
+ if (client != null)
+ clients.put(id, client);
+ }
+ LOG.info("Start AlipayService Successfully!");
+ } catch (Exception e) {
+ LOG.error("Start AlipayService Failed!" + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * https://docs.open.alipay.com/270/105899/
+ *
+ * AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
+ *
+ * 配置参数 示例值解释 获取方式/示例值
+ * URL 支付宝网关(固定) https://openapi.alipay.com/gateway.do
+ * APPID APPID 即创建应用后生成 获取见上方创建应用
+ * APP_PRIVATE_KEY 开发者私钥,由开发者自己生成 获取见配置密钥
+ * FORMAT 参数返回格式,只支持 json json(固定)
+ * CHARSET 编码集,支持 GBK/UTF-8 开发者根据实际工程编码配置
+ * ALIPAY_PUBLIC_KEY 支付宝公钥,由支付宝生成 获取详见配置密钥
+ * SIGN_TYPE 商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2 RSA2
+ *
+ * @param conf
+ * @param id
+ * @return
+ */
+ private AlipayClient createAlipayClient(PropsConf conf, String id) {
+ AlipayConfig config = new AlipayConfig();
+ config.setServerUrl(conf.getConf(id, F_URL, "https://openapi.alipay.com/gateway.do"));
+ config.setAppId(conf.getConf(id, F_APP_ID));
+ config.setPrivateKey(conf.getConf(id, F_PRIVATE_KEY));
+ config.setFormat(conf.getConf(id, F_FORMAT, AlipayConstants.FORMAT_JSON));
+ config.setCharset(conf.getConf(id, F_CHARSET, AlipayConstants.CHARSET_UTF8));
+ config.setAlipayPublicKey(conf.getConf(id, F_PUBLIC_KEY));//alipay public key
+ config.setSignType(conf.getConf(id, F_SIGN_TYPE, AlipayConstants.SIGN_TYPE_RSA2));
+ String encryptKey = conf.getConf(id, F_ENCRYPT_KEY);
+ if (encryptKey != null && !"".equals(encryptKey)) {
+ config.setEncryptKey(encryptKey);
+ config.setEncryptType(conf.getConf(id, F_ENCRYPT_TYPE, AlipayConstants.ENCRYPT_TYPE_AES));
+ }
+ try {
+ LOG.info("createAlipayClient {} {}", id, config.getAppId());
+ return new DefaultAlipayClient(config);
+ } catch (AlipayApiException e) {
+ LOG.error("failed to createAlipayClient " + e.getMessage(), e);
+ return null;
+ }
+ }
+
+ @Stop
+ void stop() {
+// if (clients != null) for (Map.Entry c : clients.entrySet()) {
+// try {
+// } catch (Exception e) {
+// LOG.error(e.getMessage(), e.fillInStackTrace());
+// }
+// }
+ clients.clear();
+ LOG.info("Stop AlipayService");
+ }
+
+ @Override
+ public AlipayClient getClient(String id) {
+ if (id == null) return null;
+ return clients.get(id);
+ }
+
+ @Override
+ public boolean checkAsyncReturn(String id, Map param) {
+ try {
+ return AlipaySignature.rsaCheckV2(param, getConf(id, F_PUBLIC_KEY), getConf(id, F_CHARSET), getConf(id, F_SIGN_TYPE));
+ } catch (AlipayApiException e) {
+ LOG.error(e.getErrMsg(), e);
+ }
+ return false;
+ }
+
+ @Override
+ public String getConf(String id, String key) {
+ return alipayConf.getConf(id, key);
+ }
+
+
+}
diff --git a/jframe-plugin/jframe-alipay/src/main/resources/META-INF/plugin.properties b/jframe-plugin/jframe-alipay/src/main/resources/META-INF/plugin.properties
new file mode 100644
index 0000000..c55908b
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/main/resources/META-INF/plugin.properties
@@ -0,0 +1,7 @@
+Plugin-Name=jframe.alipay.AlipayPlugin
+Plugin-Class=jframe.alipay.AlipayPlugin
+#Default library path is META-INF/lib/
+#Plugin-Lib =
+#Default DLL path is META-INF/dll
+#Plugin-Dll =
+Plugin-Service=jframe.alipay.service.AlipayService
diff --git a/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/TestAlipayService.java b/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/TestAlipayService.java
new file mode 100644
index 0000000..07c1979
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/TestAlipayService.java
@@ -0,0 +1,10 @@
+package jframe.alipay.service;
+
+/**
+ * @author dzh
+ * @date 2019-07-22 14:59
+ */
+public class TestAlipayService {
+
+
+}
diff --git a/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/alipay.properties b/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/alipay.properties
new file mode 100644
index 0000000..1441e6a
--- /dev/null
+++ b/jframe-plugin/jframe-alipay/src/test/java/jframe/alipay/service/alipay.properties
@@ -0,0 +1,11 @@
+group.id=test
+#
+@test.url=https://openapi.alipaydev.com/gateway.do
+@test.app.id=
+@test.private.key=
+@test.return.url=
+@test.notify.url=
+format=json
+sign.type=RSA2
+charset=UTF-8
+public.key=
\ No newline at end of file
diff --git a/jframe-plugin/jframe-aliyun/pom.xml b/jframe-plugin/jframe-aliyun/pom.xml
index e742611..d79fe4e 100644
--- a/jframe-plugin/jframe-aliyun/pom.xml
+++ b/jframe-plugin/jframe-aliyun/pom.xml
@@ -1,39 +1,39 @@
- 4.0.0
-
- io.github.dzh
- jframe-plugin
- 2.0.0-SNAPSHOT
-
- jframe-aliyun
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ io.github.dzh
+ jframe-plugin
+ 2.0.0-SNAPSHOT
+
+ jframe-aliyun
-
-
- com.aliyun
- aliyun-java-sdk-core
- 4.2.1
-
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+ 4.2.1
+
-
- com.aliyun.oss
- aliyun-sdk-oss
- 3.3.0
-
-
- com.aliyun
- aliyun-java-sdk-sts
- 3.0.0
-
-
- com.aliyun
- aliyun-java-sdk-dysmsapi
- 1.1.0
-
-
- com.aliyun
- aliyun-java-sdk-dm
- 3.3.1
-
-
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ 3.6.0
+
+
+ com.aliyun
+ aliyun-java-sdk-sts
+ 3.0.1
+
+
+ com.aliyun
+ aliyun-java-sdk-dysmsapi
+ 1.1.0
+
+
+ com.aliyun
+ aliyun-java-sdk-dm
+ 3.3.1
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/AliyunField.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/AliyunField.java
index 8514e1d..1a0f645 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/AliyunField.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/AliyunField.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.aliyun;
@@ -16,6 +16,7 @@ public interface AliyunField {
String K_client_conn_timetout = "client.conn.timetout";
String K_client_max_retry = "client.max.retry";
String K_client_socket_timetout = "client.socket.timetout";
+ String K_client_protocol = "client.protocol";
String K_roleArn = "roleArn";
String K_policy = "policy";
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/DMService.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/DMService.java
index 2033aee..558c642 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/DMService.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/DMService.java
@@ -3,19 +3,20 @@
import com.aliyuncs.dm.model.v20151123.SingleSendMailRequest;
import com.aliyuncs.dm.model.v20151123.SingleSendMailResponse;
import com.aliyuncs.exceptions.ClientException;
-
import jframe.core.plugin.annotation.Service;
/**
* 邮件推送服务
- *
+ *
* @author dzh
- * @date Dec 10, 2018 1:46:37 PM
* @version 0.0.1
+ * @date Dec 10, 2018 1:46:37 PM
*/
-@Service(clazz = "jframe.aliyun.service.dm.DMServiceImpl", id = "jframe.service.aliyun.dm")
+@Service(clazz = "jframe.aliyun.service.dm.DMServiceImpl", id = DMService.ID)
public interface DMService {
+ String ID = "jframe.service.aliyun.dm";
+
SingleSendMailResponse singleSend(String id, SingleSendMailRequest request) throws ClientException;
}
\ No newline at end of file
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/OSSService.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/OSSService.java
index 7c67095..4385f51 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/OSSService.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/OSSService.java
@@ -1,10 +1,9 @@
/**
- *
+ *
*/
package jframe.aliyun.service;
import com.aliyun.oss.OSSClient;
-
import jframe.core.plugin.annotation.Service;
/**
@@ -12,9 +11,11 @@
* @date Feb 22, 2016 11:07:15 AM
* @since 1.0
*/
-@Service(clazz = "jframe.aliyun.service.oss.OSSServiceImpl", id = "jframe.service.aliyun.oss")
+@Service(clazz = "jframe.aliyun.service.oss.OSSServiceImpl", id = OSSService.ID)
public interface OSSService {
+ String ID = "jframe.service.aliyun.oss";
+
OSSClient getOSSClient(String id);
}
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/SMSService.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/SMSService.java
index 32d8f8b..ed956ef 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/SMSService.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/SMSService.java
@@ -3,19 +3,20 @@
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
-
import jframe.core.plugin.annotation.Service;
/**
* 阿里云短信
- *
+ *
* @author dzh
- * @date Nov 19, 2018 7:00:39 PM
* @version 0.0.1
+ * @date Nov 19, 2018 7:00:39 PM
*/
-@Service(clazz = "jframe.aliyun.service.sms.SMSServiceImpl", id = "jframe.service.aliyun.sms")
+@Service(clazz = "jframe.aliyun.service.sms.SMSServiceImpl", id = SMSService.ID)
public interface SMSService {
+ String ID = "jframe.service.aliyun.sms";
+
SendSmsResponse send(String id, SendSmsRequest request) throws ClientException;
}
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/STSService.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/STSService.java
index ad06e9f..b4dfb33 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/STSService.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/STSService.java
@@ -1,23 +1,25 @@
/**
- *
+ *
*/
package jframe.aliyun.service;
-import java.util.Map;
-
import jframe.core.plugin.annotation.Service;
+import java.util.Map;
+
/**
* @author dzh
* @date Feb 28, 2016 9:13:38 AM
* @since 1.0
*/
-@Service(clazz = "jframe.aliyun.service.sts.STSServiceImpl", id = "jframe.service.aliyun.sts")
+@Service(clazz = "jframe.aliyun.service.sts.STSServiceImpl", id = STSService.ID)
public interface STSService {
+ String ID = "jframe.service.aliyun.sts";
+
/**
* 获取临时访问权限
- *
+ *
* @param id
* @return
*/
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/dm/DMServiceImpl.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/dm/DMServiceImpl.java
index 4bac845..bf84f03 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/dm/DMServiceImpl.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/dm/DMServiceImpl.java
@@ -1,21 +1,11 @@
package jframe.aliyun.service.dm;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.dm.model.v20151123.SingleSendMailRequest;
import com.aliyuncs.dm.model.v20151123.SingleSendMailResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
-
import jframe.aliyun.AliyunField;
import jframe.aliyun.AliyunPlugin;
import jframe.aliyun.service.DMService;
@@ -25,11 +15,19 @@
import jframe.core.plugin.annotation.Start;
import jframe.core.plugin.annotation.Stop;
import jframe.core.util.PropsConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* @author dzh
- * @date Dec 10, 2018 2:10:20 PM
* @version 0.0.1
+ * @date Dec 10, 2018 2:10:20 PM
*/
@Injector
public class DMServiceImpl implements DMService, AliyunField {
@@ -51,7 +49,9 @@ void start() {
try {
String file = plugin.getConfig(FILE_ALIDM, plugin.getConfig(Config.APP_CONF) + "/alidm.properties");
- if (!new File(file).exists()) { throw new FileNotFoundException("not found " + file); }
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
_config.init(file);
for (String id : _config.getGroupIds()) {
// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
@@ -66,11 +66,10 @@ void start() {
DefaultAcsClient client = new DefaultAcsClient(profile);
clients.put(id, client);
}
+ LOG.info("Start DMService Successfully!");
} catch (Exception e) {
- LOG.error("Start DMService Failure!" + e.getMessage(), e);
- return;
+ LOG.error("Start DMService Failed!" + e.getMessage(), e);
}
- LOG.info("Start DMService Successfully!");
}
@Stop
@@ -88,7 +87,9 @@ void stop() {
@Override
public SingleSendMailResponse singleSend(String id, SingleSendMailRequest request) throws ClientException {
DefaultAcsClient client = clients.get(id);
- if (client == null) { throw new NullPointerException("not found dm id:" + id); }
+ if (client == null) {
+ throw new NullPointerException("not found dm id:" + id);
+ }
return client.getAcsResponse(request);
}
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/oss/OSSServiceImpl.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/oss/OSSServiceImpl.java
index c37e820..03523f1 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/oss/OSSServiceImpl.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/oss/OSSServiceImpl.java
@@ -1,19 +1,12 @@
/**
- *
+ *
*/
package jframe.aliyun.service.oss;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
-
+import com.aliyun.oss.common.auth.DefaultCredentialProvider;
+import com.aliyun.oss.common.comm.Protocol;
import jframe.aliyun.AliyunField;
import jframe.aliyun.AliyunPlugin;
import jframe.aliyun.service.OSSService;
@@ -22,24 +15,31 @@
import jframe.core.plugin.annotation.Injector;
import jframe.core.plugin.annotation.Start;
import jframe.core.plugin.annotation.Stop;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
/**
- *
+ *
* https://help.aliyun.com/document_detail/32010.html?spm=a2c4g.11186623.6.745.735dc06dS65fFb
- *
+ *
* // Endpoint以杭州为例,其它Region请按实际情况填写。
* String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
* // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
* String accessKeyId = "";
* String accessKeySecret = "";
* String securityToken = "";
- *
+ *
* // 创建OSSClient实例。
* OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret, securityToken);
- *
+ *
* // 关闭OSSClient。
* ossClient.shutdown();
- *
+ *
* @author dzh
* @date Feb 26, 2016 11:59:58 AM
* @since 1.0
@@ -64,23 +64,28 @@ void start() {
try {
String file = plugin.getConfig(FILE_ALIOSS, plugin.getConfig(Config.APP_CONF) + "/alioss.properties");
- if (!new File(file).exists()) { throw new FileNotFoundException("not found " + file); }
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
_config.init(file);
for (String id : _config.getGroupIds()) {
String endpoint = _config.getConf(id, AliyunField.K_endpoint);
String accessKeyId = _config.getConf(id, AliyunField.K_accessKeyId);
String accessKeySecret = _config.getConf(id, AliyunField.K_accessKeySecret);
+ String protocol = _config.getConf(id, AliyunField.K_client_protocol, Protocol.HTTPS.toString());
ClientConfiguration conf = new ClientConfiguration();
+ conf.setProtocol(Protocol.HTTPS.toString().equals(protocol) ? Protocol.HTTPS : Protocol.HTTP);
// TODO config client
- OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret, conf);
+ OSSClient ossClient = new OSSClient(endpoint,
+ new DefaultCredentialProvider(accessKeyId, accessKeySecret), conf);
+ LOG.info("OSSClient {} {} {}", id, endpoint, conf.getProtocol());
clients.put(id, ossClient);
}
+ LOG.info("Start OSSService Successfully!");
} catch (Exception e) {
- LOG.error("Start OSSService Failure!" + e.getMessage(), e);
- return;
+ LOG.error("Start OSSService Failed!" + e.getMessage(), e);
}
- LOG.info("Start OSSService Successfully!");
}
@Stop
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sms/SMSServiceImpl.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sms/SMSServiceImpl.java
index 431178d..8e50e9b 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sms/SMSServiceImpl.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sms/SMSServiceImpl.java
@@ -1,21 +1,11 @@
package jframe.aliyun.service.sms;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
-
import jframe.aliyun.AliyunField;
import jframe.aliyun.AliyunPlugin;
import jframe.aliyun.service.SMSService;
@@ -25,15 +15,23 @@
import jframe.core.plugin.annotation.Start;
import jframe.core.plugin.annotation.Stop;
import jframe.core.util.PropsConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* https://help.aliyun.com/document_detail/55284.html?spm=a2c4g.11186623.6.566.5d1b4175GzAYkw
- *
+ *
* https://helpcdn.aliyun.com/document_detail/68360.html
- *
+ *
* @author dzh
- * @date Nov 19, 2018 7:01:24 PM
* @version 0.0.1
+ * @date Nov 19, 2018 7:01:24 PM
*/
@Injector
public class SMSServiceImpl implements SMSService, AliyunField {
@@ -55,7 +53,9 @@ void start() {
try {
String file = plugin.getConfig(FILE_ALISMS, plugin.getConfig(Config.APP_CONF) + "/alisms.properties");
- if (!new File(file).exists()) { throw new FileNotFoundException("not found " + file); }
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
_config.init(file);
for (String id : _config.getGroupIds()) {
// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
@@ -69,11 +69,10 @@ void start() {
DefaultAcsClient client = new DefaultAcsClient(profile);
clients.put(id, client);
}
+ LOG.info("Start SMSService Successfully!");
} catch (Exception e) {
- LOG.error("Start SMSService Failure!" + e.getMessage(), e);
- return;
+ LOG.error("Start SMSService Failed!" + e.getMessage(), e);
}
- LOG.info("Start SMSService Successfully!");
}
@Stop
@@ -91,7 +90,9 @@ void stop() {
@Override
public SendSmsResponse send(String id, SendSmsRequest request) throws ClientException {
DefaultAcsClient client = clients.get(id);
- if (client == null) { throw new NullPointerException("not found sms id:" + id); }
+ if (client == null) {
+ throw new NullPointerException("not found sms id:" + id);
+ }
return client.getAcsResponse(request);// TODO async
}
diff --git a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sts/STSServiceImpl.java b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sts/STSServiceImpl.java
index 02ec68d..21dc982 100644
--- a/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sts/STSServiceImpl.java
+++ b/jframe-plugin/jframe-aliyun/src/main/java/jframe/aliyun/service/sts/STSServiceImpl.java
@@ -1,18 +1,8 @@
/**
- *
+ *
*/
package jframe.aliyun.service.sts;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
@@ -21,7 +11,6 @@
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
-
import jframe.aliyun.AliyunField;
import jframe.aliyun.AliyunPlugin;
import jframe.aliyun.service.STSService;
@@ -30,10 +19,19 @@
import jframe.core.plugin.annotation.Injector;
import jframe.core.plugin.annotation.Start;
import jframe.core.plugin.annotation.Stop;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* https://help.aliyun.com/document_detail/28788.html?spm=a2c4g.11186623.6.695.uQYP1L
- *
+ *
* @author dzh
* @date Feb 29, 2016 12:44:39 PM
* @since 1.0
@@ -58,7 +56,9 @@ void start() {
try {
String file = plugin.getConfig(FILE_ALISTS, plugin.getConfig(Config.APP_CONF) + "/alists.properties");
- if (!new File(file).exists()) { throw new FileNotFoundException("not found " + file); }
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
_config.init(file);
for (String id : _config.getGroupIds()) {
// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
@@ -67,11 +67,11 @@ void start() {
DefaultAcsClient client = new DefaultAcsClient(profile);
clients.put(id, client);
}
+ LOG.info("Start STSService Successfully!");
} catch (Exception e) {
- LOG.error("Start STSService Failure!" + e.getMessage(), e);
- return;
+ LOG.error("Start STSService Failed!" + e.getMessage(), e);
}
- LOG.info("Start STSService Successfully!");
+
}
@Stop
@@ -111,6 +111,8 @@ AssumeRoleResponse assumeRole(String id, String roleArn, String roleSessionName,
// 创建一个 AssumeRoleRequest 并设置请求参数
final AssumeRoleRequest request = new AssumeRoleRequest();
+ // https://help.aliyun.com/document_detail/66053.html?spm=a2c4g.11186623.6.799.7c6d7074SK0BQS
+ request.setEndpoint(_config.getConf(id, K_endpoint, "sts.aliyuncs.com"));
request.setVersion(_config.getConf(id, K_api_version));
request.setMethod(MethodType.POST);
request.setProtocol(protocolType);
diff --git a/jframe-plugin/jframe-aliyun/src/test/java/jframe/aliyun/service/oss/oss-config.properties b/jframe-plugin/jframe-aliyun/src/test/java/jframe/aliyun/service/oss/oss-config.properties
index a1c7eb1..02489fe 100644
--- a/jframe-plugin/jframe-aliyun/src/test/java/jframe/aliyun/service/oss/oss-config.properties
+++ b/jframe-plugin/jframe-aliyun/src/test/java/jframe/aliyun/service/oss/oss-config.properties
@@ -8,4 +8,5 @@ group.id = test
client.max.conn = 100
client.conn.timeout = 5000
client.max.retry = 3
-client.socket.timeout = 2000
\ No newline at end of file
+client.socket.timeout = 2000
+client.protocol = http
\ No newline at end of file
diff --git a/jframe-plugin/jframe-datasource/pom.xml b/jframe-plugin/jframe-datasource/pom.xml
index b47d36e..fbce88a 100644
--- a/jframe-plugin/jframe-datasource/pom.xml
+++ b/jframe-plugin/jframe-datasource/pom.xml
@@ -12,12 +12,12 @@
com.alibaba
druid
- 1.1.12
+ 1.2.22
mysql
mysql-connector-java
- 8.0.13
+ 8.0.33
\ No newline at end of file
diff --git a/jframe-plugin/jframe-datasource/src/main/java/jframe/datasource/DataSourcePlugin.java b/jframe-plugin/jframe-datasource/src/main/java/jframe/datasource/DataSourcePlugin.java
index d3bd74c..3dfc527 100644
--- a/jframe-plugin/jframe-datasource/src/main/java/jframe/datasource/DataSourcePlugin.java
+++ b/jframe-plugin/jframe-datasource/src/main/java/jframe/datasource/DataSourcePlugin.java
@@ -13,4 +13,5 @@
*/
@Plugin(startOrder = 1, stopOrder = 1000)
public class DataSourcePlugin extends DefPlugin {
+
}
diff --git a/jframe-plugin/jframe-freemarker/src/main/java/jframe/freemarker/service/FreemarkerService.java b/jframe-plugin/jframe-freemarker/src/main/java/jframe/freemarker/service/FreemarkerService.java
index eb6d7ef..97ad5a7 100644
--- a/jframe-plugin/jframe-freemarker/src/main/java/jframe/freemarker/service/FreemarkerService.java
+++ b/jframe-plugin/jframe-freemarker/src/main/java/jframe/freemarker/service/FreemarkerService.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.freemarker.service;
@@ -11,9 +11,11 @@
* @date Aug 25, 2016 1:50:52 PM
* @since 1.0
*/
-@Service(clazz = "jframe.freemarker.service.impl.FreemarkerServiceImpl", id = "jframe.service.freemarker")
+@Service(clazz = "jframe.freemarker.service.impl.FreemarkerServiceImpl", id = FreemarkerService.ID)
public interface FreemarkerService {
+ String ID = "jframe.service.freemarker";
+
Template getTemplate(String id, String ftl) throws Exception;
}
diff --git a/jframe-plugin/jframe-getui/src/main/java/jframe/getui/GetuiService.java b/jframe-plugin/jframe-getui/src/main/java/jframe/getui/GetuiService.java
index f3c9069..16d54c6 100644
--- a/jframe-plugin/jframe-getui/src/main/java/jframe/getui/GetuiService.java
+++ b/jframe-plugin/jframe-getui/src/main/java/jframe/getui/GetuiService.java
@@ -1,56 +1,56 @@
/**
- *
+ *
*/
package jframe.getui;
-import java.util.List;
-
-import jframe.core.plugin.annotation.Service;
-
import com.gexin.rp.sdk.base.IPushResult;
import com.gexin.rp.sdk.base.ITemplate;
import com.gexin.rp.sdk.base.impl.SingleMessage;
+import jframe.core.plugin.annotation.Service;
+
+import java.util.List;
/**
* @author dzh
* @date Sep 29, 2014 12:00:46 PM
* @since 1.0
*/
-@Service(clazz = "jframe.getui.andriod.GetuiServiceImpl", id = "jframe.service.getui")
+@Service(clazz = "jframe.getui.andriod.GetuiServiceImpl", id = GetuiService.ID)
public interface GetuiService {
+ String ID = "jframe.service.getui";
// IPushResult push2App(ITemplate data, boolean isOffline,
// long offlineExpireTime) throws Exception;
- IPushResult push2Single(ITemplate data, boolean isOffline,
- long offlineExpireTime, String token) throws Exception;
-
- public static class Utils {
-
- public SingleMessage createSingleMessage(boolean isOffline,
- long offlineExpireTime, ITemplate data) {
- SingleMessage message = new SingleMessage();
- message.setOffline(isOffline);
- message.setOfflineExpireTime(offlineExpireTime);
- message.setData(data);
- return message;
- }
-
- // public ITemplate createTemplate() {
- // PopupTransmissionTemplate template = new PopupTransmissionTemplate();
- // template.setAppId(GetuiConfig.APPID);
- // template.setAppkey(GetuiConfig.APPKEY);
- // template.setText("");
- // template.setTitle("");
- // template.setImg("");
- // template.setConfirmButtonText("");
- // template.setCancelButtonText("");
- // template.setTransmissionContent("111");
- // template.setTransmissionType(1);
- // }
-
- }
-
- IPushResult push2List(ITemplate data, boolean isOffline,
- long offlineExpireTime, List token);
+ IPushResult push2Single(ITemplate data, boolean isOffline,
+ long offlineExpireTime, String token) throws Exception;
+
+ public static class Utils {
+
+ public SingleMessage createSingleMessage(boolean isOffline,
+ long offlineExpireTime, ITemplate data) {
+ SingleMessage message = new SingleMessage();
+ message.setOffline(isOffline);
+ message.setOfflineExpireTime(offlineExpireTime);
+ message.setData(data);
+ return message;
+ }
+
+ // public ITemplate createTemplate() {
+ // PopupTransmissionTemplate template = new PopupTransmissionTemplate();
+ // template.setAppId(GetuiConfig.APPID);
+ // template.setAppkey(GetuiConfig.APPKEY);
+ // template.setText("");
+ // template.setTitle("");
+ // template.setImg("");
+ // template.setConfirmButtonText("");
+ // template.setCancelButtonText("");
+ // template.setTransmissionContent("111");
+ // template.setTransmissionType(1);
+ // }
+
+ }
+
+ IPushResult push2List(ITemplate data, boolean isOffline,
+ long offlineExpireTime, List token);
}
diff --git a/jframe-plugin/jframe-getui/src/main/java/jframe/getui/MultiGetuiService.java b/jframe-plugin/jframe-getui/src/main/java/jframe/getui/MultiGetuiService.java
index 2c99742..b9d91ff 100644
--- a/jframe-plugin/jframe-getui/src/main/java/jframe/getui/MultiGetuiService.java
+++ b/jframe-plugin/jframe-getui/src/main/java/jframe/getui/MultiGetuiService.java
@@ -1,59 +1,60 @@
/**
- *
+ *
*/
package jframe.getui;
-import java.util.List;
-
-import jframe.core.plugin.annotation.Service;
-
import com.gexin.rp.sdk.base.IPushResult;
import com.gexin.rp.sdk.base.ITemplate;
import com.gexin.rp.sdk.base.impl.SingleMessage;
+import jframe.core.plugin.annotation.Service;
+
+import java.util.List;
/**
* @author dzh
* @date Aug 20, 2015 3:52:51 PM
* @since 1.0
*/
-@Service(clazz = "jframe.getui.andriod.MultiGetuiServiceImpl", id = "jframe.service.multigetui")
+@Service(clazz = "jframe.getui.andriod.MultiGetuiServiceImpl", id = MultiGetuiService.ID)
public interface MultiGetuiService {
- // IPushResult push2App(ITemplate data, boolean isOffline,
- // long offlineExpireTime) throws Exception;
-
- IPushResult push2Single(String id, ITemplate data, boolean isOffline,
- long offlineExpireTime, String token) throws Exception;
-
- public static class Utils {
-
- public SingleMessage createSingleMessage(boolean isOffline,
- long offlineExpireTime, ITemplate data) {
- SingleMessage message = new SingleMessage();
- message.setOffline(isOffline);
- message.setOfflineExpireTime(offlineExpireTime);
- message.setData(data);
- return message;
- }
-
- // public ITemplate createTemplate() {
- // PopupTransmissionTemplate template = new PopupTransmissionTemplate();
- // template.setAppId(GetuiConfig.APPID);
- // template.setAppkey(GetuiConfig.APPKEY);
- // template.setText("");
- // template.setTitle("");
- // template.setImg("");
- // template.setConfirmButtonText("");
- // template.setCancelButtonText("");
- // template.setTransmissionContent("111");
- // template.setTransmissionType(1);
- // }
-
- }
-
- IPushResult push2List(String id, ITemplate data, boolean isOffline,
- long offlineExpireTime, List token);
-
- String getConf(String id, String key);
+ String ID = "jframe.service.multigetui";
+
+ // IPushResult push2App(ITemplate data, boolean isOffline,
+ // long offlineExpireTime) throws Exception;
+
+ IPushResult push2Single(String id, ITemplate data, boolean isOffline,
+ long offlineExpireTime, String token) throws Exception;
+
+ public static class Utils {
+
+ public SingleMessage createSingleMessage(boolean isOffline,
+ long offlineExpireTime, ITemplate data) {
+ SingleMessage message = new SingleMessage();
+ message.setOffline(isOffline);
+ message.setOfflineExpireTime(offlineExpireTime);
+ message.setData(data);
+ return message;
+ }
+
+ // public ITemplate createTemplate() {
+ // PopupTransmissionTemplate template = new PopupTransmissionTemplate();
+ // template.setAppId(GetuiConfig.APPID);
+ // template.setAppkey(GetuiConfig.APPKEY);
+ // template.setText("");
+ // template.setTitle("");
+ // template.setImg("");
+ // template.setConfirmButtonText("");
+ // template.setCancelButtonText("");
+ // template.setTransmissionContent("111");
+ // template.setTransmissionType(1);
+ // }
+
+ }
+
+ IPushResult push2List(String id, ITemplate data, boolean isOffline,
+ long offlineExpireTime, List token);
+
+ String getConf(String id, String key);
}
diff --git a/jframe-plugin/jframe-google/pom.xml b/jframe-plugin/jframe-google/pom.xml
new file mode 100644
index 0000000..0fa451d
--- /dev/null
+++ b/jframe-plugin/jframe-google/pom.xml
@@ -0,0 +1,15 @@
+
+
+
+ jframe-plugin
+ io.github.dzh
+ 2.0.0-SNAPSHOT
+
+ 4.0.0
+
+ jframe-google
+
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-google/src/main/java/jframe/google/GooglePlugin.java b/jframe-plugin/jframe-google/src/main/java/jframe/google/GooglePlugin.java
new file mode 100644
index 0000000..0f55ad5
--- /dev/null
+++ b/jframe-plugin/jframe-google/src/main/java/jframe/google/GooglePlugin.java
@@ -0,0 +1,10 @@
+package jframe.google;
+
+import jframe.core.plugin.DefPlugin;
+
+/**
+ * @author dzh
+ * @date 2019-05-08 10:59
+ */
+public class GooglePlugin extends DefPlugin {
+}
diff --git a/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GeocodingApi.java b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GeocodingApi.java
new file mode 100644
index 0000000..1b746e8
--- /dev/null
+++ b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GeocodingApi.java
@@ -0,0 +1,11 @@
+package jframe.google.service;
+
+/**
+ * https://developers.google.com/maps/documentation/geocoding/start
+ *
+ * @author dzh
+ * @date 2019-05-08 12:34
+ */
+public interface GeocodingApi {
+
+}
diff --git a/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GoogleService.java b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GoogleService.java
new file mode 100644
index 0000000..87f1c1e
--- /dev/null
+++ b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/GoogleService.java
@@ -0,0 +1,14 @@
+package jframe.google.service;
+
+import jframe.core.plugin.annotation.Service;
+
+/**
+ * @author dzh
+ * @date 2019-05-08 11:00
+ */
+@Service(clazz = "jframe.google.service.impl.GoogleServiceImpl", id = "jframe.service.google")
+public interface GoogleService {
+
+
+
+}
diff --git a/jframe-plugin/jframe-google/src/main/java/jframe/google/service/impl/GoogleServiceImpl.java b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/impl/GoogleServiceImpl.java
new file mode 100644
index 0000000..00f24b9
--- /dev/null
+++ b/jframe-plugin/jframe-google/src/main/java/jframe/google/service/impl/GoogleServiceImpl.java
@@ -0,0 +1,10 @@
+package jframe.google.service.impl;
+
+import jframe.google.service.GoogleService;
+
+/**
+ * @author dzh
+ * @date 2019-05-08 11:01
+ */
+public class GoogleServiceImpl implements GoogleService {
+}
diff --git a/jframe-plugin/jframe-google/src/main/resources/META-INF/plugin.properties b/jframe-plugin/jframe-google/src/main/resources/META-INF/plugin.properties
new file mode 100644
index 0000000..0940fc7
--- /dev/null
+++ b/jframe-plugin/jframe-google/src/main/resources/META-INF/plugin.properties
@@ -0,0 +1,9 @@
+Plugin-Name=jframe.google.GooglePlugin
+Plugin-Class=jframe.google.GooglePlugin
+#Default library path is META-INF/lib/
+#Plugin-Lib =
+#Default DLL path is META-INF/dll
+#Plugin-Dll =
+Plugin-Service=jframe.google.service.GoogleService
+#Export-Class=
+
diff --git a/jframe-plugin/jframe-httpclient/pom.xml b/jframe-plugin/jframe-httpclient/pom.xml
index 917f582..6580ad2 100644
--- a/jframe-plugin/jframe-httpclient/pom.xml
+++ b/jframe-plugin/jframe-httpclient/pom.xml
@@ -1,28 +1,28 @@
- 4.0.0
-
- jframe-plugin
- 2.0.0-SNAPSHOT
- io.github.dzh
-
- jframe-httpclient
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ jframe-plugin
+ 2.0.0-SNAPSHOT
+ io.github.dzh
+
+ jframe-httpclient
-
-
- org.apache.httpcomponents
- httpcore
- 4.4.10
-
-
- org.apache.httpcomponents
- httpclient
- 4.5.6
-
-
- com.google.code.gson
- gson
- 2.8.5
-
-
+
+
+ org.apache.httpcomponents
+ httpcore
+ 4.4.13
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.11
+
+
+ com.google.code.gson
+ gson
+ 2.8.5
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/HttpClientConfig.java b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/HttpClientConfig.java
index 918d561..a0afba2 100644
--- a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/HttpClientConfig.java
+++ b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/HttpClientConfig.java
@@ -1,18 +1,18 @@
/**
- *
+ *
*/
package jframe.httpclient;
+import jframe.core.util.PropsConf;
+
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
-import jframe.core.util.PropsConf;
-
/**
* TODO 配置文件验证
- *
+ *
* @author dzh
* @date Dec 3, 2014 11:07:29 AM
* @since 1.0
@@ -59,12 +59,12 @@ public static String getConf(String group, String key) {
}
/**
- *
+ *
* @param gid
* @return
*/
public static List getHostByGroup(String gid) {
- List hosts = new LinkedList();
+ List hosts = new LinkedList<>();
for (String host : getHosts()) {
if (gid.equals(CONFIG.getConf(host, GROUP))) {
hosts.add(host);
diff --git a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/HttpClientService.java b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/HttpClientService.java
index 610bdd7..be2a8f4 100644
--- a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/HttpClientService.java
+++ b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/HttpClientService.java
@@ -1,12 +1,12 @@
/**
- *
+ *
*/
package jframe.httpclient.service;
-import java.util.Map;
-
import jframe.core.plugin.annotation.Service;
+import java.util.Map;
+
/**
*
* 特性:
@@ -15,14 +15,16 @@
*
TODO 支持https
* TODO 发送失败异常处理
*
- *
+ *
* @author dzh
* @date Dec 2, 2014 12:10:16 PM
* @since 1.0
*/
-@Service(clazz = "jframe.httpclient.service.impl.HttpClientServiceImpl", id = "jframe.service.httpclient")
+@Service(clazz = "jframe.httpclient.service.impl.HttpClientServiceImpl", id = HttpClientService.ID)
public interface HttpClientService {
+ String ID = "jframe.service.httpclient";
+
String P_MIMETYPE = "mimeType";
String P_METHOD = "method";
diff --git a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/impl/HttpClientServiceImpl.java b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/impl/HttpClientServiceImpl.java
index 176567d..a97093e 100644
--- a/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/impl/HttpClientServiceImpl.java
+++ b/jframe-plugin/jframe-httpclient/src/main/java/jframe/httpclient/service/impl/HttpClientServiceImpl.java
@@ -1,18 +1,18 @@
/**
- *
+ *
*/
package jframe.httpclient.service.impl;
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.http.HeaderElement;
-import org.apache.http.HeaderElementIterator;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import jframe.core.plugin.annotation.InjectPlugin;
+import jframe.core.plugin.annotation.Injector;
+import jframe.core.plugin.annotation.Start;
+import jframe.core.plugin.annotation.Stop;
+import jframe.httpclient.HttpClientConfig;
+import jframe.httpclient.HttpClientPlugin;
+import jframe.httpclient.service.HttpClientService;
+import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -34,19 +34,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-import jframe.core.plugin.annotation.InjectPlugin;
-import jframe.core.plugin.annotation.Injector;
-import jframe.core.plugin.annotation.Start;
-import jframe.core.plugin.annotation.Stop;
-import jframe.httpclient.HttpClientConfig;
-import jframe.httpclient.HttpClientPlugin;
-import jframe.httpclient.service.HttpClientService;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
- *
+ *
* @author dzh
* @date Dec 2, 2014 12:11:23 PM
* @since 1.0
@@ -106,7 +100,8 @@ public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
- } catch (NumberFormatException ignore) {}
+ } catch (NumberFormatException ignore) {
+ }
}
}
@@ -200,31 +195,28 @@ public String send(String id, String path, String data, Map head
//
String ip = paras.containsKey("ip") ? paras.get("ip") : HttpClientConfig.getConf(id, HttpClientConfig.IP);
String port = paras.containsKey("port") ? paras.get("port") : HttpClientConfig.getConf(id, HttpClientConfig.PORT, "80");
- String scheme = HttpClientConfig.getConf(id, HttpClientConfig.SCHEME, HttpHost.DEFAULT_SCHEME_NAME);
-
+ String scheme = paras.containsKey(HttpClientConfig.SCHEME) ? paras.get(HttpClientConfig.SCHEME)
+ : HttpClientConfig.getConf(id, HttpClientConfig.SCHEME, HttpHost.DEFAULT_SCHEME_NAME);
HttpHost target = new HttpHost(ip, Integer.parseInt(port), scheme);
+ String method = paras.containsKey(HttpClientConfig.HTTP_METHOD) ? paras.get(HttpClientConfig.HTTP_METHOD)
+ : HttpClientConfig.getConf(id, HttpClientConfig.HTTP_METHOD, HttpClientConfig.M_POST);
HttpRequestBase request;
- String mehtod = HttpClientConfig.getConf(id, HttpClientConfig.HTTP_METHOD, HttpClientConfig.M_POST);
- if (HttpClientConfig.M_GET.equals(mehtod)) {
+ if (HttpClientConfig.M_GET.equals(method)) {
request = new HttpGet(target.toURI() + path + "?" + data);
} else {
request = new HttpPost(target.toURI() + path);
- String mimeType = paras.isEmpty() ? "text/plain" : paras.get(P_MIMETYPE);
+ String mimeType = paras.getOrDefault(P_MIMETYPE, "text/plain");
((HttpPost) request).setEntity(
new StringEntity(data, ContentType.create(mimeType, HttpClientConfig.getConf(id, HttpClientConfig.HTTP_CHARSET))));
}
request.setConfig(requestConfig);
- if (headers != null) {
- for (String key : headers.keySet()) {
- request.addHeader(key, headers.get(key));
- }
+ for (String key : headers.keySet()) {
+ request.addHeader(key, headers.get(key));
}
- CloseableHttpResponse rsp = null;
- try {
- rsp = httpClient.execute(request);
+ try (CloseableHttpResponse rsp = httpClient.execute(request)) {
// ResponseHandler responseHandler = new
// ResponseHandler() {
//
@@ -260,10 +252,6 @@ public String send(String id, String path, String data, Map head
// return (T) EntityUtils.toString(entity, charset);
// }
return EntityUtils.toString(entity, charset);
- } finally {
- if (rsp != null) {
- rsp.close();
- }
}
}
@@ -349,7 +337,8 @@ public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
- } catch (NumberFormatException ignore) {}
+ } catch (NumberFormatException ignore) {
+ }
}
}
diff --git a/jframe-plugin/jframe-httpclient/src/test/java/test/client/httpclient.properties b/jframe-plugin/jframe-httpclient/src/test/java/test/client/httpclient.properties
index a9f5fe1..d6d9b16 100644
--- a/jframe-plugin/jframe-httpclient/src/test/java/test/client/httpclient.properties
+++ b/jframe-plugin/jframe-httpclient/src/test/java/test/client/httpclient.properties
@@ -1,22 +1,19 @@
-group.id = host1 host2
-
-@host1.ip = localhost
-@host1.port =
-@host1.scheme = http
-@host1.group =
+group.id=host1 host2
+@host1.ip=localhost
+@host1.port=
+@host1.scheme=http
+@host1.group=
#@host1.http.method = post
#@host1.http.max.conn.route = 60
#@host1.http.keep-alive = 5
-
-@host2.ip = 192.168.1.123
-@host2.port = 8038
-@host1.scheme = http
-@host2.group =
-
-http.method = post
-http.max.conn = 200
-http.max.conn.route = 50
-http.keep-alive = 5
+@host2.ip=192.168.1.123
+@host2.port=8038
+@host2.scheme=http
+@host2.group=
+http.method=post
+http.max.conn=200
+http.max.conn.route=50
+http.keep-alive=5
#second
-http.idle.conn.close = 30
-http.charset = utf-8
+http.idle.conn.close=30
+http.charset=utf-8
diff --git a/jframe-plugin/jframe-id/pom.xml b/jframe-plugin/jframe-id/pom.xml
new file mode 100644
index 0000000..b037bd0
--- /dev/null
+++ b/jframe-plugin/jframe-id/pom.xml
@@ -0,0 +1,25 @@
+
+
+ 4.0.0
+
+ io.github.dzh
+ jframe-plugin
+ 2.0.0-SNAPSHOT
+
+
+ jframe-id
+
+
+
+
+
+ ${project.groupId}
+ jframe-zk
+ ${project.version}
+ plugin
+
+
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-id/snowflake-eg.properties b/jframe-plugin/jframe-id/snowflake-eg.properties
new file mode 100644
index 0000000..be2e3f0
--- /dev/null
+++ b/jframe-plugin/jframe-id/snowflake-eg.properties
@@ -0,0 +1,22 @@
+#snowflake id
+#default false,service disabled if true
+#snowflake.disabled=${snowflake.disabled}
+#e.g. 2025-06-01T00:00:00Z
+snowflake.epoch=${snowflake.epoch}
+#
+snowflake.datacenter.id=${snowflake.datacenter.id}
+snowflake.worker.id=${snowflake.worker.id}
+#bit number
+snowflake.timestamp.bits=${snowflake.timestamp.bits}
+snowflake.datacenter.bits=${snowflake.datacenter.bits}
+snowflake.worker.bits=${snowflake.worker.bits}
+snowflake.sequence.bits=${snowflake.sequence.bits}
+# worker id generation:[zk,ip]
+snowflake.worker.generator=${snowflake.worker.generator}
+#worker's ip env name
+snowflake.worker.env.ip=${snowflake.worker.env.ip}
+#zk
+snowflake.zk.id=${snowflake.zk.id}
+snowflake.zk.worker.path=${snowflake.zk.worker.path}
+
+
diff --git a/jframe-plugin/jframe-id/src/main/java/jframe/id/IdField.java b/jframe-plugin/jframe-id/src/main/java/jframe/id/IdField.java
new file mode 100644
index 0000000..8021420
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/java/jframe/id/IdField.java
@@ -0,0 +1,32 @@
+package jframe.id;
+
+/**
+ * @author dzh
+ * @date 2025/6/21 16:42
+ */
+public interface IdField {
+ /******snowflake******/
+ String SNOWFLAKE_DISABLED = "snowflake.disabled";//default false
+ String SNOWFLAKE_EPOCH = "snowflake.epoch";
+ String SNOWFLAKE_WORKER_ID = "snowflake.worker.id";
+ String SNOWFLAKE_DATACENTER_ID = "snowflake.datacenter.id";
+ // the number of binary digits
+ String SNOWFLAKE_TIMESTAMP_BITS = "snowflake.timestamp.bits";
+ String SNOWFLAKE_DATACENTER_BITS = "snowflake.datacenter.bits";
+ String SNOWFLAKE_WORKER_BITS = "snowflake.worker.bits";
+ String SNOWFLAKE_SEQUENCE_BITS = "snowflake.sequence.bits";
+ // worker id generation method
+ String SNOWFLAKE_WORKER_GENERATOR = "snowflake.worker.generator";
+ String SNOWFLAKE_WORKER_ENV_IP = "snowflake.worker.env.ip";//worker's ip environment variable name
+ // zk
+ String SNOWFLAKE_ZK_ID = "snowflake.zk.id"; // jframe-zk curator group id
+ String SNOWFLAKE_ZK_WORKER_PATH = "snowflake.zk.worker.path";
+ //
+ String WORK_GENERATOR_IP = "ip";
+ String WORK_GENERATOR_ZK = "zk";
+ //default env name
+ String ENV_HOST_IP = "HOST_IP";
+ //default zk id
+ String ZK_ID = "snowflake";
+ String ZK_WORKER_PATH = "/snowflake/worker_ids";
+}
diff --git a/jframe-plugin/jframe-id/src/main/java/jframe/id/IdPlugin.java b/jframe-plugin/jframe-id/src/main/java/jframe/id/IdPlugin.java
new file mode 100644
index 0000000..6d90c76
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/java/jframe/id/IdPlugin.java
@@ -0,0 +1,11 @@
+package jframe.id;
+
+import jframe.core.plugin.DefPlugin;
+
+/**
+ * @author dzh
+ * @date 2025/6/21 16:10
+ */
+public class IdPlugin extends DefPlugin {
+
+}
diff --git a/jframe-plugin/jframe-id/src/main/java/jframe/id/service/IdService.java b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/IdService.java
new file mode 100644
index 0000000..2379dff
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/IdService.java
@@ -0,0 +1,15 @@
+package jframe.id.service;
+
+import jframe.core.plugin.annotation.Service;
+
+/**
+ * @author dzh
+ * @date 2025/6/21 16:10
+ */
+@Service(clazz = "jframe.id.service.SnowflakeService", id = IdService.ID)
+public interface IdService {
+
+ String ID = "jframe.service.id";
+
+ long nextId();
+}
diff --git a/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeIdGenerator.java b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeIdGenerator.java
new file mode 100644
index 0000000..9febdfd
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeIdGenerator.java
@@ -0,0 +1,201 @@
+package jframe.id.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Instant;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * +------------------+----------------+----------------+----------------+
+ * | 1位符号位 | 41位时间戳 | 5位数据中心ID | 5位机器ID | 12位序列号 |
+ * +------------------+----------------+----------------+----------------+
+ * 雪花算法 ID 结构
+ * 一个标准的雪花算法 ID 由以下部分组成(总长度 64 位):
+ * 部分 位数 说明
+ * 符号位 1 位 固定为 0,表示正数
+ * 时间戳 41 位 记录生成 ID 的时间戳(毫秒级),支持约 69 年的时间范围
+ * 工作机器 ID 10 位 用于标识不同的机器节点,最多支持 1024 个节点(5 位数据中心 ID + 5 位机器 ID)
+ * 序列号 12 位 同一毫秒内生成的不同 ID,每毫秒最多生成 4096 个 ID
+ *
+ *
+ * 组合 数据中心数 每中心机器数 全局总机器数 适用场景
+ * 5+5 32 32 1,024 中小型分布式系统
+ * 4+6 16 64 1,024 数据中心少但规模大
+ * 3+7 8 128 1,024 容器化环境(Pod 动态创建)
+ * 2+10 4 1,024 4,096 超大规模单数据中心
+ *
+ * @author dzh
+ * @date 2025/6/19 23:12
+ */
+public class SnowflakeIdGenerator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SnowflakeIdGenerator.class);
+ // 开始时间戳 e.g. Instant.parse("2025-06-01T00:00:00Z").toEpochMilli();
+ private final long epoch;
+ // 位移定义
+// private final int timestampBits; // 扩展为42位,支持138年
+// private final int dataCenterIdBits;
+// private final int workerIdBits;
+// private final int sequenceBits;
+
+ //左移位数
+// private final int workerIdShift;
+// private final int dataCenterIdShift;
+ private final int timestampShift;
+
+ // 计算时间戳上限(毫秒)
+ private final long maxTimestamp;
+ //~(-1L << dataCenterIdBits)
+// private long maxDataCenterId = (1L << dataCenterIdBits) - 1;//8
+ //~(-1L << workerIdBits)
+// private long maxWorkerId = (1L << workerIdBits) - 1;//64
+ // ~(-1L << sequenceBits);
+ private final long maxSequence;// 4095
+
+ // 左移后的值
+ private final long dataCenterIdOffset;
+ private final long workerIdOffset;
+
+ // 使用原子变量替代普通变量
+ private final AtomicLong lastTimestamp = new AtomicLong(-1);
+ private final AtomicLong sequence = new AtomicLong(0);
+
+ // 单例模式:使用静态内部类实现延迟加载和线程安全
+// private static class SingletonHolder {
+// private static final SnowflakeIdGenerator INSTANCE;
+//
+// static {
+// try {
+// // 从机器IP自动生成dataCenterId和workerId
+// INSTANCE = new SnowflakeIdGenerator();
+// } catch (Exception e) {
+// throw new RuntimeException("Failed to initialize SnowflakeIdGenerator", e);
+// }
+// }
+// }
+
+ // 获取单例实例的静态方法
+// public static SnowflakeIdGenerator getInstance() {
+// return SingletonHolder.INSTANCE;
+// }
+
+ // 私有构造函数,防止外部实例化
+ public SnowflakeIdGenerator(String epoch, long dataCenterId, long workerId, int timestampBits, int dataCenterIdBits, int workerIdBits, int sequenceBits) throws Exception {
+ if (epoch == null || epoch.isEmpty()) throw new IllegalArgumentException("epoch is empty");
+ this.epoch = Instant.parse(epoch).toEpochMilli();
+
+ int sunBits = timestampBits + dataCenterIdBits + workerIdBits + sequenceBits;
+ if (sunBits != 63) {
+ throw new IllegalArgumentException("timestampBits+dataCenterId+workerIdBits+sequenceBits != 63,sumBits=" + sunBits);
+ }
+ //设置左移数量
+ int workerIdShift = sequenceBits;
+ int dataCenterIdShift = sequenceBits + workerIdBits;
+ this.timestampShift = sequenceBits + workerIdBits + dataCenterIdBits;
+ // 计算时间戳上限(毫秒)
+ this.maxTimestamp = (1L << timestampBits) - 1;
+ // 计算最大序列号
+ this.maxSequence = (1L << sequenceBits) - 1;// 4095
+
+ long maxDataCenterId = (1L << dataCenterIdBits) - 1;//8
+ // 校验生成的ID
+ if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
+ throw new IllegalArgumentException("Invalid dataCenterId: " + dataCenterId);
+ }
+ long maxWorkerId = (1L << workerIdBits) - 1;//64
+ if (workerId > maxWorkerId || workerId < 0) {
+ throw new IllegalArgumentException("Invalid workerId: " + workerId);
+ }
+ this.dataCenterIdOffset = dataCenterId << dataCenterIdShift;
+ this.workerIdOffset = workerId << workerIdShift;
+
+ LOG.info("SnowflakeIdGenerator(epoch={}, dataCenterId={}, workerId={}, timestampBits={}, dataCenterIdBits={}, workerIdBits={}, sequenceBits={})", epoch, dataCenterId, workerId, timestampBits, dataCenterIdBits, workerIdBits, sequenceBits);
+// LOG.info("SnowflakeIdGenerator initialized with DataCenterID: {}, workerId: {}", dataCenterId, workerId);
+ }
+
+ // 无锁化ID生成方法(保持不变)
+ public long nextId() {
+ long currentTimestamp = System.currentTimeMillis();
+
+ // 检查时间戳是否超出限制
+ long elapsedTime = currentTimestamp - epoch;
+ if (elapsedTime > maxTimestamp) {
+ throw new RuntimeException("Timestamp limit exceeded: " + elapsedTime + "ms");
+ }
+
+ long oldTimestamp;
+ long oldSequence;
+ long newSequence;
+ // 处理时钟回拨(先检查再获取锁)
+ if (currentTimestamp < lastTimestamp.get()) {
+ throw new RuntimeException("Clock moved backwards...");
+ }
+
+ // 无锁循环CAS更新序列号
+ do {
+ oldTimestamp = lastTimestamp.get();
+
+ if (currentTimestamp > oldTimestamp) {
+ // 新的毫秒,重置序列号
+ if (sequence.compareAndSet(sequence.get(), 0)) {
+ break;
+ }
+ } else if (currentTimestamp == oldTimestamp) {
+ // 同一毫秒,尝试递增序列号
+ oldSequence = sequence.get();
+ newSequence = (oldSequence + 1) & maxSequence;
+ if (newSequence == 0) {
+ // 序列号用尽,等待下一毫秒
+ currentTimestamp = waitNextMillis(oldTimestamp);
+ continue;
+ }
+ if (sequence.compareAndSet(oldSequence, newSequence)) {
+ break;
+ }
+ } else {
+ // currentTimestamp < oldTimestamp 已在前面处理
+ throw new IllegalStateException("Invalid timestamp state");
+ }
+ } while (true);
+
+ // 更新lastTimestamp(使用CAS保证原子性)
+ if (!lastTimestamp.compareAndSet(oldTimestamp, currentTimestamp)) {
+ throw new IllegalStateException("Failed to update timestamp");
+ }
+
+ // 生成ID
+ return ((currentTimestamp - epoch) << timestampShift) | this.dataCenterIdOffset | this.workerIdOffset | sequence.get();
+ }
+
+ // 等待下一毫秒(保持不变)
+ private long waitNextMillis(long lastTimestamp) {
+ long timestamp = System.currentTimeMillis();
+ while (timestamp <= lastTimestamp) {
+ timestamp = System.currentTimeMillis();
+ }
+ return timestamp;
+ }
+
+ @Override
+ public String toString() {
+// String date = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ROOT).withZone(ZoneId.of("UTC")).format(Instant.ofEpochMilli(epoch));
+ String date = Instant.ofEpochMilli(epoch).toString();
+ return String.format("epoch=%s, dataCenterIdOffset=%s, workerIdOffset=%s, timestampShift=%s, maxTimestamp=%s, maxSequence=%s", date, dataCenterIdOffset, workerIdOffset, timestampShift, maxTimestamp, maxSequence);
+ }
+
+ // 测试示例
+// public static void main(String[] args) {
+// // 获取单例实例并生成ID
+// try {
+// SnowflakeIdGenerator generator = new SnowflakeIdGenerator();
+// // 生成10个ID测试
+// for (int i = 0; i < 10; i++) {
+// System.out.println(generator.nextId());
+// }
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+//
+// }
+}
diff --git a/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeService.java b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeService.java
new file mode 100644
index 0000000..3c88256
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/java/jframe/id/service/SnowflakeService.java
@@ -0,0 +1,280 @@
+package jframe.id.service;
+
+import jframe.core.conf.Config;
+import jframe.core.plugin.annotation.*;
+import jframe.core.util.PropsConf;
+import jframe.id.IdField;
+import jframe.id.IdPlugin;
+import jframe.zk.service.CuratorService;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author dzh
+ * @date 2025/6/21 16:12
+ */
+@Injector
+public class SnowflakeService implements IdService {
+
+ static Logger LOG = LoggerFactory.getLogger(SnowflakeService.class);
+
+ @InjectPlugin
+ static IdPlugin Plugin;
+
+ @InjectService(id = CuratorService.ID)
+ static CuratorService ZK;
+
+ static String FILE_SNOWFLAKE = "file.snowflake";
+
+ static PropsConf _config = new PropsConf();
+
+ static SnowflakeIdGenerator _generator;
+
+ private long workerId;
+
+ @Start
+ void start() {
+ LOG.info("SnowflakeService startup...");
+
+ try {
+ String file = Plugin.getConfig(FILE_SNOWFLAKE, Plugin.getConfig(Config.APP_CONF) + "/snowflake.properties");
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
+ _config.init(file);
+ LOG.info("load snowflake config {}", _config);
+
+ if (disabled()) {
+ LOG.info("SnowflakeService is disabled");
+ return;
+ }
+ this.workerId = workerId();
+ _generator = new SnowflakeIdGenerator(epoch(), dataCenterId(), this.workerId, timestampBits(), dataCenterBits(), workerBits(), sequenceBits());
+ } catch (Exception e) {
+ LOG.error("SnowflakeService startup failed!", e);
+ return;
+ }
+ LOG.info("SnowflakeService startup success!");
+ }
+
+ protected boolean disabled() {
+ return _config.getConfBool(null, IdField.SNOWFLAKE_DISABLED, "false");
+ }
+
+ protected String epoch() {
+ return _config.getConf(null, IdField.SNOWFLAKE_EPOCH, "2025-06-01T00:00:00Z");
+ }
+
+ protected long dataCenterId() {
+ return _config.getConfLong(null, IdField.SNOWFLAKE_DATACENTER_ID, "0");
+ }
+
+ protected long workerId() {
+ String workerGenerator = _config.getConf(null, IdField.SNOWFLAKE_WORKER_GENERATOR, "");
+ switch (workerGenerator) {
+ case IdField.WORK_GENERATOR_IP:
+ return generateWorkerIdFromIP();
+ case IdField.WORK_GENERATOR_ZK:
+ return generateWorkerIdFromZK();
+ default:
+ return _config.getConfLong(null, IdField.SNOWFLAKE_WORKER_ID, "0");
+ }
+ }
+
+ private boolean isZK() {
+ String workerGenerator = _config.getConf(null, IdField.SNOWFLAKE_WORKER_GENERATOR, "");
+ return IdField.WORK_GENERATOR_ZK.equals(workerGenerator);
+ }
+
+ // jframe-zk curator group id
+ protected String zkId() {
+ return _config.getConf(null, IdField.SNOWFLAKE_ZK_ID, IdField.ZK_ID);
+ }
+
+ protected String workerZKPath() {
+ return _config.getConf(null, IdField.SNOWFLAKE_ZK_WORKER_PATH, IdField.ZK_WORKER_PATH);
+ }
+
+ protected long generateWorkerIdFromZK() {
+ try {
+ CuratorFramework zk = ZK.client(zkId());
+ String workerIdPath = workerZKPath(); //parent path
+ if (zk.checkExists().forPath(workerIdPath) == null) {
+ zk.create().creatingParentsIfNeeded().forPath(workerIdPath);
+ }
+ // 获取当前所有已分配的ID
+ List existingNodes = zk.getChildren().forPath(workerIdPath);
+ LOG.info("existing workers {}", existingNodes);
+ Set usedIds = new HashSet<>();
+ // 解析现有节点中的ID
+ for (String node : existingNodes) {
+ try {
+ long id = Long.parseLong(node.substring("worker-".length()));
+ usedIds.add(id);
+ } catch (NumberFormatException e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ long maxWorkerId = maxWorkerId();
+ // 查找最小的可用ID
+ for (long id = 0; id <= maxWorkerId; id++) {
+ if (!usedIds.contains(id)) {
+ // 尝试创建该ID对应的节点
+ String path = workerIdZKPath(id);
+ try {
+ zk.create().withMode(CreateMode.EPHEMERAL).forPath(path);
+ LOG.info("generate workerId {} from zk {}", id, path);
+ return id;
+ } catch (KeeperException.NodeExistsException e) {
+ // 另一个进程可能已经占用了这个ID,继续尝试下一个
+ LOG.warn(e.getMessage(), e);
+ continue;
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ return -1L;
+ }
+
+ protected long generateWorkerIdFromIP() {
+ String ip = ip();
+ if (ip == null || ip.isEmpty()) {
+ LOG.error("No valid non-loopback IP address found");
+ return -1L;
+ }
+
+ // 解析IP地址的最后两段
+ String[] parts = ip.split("\\.");
+ if (parts.length != 4) {
+ throw new IllegalArgumentException("Invalid IPv4 address: " + ip);
+ }
+
+ // 提取最后两段作为基础
+ int segment3 = Integer.parseInt(parts[2]);
+ int segment4 = Integer.parseInt(parts[3]);
+
+ // 使用简单的哈希算法生成唯一ID,这里使用异或和移位确保分布更均匀
+// long dataCenterId = (segment3 ^ ((long) segment4 << 4)) % (maxDataCenterId() + 1);
+ long workerId = (segment4 ^ ((long) segment3 << 4)) % (maxWorkerId() + 1);
+ // 确保生成的ID为正数
+// dataCenterId = Math.abs(dataCenterId);
+ workerId = Math.abs(workerId);
+
+// LOG.info("generateDataCenterAndworkerId {} {} {}", ip, dataCenterId, workerId);
+// return new long[]{dataCenterId, workerId};
+ return workerId;
+ }
+
+
+ protected int timestampBits() {
+ return _config.getConfInt(null, IdField.SNOWFLAKE_TIMESTAMP_BITS, "41");
+ }
+
+ protected int dataCenterBits() {
+ return _config.getConfInt(null, IdField.SNOWFLAKE_DATACENTER_BITS, "5");
+ }
+
+ protected int workerBits() {
+ return _config.getConfInt(null, IdField.SNOWFLAKE_WORKER_BITS, "5");
+ }
+
+ protected int sequenceBits() {
+ return _config.getConfInt(null, IdField.SNOWFLAKE_SEQUENCE_BITS, "12");
+ }
+
+ @Override
+ public long nextId() {
+ if (_generator == null || disabled()) return 0L;
+ return _generator.nextId();
+ }
+
+ protected String ip() {
+ String ip = System.getenv(ipEnv());
+ if (ip == null || ip.isEmpty()) {
+ try {
+ ip = nonLoopbackIP();
+ } catch (SocketException e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ return ip;
+ }
+
+ protected String ipEnv() {
+ return _config.getConf(null, IdField.SNOWFLAKE_WORKER_ENV_IP, IdField.ENV_HOST_IP);
+ }
+
+ // 获取非回环IP地址(保持不变)
+ public static String nonLoopbackIP() throws SocketException {
+ Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
+
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface ni = interfaces.nextElement();
+ if (ni.isUp() && !ni.isLoopback() && !ni.isVirtual()) {
+ Enumeration addresses = ni.getInetAddresses();
+ while (addresses.hasMoreElements()) {
+ InetAddress addr = addresses.nextElement();
+ //todo 这个判断是否正确
+ if (!addr.isLoopbackAddress() && addr.getHostAddress().indexOf(':') == -1) {
+ return addr.getHostAddress();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public long maxWorkerId() {
+ int workerIdBits = workerBits();
+ return (1L << workerIdBits) - 1;
+ }
+
+ public long maxDataCenterId() {
+ int dataCenterIdBits = dataCenterBits();
+ return (1L << dataCenterIdBits) - 1;
+ }
+
+ @Stop
+ void stop() {
+ if (isZK()) {
+ releaseWorkerId(workerId);
+ }
+ }
+
+ public String workerIdZKPath(long workerId) {
+ String workerIdPath = workerZKPath();
+ return workerIdPath + "/worker-" + String.format("%010d", workerId);
+ }
+
+ private void releaseWorkerId(long workerId) {
+ String path = workerIdZKPath(workerId);
+ try {
+ CuratorFramework zk = ZK.client(zkId());
+ if (zk.checkExists().forPath(path) != null) {
+ zk.delete().forPath(path);
+ LOG.info("Worker ID {} released successfully", workerId);
+ } else {
+ LOG.warn("Worker ID {} already deleted", workerId);
+ }
+ } catch (Exception e) {
+ LOG.error("Failed to release worker ID {}", workerId, e);
+ }
+ }
+
+}
diff --git a/jframe-plugin/jframe-id/src/main/resources/META-INF/plugin.properties b/jframe-plugin/jframe-id/src/main/resources/META-INF/plugin.properties
new file mode 100644
index 0000000..7c6d6e4
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/main/resources/META-INF/plugin.properties
@@ -0,0 +1,4 @@
+Plugin-Name=jframe.id.IdPlugin
+Plugin-Class=jframe.id.IdPlugin
+Plugin-Service=jframe.id.service.IdService
+Import-Class=jframe.zk.service.CuratorService
\ No newline at end of file
diff --git a/jframe-plugin/jframe-id/src/test/java/jframe/id/service/TestIDUtil.java b/jframe-plugin/jframe-id/src/test/java/jframe/id/service/TestIDUtil.java
new file mode 100644
index 0000000..e13c959
--- /dev/null
+++ b/jframe-plugin/jframe-id/src/test/java/jframe/id/service/TestIDUtil.java
@@ -0,0 +1,51 @@
+package jframe.id.service;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+/**
+ * @author dzh
+ * @date 2025/6/20 00:28
+ */
+public class TestIDUtil {
+
+ static Logger LOG = LoggerFactory.getLogger(TestIDUtil.class);
+
+ @Test
+ public void testSnowflake() throws Exception {
+ SnowflakeIdGenerator id = new SnowflakeIdGenerator("2025-06-01T00:00:00Z", 0, 1, 41, 5, 5, 12);
+ LOG.info("id generator: {}", id);
+ for (int i = 0; i < 6; i++) {
+ LOG.info("{} {}", i, id.nextId());
+ }
+ }
+
+ @Test
+ public void decodeID() {
+ long id = 7738971916341248L;
+ long epoch = Instant.parse("2025-06-01T00:00:00Z").toEpochMilli();
+ long currentTime = id >> 22 + epoch;
+ LOG.info("{} {}", currentTime, Instant.ofEpochMilli(currentTime).toString());
+ }
+
+ @Test
+ public void testZkWorkerPath() {
+ SnowflakeService sfs = new SnowflakeService();
+ String workerPath = sfs.workerIdZKPath(1);
+ LOG.info("workerPath: {}", workerPath);
+ }
+
+ @Test
+ public void testEpoch() {
+ long epoch = System.currentTimeMillis();
+ String date = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ROOT).withZone(ZoneId.of("UTC")).format(Instant.ofEpochMilli(epoch));
+ LOG.info("{} {} {}", epoch, date, Instant.ofEpochMilli(epoch).toString());
+ }
+
+}
diff --git a/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisService.java b/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisService.java
index d146c31..1109206 100644
--- a/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisService.java
+++ b/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisService.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.jedis.service;
@@ -12,11 +12,12 @@
* @date Dec 2, 2014 10:37:37 AM
* @since 1.0
*/
-@Service(clazz = "jframe.jedis.service.JedisServiceImpl", id = "jframe.service.jedis")
+@Service(clazz = "jframe.jedis.service.JedisServiceImpl", id = JedisService.ID)
public interface JedisService {
+ String ID = "jframe.service.jedis";
/**
- *
+ *
* @return jedis.host.default's jedis
*/
Jedis getJedis();
@@ -25,7 +26,7 @@ public interface JedisService {
/**
* use {@link redis.clients.jedis.Jedis#close()}
- *
+ *
* @param jedis
*/
@Deprecated
@@ -33,7 +34,7 @@ public interface JedisService {
/**
* use {@link redis.clients.jedis.Jedis#close()}
- *
+ *
* @param jedis
*/
@Deprecated
@@ -41,7 +42,7 @@ public interface JedisService {
/**
* unsupported
- *
+ *
* @param name
* @return
*/
@@ -50,8 +51,22 @@ public interface JedisService {
/************************** simple method ***************************/
String get(String id, String key);
+// String getdel(String id, String key);
+
void setex(String id, String key, String value, Integer expiredSeconds);
void del(String id, String key);
+ long incr(String id, String key);
+
+ long incrBy(String id, String key, long val);
+
+ long decr(String id, String key);
+
+ long decrBy(String id, String key, long val);
+
+ void expire(String id, String key, int seconds);
+
+ void expireAt(String id, String key, int ts);
+
}
diff --git a/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisServiceImpl.java b/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisServiceImpl.java
index 8bc8aaf..d16277a 100644
--- a/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisServiceImpl.java
+++ b/jframe-plugin/jframe-jedis/src/main/java/jframe/jedis/service/JedisServiceImpl.java
@@ -1,8 +1,18 @@
/**
- *
+ *
*/
package jframe.jedis.service;
+import jframe.core.plugin.annotation.InjectPlugin;
+import jframe.core.plugin.annotation.Injector;
+import jframe.core.plugin.annotation.Start;
+import jframe.core.plugin.annotation.Stop;
+import jframe.core.util.PropsConf;
+import jframe.jedis.JedisPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import redis.clients.jedis.*;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -11,21 +21,6 @@
import java.util.Iterator;
import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import jframe.core.plugin.annotation.InjectPlugin;
-import jframe.core.plugin.annotation.Injector;
-import jframe.core.plugin.annotation.Start;
-import jframe.core.plugin.annotation.Stop;
-import jframe.core.util.PropsConf;
-import jframe.jedis.JedisPlugin;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisCluster;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.Protocol;
-
/**
* @author dzh
* @date Aug 6, 2014 1:31:26 PM
@@ -100,7 +95,6 @@ public void start(PropsConf conf) {
_jedis.put(h, new JedisPool(config, ip, port, timeout, "".equals(passwd) ? null : passwd, database));
} catch (Exception e) {
LOG.error(e.getMessage(), e);
- continue;
}
}
LOG.info("JedisServiceImpl start successfully");
@@ -209,11 +203,23 @@ public void recycleJedis(String name, Jedis jedis) {
@Override
public String get(String id, String key) {
try (Jedis jedis = getJedis(id)) {
- if (jedis != null) { return jedis.get(key); }
+ if (jedis != null) {
+ return jedis.get(key);
+ }
}
return null;
}
+// @Override
+// public String getdel(String id, String key) {
+// try (Jedis jedis = getJedis(id)) {
+// if (jedis != null) {
+// return jedis.get
+// }
+// }
+// return null;
+// }
+
@Override
public void setex(String id, String key, String value, Integer expiredSeconds) {
if (value == null) return; // do nothing
@@ -235,4 +241,62 @@ public void del(String id, String key) {
}
}
+ @Override
+ public long incr(String id, String key) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ return jedis.incr(key);
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long incrBy(String id, String key, long val) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ return jedis.incrBy(key, val);
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long decr(String id, String key) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ return jedis.decr(key);
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long decrBy(String id, String key, long val) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ return jedis.decrBy(key, val);
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void expire(String id, String key, int seconds) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ jedis.expire(key, seconds);
+ }
+ }
+ }
+
+ @Override
+ public void expireAt(String id, String key, int ts) {
+ try (Jedis jedis = getJedis(id)) {
+ if (jedis != null) {
+ jedis.expireAt(key, ts);
+ }
+ }
+ }
+
}
diff --git a/jframe-plugin/jframe-mybatis/pom.xml b/jframe-plugin/jframe-mybatis/pom.xml
index 0afc3e9..ff2e44e 100644
--- a/jframe-plugin/jframe-mybatis/pom.xml
+++ b/jframe-plugin/jframe-mybatis/pom.xml
@@ -19,7 +19,7 @@
org.mybatis
mybatis
- 3.4.6
+ 3.5.16
${project.groupId}
@@ -30,12 +30,12 @@
cglib
cglib
- 3.2.9
+ 3.3.0
ognl
ognl
- 3.2.8
+ 3.3.5
javassist
@@ -46,7 +46,7 @@
org.javassist
javassist
- 3.24.0-GA
+ 3.30.2-GA
\ No newline at end of file
diff --git a/jframe-plugin/jframe-mybatis/src/main/java/jframe/mybatis/MultiMybatisService.java b/jframe-plugin/jframe-mybatis/src/main/java/jframe/mybatis/MultiMybatisService.java
index 1dc97f8..6993731 100644
--- a/jframe-plugin/jframe-mybatis/src/main/java/jframe/mybatis/MultiMybatisService.java
+++ b/jframe-plugin/jframe-mybatis/src/main/java/jframe/mybatis/MultiMybatisService.java
@@ -1,10 +1,9 @@
/**
- *
+ *
*/
package jframe.mybatis;
import jframe.core.plugin.annotation.Service;
-
import org.apache.ibatis.session.SqlSessionFactory;
/**
@@ -12,15 +11,17 @@
* @date Jul 17, 2015 11:36:43 AM
* @since 1.0
*/
-@Service(clazz = "jframe.mybatis.MultiMybatisServiceImpl", id = "jframe.service.multimybatis")
+@Service(clazz = "jframe.mybatis.MultiMybatisServiceImpl", id = MultiMybatisService.ID)
public interface MultiMybatisService {
- /**
- *
- * @param id
- * environment[@id] in mybatis-config.xml
- * @return
- */
- SqlSessionFactory getSqlSessionFactory(String id);
+ String ID = "jframe.service.multimybatis";
+
+ /**
+ *
+ * @param id
+ * environment[@id] in mybatis-config.xml
+ * @return
+ */
+ SqlSessionFactory getSqlSessionFactory(String id);
}
diff --git a/jframe-plugin/jframe-qiniu/src/main/java/jframe/qiniu/service/QiniuService.java b/jframe-plugin/jframe-qiniu/src/main/java/jframe/qiniu/service/QiniuService.java
index 1dd76e7..4326f12 100644
--- a/jframe-plugin/jframe-qiniu/src/main/java/jframe/qiniu/service/QiniuService.java
+++ b/jframe-plugin/jframe-qiniu/src/main/java/jframe/qiniu/service/QiniuService.java
@@ -1,12 +1,11 @@
/**
- *
+ *
*/
package jframe.qiniu.service;
import com.qiniu.storage.BucketManager;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
-
import jframe.core.plugin.annotation.Service;
/**
@@ -14,9 +13,11 @@
* @date Jul 28, 2015 10:09:03 AM
* @since 1.0
*/
-@Service(clazz = "jframe.qiniu.service.QiniuServiceImpl", id = "jframe.service.qiniu")
+@Service(clazz = "jframe.qiniu.service.QiniuServiceImpl", id = QiniuService.ID)
public interface QiniuService {
+ String ID = "jframe.service.qiniu";
+
String uploadToken(String id, String key);
String uploadToken(String id, String key, long expires);
diff --git a/jframe-plugin/jframe-rongcloud/src/main/java/jframe/rongcloud/service/RongcloudService.java b/jframe-plugin/jframe-rongcloud/src/main/java/jframe/rongcloud/service/RongcloudService.java
index 5767f72..2893290 100644
--- a/jframe-plugin/jframe-rongcloud/src/main/java/jframe/rongcloud/service/RongcloudService.java
+++ b/jframe-plugin/jframe-rongcloud/src/main/java/jframe/rongcloud/service/RongcloudService.java
@@ -1,24 +1,26 @@
/**
- *
+ *
*/
package jframe.rongcloud.service;
-import java.util.List;
-import java.util.Map;
-
import jframe.core.plugin.annotation.Service;
import jframe.rongcloud.Fields;
+import java.util.List;
+import java.util.Map;
+
/**
* http://www.rongcloud.cn/docs/server.html
- *
+ *
* @author dzh
* @date Feb 14, 2016 9:39:42 PM
* @since 1.0
*/
-@Service(clazz = "jframe.rongcloud.service.impl.RongcloudServiceImpl", id = "jframe.service.rongcloud")
+@Service(clazz = "jframe.rongcloud.service.impl.RongcloudServiceImpl", id = RongcloudService.ID)
public interface RongcloudService extends Fields {
+ String ID = "jframe.service.rongcloud";
+
String getToken(String id, Map req);
boolean refreshUsr(String id, Map req);
diff --git a/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/UmengService.java b/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/UmengService.java
index ed8b6c1..0682127 100644
--- a/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/UmengService.java
+++ b/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/UmengService.java
@@ -1,22 +1,24 @@
/**
- *
+ *
*/
package jframe.umeng.service;
-import java.util.Map;
-
import jframe.core.plugin.annotation.Service;
+import java.util.Map;
+
/**
* https://developer.umeng.com/docs/66632/detail/68343
- *
+ *
* @author dzh
* @date Mar 4, 2016 10:12:32 PM
* @since 1.0
*/
-@Service(clazz = "jframe.umeng.service.impl.UmengServiceImpl", id = "jframe.service.umeng")
+@Service(clazz = "jframe.umeng.service.impl.UmengServiceImpl", id = UmengService.ID)
public interface UmengService {
+ String ID = "jframe.service.umeng";
+
void sendAndBroadcast(String groupId, String token, String ticker, String title, String text, Map custom)
throws Exception;
diff --git a/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/impl/UmengServiceImpl.java b/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/impl/UmengServiceImpl.java
index cb5e883..50c9ed0 100644
--- a/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/impl/UmengServiceImpl.java
+++ b/jframe-plugin/jframe-umeng/src/main/java/jframe/umeng/service/impl/UmengServiceImpl.java
@@ -1,26 +1,16 @@
/**
- *
+ *
*/
package jframe.umeng.service.impl;
-import java.io.File;
-import java.io.FileInputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import jframe.core.plugin.annotation.InjectPlugin;
-import jframe.core.plugin.annotation.InjectService;
-import jframe.core.plugin.annotation.Injector;
-import jframe.core.plugin.annotation.Start;
-import jframe.core.plugin.annotation.Stop;
+import jframe.core.plugin.annotation.*;
import jframe.httpclient.service.HttpClientService;
import jframe.umeng.UmengConfig;
import jframe.umeng.UmengPlugin;
import jframe.umeng.service.UmengService;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import push.AndroidNotification;
import push.AndroidNotification.DisplayType;
import push.UmengNotification;
@@ -29,8 +19,13 @@
import push.ios.IOSBroadcast;
import push.ios.IOSUnicast;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
/**
- *
+ *
* @author dzh
* @date Mar 4, 2016 10:13:18 PM
* @since 1.0
@@ -79,7 +74,8 @@ public void start(String path) {
}
@Stop
- void stop() {}
+ void stop() {
+ }
/**
* "alert":""/{ // 当content-available=1时(静默推送),可选; 否则必填。
@@ -147,13 +143,14 @@ void sendUmengNotification(UmengNotification n, String groupId) throws Exception
String httpid = _config.getConf(null, UmengConfig.HttpId, "umeng");
String path = "/api/send?sign=" + sign;
- Map headers = new HashMap(1, 1);
+ Map headers = new HashMap<>(1, 1);
headers.put("User-Agent", "Mozilla/5.0");
Object rsp = _http.send(httpid, path, postBody, headers, null);
+ LOG.info("m->sendUmengNotification data->{} rsp->{}", postBody, rsp);
- if (LOG.isDebugEnabled()) {
- LOG.debug("m->sendUmengNotification data->{} rsp->{}", n.getPostBody(), rsp);
- }
+// if (LOG.isDebugEnabled()) {
+// LOG.debug("m->sendUmengNotification data->{} rsp->{}", postBody, rsp);
+// }
}
@Override
diff --git a/jframe-plugin/jframe-wxpay/pom.xml b/jframe-plugin/jframe-wxpay/pom.xml
new file mode 100644
index 0000000..65de4ff
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ jframe-plugin
+ io.github.dzh
+ 2.0.0-SNAPSHOT
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 9
+ 9
+
+
+
+
+ 4.0.0
+
+ jframe-wxpay
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
+
+ commons-codec
+ commons-codec
+ 1.16.1
+
+
+
+
+
+
+
+
+
+
+
+ com.github.wechatpay-apiv3
+ wechatpay-java
+ 0.2.12
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.12.0
+
+
+
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/IWXPayDomain.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/IWXPayDomain.java
new file mode 100644
index 0000000..aa9e6e6
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/IWXPayDomain.java
@@ -0,0 +1,45 @@
+package com.github.wxpay.sdk;
+
+/**
+ * 域名管理,实现主备域名自动切换
+ */
+public abstract interface IWXPayDomain {
+ /**
+ * 上报域名网络状况
+ *
+ * @param domain 域名。 比如:api.mch.weixin.qq.com
+ * @param elapsedTimeMillis 耗时
+ * @param ex 网络请求中出现的异常。
+ * null表示没有异常
+ * ConnectTimeoutException,表示建立网络连接异常
+ * UnknownHostException, 表示dns解析异常
+ */
+ abstract void report(final String domain, long elapsedTimeMillis, final Exception ex);
+
+ /**
+ * 获取域名
+ *
+ * @param config 配置
+ * @return 域名
+ */
+ abstract DomainInfo getDomain(final WXPayConfig config);
+
+ static class DomainInfo {
+ public String domain; //域名
+ public boolean primaryDomain; //该域名是否为主域名。例如:api.mch.weixin.qq.com为主域名
+
+ public DomainInfo(String domain, boolean primaryDomain) {
+ this.domain = domain;
+ this.primaryDomain = primaryDomain;
+ }
+
+ @Override
+ public String toString() {
+ return "DomainInfo{" +
+ "domain='" + domain + '\'' +
+ ", primaryDomain=" + primaryDomain +
+ '}';
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/JframeWxpayConfig.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/JframeWxpayConfig.java
new file mode 100644
index 0000000..78b85be
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/JframeWxpayConfig.java
@@ -0,0 +1,72 @@
+package com.github.wxpay.sdk;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+
+/**
+ * @author dzh
+ * @date 2020/8/18 19:21
+ */
+public class JframeWxpayConfig extends WXPayConfig {
+
+ static Logger LOG = LoggerFactory.getLogger(JframeWxpayConfig.class);
+
+ private String appId;
+
+ private String mchId;
+ private String apikey;
+
+ private InputStream certStream;
+
+ public static JframeWxpayConfig create(String appId, String mchId, String apikey, InputStream certStream) {
+ JframeWxpayConfig conf = new JframeWxpayConfig();
+ conf.appId = appId;
+ conf.mchId = mchId;
+ conf.apikey = apikey;
+ conf.certStream = certStream;
+ return conf;
+ }
+
+ @Override
+ String getAppID() {
+ return appId;
+ }
+
+ @Override
+ String getMchID() {
+ return mchId;
+ }
+
+ @Override
+ String getKey() {
+ return apikey;
+ }
+
+ @Override
+ InputStream getCertStream() {
+ return certStream;
+ }
+
+ @Override
+ IWXPayDomain getWXPayDomain() {
+ return new IWXPayDomain() {
+
+ public void report(String domain, long elapsedTimeMillis, Exception ex) {
+ if (ex != null) {
+ LOG.info("{} {} {}", domain, elapsedTimeMillis, ex);
+ }
+ }
+
+ public DomainInfo getDomain(WXPayConfig config) {
+ return new DomainInfo(WXPayConstants.DOMAIN_API, true);
+ }
+ };
+
+ }
+
+// public boolean shouldAutoReport() {
+// return false;
+// }
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPay.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPay.java
new file mode 100644
index 0000000..4029dac
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPay.java
@@ -0,0 +1,790 @@
+package com.github.wxpay.sdk;
+
+import com.github.wxpay.sdk.WXPayConstants.SignType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=24_4 微信银行编号
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=4_2 银行字符码
+ */
+public class WXPay {
+
+ private WXPayConfig config;
+ private SignType signType;
+ private boolean autoReport;
+ private boolean useSandbox;
+ private String notifyUrl;
+ private WXPayRequest wxPayRequest;
+
+ public WXPay(final WXPayConfig config) throws Exception {
+ this(config, null, true, false);
+ }
+
+ public WXPay(final WXPayConfig config, final boolean autoReport) throws Exception {
+ this(config, null, autoReport, false);
+ }
+
+
+ public WXPay(final WXPayConfig config, final boolean autoReport, final boolean useSandbox) throws Exception {
+ this(config, null, autoReport, useSandbox);
+ }
+
+ public WXPay(final WXPayConfig config, final String notifyUrl) throws Exception {
+ this(config, notifyUrl, true, false);
+ }
+
+ public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport) throws Exception {
+ this(config, notifyUrl, autoReport, false);
+ }
+
+ public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {
+ this(config, notifyUrl, autoReport, useSandbox, null);
+ }
+
+ public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox, SignType signType) throws Exception {
+ this.config = config;
+ this.notifyUrl = notifyUrl;
+ this.autoReport = autoReport;
+ this.useSandbox = useSandbox;
+ if (signType != null) {
+ this.signType = signType;
+ }
+ if (signType == null) {
+ if (useSandbox) {
+ this.signType = SignType.MD5; // 沙箱环境
+ } else {
+ this.signType = SignType.HMACSHA256;
+ }
+ }
+
+ this.wxPayRequest = new WXPayRequest(config);
+ }
+
+ public SignType signType() {
+ return signType;
+ }
+
+ private void checkWXPayConfig() throws Exception {
+ if (this.config == null) {
+ throw new Exception("config is null");
+ }
+ if (this.config.getAppID() == null || this.config.getAppID().trim().length() == 0) {
+ throw new Exception("appid in config is empty");
+ }
+ if (this.config.getMchID() == null || this.config.getMchID().trim().length() == 0) {
+ throw new Exception("appid in config is empty");
+ }
+ if (this.config.getCertStream() == null) {
+ throw new Exception("cert stream in config is empty");
+ }
+ if (this.config.getWXPayDomain() == null) {
+ throw new Exception("config.getWXPayDomain() is null");
+ }
+
+ if (this.config.getHttpConnectTimeoutMs() < 10) {
+ throw new Exception("http connect timeout is too small");
+ }
+ if (this.config.getHttpReadTimeoutMs() < 10) {
+ throw new Exception("http read timeout is too small");
+ }
+
+ }
+
+ /**
+ * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign
+ * 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口
+ *
+ * @param reqData
+ * @return
+ * @throws Exception
+ */
+ public Map fillRequestData(Map reqData) throws Exception {
+ reqData.put("appid", config.getAppID());
+ reqData.put("mch_id", config.getMchID());
+ reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+ if (SignType.MD5.equals(this.signType)) {
+ reqData.put("sign_type", WXPayConstants.MD5);
+ } else if (SignType.HMACSHA256.equals(this.signType)) {
+ reqData.put("sign_type", WXPayConstants.HMACSHA256);
+ }
+ reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
+ return reqData;
+ }
+
+ /**
+ * 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return 签名是否有效
+ * @throws Exception
+ */
+ public boolean isResponseSignatureValid(Map reqData) throws Exception {
+ // 返回数据的签名方式和请求中给定的签名方式是一致的
+ return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), this.signType);
+ }
+
+ /**
+ * 判断支付结果通知中的sign是否有效
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return 签名是否有效
+ * @throws Exception
+ */
+ public boolean isPayResultNotifySignatureValid(Map reqData) throws Exception {
+ String signTypeInData = reqData.get(WXPayConstants.FIELD_SIGN_TYPE);
+ SignType signType;
+ if (signTypeInData == null) {
+ signType = SignType.MD5;
+ } else {
+ signTypeInData = signTypeInData.trim();
+ if (signTypeInData.length() == 0) {
+ signType = SignType.MD5;
+ } else if (WXPayConstants.MD5.equals(signTypeInData)) {
+ signType = SignType.MD5;
+ } else if (WXPayConstants.HMACSHA256.equals(signTypeInData)) {
+ signType = SignType.HMACSHA256;
+ } else {
+ throw new Exception(String.format("Unsupported sign_type: %s", signTypeInData));
+ }
+ }
+ return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), signType);
+ }
+
+
+ /**
+ * 不需要证书的请求
+ *
+ * @param urlSuffix String
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 超时时间,单位是毫秒
+ * @param readTimeoutMs 超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public String requestWithoutCert(String urlSuffix, Map reqData,
+ int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String msgUUID = reqData.get("nonce_str");
+ String reqBody = WXPayUtil.mapToXml(reqData);
+
+ String resp = this.wxPayRequest.requestWithoutCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, autoReport);
+ return resp;
+ }
+
+
+ /**
+ * 需要证书的请求
+ *
+ * @param urlSuffix String
+ * @param reqData 向wxpay post的请求数据 Map
+ * @param connectTimeoutMs 超时时间,单位是毫秒
+ * @param readTimeoutMs 超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public String requestWithCert(String urlSuffix, Map reqData,
+ int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String msgUUID = reqData.get("nonce_str");
+ String reqBody = WXPayUtil.mapToXml(reqData);
+
+ String resp = this.wxPayRequest.requestWithCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, this.autoReport);
+ return resp;
+ }
+
+ /**
+ * 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。
+ *
+ * @param xmlStr API返回的XML格式数据
+ * @return Map类型数据
+ * @throws Exception
+ */
+ public Map processResponseXml(String xmlStr) throws Exception {
+ String RETURN_CODE = "return_code";
+ String return_code;
+ Map respData = WXPayUtil.xmlToMap(xmlStr);
+ if (respData.containsKey(RETURN_CODE)) {
+ return_code = respData.get(RETURN_CODE);
+ } else {
+ throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
+ }
+
+ if (return_code.equals(WXPayConstants.FAIL)) {
+ return respData;
+ } else if (return_code.equals(WXPayConstants.SUCCESS)) {
+ if (this.isResponseSignatureValid(respData)) {
+ return respData;
+ } else {
+ throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
+ }
+ } else {
+ throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
+ }
+ }
+
+ /**
+ * 作用:提交刷卡支付
+ * 场景:刷卡支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map microPay(Map reqData) throws Exception {
+ return this.microPay(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:提交刷卡支付
+ * 场景:刷卡支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map microPay(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_MICROPAY_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.MICROPAY_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+ /**
+ * 提交刷卡支付,针对软POS,尽可能做成功
+ * 内置重试机制,最多60s
+ *
+ * @param reqData
+ * @return
+ * @throws Exception
+ */
+ public Map microPayWithPos(Map reqData) throws Exception {
+ return this.microPayWithPos(reqData, this.config.getHttpConnectTimeoutMs());
+ }
+
+ /**
+ * 提交刷卡支付,针对软POS,尽可能做成功
+ * 内置重试机制,最多60s
+ *
+ * @param reqData
+ * @param connectTimeoutMs
+ * @return
+ * @throws Exception
+ */
+ public Map microPayWithPos(Map reqData, int connectTimeoutMs) throws Exception {
+ int remainingTimeMs = 60 * 1000;
+ long startTimestampMs = 0;
+ Map lastResult = null;
+ Exception lastException = null;
+
+ while (true) {
+ startTimestampMs = WXPayUtil.getCurrentTimestampMs();
+ int readTimeoutMs = remainingTimeMs - connectTimeoutMs;
+ if (readTimeoutMs > 1000) {
+ try {
+ lastResult = this.microPay(reqData, connectTimeoutMs, readTimeoutMs);
+ String returnCode = lastResult.get("return_code");
+ if (returnCode.equals("SUCCESS")) {
+ String resultCode = lastResult.get("result_code");
+ String errCode = lastResult.get("err_code");
+ if (resultCode.equals("SUCCESS")) {
+ break;
+ } else {
+ // 看错误码,若支付结果未知,则重试提交刷卡支付
+ if (errCode.equals("SYSTEMERROR") || errCode.equals("BANKERROR") || errCode.equals("USERPAYING")) {
+ remainingTimeMs = remainingTimeMs - (int) (WXPayUtil.getCurrentTimestampMs() - startTimestampMs);
+ if (remainingTimeMs <= 100) {
+ break;
+ } else {
+ WXPayUtil.getLogger().info("microPayWithPos: try micropay again");
+ if (remainingTimeMs > 5 * 1000) {
+ Thread.sleep(5 * 1000);
+ } else {
+ Thread.sleep(1 * 1000);
+ }
+ continue;
+ }
+ } else {
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ } catch (Exception ex) {
+ lastResult = null;
+ lastException = ex;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (lastResult == null) {
+ throw lastException;
+ } else {
+ return lastResult;
+ }
+ }
+
+
+ /**
+ * 作用:统一下单
+ * 场景:公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map unifiedOrder(Map reqData) throws Exception {
+ return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:统一下单
+ * 场景:公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map unifiedOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.UNIFIEDORDER_URL_SUFFIX;
+ }
+ if (this.notifyUrl != null) {
+ reqData.put("notify_url", this.notifyUrl);
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:查询订单
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map orderQuery(Map reqData) throws Exception {
+ return this.orderQuery(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:查询订单
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据 int
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map orderQuery(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_ORDERQUERY_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.ORDERQUERY_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:撤销订单
+ * 场景:刷卡支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map reverse(Map reqData) throws Exception {
+ return this.reverse(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:撤销订单
+ * 场景:刷卡支付
+ * 其他:需要证书
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map reverse(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_REVERSE_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.REVERSE_URL_SUFFIX;
+ }
+ String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:关闭订单
+ * 场景:公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map closeOrder(Map reqData) throws Exception {
+ return this.closeOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:关闭订单
+ * 场景:公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map closeOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_CLOSEORDER_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.CLOSEORDER_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:申请退款
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map refund(Map reqData) throws Exception {
+ return this.refund(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:申请退款
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ * 其他:需要证书
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map refund(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_REFUND_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.REFUND_URL_SUFFIX;
+ }
+ String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:退款查询
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map refundQuery(Map reqData) throws Exception {
+ return this.refundQuery(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:退款查询
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map refundQuery(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_REFUNDQUERY_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.REFUNDQUERY_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:对账单下载(成功时返回对账单数据,失败时返回XML格式数据)
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map downloadBill(Map reqData) throws Exception {
+ return this.downloadBill(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:对账单下载
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ * 其他:无论是否成功都返回Map。若成功,返回的Map中含有return_code、return_msg、data,
+ * 其中return_code为`SUCCESS`,data为对账单数据。
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return 经过封装的API返回数据
+ * @throws Exception
+ */
+ public Map downloadBill(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_DOWNLOADBILL_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.DOWNLOADBILL_URL_SUFFIX;
+ }
+ String respStr = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs).trim();
+ Map ret;
+ // 出现错误,返回XML数据
+ if (respStr.indexOf("<") == 0) {
+ ret = WXPayUtil.xmlToMap(respStr);
+ } else {
+ // 正常返回csv数据
+ ret = new HashMap();
+ ret.put("return_code", WXPayConstants.SUCCESS);
+ ret.put("return_msg", "ok");
+ ret.put("data", respStr);
+ }
+ return ret;
+ }
+
+
+ /**
+ * 作用:交易保障
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map report(Map reqData) throws Exception {
+ return this.report(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:交易保障
+ * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map report(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_REPORT_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.REPORT_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return WXPayUtil.xmlToMap(respXml);
+ }
+
+
+ /**
+ * 作用:转换短链接
+ * 场景:刷卡支付、扫码支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map shortUrl(Map reqData) throws Exception {
+ return this.shortUrl(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:转换短链接
+ * 场景:刷卡支付、扫码支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map shortUrl(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_SHORTURL_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.SHORTURL_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 作用:授权码查询OPENID接口
+ * 场景:刷卡支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map authCodeToOpenid(Map reqData) throws Exception {
+ return this.authCodeToOpenid(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ }
+
+
+ /**
+ * 作用:授权码查询OPENID接口
+ * 场景:刷卡支付
+ *
+ * @param reqData 向wxpay post的请求数据
+ * @param connectTimeoutMs 连接超时时间,单位是毫秒
+ * @param readTimeoutMs 读超时时间,单位是毫秒
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map authCodeToOpenid(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+ String url;
+ if (this.useSandbox) {
+ url = WXPayConstants.SANDBOX_AUTHCODETOOPENID_URL_SUFFIX;
+ } else {
+ url = WXPayConstants.AUTHCODETOOPENID_URL_SUFFIX;
+ }
+ String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+ return this.processResponseXml(respXml);
+ }
+
+ /**
+ * 用于向微信用户个人付款
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
+ *
+ * @param reqData
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map promotionTransfers(Map reqData) throws Exception {
+ String url = "/mmpaymkttransfers/promotion/transfers";
+ reqData.put("mch_appid", config.getAppID());
+ reqData.put("mchid", config.getMchID());
+ reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+ reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), SignType.MD5));
+ String respXml = this.requestWithoutCert(url, reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ return this.processResponseXml(respXml);
+ }
+
+ /**
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
+ *
+ * @param reqData
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map gettransferinfo(Map reqData) throws Exception {
+ String url = "/mmpaymkttransfers/gettransferinfo";
+ reqData.put("appid", config.getAppID());
+ reqData.put("mch_id", config.getMchID());
+ reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+ reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), SignType.MD5));
+ String respXml = this.requestWithoutCert(url, reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ return this.processResponseXml(respXml);
+ }
+
+
+ /**
+ * 付款到银行卡
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=24_2
+ *
+ * @param reqData
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map payBank(Map reqData) throws Exception {
+ String url = "/mmpaysptrans/pay_bank";
+ reqData.put("mch_id", config.getMchID());
+ reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+ reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), SignType.MD5));
+ String respXml = this.requestWithoutCert(url, reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ return this.processResponseXml(respXml);
+ }
+
+ /**
+ * 对商户付款到银行卡操作进行结果查询
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=24_3
+ *
+ * @param reqData
+ * @return API返回数据
+ * @throws Exception
+ */
+ public Map queryBank(Map reqData) throws Exception {
+ String url = "/mmpaysptrans/query_bank";
+ reqData.put("mch_id", config.getMchID());
+ reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+ reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), SignType.MD5));
+ String respXml = this.requestWithoutCert(url, reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+ return this.processResponseXml(respXml);
+ }
+
+ /**
+ * 获取RSA加密公钥API
+ * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay_yhk.php?chapter=24_7&index=4
+ *
+ * @param reqData
+ * @return
+ * @throws Exception
+ */
+// public Map getPublicKey(Map reqData) throws Exception {
+// String url = "/mmpaysptrans/query_bank";
+// reqData.put("mch_id", config.getMchID());
+// reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+// reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), SignType.MD5));
+// String respXml = this.requestWithoutCert(url, reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+// return this.processResponseXml(respXml);
+// }
+
+
+} // end class
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConfig.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConfig.java
new file mode 100644
index 0000000..9af5dca
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConfig.java
@@ -0,0 +1,103 @@
+package com.github.wxpay.sdk;
+
+import java.io.InputStream;
+
+public abstract class WXPayConfig {
+
+
+
+ /**
+ * 获取 App ID
+ *
+ * @return App ID
+ */
+ abstract String getAppID();
+
+
+ /**
+ * 获取 Mch ID
+ *
+ * @return Mch ID
+ */
+ abstract String getMchID();
+
+
+ /**
+ * 获取 API 密钥
+ *
+ * @return API密钥
+ */
+ abstract String getKey();
+
+
+ /**
+ * 获取商户证书内容
+ *
+ * @return 商户证书内容
+ */
+ abstract InputStream getCertStream();
+
+ /**
+ * HTTP(S) 连接超时时间,单位毫秒
+ *
+ * @return
+ */
+ public int getHttpConnectTimeoutMs() {
+ return 6*1000;
+ }
+
+ /**
+ * HTTP(S) 读数据超时时间,单位毫秒
+ *
+ * @return
+ */
+ public int getHttpReadTimeoutMs() {
+ return 8*1000;
+ }
+
+ /**
+ * 获取WXPayDomain, 用于多域名容灾自动切换
+ * @return
+ */
+ abstract IWXPayDomain getWXPayDomain();
+
+ /**
+ * 是否自动上报。
+ * 若要关闭自动上报,子类中实现该函数返回 false 即可。
+ *
+ * @return
+ */
+ public boolean shouldAutoReport() {
+ return true;
+ }
+
+ /**
+ * 进行健康上报的线程的数量
+ *
+ * @return
+ */
+ public int getReportWorkerNum() {
+ return 6;
+ }
+
+
+ /**
+ * 健康上报缓存消息的最大数量。会有线程去独立上报
+ * 粗略计算:加入一条消息200B,10000消息占用空间 2000 KB,约为2MB,可以接受
+ *
+ * @return
+ */
+ public int getReportQueueMaxSize() {
+ return 10000;
+ }
+
+ /**
+ * 批量上报,一次最多上报多个数据
+ *
+ * @return
+ */
+ public int getReportBatchSize() {
+ return 10;
+ }
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConstants.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConstants.java
new file mode 100644
index 0000000..5d37939
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayConstants.java
@@ -0,0 +1,83 @@
+package com.github.wxpay.sdk;
+
+import org.apache.http.client.HttpClient;
+
+/**
+ * 常量
+ */
+public class WXPayConstants {
+
+ public enum SignType {
+ MD5, HMACSHA256;
+
+ public String typeName() {
+ switch (this) {
+ case MD5:
+ return WXPayConstants.MD5;
+ case HMACSHA256:
+ return WXPayConstants.HMACSHA256;
+ }
+ return WXPayConstants.MD5;
+ }
+
+ public static SignType of(String name) {
+ if (name == null) return MD5;
+
+ switch (name) {
+ case WXPayConstants.MD5:
+ return MD5;
+ case WXPayConstants.HMACSHA256:
+ return HMACSHA256;
+ default:
+ return MD5;
+ }
+ }
+
+ }
+
+ public static final String DOMAIN_API = "api.mch.weixin.qq.com";
+ public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com";
+ public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com";
+ public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com";
+
+
+ public static final String FAIL = "FAIL";
+ public static final String SUCCESS = "SUCCESS";
+ public static final String HMACSHA256 = "HMAC-SHA256";
+ public static final String MD5 = "MD5";
+
+ public static final String FIELD_SIGN = "sign";
+ public static final String FIELD_SIGN_TYPE = "sign_type";
+
+ public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9";
+ public static final String USER_AGENT = WXPAYSDK_VERSION +
+ " (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
+ ") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();
+
+ public static final String MICROPAY_URL_SUFFIX = "/pay/micropay";
+ public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";
+ public static final String ORDERQUERY_URL_SUFFIX = "/pay/orderquery";
+ public static final String REVERSE_URL_SUFFIX = "/secapi/pay/reverse";
+ public static final String CLOSEORDER_URL_SUFFIX = "/pay/closeorder";
+ public static final String REFUND_URL_SUFFIX = "/secapi/pay/refund";
+ public static final String REFUNDQUERY_URL_SUFFIX = "/pay/refundquery";
+ public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";
+ public static final String REPORT_URL_SUFFIX = "/payitil/report";
+ public static final String SHORTURL_URL_SUFFIX = "/tools/shorturl";
+ public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid";
+
+ // sandbox
+ public static final String SANDBOX_MICROPAY_URL_SUFFIX = "/sandboxnew/pay/micropay";
+ public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";
+ public static final String SANDBOX_ORDERQUERY_URL_SUFFIX = "/sandboxnew/pay/orderquery";
+ public static final String SANDBOX_REVERSE_URL_SUFFIX = "/sandboxnew/secapi/pay/reverse";
+ public static final String SANDBOX_CLOSEORDER_URL_SUFFIX = "/sandboxnew/pay/closeorder";
+ public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/secapi/pay/refund";
+ public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX = "/sandboxnew/pay/refundquery";
+ public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";
+ public static final String SANDBOX_REPORT_URL_SUFFIX = "/sandboxnew/payitil/report";
+ public static final String SANDBOX_SHORTURL_URL_SUFFIX = "/sandboxnew/tools/shorturl";
+ public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";
+
+}
+
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayReport.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayReport.java
new file mode 100644
index 0000000..88c411a
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayReport.java
@@ -0,0 +1,265 @@
+package com.github.wxpay.sdk;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * 交易保障
+ */
+public class WXPayReport {
+
+ public static class ReportInfo {
+
+ /**
+ * 布尔变量使用int。0为false, 1为true。
+ */
+
+ // 基本信息
+ private String version = "v1";
+ private String sdk = WXPayConstants.WXPAYSDK_VERSION;
+ private String uuid; // 交易的标识
+ private long timestamp; // 上报时的时间戳,单位秒
+ private long elapsedTimeMillis; // 耗时,单位 毫秒
+
+ // 针对主域名
+ private String firstDomain; // 第1次请求的域名
+ private boolean primaryDomain; //是否主域名
+ private int firstConnectTimeoutMillis; // 第1次请求设置的连接超时时间,单位 毫秒
+ private int firstReadTimeoutMillis; // 第1次请求设置的读写超时时间,单位 毫秒
+ private int firstHasDnsError; // 第1次请求是否出现dns问题
+ private int firstHasConnectTimeout; // 第1次请求是否出现连接超时
+ private int firstHasReadTimeout; // 第1次请求是否出现连接超时
+
+ public ReportInfo(String uuid, long timestamp, long elapsedTimeMillis, String firstDomain, boolean primaryDomain, int firstConnectTimeoutMillis, int firstReadTimeoutMillis, boolean firstHasDnsError, boolean firstHasConnectTimeout, boolean firstHasReadTimeout) {
+ this.uuid = uuid;
+ this.timestamp = timestamp;
+ this.elapsedTimeMillis = elapsedTimeMillis;
+ this.firstDomain = firstDomain;
+ this.primaryDomain = primaryDomain;
+ this.firstConnectTimeoutMillis = firstConnectTimeoutMillis;
+ this.firstReadTimeoutMillis = firstReadTimeoutMillis;
+ this.firstHasDnsError = firstHasDnsError?1:0;
+ this.firstHasConnectTimeout = firstHasConnectTimeout?1:0;
+ this.firstHasReadTimeout = firstHasReadTimeout?1:0;
+ }
+
+ @Override
+ public String toString() {
+ return "ReportInfo{" +
+ "version='" + version + '\'' +
+ ", sdk='" + sdk + '\'' +
+ ", uuid='" + uuid + '\'' +
+ ", timestamp=" + timestamp +
+ ", elapsedTimeMillis=" + elapsedTimeMillis +
+ ", firstDomain='" + firstDomain + '\'' +
+ ", primaryDomain=" + primaryDomain +
+ ", firstConnectTimeoutMillis=" + firstConnectTimeoutMillis +
+ ", firstReadTimeoutMillis=" + firstReadTimeoutMillis +
+ ", firstHasDnsError=" + firstHasDnsError +
+ ", firstHasConnectTimeout=" + firstHasConnectTimeout +
+ ", firstHasReadTimeout=" + firstHasReadTimeout +
+ '}';
+ }
+
+ /**
+ * 转换成 csv 格式
+ *
+ * @return
+ */
+ public String toLineString(String key) {
+ String separator = ",";
+ Object[] objects = new Object[] {
+ version, sdk, uuid, timestamp, elapsedTimeMillis,
+ firstDomain, primaryDomain, firstConnectTimeoutMillis, firstReadTimeoutMillis,
+ firstHasDnsError, firstHasConnectTimeout, firstHasReadTimeout
+ };
+ StringBuffer sb = new StringBuffer();
+ for(Object obj: objects) {
+ sb.append(obj).append(separator);
+ }
+ try {
+ String sign = WXPayUtil.HMACSHA256(sb.toString(), key);
+ sb.append(sign);
+ return sb.toString();
+ }
+ catch (Exception ex) {
+ return null;
+ }
+
+ }
+
+ }
+
+ private static final String REPORT_URL = "http://report.mch.weixin.qq.com/wxpay/report/default";
+ // private static final String REPORT_URL = "http://127.0.0.1:5000/test";
+
+
+ private static final int DEFAULT_CONNECT_TIMEOUT_MS = 6*1000;
+ private static final int DEFAULT_READ_TIMEOUT_MS = 8*1000;
+
+ private LinkedBlockingQueue reportMsgQueue = null;
+ private WXPayConfig config;
+ private ExecutorService executorService;
+
+ private volatile static WXPayReport INSTANCE;
+
+ private WXPayReport(final WXPayConfig config) {
+ this.config = config;
+ reportMsgQueue = new LinkedBlockingQueue(config.getReportQueueMaxSize());
+
+ // 添加处理线程
+ executorService = Executors.newFixedThreadPool(config.getReportWorkerNum(), new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ Thread t = Executors.defaultThreadFactory().newThread(r);
+ t.setDaemon(true);
+ return t;
+ }
+ });
+
+ if (config.shouldAutoReport()) {
+ WXPayUtil.getLogger().info("report worker num: {}", config.getReportWorkerNum());
+ for (int i = 0; i < config.getReportWorkerNum(); ++i) {
+ executorService.execute(new Runnable() {
+ public void run() {
+ while (true) {
+ // 先用 take 获取数据
+ try {
+ StringBuffer sb = new StringBuffer();
+ String firstMsg = reportMsgQueue.take();
+ WXPayUtil.getLogger().info("get first report msg: {}", firstMsg);
+ String msg = null;
+ sb.append(firstMsg); //会阻塞至有消息
+ int remainNum = config.getReportBatchSize() - 1;
+ for (int j=0; jcreate()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
+ .register("https", SSLConnectionSocketFactory.getSocketFactory())
+ .build(),
+ null,
+ null,
+ null
+ );
+ HttpClient httpClient = HttpClientBuilder.create()
+ .setConnectionManager(connManager)
+ .build();
+
+ HttpPost httpPost = new HttpPost(REPORT_URL);
+
+ RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
+ httpPost.setConfig(requestConfig);
+
+ StringEntity postEntity = new StringEntity(data, "UTF-8");
+ httpPost.addHeader("Content-Type", "text/xml");
+ httpPost.addHeader("User-Agent", WXPayConstants.USER_AGENT);
+ httpPost.setEntity(postEntity);
+
+ HttpResponse httpResponse = httpClient.execute(httpPost);
+ HttpEntity httpEntity = httpResponse.getEntity();
+ return EntityUtils.toString(httpEntity, "UTF-8");
+ }
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayRequest.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayRequest.java
new file mode 100644
index 0000000..7209777
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayRequest.java
@@ -0,0 +1,258 @@
+package com.github.wxpay.sdk;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+import static com.github.wxpay.sdk.WXPayConstants.USER_AGENT;
+
+public class WXPayRequest {
+ private WXPayConfig config;
+ public WXPayRequest(WXPayConfig config) throws Exception{
+
+ this.config = config;
+ }
+
+ /**
+ * 请求,只请求一次,不做重试
+ * @param domain
+ * @param urlSuffix
+ * @param uuid
+ * @param data
+ * @param connectTimeoutMs
+ * @param readTimeoutMs
+ * @param useCert 是否使用证书,针对退款、撤销等操作
+ * @return
+ * @throws Exception
+ */
+ private String requestOnce(final String domain, String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert) throws Exception {
+ BasicHttpClientConnectionManager connManager;
+ if (useCert) {
+ // 证书
+ char[] password = config.getMchID().toCharArray();
+ InputStream certStream = config.getCertStream();
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(certStream, password);
+
+ // 实例化密钥库 & 初始化密钥工厂
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, password);
+
+ // 创建 SSLContext
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
+
+ SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
+ sslContext,
+ new String[]{"TLSv1"},
+ null,
+ new DefaultHostnameVerifier());
+
+ connManager = new BasicHttpClientConnectionManager(
+ RegistryBuilder.create()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
+ .register("https", sslConnectionSocketFactory)
+ .build(),
+ null,
+ null,
+ null
+ );
+ }
+ else {
+ connManager = new BasicHttpClientConnectionManager(
+ RegistryBuilder.create()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
+ .register("https", SSLConnectionSocketFactory.getSocketFactory())
+ .build(),
+ null,
+ null,
+ null
+ );
+ }
+
+ HttpClient httpClient = HttpClientBuilder.create()
+ .setConnectionManager(connManager)
+ .build();
+
+ String url = "https://" + domain + urlSuffix;
+ HttpPost httpPost = new HttpPost(url);
+
+ RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
+ httpPost.setConfig(requestConfig);
+
+ StringEntity postEntity = new StringEntity(data, "UTF-8");
+ httpPost.addHeader("Content-Type", "text/xml");
+ httpPost.addHeader("User-Agent", USER_AGENT + " " + config.getMchID());
+ httpPost.setEntity(postEntity);
+
+ HttpResponse httpResponse = httpClient.execute(httpPost);
+ HttpEntity httpEntity = httpResponse.getEntity();
+ return EntityUtils.toString(httpEntity, "UTF-8");
+
+ }
+
+
+ private String request(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert, boolean autoReport) throws Exception {
+ Exception exception = null;
+ long elapsedTimeMillis = 0;
+ long startTimestampMs = WXPayUtil.getCurrentTimestampMs();
+ boolean firstHasDnsErr = false;
+ boolean firstHasConnectTimeout = false;
+ boolean firstHasReadTimeout = false;
+ IWXPayDomain.DomainInfo domainInfo = config.getWXPayDomain().getDomain(config);
+ if(domainInfo == null){
+ throw new Exception("WXPayConfig.getWXPayDomain().getDomain() is empty or null");
+ }
+ try {
+ String result = requestOnce(domainInfo.domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert);
+ elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
+ config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, null);
+ WXPayReport.getInstance(config).report(
+ uuid,
+ elapsedTimeMillis,
+ domainInfo.domain,
+ domainInfo.primaryDomain,
+ connectTimeoutMs,
+ readTimeoutMs,
+ firstHasDnsErr,
+ firstHasConnectTimeout,
+ firstHasReadTimeout);
+ return result;
+ }
+ catch (UnknownHostException ex) { // dns 解析错误,或域名不存在
+ exception = ex;
+ firstHasDnsErr = true;
+ elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
+ WXPayUtil.getLogger().warn("UnknownHostException for domainInfo {}", domainInfo);
+ WXPayReport.getInstance(config).report(
+ uuid,
+ elapsedTimeMillis,
+ domainInfo.domain,
+ domainInfo.primaryDomain,
+ connectTimeoutMs,
+ readTimeoutMs,
+ firstHasDnsErr,
+ firstHasConnectTimeout,
+ firstHasReadTimeout
+ );
+ }
+ catch (ConnectTimeoutException ex) {
+ exception = ex;
+ firstHasConnectTimeout = true;
+ elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
+ WXPayUtil.getLogger().warn("connect timeout happened for domainInfo {}", domainInfo);
+ WXPayReport.getInstance(config).report(
+ uuid,
+ elapsedTimeMillis,
+ domainInfo.domain,
+ domainInfo.primaryDomain,
+ connectTimeoutMs,
+ readTimeoutMs,
+ firstHasDnsErr,
+ firstHasConnectTimeout,
+ firstHasReadTimeout
+ );
+ }
+ catch (SocketTimeoutException ex) {
+ exception = ex;
+ firstHasReadTimeout = true;
+ elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
+ WXPayUtil.getLogger().warn("timeout happened for domainInfo {}", domainInfo);
+ WXPayReport.getInstance(config).report(
+ uuid,
+ elapsedTimeMillis,
+ domainInfo.domain,
+ domainInfo.primaryDomain,
+ connectTimeoutMs,
+ readTimeoutMs,
+ firstHasDnsErr,
+ firstHasConnectTimeout,
+ firstHasReadTimeout);
+ }
+ catch (Exception ex) {
+ exception = ex;
+ elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
+ WXPayReport.getInstance(config).report(
+ uuid,
+ elapsedTimeMillis,
+ domainInfo.domain,
+ domainInfo.primaryDomain,
+ connectTimeoutMs,
+ readTimeoutMs,
+ firstHasDnsErr,
+ firstHasConnectTimeout,
+ firstHasReadTimeout);
+ }
+ config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, exception);
+ throw exception;
+ }
+
+
+ /**
+ * 可重试的,非双向认证的请求
+ * @param urlSuffix
+ * @param uuid
+ * @param data
+ * @return
+ */
+ public String requestWithoutCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception {
+ return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), false, autoReport);
+ }
+
+ /**
+ * 可重试的,非双向认证的请求
+ * @param urlSuffix
+ * @param uuid
+ * @param data
+ * @param connectTimeoutMs
+ * @param readTimeoutMs
+ * @return
+ */
+ public String requestWithoutCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception {
+ return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, false, autoReport);
+ }
+
+ /**
+ * 可重试的,双向认证的请求
+ * @param urlSuffix
+ * @param uuid
+ * @param data
+ * @return
+ */
+ public String requestWithCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception {
+ return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), true, autoReport);
+ }
+
+ /**
+ * 可重试的,双向认证的请求
+ * @param urlSuffix
+ * @param uuid
+ * @param data
+ * @param connectTimeoutMs
+ * @param readTimeoutMs
+ * @return
+ */
+ public String requestWithCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception {
+ return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, true, autoReport);
+ }
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayUtil.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayUtil.java
new file mode 100644
index 0000000..e893353
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayUtil.java
@@ -0,0 +1,295 @@
+package com.github.wxpay.sdk;
+
+import com.github.wxpay.sdk.WXPayConstants.SignType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.*;
+
+
+public class WXPayUtil {
+
+ private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ private static final Random RANDOM = new SecureRandom();
+
+ /**
+ * XML格式字符串转换为Map
+ *
+ * @param strXML XML字符串
+ * @return XML数据转换后的Map
+ * @throws Exception
+ */
+ public static Map xmlToMap(String strXML) throws Exception {
+ try {
+ Map data = new HashMap();
+ DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
+ InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
+ org.w3c.dom.Document doc = documentBuilder.parse(stream);
+ doc.getDocumentElement().normalize();
+ NodeList nodeList = doc.getDocumentElement().getChildNodes();
+ for (int idx = 0; idx < nodeList.getLength(); ++idx) {
+ Node node = nodeList.item(idx);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ org.w3c.dom.Element element = (org.w3c.dom.Element) node;
+ data.put(element.getNodeName(), element.getTextContent());
+ }
+ }
+ try {
+ stream.close();
+ } catch (Exception ex) {
+ // do nothing
+ }
+ return data;
+ } catch (Exception ex) {
+ WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
+ throw ex;
+ }
+
+ }
+
+ /**
+ * 将Map转换为XML格式的字符串
+ *
+ * @param data Map类型数据
+ * @return XML格式的字符串
+ * @throws Exception
+ */
+ public static String mapToXml(Map data) throws Exception {
+ org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
+ org.w3c.dom.Element root = document.createElement("xml");
+ document.appendChild(root);
+ for (String key: data.keySet()) {
+ String value = data.get(key);
+ if (value == null) {
+ value = "";
+ }
+ value = value.trim();
+ org.w3c.dom.Element filed = document.createElement(key);
+ filed.appendChild(document.createTextNode(value));
+ root.appendChild(filed);
+ }
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ DOMSource source = new DOMSource(document);
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ transformer.transform(source, result);
+ String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+ try {
+ writer.close();
+ }
+ catch (Exception ex) {
+ }
+ return output;
+ }
+
+
+ /**
+ * 生成带有 sign 的 XML 格式字符串
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @return 含有sign字段的XML
+ */
+ public static String generateSignedXml(final Map data, String key) throws Exception {
+ return generateSignedXml(data, key, SignType.MD5);
+ }
+
+ /**
+ * 生成带有 sign 的 XML 格式字符串
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @param signType 签名类型
+ * @return 含有sign字段的XML
+ */
+ public static String generateSignedXml(final Map data, String key, SignType signType) throws Exception {
+ String sign = generateSignature(data, key, signType);
+ data.put(WXPayConstants.FIELD_SIGN, sign);
+ return mapToXml(data);
+ }
+
+
+ /**
+ * 判断签名是否正确
+ *
+ * @param xmlStr XML格式数据
+ * @param key API密钥
+ * @return 签名是否正确
+ * @throws Exception
+ */
+ public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
+ Map data = xmlToMap(xmlStr);
+ if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+ return false;
+ }
+ String sign = data.get(WXPayConstants.FIELD_SIGN);
+ return generateSignature(data, key).equals(sign);
+ }
+
+ /**
+ * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @return 签名是否正确
+ * @throws Exception
+ */
+ public static boolean isSignatureValid(Map data, String key) throws Exception {
+ return isSignatureValid(data, key, SignType.MD5);
+ }
+
+ /**
+ * 判断签名是否正确,必须包含sign字段,否则返回false。
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @param signType 签名方式
+ * @return 签名是否正确
+ * @throws Exception
+ */
+ public static boolean isSignatureValid(Map data, String key, SignType signType) throws Exception {
+ if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+ return false;
+ }
+ String sign = data.get(WXPayConstants.FIELD_SIGN);
+ return generateSignature(data, key, signType).equals(sign);
+ }
+
+ /**
+ * 生成签名
+ *
+ * @param data 待签名数据
+ * @param key API密钥
+ * @return 签名
+ */
+ public static String generateSignature(final Map data, String key) throws Exception {
+ return generateSignature(data, key, SignType.MD5);
+ }
+
+ /**
+ * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
+ *
+ * @param data 待签名数据
+ * @param key API密钥
+ * @param signType 签名方式
+ * @return 签名
+ */
+ public static String generateSignature(final Map data, String key, SignType signType) throws Exception {
+ Set keySet = data.keySet();
+ String[] keyArray = keySet.toArray(new String[keySet.size()]);
+ Arrays.sort(keyArray);
+ StringBuilder sb = new StringBuilder();
+ for (String k : keyArray) {
+ if (k.equals(WXPayConstants.FIELD_SIGN)) {
+ continue;
+ }
+ if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
+ sb.append(k).append("=").append(data.get(k).trim()).append("&");
+ }
+ sb.append("key=").append(key);
+ if (SignType.MD5.equals(signType)) {
+ return MD5(sb.toString()).toUpperCase();
+ }
+ else if (SignType.HMACSHA256.equals(signType)) {
+ return HMACSHA256(sb.toString(), key);
+ }
+ else {
+ throw new Exception(String.format("Invalid sign_type: %s", signType));
+ }
+ }
+
+
+ /**
+ * 获取随机字符串 Nonce Str
+ *
+ * @return String 随机字符串
+ */
+ public static String generateNonceStr() {
+ char[] nonceChars = new char[32];
+ for (int index = 0; index < nonceChars.length; ++index) {
+ nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
+ }
+ return new String(nonceChars);
+ }
+
+
+ /**
+ * 生成 MD5
+ *
+ * @param data 待处理数据
+ * @return MD5结果
+ */
+ public static String MD5(String data) throws Exception {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] array = md.digest(data.getBytes("UTF-8"));
+ StringBuilder sb = new StringBuilder();
+ for (byte item : array) {
+ sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+ }
+ return sb.toString().toUpperCase();
+ }
+
+ /**
+ * 生成 HMACSHA256
+ * @param data 待处理数据
+ * @param key 密钥
+ * @return 加密结果
+ * @throws Exception
+ */
+ public static String HMACSHA256(String data, String key) throws Exception {
+ Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
+ sha256_HMAC.init(secret_key);
+ byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
+ StringBuilder sb = new StringBuilder();
+ for (byte item : array) {
+ sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+ }
+ return sb.toString().toUpperCase();
+ }
+
+ /**
+ * 日志
+ * @return
+ */
+ public static Logger getLogger() {
+ Logger logger = LoggerFactory.getLogger("wxpay java sdk");
+ return logger;
+ }
+
+ /**
+ * 获取当前时间戳,单位秒
+ * @return
+ */
+ public static long getCurrentTimestamp() {
+ return System.currentTimeMillis()/1000;
+ }
+
+ /**
+ * 获取当前时间戳,单位毫秒
+ * @return
+ */
+ public static long getCurrentTimestampMs() {
+ return System.currentTimeMillis();
+ }
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayXmlUtil.java b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayXmlUtil.java
new file mode 100644
index 0000000..500d9a4
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/com/github/wxpay/sdk/WXPayXmlUtil.java
@@ -0,0 +1,30 @@
+package com.github.wxpay.sdk;
+
+import org.w3c.dom.Document;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * 2018/7/3
+ */
+public final class WXPayXmlUtil {
+ public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ documentBuilderFactory.setXIncludeAware(false);
+ documentBuilderFactory.setExpandEntityReferences(false);
+
+ return documentBuilderFactory.newDocumentBuilder();
+ }
+
+ public static Document newDocument() throws ParserConfigurationException {
+ return newDocumentBuilder().newDocument();
+ }
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayConf.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayConf.java
new file mode 100644
index 0000000..a310f8b
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayConf.java
@@ -0,0 +1,35 @@
+package jframe.wxpay;
+
+import jframe.core.util.PropsConf;
+
+import java.io.InputStream;
+
+/**
+ * @author dzh
+ * @date 2020/8/18 19:39
+ */
+public class WxpayConf extends PropsConf {
+
+ public static final String CERTNAME = "apiclient_cert.p12";
+ public static final String V3_PRIVATE_KEY = "apiclient_key.pem";
+
+ public static final String P_appId = "appId";
+ public static final String P_mchId = "mchId";
+ public static final String P_apiKey = "apiKey";
+ public static final String P_certPath = "certPath";
+ public static final String P_notifyUrl = "notifyUrl";
+ public static final String P_autoReport = "autoReport";
+ public static final String P_useSandbox = "useSandbox";
+ public static final String P_signType = "signType";
+ //v3
+ public static final String P_apiKeyV3 = "apiKeyV3";
+ public static final String P_privateKeyPath = "privateKeyPath";
+ public static final String P_certSN = "certSN";
+ public static final String P_notifyOrderV3 = "notifyOrderV3";
+ public static final String P_notifyRefundV3 = "notifyRefundV3";
+
+ public synchronized void init(InputStream is) throws Exception {
+ super.init(is);
+ }
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayPlugin.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayPlugin.java
new file mode 100644
index 0000000..83fe5bb
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/WxpayPlugin.java
@@ -0,0 +1,11 @@
+package jframe.wxpay;
+
+import jframe.core.plugin.DefPlugin;
+
+/**
+ * @author dzh
+ * @date 2020/8/18 16:44
+ */
+public class WxpayPlugin extends DefPlugin {
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayService.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayService.java
new file mode 100644
index 0000000..8c685f6
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayService.java
@@ -0,0 +1,84 @@
+package jframe.wxpay.service;
+
+import jframe.core.plugin.annotation.Service;
+
+import java.util.Map;
+
+/**
+ * API列表
+ * 付款到零钱
+ *
+ * @author dzh
+ * @date 2020/8/18 16:45
+ */
+@Service(clazz = "jframe.wxpay.service.impl.WxpayServiceV2Impl", id = WxpayService.ID)
+public interface WxpayService {
+
+ String ID = "jframe.service.wxpay";
+
+ String V2 = "v2";
+
+ String NOTIFY_SUCC = "";
+ String NOTIFY_FAIL = "";
+
+ default String version() {
+ return V2;
+ }
+
+ /**
+ * @param id groupid
+ * @param key properties key
+ * @return properties value
+ */
+ String conf(String id, String key);
+
+ Map orderPrepay(String id, Map req) throws Exception;
+
+ /**
+ * 签名预支付信息,返回给前端
+ * 预支付信息
+ *
+ * Map{appId,timeStamp,nonceStr,package,signType}
+ *
+ * @param id group id
+ * @param req Map{prepareId,nonceStr}
+ * @return Map{timeStamp,nonceStr,package,package,signType,paySign}
+ */
+ Map signPrepay(String id, Map req) throws Exception;
+
+ Map orderPrepayAndSign(String id, Map req) throws Exception;
+
+ Map orderClose(String id, Map req) throws Exception;
+
+ /**
+ * 订单查询
+ *
+ * @param id group id
+ * @param req map{transaction_id,out_trade_no}
+ * @return order
+ */
+ Map orderQuery(String id, Map req) throws Exception;
+
+ Map processResponseXml(String id, String xmlStr) throws Exception;
+
+ @Deprecated
+ Map processResponseXmlUnsafe(String xmlStr) throws Exception;
+
+ boolean isResponseSignatureValid(String id, Map res) throws Exception;
+
+ Map refund(String id, Map req) throws Exception;
+
+ // 退款通知
+ Map refundNotify(String id, String reqBody, Map headers) throws Exception;
+
+ Map refundQuery(String id, Map req) throws Exception;
+
+ Map promotionTransfers(String id, Map reqData) throws Exception;
+
+ Map gettransferinfo(String id, Map reqData) throws Exception;
+
+ Map payBank(String id, Map reqData) throws Exception;
+
+ Map queryBank(String id, Map reqData) throws Exception;
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayServiceV3.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayServiceV3.java
new file mode 100644
index 0000000..818de1e
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/WxpayServiceV3.java
@@ -0,0 +1,44 @@
+package jframe.wxpay.service;
+
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import jframe.core.plugin.annotation.Service;
+
+import java.util.Map;
+
+/**
+ * @author dzh
+ * @date 2024/7/3 09:49
+ */
+@Service(clazz = "jframe.wxpay.service.impl.WxpayServiceV3Impl", id = WxpayServiceV3.ID)
+public interface WxpayServiceV3 {
+
+ String ID = "jframe.service.wxpayv3";
+
+ String V3 = "v3";
+
+ default String version() {
+ return V3;
+ }
+
+ String conf(String id, String key);
+
+ Map orderPrepay(String id, Map req) throws Exception;
+
+ Map signPrepay(String id, Map req) throws Exception;
+
+ Map orderPrepayAndSign(String id, Map req) throws Exception;
+
+ void orderClose(String id, Map req) throws Exception;
+
+ Transaction orderQuery(String id, Map req) throws Exception;
+
+ Transaction orderNotify(String id, String reqBody, Map headers) throws Exception;
+
+ Refund refund(String id, Map req) throws Exception;
+
+ Refund refundQuery(String id, Map req) throws Exception;
+
+ RefundNotification refundNotify(String id, String reqBody, Map headers) throws Exception;
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV2Impl.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV2Impl.java
new file mode 100644
index 0000000..70f724d
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV2Impl.java
@@ -0,0 +1,198 @@
+package jframe.wxpay.service.impl;
+
+import com.github.wxpay.sdk.JframeWxpayConfig;
+import com.github.wxpay.sdk.WXPay;
+import com.github.wxpay.sdk.WXPayConstants;
+import com.github.wxpay.sdk.WXPayUtil;
+import jframe.core.conf.Config;
+import jframe.core.plugin.annotation.InjectPlugin;
+import jframe.core.plugin.annotation.Injector;
+import jframe.core.plugin.annotation.Start;
+import jframe.core.plugin.annotation.Stop;
+import jframe.wxpay.WxpayConf;
+import jframe.wxpay.WxpayPlugin;
+import jframe.wxpay.service.WxpayService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 开发文档首页
+ *
+ * @author dzh
+ * @date 2020/8/18 17:40
+ */
+@Injector
+public class WxpayServiceV2Impl implements WxpayService {
+
+ static Logger LOG = LoggerFactory.getLogger(WxpayServiceV2Impl.class);
+
+ @InjectPlugin
+ static WxpayPlugin plugin;
+
+ static String FILE_WXPAY = "file.wxpay";
+
+ //group id -> AlipayClient
+ private final Map clients = new HashMap<>();
+
+ private WxpayConf wxpayConf;
+
+ @Start
+ void start() {
+ LOG.info("Start WxpayServiceV2");
+ try {
+ String file = plugin.getConfig(FILE_WXPAY, plugin.getConfig(Config.APP_CONF) + "/wxpay.properties");
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
+ wxpayConf = new WxpayConf();
+ wxpayConf.init(file);
+ for (String id : wxpayConf.getGroupIds()) {
+ WXPay wxpay = createWxpay(wxpayConf, id);
+ clients.put(id, wxpay);
+ LOG.info("createWxpay id {}", id);
+ }
+ } catch (Exception e) {
+ LOG.error("Start WxpayServiceV2 Failed!" + e.getMessage(), e);
+ }
+ }
+
+ @Stop
+ void stop() {
+ clients.clear();
+ LOG.info("Stop WxpayServiceV2");
+ }
+
+ /**
+ * @param id groupid
+ * @return cert bytes
+ */
+ byte[] loadCert(WxpayConf props, String id) throws IOException {
+ String certPath = props.getConf(id, WxpayConf.P_certPath);
+ File file = new File(certPath);
+ if (!file.exists()) {
+ file = Paths.get(plugin.getConfig(Config.APP_CONF), WxpayConf.CERTNAME).toFile();
+ }
+ if (!file.exists()) {
+ throw new FileNotFoundException(WxpayConf.CERTNAME);
+ }
+ try (InputStream certStream = Files.newInputStream(file.toPath())) {
+ byte[] certData = new byte[(int) file.length()];
+ long size = certStream.read(certData);
+ LOG.info("read {} {}", size, WxpayConf.CERTNAME);
+ return certData;
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ throw new IOException(e.getMessage(), e.getCause());
+ }
+ }
+
+ private WXPay createWxpay(WxpayConf props, String id) throws Exception {
+ byte[] bytes = loadCert(props, id);
+ JframeWxpayConfig conf = JframeWxpayConfig.create(props.getConf(id, WxpayConf.P_appId), props.getConf(id, WxpayConf.P_mchId), props.getConf(id, WxpayConf.P_apiKey), new ByteArrayInputStream(bytes));
+ return new WXPay(conf, props.getConf(id, WxpayConf.P_notifyUrl), Boolean.parseBoolean(props.getConf(id, WxpayConf.P_autoReport, "true")), Boolean.parseBoolean(props.getConf(id, WxpayConf.P_useSandbox, "false")), WXPayConstants.SignType.of(props.getConf(id, WxpayConf.P_signType)));
+ }
+
+ @Override
+ public String conf(String id, String key) {
+ return wxpayConf.getConf(id, key);
+ }
+
+ @Override
+ public Map orderPrepay(String id, Map req) throws Exception {
+// req.putIfAbsent("appid", conf(id, WxpayConf.P_appId));
+// req.putIfAbsent("mch_id", conf(id, WxpayConf.P_mchId));
+ return clients.get(id).unifiedOrder(req);
+ }
+
+ @Override
+ public Map signPrepay(String id, Map req) throws Exception {
+ String prepayId = req.get("prepayId");
+ if (prepayId == null) {
+ return Collections.emptyMap();
+ }
+ //appId,timeStamp,nonceStr,package,signType
+ Map data = new HashMap<>();
+ data.put("appId", conf(id, WxpayConf.P_appId));
+ data.put("timeStamp", String.valueOf(WXPayUtil.getCurrentTimestamp()));
+ data.put("nonceStr", req.getOrDefault("nonceStr", WXPayUtil.generateNonceStr()));
+ data.put("package", prepayId.startsWith("prepay_id") ? prepayId : "prepay_id=" + prepayId);
+ WXPayConstants.SignType signType = clients.get(id).signType();
+ data.put("signType", signType.typeName());
+ String paySign = WXPayUtil.generateSignature(data, conf(id, WxpayConf.P_apiKey), signType);
+ //timeStamp,nonceStr,package,signType,paySign
+ data.put("paySign", paySign);
+ return data;
+ }
+
+ @Override
+ public Map orderPrepayAndSign(String id, Map req) throws Exception {
+ return signPrepay(id, orderPrepay(id, req));
+ }
+
+ @Override
+ public Map orderClose(String id, Map req) throws Exception {
+ return clients.get(id).closeOrder(req);
+ }
+
+ @Override
+ public Map orderQuery(String id, Map req) throws Exception {
+ return clients.get(id).orderQuery(req);
+ }
+
+ @Override
+ public Map processResponseXml(String id, String xmlStr) throws Exception {
+ return clients.get(id).processResponseXml(xmlStr);
+ }
+
+ @Override
+ public Map processResponseXmlUnsafe(String xmlStr) throws Exception {
+ return WXPayUtil.xmlToMap(xmlStr);
+ }
+
+ @Override
+ public boolean isResponseSignatureValid(String id, Map res) throws Exception {
+ return clients.get(id).isResponseSignatureValid(res);
+ }
+
+ @Override
+ public Map refund(String id, Map req) throws Exception {
+ return clients.get(id).refund(req);
+ }
+
+ @Override
+ public Map refundNotify(String id, String reqBody, Map headers) throws Exception {
+ return Map.of();//todo
+ }
+
+ @Override
+ public Map refundQuery(String id, Map req) throws Exception {
+ return clients.get(id).refundQuery(req);
+ }
+
+ @Override
+ public Map promotionTransfers(String id, Map reqData) throws Exception {
+ return clients.get(id).promotionTransfers(reqData);
+ }
+
+ @Override
+ public Map gettransferinfo(String id, Map reqData) throws Exception {
+ return clients.get(id).gettransferinfo(reqData);
+ }
+
+ @Override
+ public Map payBank(String id, Map reqData) throws Exception {
+ return clients.get(id).payBank(reqData);
+ }
+
+ @Override
+ public Map queryBank(String id, Map reqData) throws Exception {
+ return clients.get(id).queryBank(reqData);
+ }
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV3Impl.java b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV3Impl.java
new file mode 100644
index 0000000..f82edf8
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/java/jframe/wxpay/service/impl/WxpayServiceV3Impl.java
@@ -0,0 +1,300 @@
+package jframe.wxpay.service.impl;
+
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.notification.NotificationConfig;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
+import com.wechat.pay.java.core.util.NonceUtil;
+import com.wechat.pay.java.service.payments.jsapi.JsapiService;
+import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+import com.wechat.pay.java.service.payments.jsapi.model.*;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.RefundService;
+import com.wechat.pay.java.service.refund.model.*;
+import jframe.core.plugin.annotation.InjectPlugin;
+import jframe.core.plugin.annotation.Injector;
+import jframe.core.plugin.annotation.Start;
+import jframe.core.plugin.annotation.Stop;
+import jframe.wxpay.WxpayConf;
+import jframe.wxpay.WxpayPlugin;
+import jframe.wxpay.service.WxpayServiceV3;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * V3开发说明
+ * 接口文档
+ * wechatpay-apache-httpclient
+ * v3 java sdk
+ *
+ * 请求的唯一标示包含在应答的HTTP头Request-ID中
+ *
+ * User-Agent
+ * 使用HTTP客户端默认的User-Agent。
+ * 遵循HTTP协议,使用自身系统和应用的名称和版本等信息,组成自己独有的User-Agent。
+ *
+ * Accept-Language
+ * en
+ * zh-CN
+ * zh-HK
+ * zh-TW
+ *
+ * @author dzh
+ * @date 2020/8/18 17:38
+ */
+@Injector
+public class WxpayServiceV3Impl implements WxpayServiceV3 {
+
+ static Logger LOG = LoggerFactory.getLogger(WxpayServiceV3Impl.class);
+
+ @InjectPlugin
+ static WxpayPlugin plugin;
+
+ static String FILE_WXPAY = "file.wxpay";
+
+ private WxpayConf wxpayConf;
+
+ // 使用自动更新平台证书的RSA配置
+ // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
+ private final Map payConf = new HashMap<>();//mchId->conf
+
+ @Start
+ void start() {
+ LOG.info("Start {}", WxpayServiceV3Impl.class.getSimpleName());
+ try {
+ String file = plugin.getConfig(FILE_WXPAY, plugin.getConfig(jframe.core.conf.Config.APP_CONF) + "/wxpay.properties");
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
+ wxpayConf = new WxpayConf();
+ wxpayConf.init(file);
+
+ initPayConf(wxpayConf);
+
+ LOG.info("WxpayServiceV3 start successfully!");
+ } catch (Exception e) {
+ LOG.error("WxpayServiceV3 start failed! {}", e.getMessage(), e);
+ }
+ }
+
+ private void initPayConf(WxpayConf wxpayConf) {
+ for (String id : wxpayConf.getGroupIds()) {
+ String mid = wxpayConf.getConf(id, WxpayConf.P_mchId);
+ if (payConf.containsKey(mid)) continue;
+ String privateKeyPath = wxpayConf.getConf(id, WxpayConf.P_privateKeyPath);
+ if (privateKeyPath == null || privateKeyPath.trim().isEmpty()) {
+ privateKeyPath = plugin.getConfig(jframe.core.conf.Config.APP_CONF) + "/" + WxpayConf.V3_PRIVATE_KEY;
+ }
+ RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder().merchantId(mid).privateKeyFromPath(privateKeyPath).merchantSerialNumber(wxpayConf.getConf(id, WxpayConf.P_certSN)).apiV3Key(wxpayConf.getConf(id, WxpayConf.P_apiKeyV3)).build();
+ payConf.put(mid, config);
+ }
+ }
+
+ private RSAAutoCertificateConfig payConfig(String id) {
+ String mid = wxpayConf.getConf(id, WxpayConf.P_mchId);
+ return payConf.get(mid);
+ }
+
+ @Stop
+ void stop() {
+ payConf.clear();
+ LOG.info("WxpayServiceV3 stopped");
+ }
+
+ @Override
+ public String conf(String id, String key) {
+ return wxpayConf.getConf(id, key);
+ }
+
+ private PrepayRequest toPrepayRequest(String id, Map req) {
+ PrepayRequest request = new PrepayRequest();
+ request.setAppid(conf(id, WxpayConf.P_appId));
+ request.setMchid(conf(id, WxpayConf.P_mchId));
+ request.setDescription(req.getOrDefault("description", req.get("body")));
+ request.setOutTradeNo(req.get("out_trade_no"));
+ if (req.containsKey("time_expire")) request.setTimeExpire(req.get("time_expire"));
+ if (req.containsKey("attach")) request.setAttach(req.get("attach"));
+ if (req.containsKey("notify_url")) request.setNotifyUrl(req.get("notify_url"));
+ else request.setNotifyUrl(conf(id, WxpayConf.P_notifyOrderV3));
+ if (req.containsKey("goods_tag")) request.setGoodsTag(req.get("goods_tag"));
+ if (req.containsKey("support_fapiao"))
+ request.setSupportFapiao(Boolean.parseBoolean(req.get("support_fapiao")));
+ Amount amount = new Amount();
+ amount.setTotal(Integer.parseInt(req.get("total_fee")));
+ amount.setCurrency(req.getOrDefault("currency", "CNY"));
+ request.setAmount(amount);
+ Payer payer = new Payer();
+ payer.setOpenid(req.get("openid"));
+ request.setPayer(payer);
+ //
+// request.setDetail();
+// request.setSceneInfo();
+// request.setSettleInfo();
+ return request;
+ }
+
+ //https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/direct-jsons/jsapi-prepay.html
+ @Override
+ public Map orderPrepay(String id, Map req) throws Exception {
+ JsapiService service = new JsapiService.Builder().config(payConfig(id)).build();
+ PrepayResponse response = service.prepay(toPrepayRequest(id, req));
+ return Map.of("prepay_id", response.getPrepayId());
+ }
+
+ /**
+ * @param id group id
+ * @param req Map{prepareId,nonceStr}
+ * @return replace with orderPrepay
+ */
+ @Override
+ public Map signPrepay(String id, Map req) throws Exception {
+ Config config = payConfig(id);
+// Signer signer = config.createSigner();
+
+ String appid = conf(id, WxpayConf.P_appId);
+ String prepayId = req.get("prepay_id");
+ long timestamp = Instant.now().getEpochSecond();
+ String nonceStr = NonceUtil.createNonce(32);
+ String packageVal = "prepay_id=" + prepayId;
+ String message = appid + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
+ String sign = config.createSigner().sign(message).getSign();
+
+ Map data = new HashMap<>();
+ data.put("appId", appid);
+ data.put("timeStamp", String.valueOf(timestamp));
+ data.put("nonceStr", nonceStr);
+ data.put("package", packageVal);
+ data.put("signType", "RSA");
+ data.put("paySign", sign);
+ return data;
+ }
+
+ @Override
+ public Map orderPrepayAndSign(String id, Map req) throws Exception {
+ JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(payConfig(id)).build();
+ PrepayRequest request = toPrepayRequest(id, req);
+ PrepayWithRequestPaymentResponse prepayRes = service.prepayWithRequestPayment(request);
+ //appId,timeStamp,nonceStr,package,signType
+ Map data = new HashMap<>();
+ data.put("appId", conf(id, WxpayConf.P_appId));
+ data.put("timeStamp", prepayRes.getTimeStamp());
+ data.put("nonceStr", prepayRes.getNonceStr());
+ data.put("package", prepayRes.getPackageVal());
+ data.put("signType", prepayRes.getSignType());
+ data.put("paySign", prepayRes.getPaySign());
+ return data;
+ }
+
+ //https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/close-order.html
+ @Override
+ public void orderClose(String id, Map req) throws Exception {
+ JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(payConfig(id)).build();
+ CloseOrderRequest request = new CloseOrderRequest();
+ request.setMchid(conf(id, WxpayConf.P_mchId));
+ request.setOutTradeNo(req.get("out_trade_no"));
+ service.closeOrder(request);
+ }
+
+ @Override
+ public Transaction orderQuery(String id, Map req) throws Exception {
+ JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(payConfig(id)).build();
+
+ Transaction t = null;
+ if (req.containsKey("out_trade_no")) {
+ QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
+ request.setMchid(conf(id, WxpayConf.P_mchId));
+ request.setOutTradeNo(req.get("out_trade_no"));
+ t = service.queryOrderByOutTradeNo(request);
+ } else if (req.containsKey("transaction_id")) {
+ QueryOrderByIdRequest request = new QueryOrderByIdRequest();
+ request.setMchid(conf(id, WxpayConf.P_mchId));
+ request.setTransactionId(req.get("transaction_id"));
+ t = service.queryOrderById(request);
+ }
+// if (t != null) {
+// return Map.of("appid", t.getAppid(), "out_trade_no", t.getOutTradeNo(), "transaction_id", t.getTransactionId(), "trade_type", t.getTradeType().name(), "trade_state", t.getTradeState().name(), "trade_state_desc", t.getTradeStateDesc(), "attach", t.getAttach());
+// }
+ return t;
+ }
+
+ /**
+ * 通知API
+ * 具体步骤如下:
+ *
+ * 使用回调通知请求的数据,构建 RequestParam。
+ * HTTP 请求体 body。切记使用原始报文,不要用 JSON 对象序列化后的字符串,避免验签的 body 和原文不一致。
+ * HTTP 头 Wechatpay-Signature。应答的微信支付签名。
+ * HTTP 头 Wechatpay-Serial。微信支付平台证书的序列号,验签必须使用序列号对应的微信支付平台证书。
+ * HTTP 头 Wechatpay-Nonce。签名中的随机数。
+ * HTTP 头 Wechatpay-Timestamp。签名中的时间戳。
+ * HTTP 头 Wechatpay-Signature-Type。签名类型。
+ * 初始化 RSAAutoCertificateConfig。微信支付平台证书由 SDK 的自动更新平台能力提供,也可以使用本地证书。
+ * 初始化 NotificationParser。
+ * 调用 NotificationParser.parse() 验签、解密并将 JSON 转换成具体的通知回调对象。如果验签失败,SDK 会抛出 ValidationException。
+ * 接下来可以执行你的业务逻辑了。如果执行成功,你应返回 200 OK 的状态码。如果执行失败,你应返回 4xx 或者 5xx的状态码,例如数据库操作失败建议返回 500 Internal Server Error。
+ *
+ * @param id group id
+ * @param reqBody request body
+ * @param headers request headers contains signature info
+ * @return Transaction
+ */
+ @Override
+ public Transaction orderNotify(String id, String reqBody, Map headers) throws Exception {
+ NotificationConfig config = payConfig(id);
+ NotificationParser parser = new NotificationParser(config);
+
+ // 构造 RequestParam
+ RequestParam requestParam = new RequestParam.Builder().serialNumber(headers.get("Wechatpay-Serial")).nonce(headers.get("Wechatpay-Nonce")).signature(headers.get("Wechatpay-Signature")).timestamp(headers.get("Wechatpay-Timestamp")).body(reqBody).build();
+ return parser.parse(requestParam, Transaction.class);
+// return Map.of("out_trade_no", od.getOutTradeNo(), "success_time", od.getSuccessTime(), "openid", od.getPayer().getOpenid(), "transaction_id", od.getTransactionId(), "result_code", od.getTradeState().name());
+ }
+
+
+ //https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/create.html
+ @Override
+ public Refund refund(String id, Map req) throws Exception {
+ RefundService service = new RefundService.Builder().config(payConfig(id)).build();
+ CreateRequest request = new CreateRequest();
+ request.setTransactionId(req.get("transaction_id"));
+ request.setOutTradeNo(req.get("out_trade_no"));
+ request.setOutRefundNo(req.get("out_refund_no"));
+ if (req.containsKey("reason")) request.setReason(req.get("reason"));
+ if (req.containsKey("notify_url")) request.setNotifyUrl(req.get("notify_url"));
+ else request.setNotifyUrl(conf(id, WxpayConf.P_notifyRefundV3));
+// if(req.containsKey("funds_account"))
+// request.setFundsAccount();
+ AmountReq amount = new AmountReq();
+ amount.setCurrency(req.getOrDefault("amount_currency", "CNY"));
+ amount.setRefund(Long.parseLong(req.get("amount_refund")));
+ amount.setTotal(Long.parseLong(req.getOrDefault("amount_total", req.get("refund"))));
+ request.setAmount(amount);
+ return service.create(request);
+ }
+
+ //https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/query-by-out-refund-no.html
+ @Override
+ public Refund refundQuery(String id, Map req) throws Exception {
+ RefundService service = new RefundService.Builder().config(payConfig(id)).build();
+ QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
+ request.setOutRefundNo(req.get("out_refund_no"));
+ return service.queryByOutRefundNo(request);
+ }
+
+ @Override
+ public RefundNotification refundNotify(String id, String reqBody, Map headers) throws Exception {
+ NotificationConfig config = payConfig(id);
+ NotificationParser parser = new NotificationParser(config);
+ // 构造 RequestParam
+ RequestParam requestParam = new RequestParam.Builder().serialNumber(headers.get("Wechatpay-Serial")).nonce(headers.get("Wechatpay-Nonce")).signature(headers.get("Wechatpay-Signature")).timestamp(headers.get("Wechatpay-Timestamp")).body(reqBody).build();
+ return parser.parse(requestParam, RefundNotification.class);
+ }
+
+}
diff --git a/jframe-plugin/jframe-wxpay/src/main/resources/META-INF/plugin.properties b/jframe-plugin/jframe-wxpay/src/main/resources/META-INF/plugin.properties
new file mode 100644
index 0000000..194c05e
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/main/resources/META-INF/plugin.properties
@@ -0,0 +1,7 @@
+Plugin-Name=jframe.wxpay.WxpayPlugin
+Plugin-Class=jframe.wxpay.WxpayPlugin
+#Default library path is META-INF/lib/
+#Plugin-Lib =
+#Default DLL path is META-INF/dll
+#Plugin-Dll =
+Plugin-Service=jframe.wxpay.service.WxpayService jframe.wxpay.service.WxpayServiceV3
diff --git a/jframe-plugin/jframe-wxpay/src/test/resources/wxpay.properties b/jframe-plugin/jframe-wxpay/src/test/resources/wxpay.properties
new file mode 100644
index 0000000..828d40c
--- /dev/null
+++ b/jframe-plugin/jframe-wxpay/src/test/resources/wxpay.properties
@@ -0,0 +1,13 @@
+group.id=xxx
+#
+@xxx.appId=
+@xxx.mchId=
+@xxx.apiKey=
+@xxx.certPath=
+@xxx.notifyUrl=
+@xxx.autoReport=true
+@xxx.useSandbox=false
+# common
+signType=MD5
+
+
diff --git a/jframe-plugin/jframe-zk/pom.xml b/jframe-plugin/jframe-zk/pom.xml
index 382bfbf..b1cb173 100644
--- a/jframe-plugin/jframe-zk/pom.xml
+++ b/jframe-plugin/jframe-zk/pom.xml
@@ -1,35 +1,35 @@
- 4.0.0
-
- jframe-plugin
- 2.0.0-SNAPSHOT
- io.github.dzh
-
- jframe-zk
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ jframe-plugin
+ 2.0.0-SNAPSHOT
+ io.github.dzh
+
+ jframe-zk
-
- 4.0.1
-
+
+ 5.1.0
+
-
-
- org.apache.curator
- curator-client
- ${curator.version}
-
-
- org.apache.curator
- curator-framework
- ${curator.version}
-
-
- org.apache.curator
- curator-recipes
- ${curator.version}
-
-
-
+
+
+ org.apache.curator
+ curator-client
+ ${curator.version}
+
+
+ org.apache.curator
+ curator-framework
+ ${curator.version}
+
+
+ org.apache.curator
+ curator-recipes
+ ${curator.version}
+
+
+
\ No newline at end of file
diff --git a/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/CuratorService.java b/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/CuratorService.java
index fff9b9c..bc0d5cb 100644
--- a/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/CuratorService.java
+++ b/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/CuratorService.java
@@ -1,17 +1,18 @@
package jframe.zk.service;
-import org.apache.curator.framework.CuratorFramework;
-
import jframe.core.plugin.annotation.Service;
+import org.apache.curator.framework.CuratorFramework;
/**
* @author dzh
- * @date Dec 12, 2018 7:12:56 PM
* @version 0.0.1
+ * @date Dec 12, 2018 7:12:56 PM
*/
-@Service(clazz = "jframe.zk.service.impl.CuratorServiceImpl", id = "jframe.service.zk.curator")
+@Service(clazz = "jframe.zk.service.impl.CuratorServiceImpl", id = CuratorService.ID)
public interface CuratorService {
+ String ID = "jframe.service.zk.curator";
+
CuratorFramework client(String id);
}
diff --git a/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/impl/CuratorServiceImpl.java b/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/impl/CuratorServiceImpl.java
index b2e8399..60b3cd5 100644
--- a/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/impl/CuratorServiceImpl.java
+++ b/jframe-plugin/jframe-zk/src/main/java/jframe/zk/service/impl/CuratorServiceImpl.java
@@ -1,22 +1,8 @@
/**
- *
+ *
*/
package jframe.zk.service.impl;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.curator.RetryPolicy;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.framework.imps.CuratorFrameworkState;
-import org.apache.curator.retry.ExponentialBackoffRetry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import jframe.core.conf.Config;
import jframe.core.plugin.annotation.InjectPlugin;
import jframe.core.plugin.annotation.Injector;
@@ -26,6 +12,19 @@
import jframe.zk.ZkField;
import jframe.zk.ZkPlugin;
import jframe.zk.service.CuratorService;
+import org.apache.curator.RetryPolicy;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.imps.CuratorFrameworkState;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* @author dzh
@@ -52,7 +51,9 @@ void start() {
try {
String file = Plugin.getConfig(FILE_CURATOR, Plugin.getConfig(Config.APP_CONF) + "/curator.properties");
- if (!new File(file).exists()) { throw new FileNotFoundException("not found " + file); }
+ if (!new File(file).exists()) {
+ throw new FileNotFoundException("not found " + file);
+ }
_config.init(file);
for (String id : _config.getGroupIds()) {
String connectString = _config.getConf(id, ZkField.ConnectString);
@@ -63,8 +64,7 @@ void start() {
int retryInterval = _config.getConfInt(id, ZkField.RetryInterval, "5000");
int retryTimes = _config.getConfInt(id, ZkField.RetryTimes, "3");
RetryPolicy retryPolicy = new ExponentialBackoffRetry(retryInterval, retryTimes);
- CuratorFramework zkCli = CuratorFrameworkFactory.builder().connectString(connectString).retryPolicy(retryPolicy)
- .connectionTimeoutMs(connectTimeout).sessionTimeoutMs(sessionTimeout).namespace(ns).build();
+ CuratorFramework zkCli = CuratorFrameworkFactory.builder().connectString(connectString).retryPolicy(retryPolicy).connectionTimeoutMs(connectTimeout).sessionTimeoutMs(sessionTimeout).namespace(ns).build();
try {
zkCli.start();
zkCli.blockUntilConnected(10, TimeUnit.SECONDS);
@@ -75,7 +75,7 @@ void start() {
if (zkCli.getState() == CuratorFrameworkState.STARTED) clients.put(id, zkCli);
}
} catch (Exception e) {
- LOG.error("Start CuratorService Failure!" + e.getMessage(), e);
+ LOG.error("Start CuratorService Failure!", e);
return;
}
LOG.info("Start CuratorService Successfully!");
diff --git a/jframe-plugin/pom.xml b/jframe-plugin/pom.xml
index 252a4dc..102f6da 100644
--- a/jframe-plugin/pom.xml
+++ b/jframe-plugin/pom.xml
@@ -1,141 +1,137 @@
- 4.0.0
- jframe-plugin
- 2.0.0-SNAPSHOT
- pom
-
- UTF-8
- 2.0.0-SNAPSHOT
- 1.7.25
-
-
- jframe-activemq
- jframe-clrfile
- jframe-datasource
- jframe-watch
- jframe-mybatis
- jframe-getui
- jframe-pushy
- jframe-apns
- jframe-memcached-client
- jframe-jedis
- jframe-httpclient
- jframe-mongodb-client
- jframe-yunpian
- jframe-qiniu
- jframe-activemq-client
- jframe-rabbitmq-client
- jframe-rongcloud
- jframe-aliyun
- jframe-umeng
- jframe-zk
- jframe-netty-http
- jframe-azure
- jframe-yunsms
- jframe-californium
- jframe-mqtt-client
- jframe-wx
- jframe-freemarker
- jframe-elasticsearch
- jframe-redisson
- jframe-qcloud
-
-
-
-
- ${project.groupId}
- jframe-ext
- ${jframe.version}
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.0
-
- 1.8
- 1.8
- ${project.build.sourceEncoding}
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.1.1
-
-
- plugin
-
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- 3.1.0
-
-
- compile
-
-
-
- ${project.build.sourceEncoding}
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M2
-
- true
-
-
-
- org.apache.maven.plugins
- maven-clean-plugin
- 3.1.0
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M2
-
- true
-
-
-
-
-
-
- junit
- junit
- 4.10
- test
-
-
- org.slf4j
- slf4j-api
- ${slf4j.version}
-
-
- org.slf4j
- slf4j-simple
- ${slf4j.version}
- test
-
-
- ${project.groupId}
- jframe-core
- ${jframe.version}
-
-
- io.github.dzh
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ jframe-plugin
+ 2.0.0-SNAPSHOT
+ pom
+ io.github.dzh
+
+ UTF-8
+ 2.0.0-SNAPSHOT
+ 1.7.36
+
+
+ jframe-activemq
+ jframe-activemq-client
+ jframe-clrfile
+ jframe-datasource
+ jframe-watch
+ jframe-mybatis
+ jframe-getui
+ jframe-pushy
+ jframe-apns
+ jframe-memcached-client
+ jframe-jedis
+ jframe-httpclient
+ jframe-mongodb-client
+ jframe-yunpian
+ jframe-qiniu
+ jframe-rabbitmq-client
+ jframe-rongcloud
+ jframe-aliyun
+ jframe-umeng
+ jframe-zk
+ jframe-netty-http
+ jframe-azure
+ jframe-yunsms
+ jframe-californium
+ jframe-mqtt-client
+ jframe-wx
+ jframe-freemarker
+ jframe-elasticsearch
+ jframe-redisson
+ jframe-qcloud
+ jframe-google
+ jframe-alipay
+ jframe-wxpay
+ jframe-id
+
+
+
+
+ ${project.groupId}
+ jframe-ext
+ ${jframe.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.13.0
+
+ 11
+ 11
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+ plugin
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.3.1
+
+
+ compile
+
+
+
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 3.3.2
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.2.5
+
+ true
+
+
+
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+ test
+
+
+ ${project.groupId}
+ jframe-core
+ ${jframe.version}
+
+
\ No newline at end of file
diff --git a/jframe/jframe-core/src/main/java/jframe/core/DefFrame.java b/jframe/jframe-core/src/main/java/jframe/core/DefFrame.java
index 293da3b..559f755 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/DefFrame.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/DefFrame.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.core;
@@ -15,8 +15,8 @@
import jframe.core.unit.UnitManager;
/**
- * @ThreadSafe
* @author dzh
+ * @ThreadSafe
* @date Sep 23, 2013 2:44:01 PM
* @since 1.0
*/
@@ -46,7 +46,7 @@ public boolean init(Config conf) {
_status = FRAME_STATUS.INIT;
}
- LOG.debug("DefFrame is initing");
+ LOG.debug("DefFrame init");
conf.setFrame(this);
this._cnf = conf;
@@ -94,7 +94,9 @@ public void run() {
*/
public void stop() {
synchronized (_lock) {
- if (_status == FRAME_STATUS.STOP) { return; }
+ if (_status == FRAME_STATUS.STOP) {
+ return;
+ }
_status = FRAME_STATUS.STOP;
}
LOG.debug("DefFrame is stopping");
@@ -116,15 +118,15 @@ public FrameEvent waitForStop(long timeout) {
FrameEvent event = null;
switch (_status) {
- case INIT:
- event = new FrameEvent(FrameEvent.Init, this);
- break;
- case START:
- event = new FrameEvent(FrameEvent.Start, this);
- break;
- default:
- event = new FrameEvent(FrameEvent.Stop, this);
- break;
+ case INIT:
+ event = new FrameEvent(FrameEvent.Init, this);
+ break;
+ case START:
+ event = new FrameEvent(FrameEvent.Start, this);
+ break;
+ default:
+ event = new FrameEvent(FrameEvent.Stop, this);
+ break;
}
return event;
}
diff --git a/jframe/jframe-core/src/main/java/jframe/core/FrameEvent.java b/jframe/jframe-core/src/main/java/jframe/core/FrameEvent.java
index ef5f92a..9649c12 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/FrameEvent.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/FrameEvent.java
@@ -17,9 +17,9 @@ public class FrameEvent extends EventObject {
*/
private static final long serialVersionUID = 1L;
- private int type;
+ private final int type;
- public static final int Init = 1 << 0;
+ public static final int Init = 1;
public static final int Start = 1 << 1;
public static final int Stop = 1 << 2;
diff --git a/jframe/jframe-core/src/main/java/jframe/core/conf/VarHandler.java b/jframe/jframe-core/src/main/java/jframe/core/conf/VarHandler.java
index 2717bbc..9351a99 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/conf/VarHandler.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/conf/VarHandler.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.core.conf;
@@ -7,7 +7,7 @@
import java.util.regex.Pattern;
/**
- *
+ *
* @author dzh
* @date Oct 11, 2013 1:12:37 PM
* @since 1.0
@@ -16,7 +16,7 @@ public class VarHandler {
public static final Pattern P_VAR = Pattern.compile(Config.REGEX_VAR, Pattern.CASE_INSENSITIVE);
- private Config _config;
+ private final Config _config;
public VarHandler(Config config) {
this._config = config;
@@ -24,22 +24,22 @@ public VarHandler(Config config) {
/**
* 利用config中的变量值,替换value里的变量
- *
- * @param v
- * @return
+ *
+ * @param input 待替换的字符串
+ * @return 替换后的字符串
*/
public String replace(String input) {
return replace(_config, input);
}
/**
- *
- * @param system
- * jvm系统变量,一般是System.getProperty
- * @param input
- * @return
+ *
+ * @param config system jvm系统变量,一般是System.getProperty
+ * @param input 待替换的字符串
+ * @return 替换后的字符串
*/
public String replace(Config config, String input) {
+ if (input == null || input.isEmpty()) return input;
Matcher m = P_VAR.matcher(input);
String var = null;
String val = null;
@@ -49,6 +49,9 @@ public String replace(Config config, String input) {
if (val == null) {
// LOG.warn("Not found variable's value: " + var);
continue;
+ } else if (val.equals(input)) {
+ // LOG.warn("Variable's value is same as input: " + var);
+ continue;
}
input = input.replaceAll("\\$\\{" + var + "\\}", val);
diff --git a/jframe/jframe-core/src/main/java/jframe/core/dispatch/DefDispatchFactory.java b/jframe/jframe-core/src/main/java/jframe/core/dispatch/DefDispatchFactory.java
index 303be81..33d4be1 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/dispatch/DefDispatchFactory.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/dispatch/DefDispatchFactory.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.core.dispatch;
@@ -10,68 +10,68 @@
/**
* dispatch管理管理工厂
- *
+ *
* @author dzh
* @date Jun 20, 2013 9:47:12 AM
*/
public class DefDispatchFactory implements DispatchFactory {
- private final Object _lock = new Object();
+ private final Object _lock = new Object();
- private List _dList = new ArrayList(2);
+ private List _dList = new ArrayList(2);
- private DefDispatchFactory() {
+ private DefDispatchFactory() {
- }
+ }
- public static final DispatchFactory newInstance() {
- return new DefDispatchFactory();
- }
+ public static DispatchFactory newInstance() {
+ return new DefDispatchFactory();
+ }
- public Dispatcher findDispatcher(String dispatcherID) {
- List list = _dList;
- Dispatcher dl = null;
- synchronized (_lock) {
- for (Dispatcher d : list) {
- if (d.getID().equals(dispatcherID)) {
- dl = d;
- break;
- }
- }
- }
- return dl;
- }
+ public Dispatcher findDispatcher(String dispatcherID) {
+ List list = _dList;
+ Dispatcher dl = null;
+ synchronized (_lock) {
+ for (Dispatcher d : list) {
+ if (d.getID().equals(dispatcherID)) {
+ dl = d;
+ break;
+ }
+ }
+ }
+ return dl;
+ }
- public Dispatcher createDispatcher(String dispatcherID, Config config) {
- Dispatcher d = DefDispatcher.newDispatcher(dispatcherID, config);
- d.start();
- synchronized (_lock) {
- _dList.add(d);
- }
- return d;
- }
+ public Dispatcher createDispatcher(String dispatcherID, Config config) {
+ Dispatcher d = DefDispatcher.newDispatcher(dispatcherID, config);
+ d.start();
+ synchronized (_lock) {
+ _dList.add(d);
+ }
+ return d;
+ }
- /**
- * if dispatcherID==Null, close all delegates
- */
- public void removeDispatcher(String dispatcherID) {
- List list = _dList;
- if (dispatcherID == null) {
- synchronized (_lock) {
- for (Dispatcher d : list) {
- d.close();
- }
- }
- list.clear();
- } else {
- synchronized (_lock) {
- Dispatcher d = findDispatcher(dispatcherID);
- if (d != null) {
- d.close();
- list.remove(d);
- }
- }
- }
- }
+ /**
+ * if dispatcherID==Null, close all delegates
+ */
+ public void removeDispatcher(String dispatcherID) {
+ List list = _dList;
+ if (dispatcherID == null) {
+ synchronized (_lock) {
+ for (Dispatcher d : list) {
+ d.close();
+ }
+ }
+ list.clear();
+ } else {
+ synchronized (_lock) {
+ Dispatcher d = findDispatcher(dispatcherID);
+ if (d != null) {
+ d.close();
+ list.remove(d);
+ }
+ }
+ }
+ }
}
diff --git a/jframe/jframe-core/src/main/java/jframe/core/plugin/DefPluginContext.java b/jframe/jframe-core/src/main/java/jframe/core/plugin/DefPluginContext.java
index 908eaee..d6dda6e 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/plugin/DefPluginContext.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/plugin/DefPluginContext.java
@@ -1,21 +1,8 @@
/**
- *
+ *
*/
package jframe.core.plugin;
-import java.lang.reflect.Proxy;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.TreeSet;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import jframe.core.conf.Config;
import jframe.core.conf.ConfigConstants;
import jframe.core.dispatch.DefDispatcher;
@@ -27,6 +14,11 @@
import jframe.core.plugin.dispatch.DispatchSourceHandler;
import jframe.core.plugin.dispatch.DispatchTargetHandler;
import jframe.core.signal.Signal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Proxy;
+import java.util.*;
/**
* @author dzh
@@ -121,7 +113,7 @@ public PluginRef regPlugin(Plugin plugin) {
}
/**
- * @param plugin
+ * @param ref
*/
private void regDispatch(PluginRef ref) {
Plugin plugin = ref.getPlugin();
@@ -147,7 +139,7 @@ private void regDispatch(PluginRef ref) {
private void createDispatchTarget(PluginRef ref) {
Object pdt = ref.getPolicy(PluginRef.DispatchTarget);
if (pdt == null) {
- pdt = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { DispatchTarget.class }, new DispatchTargetHandler(ref));
+ pdt = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{DispatchTarget.class}, new DispatchTargetHandler(ref));
ref.regPolicy(PluginRef.DispatchTarget, pdt);
if (getDispatcher() != null)
getDispatcher().addDispatchTarget((DispatchTarget) pdt);
@@ -163,7 +155,7 @@ private void createDispatchTarget(PluginRef ref) {
private void createDispatchSource(PluginRef ref) {
Object pds = ref.getPolicy(PluginRef.DispatchSource); // null is normal
if (pds == null) {
- pds = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { DispatchSource.class }, new DispatchSourceHandler(ref));
+ pds = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{DispatchSource.class}, new DispatchSourceHandler(ref));
ref.regPolicy(PluginRef.DispatchSource, pds);
if (getDispatcher() != null)
getDispatcher().addDispatchSource((DispatchSource) pds);
@@ -230,7 +222,7 @@ public void signal(Signal sig) {
* 关闭dispatch
*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.PluginContext#dispose()
*/
public void dispose() {
@@ -253,7 +245,7 @@ private int newPluginID() {
/*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.PluginContext#getConfig()
*/
public Config getConfig() {
@@ -262,7 +254,7 @@ public Config getConfig() {
/*
* (non-Javadoc)
- *
+ *
* @see
* jframe.core.plugin.PluginContext#regPluginListener(jframe.core.plugin
* .PluginListener)
@@ -277,7 +269,7 @@ public void regPluginListener(PluginListener l) {
/*
* (non-Javadoc)
- *
+ *
* @see
* jframe.core.plugin.PluginContext#unregPluginListener(jframe.core.plugin
* .PluginListener)
@@ -290,7 +282,7 @@ public void unregPluginListener(PluginListener l) {
/*
* (non-Javadoc)
- *
+ *
* @see
* jframe.core.plugin.PluginContext#notifyPluginEvent(jframe.core.plugin
* .PluginEvent)
@@ -305,10 +297,8 @@ public void notifyPluginEvent(PluginEvent event) {
}
/**
- *
* (non-Javadoc)
- *
- * @see jframe.core.plugin.PluginContext#containRef(jframe.core.plugin.Plugin)
+ *
* @return if find PluginRef return it, or return null
*/
private PluginRef containRef(Plugin plugin) {
@@ -326,7 +316,7 @@ private PluginRef containRef(Plugin plugin) {
/*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.IDispatchable#getDispatcher()
*/
public Dispatcher getDispatcher() {
@@ -335,7 +325,7 @@ public Dispatcher getDispatcher() {
/*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.PluginContext#getPlugin(java.lang.String)
*/
public PluginRef getPlugin(String name) {
@@ -350,7 +340,7 @@ public PluginRef getPlugin(String name) {
/*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.PluginContext#regPlugins(java.util.Collection,
* java.util.Comparator)
*/
@@ -383,7 +373,7 @@ public void regPlugins(Collection plugins, Comparator super Plugin> co
/*
* (non-Javadoc)
- *
+ *
* @see jframe.core.plugin.PluginContext#unregPlugins(java.util.Collection,
* java.util.Comparator)
*/
@@ -419,7 +409,7 @@ public PluginComparator(TYPE type) {
/*
* (non-Javadoc)
- *
+ *
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Plugin o1, Plugin o2) {
@@ -427,14 +417,14 @@ public int compare(Plugin o1, Plugin o2) {
jframe.core.plugin.annotation.Plugin ap1 = o1.getClass().getAnnotation(jframe.core.plugin.annotation.Plugin.class);
jframe.core.plugin.annotation.Plugin ap2 = o2.getClass().getAnnotation(jframe.core.plugin.annotation.Plugin.class);
switch (type) {
- case START: {
- v = minus(ap1.startOrder(), ap2.startOrder());
- break;
- }
- case STOP: {
- v = minus(ap1.stopOrder(), ap2.stopOrder());
- break;
- }
+ case START: {
+ v = minus(ap1.startOrder(), ap2.startOrder());
+ break;
+ }
+ case STOP: {
+ v = minus(ap1.stopOrder(), ap2.stopOrder());
+ break;
+ }
}
if (v == 0) {
@@ -445,7 +435,7 @@ public int compare(Plugin o1, Plugin o2) {
/**
* 负数作为最大整数
- *
+ *
* @param minuend
* @param subtrahend
* @return
@@ -463,7 +453,7 @@ int minus(int minuend, int subtrahend) {
/*
* (non-Javadoc)
- *
+ *
* @see
* jframe.core.plugin.PluginContext#unregPlugin(jframe.core.plugin.PluginRef
* )
diff --git a/jframe/jframe-core/src/main/java/jframe/core/plugin/loader/ext/PluginServiceClassLoader.java b/jframe/jframe-core/src/main/java/jframe/core/plugin/loader/ext/PluginServiceClassLoader.java
index 09cbcbf..2453207 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/plugin/loader/ext/PluginServiceClassLoader.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/plugin/loader/ext/PluginServiceClassLoader.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.core.plugin.loader.ext;
@@ -52,9 +52,8 @@ protected void injectImportService(Field f) {
/**
* register export-service
- *
+ *
* @param pc
- * @param p
*/
public void loadService(PluginCase pc) {
ServiceContext sc = plc.getServiceContext();
diff --git a/jframe/jframe-core/src/main/java/jframe/core/unit/PluginUnit.java b/jframe/jframe-core/src/main/java/jframe/core/unit/PluginUnit.java
index 70d96b0..603814b 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/unit/PluginUnit.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/unit/PluginUnit.java
@@ -1,18 +1,8 @@
/**
- *
+ *
*/
package jframe.core.unit;
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import jframe.core.Frame;
import jframe.core.conf.Config;
import jframe.core.plugin.DefPluginContext;
@@ -27,13 +17,22 @@
import jframe.core.plugin.loader.ext.PluginServiceCreator;
import jframe.core.signal.Signal;
import jframe.core.util.FileUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
/**
*
* Feature:
*
load plug-in
*
- *
+ *
* @author dzh
* @date Sep 23, 2013 2:47:41 PM
* @since 1.0
@@ -75,7 +74,7 @@ public void start() throws UnitException {
}
/**
- *
+ *
*/
private void cleanCache() {
Config config = getFrame().getConfig();
@@ -89,8 +88,7 @@ private void cleanCache() {
}
/**
- *
- * @param path_plugin
+ *
*/
private List loadPlugin() {
// create plugin
diff --git a/jframe/jframe-core/src/main/java/jframe/core/unit/UnitManager.java b/jframe/jframe-core/src/main/java/jframe/core/unit/UnitManager.java
index faa9e52..0ba8a6b 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/unit/UnitManager.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/unit/UnitManager.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.core.unit;
@@ -19,7 +19,7 @@
*
* UnitManager
*
- *
+ *
* @author dzh
* @date Sep 24, 2013 11:07:49 AM
* @since 1.0
@@ -43,9 +43,9 @@ public static final UnitManager createManager(Config conf) {
/**
* register unit, to be unregistered if u exist
- *
- * @param u
- * @return
+ *
+ * @param u Unit
+ * @return Unit
* @throws UnitException
*/
public Unit regUnit(Unit u) throws UnitException {
@@ -81,7 +81,7 @@ public Unit regUnit(Unit u) throws UnitException {
/**
* unregister unit
- *
+ *
* @param u
* @return
* @throws UnitException
@@ -123,7 +123,7 @@ public void dispose() {
*
* Initialize Manager and Register Units
*
- *
+ *
* @throws UnitException
*/
public void start() throws UnitException {
@@ -137,9 +137,8 @@ public void start() throws UnitException {
/**
* load unit from unit.properties
- *
- * @param file
- * @throws UnitException
+ *
+ * @param file unit.properties file
*/
private void loadUnit(String file) throws UnitException {
if (file == null) {
diff --git a/jframe/jframe-core/src/main/java/jframe/core/util/PropsConf.java b/jframe/jframe-core/src/main/java/jframe/core/util/PropsConf.java
index 1826d53..01bf08b 100644
--- a/jframe/jframe-core/src/main/java/jframe/core/util/PropsConf.java
+++ b/jframe/jframe-core/src/main/java/jframe/core/util/PropsConf.java
@@ -1,21 +1,21 @@
/**
- *
+ *
*/
package jframe.core.util;
-import java.io.FileInputStream;
+import jframe.core.conf.VarHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import jframe.core.conf.VarHandler;
-
/**
*
* Feature:
@@ -23,7 +23,7 @@
*
属性值支持jframe配置变量${conf.key}
* 属性查询优先级,自定义ID->默认组
*
- *
+ *
* @author dzh
* @date Nov 17, 2014 4:52:33 PM
* @since 1.0
@@ -37,11 +37,7 @@ public class PropsConf {
public synchronized void init(String file) throws Exception {
if (init) return;
- try {
- init(new FileInputStream(file));
- } catch (Exception e) {
- throw e;
- }
+ init(Files.newInputStream(Paths.get(file)));
init = true;
}
@@ -50,7 +46,7 @@ public synchronized void init(String file) throws Exception {
public synchronized void init(InputStream is) throws Exception {
if (is == null || init) return;
- conf = new HashMap();
+ conf = new HashMap<>();
try {
Properties p = new Properties();
p.load(is);
@@ -58,8 +54,6 @@ public synchronized void init(InputStream is) throws Exception {
for (Entry
- *
+ *
*
* msg meta:
*
d.kafka.r.topic 对应{@link ProducerRecord}的topic
@@ -38,30 +36,15 @@
* d.kafka.r.partition
* d.kafka.r.timestamp
*
- *
+ *
* @author dzh
- * @date Dec 26, 2018 5:16:26 PM
* @version 0.0.1
+ * @date Dec 26, 2018 5:16:26 PM
*/
-public class KafkaDispatcher extends AbstractDispatcher {
+public class KafkaDispatcher extends AbstractDispatcher implements KafkaConst {
static Logger LOG = LoggerFactory.getLogger(KafkaDispatcher.class);
- // default
- public static final String DEFAULT_TOPIC = "jframe";
-
- // config
- public static final String FILE_KAFKA_PRODUCER = "file.kafka.producer";
- public static final String FILE_KAFKA_CONSUMER = "file.kafka.consumer";
- public static final String D_KAFKA_SUBSCRIBE = "d.kafka.subscribe";
- public static final String D_KAFKA_SUBSCRIBE_REGEX = "d.kafka.subscribe.regex";
-
- // msg meta
- public static final String D_KAFKA_R_TOPIC = "d.kafka.r.topic";
- public static final String D_KAFKA_R_KEY = "d.kafka.r.key";
- public static final String D_KAFKA_R_PARTITION = "d.kafka.r.partition";
- public static final String D_KAFKA_R_TIMESTAMP = "d.kafka.r.timestamp";
-
private Producer> producer;
private Consumer> consumer;
@@ -118,10 +101,10 @@ private void startProducer() {
/**
* http://kafka.apache.org/21/javadoc/index.html?org/apache/kafka/clients/producer/KafkaProducer.html
- *
+ *
* @param props
*/
- private void loadDefaultProducer(Properties props) {
+ protected void loadDefaultProducer(Properties props) {
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("delivery.timeout.ms", 30000);
@@ -153,27 +136,26 @@ private void startConsumer() {
consumer.seekToEnd(Collections.emptyList());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
- close();
+// close();
+// return;
}
- final boolean autoCommit = "true".equals(props.get("enable.auto.commit")) ? true : false;
+ final boolean autoCommit = "true".equals(props.get("enable.auto.commit"));
this.dispatchT = new Thread(() -> {
LOG.info("{} start", Thread.currentThread().getName());
ConsumerRecords> records = null;
- while (true) {
- if (closed) break;
+ while (!closed) {
try {
- records = consumer.poll(Duration.ofMillis(1000L));
+ records = consumer.poll(Duration.ofMillis(1000L));//
+ if (records == null) continue;
+
+ records.forEach(record -> {
+ dispatch(record.value());
+ });
+ // commit if autoCommit is false
+ if (!autoCommit) consumer.commitAsync();
} catch (Exception e) {
LOG.warn(e.getMessage(), e);
- continue;
}
- if (records == null) continue;
-
- records.forEach(record -> {
- dispatch(record.value());
- });
- // commit if autoCommit is false
- if (!autoCommit) consumer.commitAsync();
}
consumer.close(Duration.ofSeconds(WAIT_CLOSED_SECOND)); // consumer close
LOG.info("{} closed", Thread.currentThread().getName());
@@ -185,10 +167,10 @@ protected Consumer> createConsumer(Properties props) {
Consumer> consumer = new KafkaConsumer<>(props);
String topics = DEFAULT_TOPIC;
if (getConfig().contain(D_KAFKA_SUBSCRIBE)) {
- topics = getConfig().getConfig(D_KAFKA_SUBSCRIBE);
+ topics = getConfig().getConfig(D_KAFKA_SUBSCRIBE); //todo put into props
consumer.subscribe(Arrays.asList(topics.split("\\s+")));
} else if (getConfig().contain(D_KAFKA_SUBSCRIBE_REGEX)) {
- topics = getConfig().getConfig(D_KAFKA_SUBSCRIBE_REGEX);
+ topics = getConfig().getConfig(D_KAFKA_SUBSCRIBE_REGEX); //todo put into props
consumer.subscribe(Pattern.compile(topics));
} else {
consumer.subscribe(Arrays.asList(topics));
@@ -199,10 +181,10 @@ protected Consumer> createConsumer(Properties props) {
/**
* http://kafka.apache.org/21/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html
- *
+ *
* @param props
*/
- private void loadDefaultConsumer(Properties props) {
+ protected void loadDefaultConsumer(Properties props) {
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "jframe");
props.put("enable.auto.commit", "true");
@@ -216,20 +198,20 @@ private void loadDefaultConsumer(Properties props) {
@Override
public void receive(Msg> msg) {
if (producer != null) {
- String topic = (String) msg.getMeta(D_KAFKA_R_TOPIC);
+ String topic = (String) msg.getMeta(M_KAFKA_TOPIC);
if (Objects.isNull(topic)) {
topic = DEFAULT_TOPIC;
}
Integer partition = partition(msg);
Long timestamp = timestamp(msg);
- String key = (String) msg.getMeta(D_KAFKA_R_KEY);
+ String key = (String) msg.getMeta(M_KAFKA_KEY);
ProducerRecord> record = new ProducerRecord<>(topic, partition, timestamp, key, msg, null);
producer.send(record);
}
}
private Long timestamp(Msg> msg) {
- Object ts = msg.getMeta(D_KAFKA_R_TIMESTAMP);
+ Object ts = msg.getMeta(M_KAFKA_TIMESTAMP);
if (ts == null) return null;
if (ts instanceof Long) return (Long) ts;
if (ts instanceof String) return Long.parseLong((String) ts);
@@ -237,7 +219,7 @@ private Long timestamp(Msg> msg) {
}
private Integer partition(Msg> msg) {
- Object p = msg.getMeta(D_KAFKA_R_PARTITION);
+ Object p = msg.getMeta(M_KAFKA_PARTITION);
if (p == null) return null;
if (p instanceof Integer) return (Integer) p;
if (p instanceof String) return Integer.parseInt((String) p);
@@ -254,18 +236,22 @@ public Consumer> getConsumer() {
@Override
public void close() {
+ if (closed) return;
// close producer
- if (enableProducer()) producer.close(WAIT_CLOSED_SECOND, TimeUnit.SECONDS);
+ if (enableProducer())
+// producer.close(WAIT_CLOSED_SECOND, TimeUnit.SECONDS);
+ producer.close(Duration.ofSeconds(WAIT_CLOSED_SECOND));
// close dispatcher and consumer
if (enableConsumer()) {
- closed = true;
if (dispatchT != null) {
try {
dispatchT.join(WAIT_CLOSED_SECOND * 1000L);
- } catch (InterruptedException e) {}
+ } catch (InterruptedException e) {
+ }
}
}
+ closed = true;
super.close();
}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConst.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConst.java
new file mode 100644
index 0000000..85497d2
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConst.java
@@ -0,0 +1,23 @@
+package jframe.ext.dispatch.mns;
+
+/**
+ * @author dzh
+ * @date 2022/11/18 11:06
+ */
+public interface MnsConst {
+
+ String FILE_MNS = "file.mns";
+
+ // conf field
+ String MNS_ACCESSKEYID = "mns.accesskeyid";
+ String MNS_ACCESSKEYSECRET = "mns.accesskeysecret";
+ String MNS_ACCOUNTENDPOINT = "mns.accountendpoint";
+ String MNS_QUEUE = "mns.queue"; //queue name, e.g. queueName1 queueName2
+
+ // msg meta
+ String M_MNS_CODEC = "m.mns.codec";
+ String M_MNS_QUEUE = "m.mns.queue";
+
+ // default topic
+ String DEFAULT_QUEUE = "jframe";
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConsumerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConsumerDispatcher.java
new file mode 100644
index 0000000..e7275c9
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsConsumerDispatcher.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.mns;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2022/11/17 19:20
+ */
+public class MnsConsumerDispatcher extends MnsDispatcher {
+
+ public MnsConsumerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableProducer() {
+ return false;
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsDispatcher.java
new file mode 100644
index 0000000..6281b2c
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsDispatcher.java
@@ -0,0 +1,175 @@
+package jframe.ext.dispatch.mns;
+
+import com.aliyun.mns.client.*;
+import com.aliyun.mns.model.Message;
+import jframe.core.conf.Config;
+import jframe.core.dispatch.AbstractDispatcher;
+import jframe.core.msg.Msg;
+import jframe.ext.msg.MsgCodec;
+import jframe.ext.msg.TextMsgCodec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * 限制 https://help.aliyun.com/document_detail/128343.html
+ * 接入点 https://help.aliyun.com/document_detail/175569.html
+ * http(s)://AccountId.mns.cn-shanghai.aliyuncs.com
+ * http://AccountId.mns.cn-shanghai-internal.aliyuncs.com
+ *
+ * @author dzh
+ * @date 2022/11/17 16:04
+ */
+public class MnsDispatcher extends AbstractDispatcher implements AsyncCallback, MnsConst {
+
+ static Logger LOG = LoggerFactory.getLogger(MnsDispatcher.class);
+
+ private MNSClient client;
+
+ private MsgCodec msgCodec;
+
+ private String queue; //queue name, 目前支持单个队列消费
+
+ private volatile boolean closed;
+
+ private Thread dispatchT; // consume dispatch thread
+
+ public MnsDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ public void start() {
+ closed = false;
+ try {
+ initMNSClient();
+ initMsgCodec();
+ if (enableConsumer()) startConsumer();
+ if (enableProducer()) startProducer();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ close();
+ }
+ }
+
+ private void initMsgCodec() {
+ String clazz = getConfig().getConfig(M_MNS_CODEC, TextMsgCodec.class.getName());
+ try {
+ LOG.info("initMsgCodec {}", clazz);
+ msgCodec = (MsgCodec) Class.forName(clazz).newInstance();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+ private void initMNSClient() {
+ String file = getConfig().getConfig(FILE_MNS);
+ if (Objects.isNull(file)) {
+ file = getConfig().getConfig(Config.APP_CONF) + "/mns.properties";
+ }
+ Properties props = new Properties();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ return;
+ }
+ LOG.info("initMNSClient {}", props);
+
+ CloudAccount account = new CloudAccount(
+ props.getProperty(MNS_ACCESSKEYID),
+ props.getProperty(MNS_ACCESSKEYSECRET),
+ props.getProperty(MNS_ACCOUNTENDPOINT));
+ client = account.getMNSClient();
+ this.queue = props.getProperty(MNS_QUEUE, DEFAULT_QUEUE);
+ }
+
+ private void startProducer() {
+
+ }
+
+ private void startConsumer() {
+// List queues = Arrays.asList(getConfig().getConfig(MnsConst.MNS_QUEUES, "").split("\\s+"));
+// if (queues.isEmpty()) {
+// LOG.error("msg.queue is not defined. failed to create consumer");
+// return;
+// }
+ this.dispatchT = new Thread(() -> {
+ LOG.info("{} start", Thread.currentThread().getName());
+ CloudQueue q = client.getQueueRef(this.queue);
+ while (!closed) {
+ try {
+// for (String queue : queues) {
+ Message msg = q.popMessage(60);
+ if (msg != null) {
+ dispatch(msgCodec.decode(msg.getMessageBodyAsBytes()));
+ q.deleteMessage(msg.getReceiptHandle());
+ }
+// }
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ LOG.info("{} closed", Thread.currentThread().getName());
+ }, "MnsConsumeThread");
+ dispatchT.start();
+ }
+
+ @Override
+ public void receive(Msg> msg) {
+ if (enableProducer() && client != null && client.isOpen()) {
+ String q = (String) msg.getMeta(M_MNS_QUEUE);
+ if (Objects.isNull(q)) {
+ q = this.queue; //default queue
+ }
+ try {
+ AsyncResult r = client.getQueueRef(q).asyncPutMessage(new Message(msgCodec.encode(msg)), this);
+// client.getQueueRef(q).putMessage(new Message(msgCodec.encode(msg)));
+ LOG.debug("send msg {}, result {}", msg, r);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);//todo
+ }
+ } else {
+ LOG.error("discard msg {}", msg);
+ }
+ }
+
+ @Override
+ public void close() {
+ if (closed) return;
+ if (client != null) client.close();
+
+ // close dispatcher and consumer
+ if (enableConsumer()) {
+ if (dispatchT != null) {
+ try {
+ dispatchT.join(60 * 1000L);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ closed = true;
+ super.close();
+ }
+
+ protected boolean enableProducer() {
+ return true;
+ }
+
+ protected boolean enableConsumer() {
+ return true;
+ }
+
+ @Override
+ public void onSuccess(Message msg) {
+ LOG.debug("mns put message {} successfully", msg);
+ }
+
+ @Override
+ public void onFail(Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsProducerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsProducerDispatcher.java
new file mode 100644
index 0000000..b804b9e
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/mns/MnsProducerDispatcher.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.mns;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2022/11/17 19:20
+ */
+public class MnsProducerDispatcher extends MnsDispatcher {
+
+ public MnsProducerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableConsumer() {
+ return false;
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsConsumerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsConsumerDispatcher.java
new file mode 100644
index 0000000..e4627f7
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsConsumerDispatcher.java
@@ -0,0 +1,20 @@
+package jframe.ext.dispatch.ons;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2020/1/11 19:26
+ */
+public class OnsConsumerDispatcher extends OnsDispatcher {
+
+ public OnsConsumerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableProducer() {
+ return false;
+ }
+
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsDispatcher.java
new file mode 100644
index 0000000..4bba3eb
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsDispatcher.java
@@ -0,0 +1,194 @@
+package jframe.ext.dispatch.ons;
+
+import com.aliyun.openservices.ons.api.*;
+import jframe.core.conf.Config;
+import jframe.core.dispatch.AbstractDispatcher;
+import jframe.core.msg.Msg;
+import jframe.ext.dispatch.rocketmq.RmqConst;
+import jframe.ext.msg.MsgCodec;
+import jframe.ext.msg.TextMsgCodec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * aliyun rocketmq
+ * https://help.aliyun.com/document_detail/29547.html
+ *
+ * @author dzh
+ * @date 2020/1/11 19:17
+ */
+public class OnsDispatcher extends AbstractDispatcher implements RmqConst {
+
+ static Logger LOG = LoggerFactory.getLogger(OnsDispatcher.class);
+
+ private Producer producer;
+ private Consumer consumer;
+
+ private MsgCodec msgCodec;
+
+ public OnsDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ protected boolean enableProducer() {
+ return true;
+ }
+
+ protected boolean enableConsumer() {
+ return true;
+ }
+
+ @Override
+ public void start() {
+ try {
+ initMsgCodec();
+ if (enableConsumer()) startConsumer();
+ if (enableProducer()) startProducer();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ close();
+ }
+ }
+
+ //https://help.aliyun.com/document_detail/29547.html?spm=a2c4g.11186623.6.575.73a8d54cqwV0z7
+ private void startProducer() {
+ String file = getConfig().getConfig(FILE_RMQ_PRODUCER);
+ if (Objects.isNull(file)) {
+ file = getConfig().getConfig(Config.APP_CONF) + "/rmq-producer.properties";
+ }
+ Properties props = new Properties();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ return;
+ }
+
+ LOG.info("start producer with {}", props);
+
+// Properties properties = new Properties();
+// // AccessKey 阿里云身份验证,在阿里云用户信息管理控制台获取
+// properties.put(PropertyKeyConst.AccessKey, "XXX");
+// // SecretKey 阿里云身份验证,在阿里云用户信息管理控制台获取
+// properties.put(PropertyKeyConst.SecretKey, "XXX");
+// //设置发送超时时间,单位毫秒
+// properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
+// // 设置 TCP 接入域名,进入控制台的实例详情页面的获取接入点信息区域查看
+// properties.put(PropertyKeyConst.NAMESRV_ADDR,
+// "XXX");
+ producer = ONSFactory.createProducer(props);
+ // 在发送消息前,必须调用 start 方法来启动 Producer,只需调用一次即可
+ producer.start();
+ }
+
+ private void startConsumer() {
+ String file = getConfig().getConfig(FILE_RMQ_CONSUMER);
+ if (Objects.isNull(file)) {
+ file = getConfig().getConfig(Config.APP_CONF) + "/rmq-consumer.properties";
+ }
+ Properties props = new Properties();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ return;
+ }
+ LOG.info("start consumer with {}", props);
+ try {
+ consumer = createConsumer(props);
+ consumer.start();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+// close();
+ }
+ }
+
+ //https://help.aliyun.com/document_detail/29551.html?spm=a2c4g.11186623.6.581.7c13d54cmyIEny
+ private Consumer createConsumer(Properties props) {
+// Properties properties = new Properties();
+// // 您在控制台创建的 Group ID
+// properties.put(PropertyKeyConst.GROUP_ID, "XXX");
+// // AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
+// properties.put(PropertyKeyConst.AccessKey, "XXX");
+// // SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
+// properties.put(PropertyKeyConst.SecretKey, "XXX");
+// // 设置 TCP 接入域名,进入控制台的实例管理页面的“获取接入点信息”区域查看
+// properties.put(PropertyKeyConst.NAMESRV_ADDR,
+// "XXX");
+ // 集群订阅方式 (默认)
+// properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING);
+ // 广播订阅方式
+ // properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.BROADCASTING);
+
+ Consumer consumer = ONSFactory.createConsumer(props);
+
+ boolean ingoreTimeoutMsg = Boolean.parseBoolean(props.getProperty("consume.ignore.timeout.msg", "false"));
+ int ingoreTimeoutMsgMs = Integer.parseInt(props.getProperty("consume.ignore.timeout.msg.ms", "10000"));
+
+ //订阅多个 Tag
+ consumer.subscribe(props.getProperty("consume.topic", "jframe"),
+ props.getProperty("consume.subExpression", "*"), new MessageListener() {
+ public Action consume(Message msg, ConsumeContext context) {
+ LOG.debug("consume ons msg-{}", msg);
+ try {
+ if (ingoreTimeoutMsg && (System.currentTimeMillis() - msg.getBornTimestamp()) >= ingoreTimeoutMsgMs) {
+ LOG.warn("discard ons timeout msg-{}", msg);
+ return Action.CommitMessage;
+ }
+ LOG.info("dispatch ons msg-{}", msg.getKey());
+ dispatch(msgCodec.decode(msg.getBody()));
+ } catch (Exception e) {
+ LOG.info(e.getMessage(), e);
+ return Action.ReconsumeLater;
+ }
+ return Action.CommitMessage;
+ }
+ });
+ return consumer;
+ }
+
+ private void initMsgCodec() {
+ String clazz = getConfig().getConfig(M_RMQ_CODEC, TextMsgCodec.class.getName());
+ try {
+ msgCodec = (MsgCodec) Class.forName(clazz).newInstance();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void receive(Msg> msg) {
+ if (producer != null) {
+ String topic = (String) msg.getMeta(M_RMQ_TOPIC);
+ if (Objects.isNull(topic)) {
+ topic = DEFAULT_TOPIC;
+ }
+
+ try {
+ Message rmqMsg = new Message(topic,
+ (String) msg.getMeta(M_RMQ_TAG), (String) msg.getMeta(M_RMQ_Key),
+ msgCodec.encode(msg));
+ SendResult r = producer.send(rmqMsg);
+ LOG.debug("send msg {}, sendResult {}", msg, r);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);//todo
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ // close producer
+ if (enableProducer()) producer.shutdown();
+
+ // close dispatcher and consumer
+ if (enableConsumer()) {
+ consumer.shutdown();
+ }
+ super.close();
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsProducerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsProducerDispatcher.java
new file mode 100644
index 0000000..476a6f2
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/ons/OnsProducerDispatcher.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.ons;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2020/1/11 19:29
+ */
+public class OnsProducerDispatcher extends OnsDispatcher {
+
+ public OnsProducerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableConsumer() {
+ return false;
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConst.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConst.java
new file mode 100644
index 0000000..6752897
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConst.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.rocketmq;
+
+/**
+ * @author dzh
+ * @date 2020/1/11 19:35
+ */
+public interface RmqConst {
+
+ String FILE_RMQ_PRODUCER = "file.rmq.producer";
+ String FILE_RMQ_CONSUMER = "file.rmq.consumer";
+
+ // msg meta
+ String M_RMQ_CODEC = "m.rmq.codec"; // MsgCodec
+ String M_RMQ_TOPIC = "m.rmq.topic";
+ String M_RMQ_TAG = "m.rmq.tag";
+ String M_RMQ_Key = "m.rmq.key";
+
+ String DEFAULT_TOPIC = "jframe";
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConsumerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConsumerDispatcher.java
new file mode 100644
index 0000000..3883840
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqConsumerDispatcher.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.rocketmq;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2019/12/25 18:15
+ */
+public class RmqConsumerDispatcher extends RmqDispatcher {
+
+ public RmqConsumerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableProducer() {
+ return false;
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqDispatcher.java
new file mode 100644
index 0000000..005ba57
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqDispatcher.java
@@ -0,0 +1,249 @@
+package jframe.ext.dispatch.rocketmq;
+
+import jframe.core.conf.Config;
+import jframe.core.dispatch.AbstractDispatcher;
+import jframe.core.msg.Msg;
+import jframe.ext.msg.MsgCodec;
+import jframe.ext.msg.TextMsgCodec;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * @author dzh
+ * @date 2019/12/25 13:02
+ */
+public class RmqDispatcher extends AbstractDispatcher implements RmqConst {
+
+ static Logger LOG = LoggerFactory.getLogger(RmqDispatcher.class);
+
+// private volatile boolean closed;
+
+ private DefaultMQProducer producer;
+ private DefaultMQPushConsumer consumer;
+
+// private Thread dispatchT; // consume dispatch thread
+
+ private MsgCodec msgCodec;
+
+ public RmqDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ protected boolean enableProducer() {
+ return true;
+ }
+
+ protected boolean enableConsumer() {
+ return true;
+ }
+
+ @Override
+ public void start() {
+ try {
+ initMsgCodec();
+ if (enableConsumer()) startConsumer();
+ if (enableProducer()) startProducer();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ close();
+ }
+ }
+
+ private void initMsgCodec() {
+ String clazz = getConfig().getConfig(M_RMQ_CODEC, TextMsgCodec.class.getName());
+ try {
+ msgCodec = (MsgCodec) Class.forName(clazz).newInstance();
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+ private void startProducer() throws MQClientException {
+ String file = getConfig().getConfig(FILE_RMQ_PRODUCER);
+ if (Objects.isNull(file)) {
+ file = getConfig().getConfig(Config.APP_CONF) + "/rmq-producer.properties";
+ }
+ Properties props = new Properties();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ loadDefaultProducer(props);
+ }
+
+ LOG.info("start producer with {}", props);
+ producer = new DefaultMQProducer();
+ if (props.containsKey("producer.group")) {
+ producer.setProducerGroup(props.getProperty("producer.group"));
+ }
+ if (props.containsKey("namespace")) {
+ producer.setNamespace(props.getProperty("namespace"));
+ }
+ producer.setNamesrvAddr(props.getProperty("namesrv.addr", "localhost:9876"));
+ producer.setRetryTimesWhenSendFailed(Integer.parseInt(props.getProperty("retry.times", "3")));
+ producer.setVipChannelEnabled(Boolean.parseBoolean(props.getProperty("vipChannelEnabled", "false")));
+// LOG.info("start producer {} {}", producer.getProducerGroup(), producer.getNamesrvAddr());
+ producer.start();
+// List> mqList = producer.fetchPublishMessageQueues(topic());
+// if (mqList == null || mqList.isEmpty()) {
+// producer.createTopic(topicKey(), topic(), topicQueueNum());
+// }
+ }
+
+ private void loadDefaultProducer(Properties props) {
+ props.put("producer.group", getConfig().getConfig(Config.APP_NAME));
+ props.put("namesrv.addr", "localhost:9876");
+ props.put("retry.times", "3");
+ props.put("vipChannelEnabled", "false");
+ }
+
+ private void startConsumer() {
+ String file = getConfig().getConfig(FILE_RMQ_CONSUMER);
+ if (Objects.isNull(file)) {
+ file = getConfig().getConfig(Config.APP_CONF) + "/rmq-consumer.properties";
+ }
+ Properties props = new Properties();
+ try (FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ loadDefaultConsumer(props);
+ }
+ LOG.info("start consumer with {}", props);
+ try {
+ consumer = createConsumer(props);
+ consumer.start();
+// consumer.seekToEnd(Collections.emptyList());
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+// close();
+ }
+
+ // pull mode
+// this.dispatchT = new Thread(() -> {
+// LOG.info("{} start", Thread.currentThread().getName());
+// while (true) {
+// if (closed) break;
+// try {
+// } catch (Exception e) {
+// LOG.warn(e.getMessage(), e);
+// continue;
+// }
+// dispatch(record.value());
+// }
+// LOG.info("{} closed", Thread.currentThread().getName());
+// }, "rocketmqConsumeThread");
+// dispatchT.start();
+ }
+
+ private void loadDefaultConsumer(Properties props) {
+ props.setProperty("consumer.group", getConfig().getConfig(Config.APP_NAME));
+ props.setProperty("namesrv.addr", "localhost:9876");
+
+ }
+
+ // todo multi topics
+ private DefaultMQPushConsumer createConsumer(Properties props) throws MQClientException {
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(props.getProperty("consumer.group"));
+ consumer.setNamesrvAddr(props.getProperty("namesrv.addr", "localhost:9876"));
+ String val = props.getProperty("consume.message.batch.maxsize", "1"); //[1,1024]
+// consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);
+// consumer.setConsumeTimestamp(consumeTimestamp());
+ consumer.setConsumeMessageBatchMaxSize(Integer.parseInt(val));
+ val = props.getProperty("consume.timeout", "5"); //minutes
+ consumer.setConsumeTimeout(Long.parseLong(val));
+ consumer.subscribe(props.getProperty("consume.topic", RmqConst.DEFAULT_TOPIC),
+ props.getProperty("consume.subExpression", "*"));
+ consumer.setVipChannelEnabled(false);
+ val = props.getProperty("consume.thread.max");
+ if (val != null)
+ consumer.setConsumeThreadMax(Integer.parseInt(val));
+ val = props.getProperty("consume.thread.min");
+ if (val != null)
+ consumer.setConsumeThreadMin(Integer.parseInt(val));
+ val = props.getProperty("consume.instance.name");
+ if (val != null)
+ consumer.setInstanceName(val);
+ val = props.getProperty("consume.pull.threshold");
+ if (val != null)
+ consumer.setPullThresholdForQueue(Integer.parseInt(val));
+ val = props.getProperty("consume.concurrently.max.span");
+ if (val != null)
+ consumer.setConsumeConcurrentlyMaxSpan(Integer.parseInt(val));// 2000
+ val = props.getProperty("consume.max.reconsume.times", "16");
+ consumer.setMaxReconsumeTimes(Integer.parseInt(val)); // 16
+ val = props.getProperty("consume.persist.consumer.offset.interval", "3000");
+ consumer.setPersistConsumerOffsetInterval(Integer.parseInt(val)); // ms
+
+ boolean ingoreTimeoutMsg = Boolean.parseBoolean(props.getProperty("consume.ignore.timeout.msg", "false"));
+ int ingoreTimeoutMsgMs = Integer.parseInt(props.getProperty("consume.ignore.timeout.msg.ms", "10000"));
+ consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
+ for (MessageExt msg : msgs) {
+ LOG.debug("consume rmq msg-{}", msg);
+ try {
+ if (ingoreTimeoutMsg && (System.currentTimeMillis() - msg.getBornTimestamp()) >= ingoreTimeoutMsgMs) {
+ LOG.warn("discard rmq timeout msg-{}", msg);
+ continue;
+ }
+ LOG.info("dispatch rmq msg-{}", msg.getKeys());
+ dispatch(msgCodec.decode(msg.getBody()));
+ } catch (Exception e) {
+ LOG.info(e.getMessage(), e);
+ if (msg.getReconsumeTimes() == consumer.getMaxReconsumeTimes()) {
+ LOG.warn("over MaxReconsumeTimes, discard msg-{}", msg);
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ return ConsumeConcurrentlyStatus.RECONSUME_LATER;
+ }
+ }
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ });
+ return consumer;
+ }
+
+ @Override
+ public void receive(Msg> msg) {
+ if (producer != null) {
+ String topic = (String) msg.getMeta(M_RMQ_TOPIC);
+ if (Objects.isNull(topic)) {
+ topic = DEFAULT_TOPIC;
+ }
+
+ try {
+ Message rmqMsg = new Message(topic,
+ (String) msg.getMeta(M_RMQ_TAG), (String) msg.getMeta(M_RMQ_Key),
+ msgCodec.encode(msg));
+ SendResult r = producer.send(rmqMsg);
+ LOG.debug("send msg {}, sendResult {}", msg, r);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);//todo
+ }
+ }
+ }
+
+// private int WAIT_CLOSED_SECOND = 60;
+
+ @Override
+ public void close() {
+ // close producer
+ if (enableProducer()) producer.shutdown();
+
+ // close dispatcher and consumer
+ if (enableConsumer()) {
+ consumer.shutdown();
+ }
+ super.close();
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqProducerDispatcher.java b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqProducerDispatcher.java
new file mode 100644
index 0000000..0c83a22
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/dispatch/rocketmq/RmqProducerDispatcher.java
@@ -0,0 +1,19 @@
+package jframe.ext.dispatch.rocketmq;
+
+import jframe.core.conf.Config;
+
+/**
+ * @author dzh
+ * @date 2019/12/25 18:16
+ */
+public class RmqProducerDispatcher extends RmqDispatcher {
+
+ public RmqProducerDispatcher(String id, Config config) {
+ super(id, config);
+ }
+
+ @Override
+ protected boolean enableConsumer() {
+ return false;
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/msg/MsgCodec.java b/jframe/jframe-ext/src/main/java/jframe/ext/msg/MsgCodec.java
new file mode 100644
index 0000000..3343ce7
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/msg/MsgCodec.java
@@ -0,0 +1,19 @@
+package jframe.ext.msg;
+
+import jframe.core.msg.Msg;
+
+import java.io.IOException;
+
+/**
+ * ThreadSafe
+ *
+ * @author dzh
+ * @date 2019/12/25 21:11
+ */
+public interface MsgCodec {
+
+ byte[] encode(Msg> msg) throws IOException;
+
+ Msg decode(byte[] msg) throws IOException;
+
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/msg/TextMsgCodec.java b/jframe/jframe-ext/src/main/java/jframe/ext/msg/TextMsgCodec.java
new file mode 100644
index 0000000..a45e349
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/msg/TextMsgCodec.java
@@ -0,0 +1,30 @@
+package jframe.ext.msg;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import jframe.core.msg.Msg;
+import jframe.core.msg.TextMsg;
+import jframe.ext.msg.MsgCodec;
+
+import java.io.IOException;
+
+/**
+ * @author dzh
+ * @date 2019/12/25 21:13
+ */
+public class TextMsgCodec implements MsgCodec {
+
+ protected String encoding = "UTF8";
+
+ static final Gson GSON = new GsonBuilder().serializeNulls().create();
+
+ @Override
+ public byte[] encode(Msg> msg) throws IOException {
+ return GSON.toJson(msg).getBytes(encoding); //todo msg's data must be String
+ }
+
+ @Override
+ public Msg decode(byte[] msg) throws IOException {
+ return GSON.fromJson(new String(msg, encoding), TextMsg.class);
+ }
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/plugin/KafkaPlugin.java b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/KafkaPlugin.java
index 2311677..b1fdd22 100644
--- a/jframe/jframe-ext/src/main/java/jframe/ext/plugin/KafkaPlugin.java
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/KafkaPlugin.java
@@ -1,23 +1,22 @@
package jframe.ext.plugin;
import jframe.core.msg.Msg;
-import jframe.core.plugin.PluginSender;
-import jframe.ext.dispatch.kafka.KafkaDispatcher;
+import jframe.ext.dispatch.kafka.KafkaConst;
/**
* @author dzh
- * @date Dec 27, 2018 3:05:36 PM
* @version 0.0.1
+ * @date Dec 27, 2018 3:05:36 PM
*/
-public abstract class KafkaPlugin extends PluginSender {
+public class KafkaPlugin extends MqPlugin {
public void send(Msg> msg, String topic, Integer partition, Long timestamp, String key) {
if (msg == null) return;
- msg.setMeta(KafkaDispatcher.D_KAFKA_R_TOPIC, topic);
- msg.setMeta(KafkaDispatcher.D_KAFKA_R_PARTITION, partition);
- msg.setMeta(KafkaDispatcher.D_KAFKA_R_TIMESTAMP, timestamp);
- msg.setMeta(KafkaDispatcher.D_KAFKA_R_KEY, key);
+ msg.setMeta(KafkaConst.M_KAFKA_TOPIC, topic);
+ msg.setMeta(KafkaConst.M_KAFKA_PARTITION, partition);
+ msg.setMeta(KafkaConst.M_KAFKA_TIMESTAMP, timestamp);
+ msg.setMeta(KafkaConst.M_KAFKA_KEY, key);
send(msg);
}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MnsPlugin.java b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MnsPlugin.java
new file mode 100644
index 0000000..dd428d1
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MnsPlugin.java
@@ -0,0 +1,20 @@
+package jframe.ext.plugin;
+
+import jframe.core.msg.Msg;
+import jframe.ext.dispatch.mns.MnsConst;
+
+/**
+ * @author dzh
+ * @date 2022/11/17 18:06
+ */
+public class MnsPlugin extends MqPlugin {
+
+ public void send(Msg> msg, String queue) {
+ if (msg == null) return;
+
+ msg.setMeta(MnsConst.M_MNS_QUEUE, queue);
+
+ send(msg);
+ }
+
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MqPlugin.java b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MqPlugin.java
new file mode 100644
index 0000000..3d006b7
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/MqPlugin.java
@@ -0,0 +1,13 @@
+package jframe.ext.plugin;
+
+import jframe.core.plugin.PluginSender;
+
+/**
+ * @author dzh
+ * @date 2022/11/18 09:48
+ */
+public class MqPlugin extends PluginSender {
+
+
+
+}
diff --git a/jframe/jframe-ext/src/main/java/jframe/ext/plugin/RocketmqPlugin.java b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/RocketmqPlugin.java
new file mode 100644
index 0000000..6e1e634
--- /dev/null
+++ b/jframe/jframe-ext/src/main/java/jframe/ext/plugin/RocketmqPlugin.java
@@ -0,0 +1,27 @@
+package jframe.ext.plugin;
+
+import jframe.core.msg.Msg;
+import jframe.ext.dispatch.rocketmq.RmqConst;
+
+/**
+ * Rocketmq Plugin
+ *
+ * @author dzh
+ * @date 2019/12/25 15:22
+ */
+public class RocketmqPlugin extends MqPlugin {
+
+ public void send(Msg> msg, String topic, String tag, String key) {
+ if (msg == null) return;
+
+ msg.setMeta(RmqConst.M_RMQ_TOPIC, topic);
+ msg.setMeta(RmqConst.M_RMQ_TAG, tag);
+ msg.setMeta(RmqConst.M_RMQ_Key, key);
+
+ send(msg);
+ }
+
+ public void send(Msg> msg, String topic) {
+ send(msg, topic, null, null);
+ }
+}
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/Main.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/Main.java
index 6c129a8..cc7ace4 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/Main.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/Main.java
@@ -1,5 +1,5 @@
/**
- *
+ *
*/
package jframe.launcher;
@@ -13,7 +13,7 @@
import jframe.launcher.api.LauncherException;
/**
- *
+ *
* @author dzh
* @date Oct 10, 2013 4:28:16 PM
* @since 1.0
@@ -23,15 +23,14 @@ public class Main {
private static final Logger LOG = LoggerFactory.getLogger(Main.class);
/**
- *
- * @param lclazz
- * launcher class
- * @param deflclazz
- * default launcher class
+ *
+ * @param lclazz launcher class
* @return
*/
public static Launcher createLauncher(String lclazz) throws LauncherException {
- if (lclazz == null || "".equals(lclazz)) { throw new LauncherException("Not found launcher class" + lclazz); }
+ if (lclazz == null || "".equals(lclazz)) {
+ throw new LauncherException("Not found launcher class" + lclazz);
+ }
try {
return (Launcher) Thread.currentThread().getContextClassLoader().loadClass(lclazz).newInstance();
} catch (Exception e) {
@@ -61,8 +60,7 @@ static void start(String launcher) {
// String fileConfig =
// System.getProperty(Config.FILE_CONFIG, appHome + File.separator + "conf" + File.separator +
// Config.FILE_CONFIG_NAME);
- String fileConfig =
- System.getProperty(Config.FILE_CONFIG, String.join(File.separator, appHome, "conf", Config.FILE_CONFIG_NAME));
+ String fileConfig = System.getProperty(Config.FILE_CONFIG, String.join(File.separator, appHome, "conf", Config.FILE_CONFIG_NAME));
Config config = l.load(fileConfig);
l.launch(config);
} catch (Exception e) {
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/MainLauncher.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/MainLauncher.java
index d04e16d..97619e9 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/MainLauncher.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/MainLauncher.java
@@ -60,7 +60,7 @@ public void launch(Config config) {
}
/**
- * @param conf
+ * @param config
*/
private void launchNormal(Config config) {
LOG.info("Launching normal mode!");
@@ -101,7 +101,7 @@ private Process launchInternal(Config config) {
}
/**
- * @param conf
+ * @param config
*/
private void launchDaemon(final Config config) {
LOG.info("Launch daemon mode! write pid: {}", config.getConfig(DefConfig.PID_DAEMON));
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/api/DefConfig.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/api/DefConfig.java
index 8b11397..29e213f 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/api/DefConfig.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/api/DefConfig.java
@@ -79,7 +79,7 @@ public String replace(String input) {
/**
* replace all variables in input
*
- * @param system
+ * @param config
* jvm系统变量,一般是System.getProperty
* @param input
* @return
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/api/Launcher.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/api/Launcher.java
index 13933f2..dd1004e 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/api/Launcher.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/api/Launcher.java
@@ -21,7 +21,7 @@ public interface Launcher {
/**
*
- * @param conf
+ * @param config
* @throws Exception
*/
void launch(Config config) throws LauncherException;
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VarProperties.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VarProperties.java
index b1c1114..5eca1c5 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VarProperties.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VarProperties.java
@@ -1,13 +1,14 @@
/**
- *
+ *
*/
package jframe.launcher.util;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
@@ -15,12 +16,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
/**
* support variable feature
- *
+ *
* @author dzh
* @date Feb 16, 2016 10:14:22 AM
* @since 1.2.1
@@ -30,7 +28,7 @@ public class VarProperties extends Properties {
static Logger LOG = LoggerFactory.getLogger(VarProperties.class);
/**
- *
+ *
*/
private static final long serialVersionUID = -6146614559017054452L;
@@ -59,21 +57,19 @@ public synchronized void load(String file) throws IOException {
}
public synchronized void load(File file) throws IOException {
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(file);
+ if (file == null) return;
+ try (InputStreamReader fis = new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8)) {
load(fis);
} catch (Exception e) {
LOG.warn(e.getMessage());
- } finally {
- if (file != null) {
- try {
- fis.close();
- } catch (IOException e) {
- LOG.error(e.getMessage());
- }
- }
}
+// finally {
+// try {
+// fis.close();
+// } catch (IOException e) {
+// LOG.error(e.getMessage());
+// }
+// }
}
@Override
@@ -89,26 +85,23 @@ private void replaceAllVar() {
/**
* TODO handle circle key
- *
- * @param key
- * @param value
- * @keys avoid circle key
- * @return
+ *
+ * @param key key
+ * @param value value
+ * @param keys set to avoid circle key
+ * @return value replaced var
*/
private String replaceVar(String key, String value, Set keys) {
if (value == null) return null;
- Matcher m = P_VAR.matcher(value);
- if (keys.contains(key)) throw new RuntimeException("circle key->" + key);
+ if (keys.contains(key)) throw new RuntimeException("circle key:" + key);
String newVal = value;
String var = null;
String val = null;
try {
+ keys.add(key);
+ Matcher m = P_VAR.matcher(value);
while (m.find()) {
- if (!keys.contains(key)) {
- keys.add(key);
- }
-
var = m.group(1);
val = replaceVar(var, getProperty(var), keys);
if (val == null) {
@@ -117,14 +110,14 @@ private String replaceVar(String key, String value, Set keys) {
newVal = newVal.replaceAll("\\$\\{" + var + "\\}", val);
}
- keys.remove(key);
-
if (containsKey(key)) put(key, newVal);
if (LOG.isDebugEnabled()) {
LOG.debug("key={}, value={}->{}", key, value, newVal);
}
} catch (Exception e) {
LOG.error("k->{}, v->{}, e->{}", key, value, e.getMessage());
+ } finally {
+ keys.remove(key);
}
return newVal;
}
diff --git a/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VmargsFile.java b/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VmargsFile.java
index 17e2360..d89eae4 100644
--- a/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VmargsFile.java
+++ b/jframe/jframe-launcher/src/main/java/jframe/launcher/util/VmargsFile.java
@@ -25,7 +25,7 @@ public class VmargsFile {
Logger LOG = LoggerFactory.getLogger(VmargsFile.class);
/**
- * @param string
+ * @param file
*/
public List loadVmargs(String file) {
File f = new File(file); // vmargs file