diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml
index 363ba1b9..b9e9a487 100644
--- a/ruoyi-common/ruoyi-common-core/pom.xml
+++ b/ruoyi-common/ruoyi-common-core/pom.xml
@@ -112,6 +112,17 @@
commons-beanutils
commons-beanutils
+
+ dom4j
+ dom4j
+ 1.4
+ compile
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.5
+
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/WXPayConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/WXPayConstants.java
new file mode 100644
index 00000000..63141bb3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/WXPayConstants.java
@@ -0,0 +1,59 @@
+package com.ruoyi.common.core.constant;
+
+import org.apache.http.client.HttpClient;
+
+/**
+ * 常量
+ */
+public class WXPayConstants {
+
+ public enum SignType {
+ MD5, HMACSHA256
+ }
+
+ 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/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java
index 9b9ecc51..a92dbd38 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java
@@ -94,6 +94,15 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
+ /**
+ * 日期路径 即年月日时分秒 如20180808010515
+ */
+ public static final String timePath()
+ {
+ Date now = new Date();
+ return DateFormatUtils.format(now, YYYYMMDDHHMMSS);
+ }
+
/**
* 日期路径 即年/月/日 如20180808
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PayUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PayUtils.java
new file mode 100644
index 00000000..bd70b8a8
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PayUtils.java
@@ -0,0 +1,280 @@
+package com.ruoyi.common.core.utils;
+
+import org.dom4j.DocumentHelper;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+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.math.BigDecimal;
+import java.net.InetAddress;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class PayUtils {
+ /**
+ * 获取当前机器的ip
+ *
+ * @return String
+ */
+ public static String getLocalIp(){
+ InetAddress ia=null;
+ String localip = null;
+ try {
+ ia=ia.getLocalHost();
+ localip=ia.getHostAddress();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return localip;
+
+ }
+
+ /**
+ * Map转换为 Xml
+ *
+ * @param map
+ * @return Xml
+ * @throws Exception
+ */
+ public static String mapToXml(Map map) throws Exception {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ //防止XXE攻击
+ documentBuilderFactory.setXIncludeAware(false);
+ documentBuilderFactory.setExpandEntityReferences(false);
+ DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+ org.w3c.dom.Document document = documentBuilder.newDocument();
+ org.w3c.dom.Element root = document.createElement("xml");
+ document.appendChild(root);
+ for (String key: map.keySet()) {
+ String value = map.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();
+ try {
+ writer.close();
+ }
+ catch (Exception ex) {
+ }
+ return output;
+ }
+
+
+ /**
+ * 创建签名Sign
+ *
+ * @param key
+ * @param parameters
+ * @return
+ */
+ public static String createSign(Map parameters,String key){
+ StringBuffer sb = new StringBuffer();
+ Set es = parameters.entrySet();
+ Iterator> it = es.iterator();
+ while(it.hasNext()) {
+ Map.Entry entry = (Map.Entry)it.next();
+ String k = (String)entry.getKey();
+ if(entry.getValue() != null || !"".equals(entry.getValue())) {
+ String v = String.valueOf(entry.getValue());
+ if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
+ sb.append(k + "=" + v + "&");
+ }
+ }
+ }
+ sb.append("key=" + key);
+ String sign = StringUtils.md5(sb.toString()).toUpperCase();
+ return sign;
+ }
+
+
+ /**
+ * XML转换为Map
+ *
+ * @param strXML
+ * @return Map
+ * @throws Exception
+ */
+ public static Map getMapFromXML(String strXML) throws Exception {
+ try {
+ Map data = new HashMap();
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ //防止XXE攻击
+ documentBuilderFactory.setXIncludeAware(false);
+ documentBuilderFactory.setExpandEntityReferences(false);
+ DocumentBuilder documentBuilder = documentBuilderFactory.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) {
+ ex.printStackTrace();
+ }
+ return data;
+ } catch (Exception ex) {
+ throw ex;
+ }
+ }
+
+ /**
+ * 生成随机数
+ *
+ * @return
+ */
+ public static String makeUUID(int len) {
+ return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
+ }
+
+ /**
+ * 获取当前的Timestamp
+ *
+ * @return
+ */
+ public static String getCurrentTimeStamp() {
+ return Long.toString(System.currentTimeMillis()/1000);
+ }
+
+ /**
+ * 获取当前的时间
+ * @return
+ */
+ public static long getCurrentTimestampMs() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * 生成订单号
+ *
+ * @return
+ */
+ public static String generateOrderNo() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
+ return sdf.format(new Date())+makeUUID(16);
+ }
+
+ /**
+ * 获取当前工程url
+ *
+ * @param request
+ * @return
+ */
+ public static String getCurrentUrl(HttpServletRequest request){
+ return request.getScheme() +"://" + request.getServerName() + ":" +request.getServerPort() +request.getContextPath();
+ }
+
+ /**
+ * Xml字符串转换为Map
+ *
+ * @param xmlStr
+ * @return
+ */
+ public static Map xmlStrToMap(String xmlStr){
+
+ try {
+ Map map = new HashMap();
+ org.dom4j.Document document = DocumentHelper.parseText(xmlStr);
+ org.dom4j.Element nodeElement = document.getRootElement();
+ List node = nodeElement.elements();
+ for (Iterator it = node.iterator(); it.hasNext();) {
+ org.dom4j.Element elm = (org.dom4j.Element) it.next();
+ map.put(elm.getName(), elm.getText());
+ elm = null;
+ }
+ return map;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+
+ /**
+ * 转换金额型到整型
+ * @param money
+ * @return
+ */
+ public static String moneyToIntegerStr(Double money){
+ BigDecimal decimal = new BigDecimal(money);
+ int amount = decimal.multiply(new BigDecimal(100))
+ .setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
+ return String.valueOf(amount);
+ }
+
+ /**
+ * 除去数组中的空值和签名参数
+ * @param sArray 签名参数组
+ * @return 去掉空值与签名参数后的新签名参数组
+ */
+ public static Map paraFilter(Map sArray) {
+
+ Map result = new HashMap();
+
+ if (sArray == null || sArray.size() <= 0) {
+ return result;
+ }
+
+ for (String key : sArray.keySet()) {
+ String value = sArray.get(key);
+ if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
+ || key.equalsIgnoreCase("sign_type")) {
+ continue;
+ }
+ result.put(key, value);
+ }
+
+ return result;
+ }
+
+ /**
+ * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
+ * @param params 需要排序并参与字符拼接的参数组
+ * @return 拼接后字符串
+ */
+ public static String createLinkString(Map params) {
+ List keys = new ArrayList(params.keySet());
+ Collections.sort(keys);
+ String prestr = "";
+ for (int i = 0; i < keys.size(); i++) {
+ String key = keys.get(i);
+ String value = params.get(key);
+ if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
+ prestr = prestr + key + "=" + value;
+ } else {
+ prestr = prestr + key + "=" + value + "&";
+ }
+ }
+ return prestr;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
index 51c7734e..8848c38f 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
@@ -4,6 +4,8 @@ import com.ruoyi.common.core.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.beans.PropertyDescriptor;
+import java.math.BigInteger;
+import java.security.MessageDigest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -507,4 +509,21 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
return false;
}
+
+ public static String md5(String str) {
+ try {
+ // 生成一个MD5加密计算摘要
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ // 计算md5函数
+ md.update(str.getBytes());
+ // digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
+ // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
+ //一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)
+ return new BigInteger(1, md.digest()).toString(16).toUpperCase();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayUtil.java
new file mode 100644
index 00000000..68ad4fad
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayUtil.java
@@ -0,0 +1,298 @@
+package com.ruoyi.common.core.utils;
+
+import com.ruoyi.common.core.constant.WXPayConstants;
+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, WXPayConstants.SignType.MD5);
+ }
+
+ /**
+ * 生成带有 sign 的 XML 格式字符串
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @param signType 签名类型
+ * @return 含有sign字段的XML
+ */
+ public static String generateSignedXml(final Map data, String key, WXPayConstants.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, WXPayConstants.SignType.MD5);
+ }
+
+ /**
+ * 判断签名是否正确,必须包含sign字段,否则返回false。
+ *
+ * @param data Map类型数据
+ * @param key API密钥
+ * @param signType 签名方式
+ * @return 签名是否正确
+ * @throws Exception
+ */
+ public static boolean isSignatureValid(Map data, String key, WXPayConstants.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, WXPayConstants.SignType.MD5);
+ }
+
+ /**
+ * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
+ *
+ * @param data 待签名数据
+ * @param key API密钥
+ * @param signType 签名方式
+ * @return 签名
+ */
+ public static String generateSignature(final Map data, String key, WXPayConstants.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 (WXPayConstants.SignType.MD5.equals(signType)) {
+ return MD5(sb.toString()).toUpperCase();
+ } else if (WXPayConstants.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/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayXmlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayXmlUtil.java
new file mode 100644
index 00000000..75148fa1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/WXPayXmlUtil.java
@@ -0,0 +1,31 @@
+package com.ruoyi.common.core.utils;
+
+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 {
+ System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
+ 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/xhpc-modules/pom.xml b/xhpc-modules/pom.xml
index 5d3cfe79..79b11525 100644
--- a/xhpc-modules/pom.xml
+++ b/xhpc-modules/pom.xml
@@ -14,6 +14,7 @@
xhpc-power-pile
xhpc-charging-station
xhpc-user
+ xhpc-payment
xhpc-modules
diff --git a/xhpc-modules/xhpc-payment/.gitignore b/xhpc-modules/xhpc-payment/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/xhpc-modules/xhpc-payment/.mvn/wrapper/MavenWrapperDownloader.java b/xhpc-modules/xhpc-payment/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 00000000..a45eb6ba
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.jar b/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..2cc7d4a5
Binary files /dev/null and b/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.properties b/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..ffdc10e5
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/xhpc-modules/xhpc-payment/mvnw b/xhpc-modules/xhpc-payment/mvnw
new file mode 100644
index 00000000..a16b5431
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/xhpc-modules/xhpc-payment/mvnw.cmd b/xhpc-modules/xhpc-payment/mvnw.cmd
new file mode 100644
index 00000000..c8d43372
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/xhpc-modules/xhpc-payment/pom.xml b/xhpc-modules/xhpc-payment/pom.xml
new file mode 100644
index 00000000..003d4a32
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/pom.xml
@@ -0,0 +1,96 @@
+
+
+
+ com.ruoyi
+ xhpc-modules
+ 3.0.0
+
+ 4.0.0
+
+ xhpc-payment
+
+
+ 账号服务
+
+
+
+ 8
+ 8
+
+
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+ com.ruoyi
+ ruoyi-common-datasource
+
+
+
+
+ com.ruoyi
+ ruoyi-common-datascope
+
+
+
+
+ com.alipay.sdk
+ alipay-sdk-java
+ ${alipay.sdk}
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.4.0
+
+
+
+ repackage
+
+
+
+
+
+
+
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/PaymentApplication.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/PaymentApplication.java
new file mode 100644
index 00000000..84c73b40
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/PaymentApplication.java
@@ -0,0 +1,21 @@
+package com.xhpc.payment;
+
+import com.ruoyi.common.security.annotation.EnableCustomConfig;
+import com.ruoyi.common.security.annotation.EnableRyFeignClients;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+/*@EnableCustomConfig*/
+@EnableRyFeignClients
+@EnableFeignClients
+@SpringBootApplication
+@MapperScan("com.xhpc.payment.mapper")
+public class PaymentApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PaymentApplication.class, args);
+ }
+
+}
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/WxPaymentController.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/WxPaymentController.java
new file mode 100644
index 00000000..477137aa
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/WxPaymentController.java
@@ -0,0 +1,621 @@
+package com.xhpc.payment.controller;
+
+import com.ruoyi.common.core.constant.HttpStatus;
+import com.ruoyi.common.core.utils.DateUtils;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.core.utils.WXPayUtil;
+import com.ruoyi.common.core.web.domain.AjaxResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.net.ssl.SSLContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 微信支付
+ * author:yuyang
+ * Date:2020/4/8
+ * Time:16:30
+ */
+@RestController
+@RequestMapping("/wx")
+@Api(value = "微信支付接口", tags = "微信支付接口")
+public class WxPaymentController {
+
+ private static final Logger logger = LoggerFactory.getLogger(WxPaymentController.class);
+
+ private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ private static final Random RANDOM = new SecureRandom();
+
+
+ @Autowired
+ private Environment environment;
+
+ @GetMapping("/payment")
+ @ApiOperation(value = "微信支付", notes = "传入order")
+ public Object getWXunifiedorder(HttpServletRequest servletRequest) {
+ AjaxResult responseData = new AjaxResult();
+ String openid = servletRequest.getParameter("openid");
+ if (StringUtils.isNull(openid)) {
+ return responseData.error(HttpStatus.BAD_REQUEST, "openid不能为空");
+ }
+ //总金额(是)订单总金额,单位为分
+ String doubleValue = servletRequest.getParameter("doubleValue");
+ if (StringUtils.isNull(doubleValue)) {
+ return responseData.error(HttpStatus.BAD_REQUEST, "充值金额不能为空");
+ }
+ Double amount = Double.parseDouble(doubleValue);
+ String orderNumber = "wx"+ DateUtils.timePath();
+ //此次生成充值订单
+ // OrderVO orderInfo = orderService.selectOrderNumber(orderNumber);
+ if (0.0 == amount) {
+ return responseData.error(HttpStatus.BAD_REQUEST, "充值金额不能为0");
+ }
+ //附加数据(否)
+ String attach = attachYu(StringUtils.valueOf("123456"), StringUtils.valueOf(amount), null, orderNumber);
+ //商品描述(是)
+ String body = "用户充值";
+ //商户订单号(是)
+ String outTradeNo = orderNumber;
+ int Fee = amount.intValue();
+ //终端ip(是)
+ String spbillCreateIp = getRemoteLoginUserIp(servletRequest);
+ //交易类型(是)
+ String tradeType = "JSAPI";
+ Date date = new Date();
+ //微信过期时间格式
+ SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
+ //过期时间半个小时
+ Date expireTime = new Date(date.getTime() + 5 * 60 * 1000);
+ String timeStr = format1.format(expireTime);
+ //发送请求
+ PrintWriter out = null;
+ BufferedReader in = null;
+ String result = "";
+ try {
+ URL realUrl = new URL(environment.getProperty("WXPAYUNIFIEDORDER"));
+ // 打开和URL之间的连接
+ URLConnection conn = realUrl.openConnection();
+ // 设置通用的请求属性
+ conn.setRequestProperty("accept", "*/*");
+ conn.setRequestProperty("Content-Type", "text/xml");
+ conn.setRequestProperty("connection", "Keep-Alive");
+ conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+ // 发送POST请求必须设置如下两行
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ // 获取URLConnection对象对应的输出流
+ out = new PrintWriter(conn.getOutputStream());
+ out.print(createXMLParam(Fee, attach, tradeType, spbillCreateIp, outTradeNo, body, timeStr, environment.getProperty("SERVERDOMAIN"), environment.getProperty("APPID"), environment.getProperty("MCHID"), environment.getProperty("KEY"), openid));
+ // flush输出流的缓冲
+ out.flush();
+ // 定义BufferedReader输入流来读取URL的响应
+ in = new BufferedReader(
+ new InputStreamReader(conn.getInputStream()));
+ String line;
+ while ((line = in.readLine()) != null) {
+ result += line;
+ System.out.println(result);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ //使用finally块来关闭输出流、输入流
+ finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+ //app
+ //Map sign = createSign(result, 1, orderInfo.getId(), environment.getProperty("KEY"), doubleValue, remarks);
+ Map sign = createSign(result, 1);
+ responseData.success(sign);
+ return responseData;
+ }
+
+
+ /**
+ * 生成签名
+ *
+ * @param result xml格式字符串
+ * @param pageType 页面类型 1-APP 2-PC
+ * @return
+ */
+ public Map createSign(String result, Integer pageType) {
+ try {
+ Map map = WXPayUtil.xmlToMap(result);
+ String return_code = map.get("return_code");
+ if ("FAIL".equals(return_code)) {
+ return null;
+ } else {
+ if (pageType == 1) {
+ //我这里是手动拼接的 可以使用微信具类生成签名
+ String nonceStr = WXPayUtil.generateNonceStr();
+ Map map1 = new HashMap<>();
+ map1.put("money", map.get("doubleValue"));
+ map1.put("appid", map.get("appid"));
+ map1.put("prepayId", map.get("prepay_id"));
+ map1.put("noncestr", nonceStr);
+ map1.put("nonceStr", nonceStr + "\",\"packageValue\":" + "\"Sign=WXPay\"");
+ map1.put("package", "Sign=WXPay");
+ map1.put("partnerid", map.get("mch_id"));
+ Long time = System.currentTimeMillis();
+ String timeStr = time.toString().substring(0, time.toString().length() - 3);
+ map1.put("timestamp", timeStr);
+ map1.put("sign", map.get("sign"));
+ map1.put("url", map.get("code_url"));
+ map1.put("key", environment.getProperty("KEY"));
+ return map1;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 生成xml格式参数
+ * 注释的是使用微信工具类生成的xml格式 添加参数时,按照abcd26个字母顺序添加
+ *
+ * @param total_fee 支付金额
+ * @param attach 自定义参数
+ * @param trade_type 交易类型
+ * @param ip 终端ip地址
+ * @param out_trade_no 交易订单号
+ * @param body 交易信息
+ * @param timeExpire 交易过期时间
+ * @param WXNotifyUrl 微信支付回调地址
+ * @param appid 应用ID
+ * @param mch_id 商户号
+ * @param key 添加key值
+ * @return
+ */
+ public String createXMLParam(Integer total_fee, String attach, String trade_type, String ip, String out_trade_no, String body, String timeExpire, String WXNotifyUrl, String appid, String mch_id, String key, String openid) {
+ String param = "";
+ String nonce_str = generateNonceStr();
+ String notify_url = WXNotifyUrl;
+ String spbill_create_ip = ip;
+ //应用ID
+ param += "appid=" + appid;
+ //附加数据 回调时可以获取
+ param += "&attach=" + attach;
+ //body 商品描述
+ param += "&body=" + body;
+ //商户号
+ param += "&mch_id=" + mch_id;
+ //随机字符串
+ param += "&nonce_str=" + nonce_str;
+ //回调地址
+ param += "¬ify_url=" + notify_url;
+ if ("JSAPI".equals(trade_type)) {
+ //用户openid
+ param += "&openid=" + openid;
+ }
+ //商户订单号
+ param += "&out_trade_no=" + out_trade_no;
+ //终端IP
+ param += "&spbill_create_ip=" + spbill_create_ip;
+ //交易结束时间
+ param += "&time_expire=" + timeExpire;
+ //总金额
+ param += "&total_fee=" + total_fee;
+ //支付类型
+ param += "&trade_type=" + trade_type;
+ //生成签名 添加key值
+ String stringSignTemp = param + "&key=" + key;
+ //签名 不参与签名 默认MD5算法
+ String sign = StringUtils.md5(stringSignTemp);
+
+ String xmlString = "\n" +
+ " " + appid + "\n" +
+ " " + attach + "\n" +
+ " " + body + "\n" +
+ " " + mch_id + "\n" +
+ " " + nonce_str + "\n" +
+ " " + notify_url + "\n";
+ if ("JSAPI".equals(trade_type)) {
+ xmlString += " " + openid + "\n";
+ }
+ xmlString +=
+ " " + out_trade_no + "\n" +
+ " " + spbill_create_ip + "\n" +
+ " " + timeExpire + "\n" +
+ " " + total_fee + "\n" +
+ " " + trade_type + "\n" +
+ " " + sign + "\n" +
+ " ";
+ return xmlString;
+ }
+
+ //附加参数
+ public String attachYu(String id, String money, String payStyle, String out_trade_no) {
+ // 发送请求参数 业务参数
+ StringBuilder attachSB = new StringBuilder();
+ attachSB.append(",{\"customerId\":" + id);
+ attachSB.append(",\"money\":\"" + money + "\"");
+ attachSB.append(",\"out_trade_no\":\"" + out_trade_no + "\"}");
+ String attach = attachSB.substring(1);
+ return attach;
+ }
+
+ /**
+ * 获取随机字符串 Nonce Str
+ *
+ * @return String 随机字符串
+ */
+ public 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);
+ }
+
+ //获取终端ip
+ public String getRemoteLoginUserIp(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_CLIENT_IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ System.out.println("THE REAL IPS IS:" + ip);
+ if (ip != null && ip.length() > 15) {
+ if (ip.indexOf(",") > 0) {
+ ip = ip.substring(0, ip.indexOf(","));
+ }
+ }
+ return ip;
+ }
+
+ /**
+ * 修改支付订单
+ *
+ * @param
+ * @param
+ * @return
+ * @throws Exception
+ */
+ /* public int addOrUpdatePaymentRecord(Long orderId, String transactionId) throws Exception {
+ Order order = orderMapper.selectById(orderId);
+ String userId = StringUtils.valueOf(order.getUserId());
+ User user = userMapper.getUserVo(userId);
+ order.setPrepayId(transactionId);
+ orderMapper.updateById(order);
+ return 0;
+ }*/
+ public int paymentCallback(Map map) throws Exception {
+ String result_code = map.get("result_code");
+ String return_code = map.get("return_code");
+ String out_trade_no = map.get("out_trade_no");
+ String openid = map.get("openid");
+ String transaction_id = map.get("transaction_id");
+
+ int flag = 0;
+ //支付订单编号
+ /*OrderVO order = orderMapper.selectOrderNumber(out_trade_no);
+ if (null != order) {
+ //检验是否需要再次回调刷新数据
+ //TODO 微信后台回调,刷新订单支付状态等相关业务
+ addOrUpdatePaymentRecord(order.getId(), transaction_id);
+ }*/
+ return flag;
+ }
+
+ /**
+ * 回调Api
+ */
+ @RequestMapping("/paymentCallback")
+ public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ ServletInputStream in = null;
+ BufferedReader reader = null;
+ StringBuilder content = new StringBuilder();
+ try {
+ in = request.getInputStream();
+ reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ String itemStr = "";// 作为输出字符串的临时串,用于判断是否读取完毕
+ while (null != (itemStr = reader.readLine())) {
+ content.append(itemStr);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (null != reader)
+ reader.close();
+ if (null != in)
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ content.toString();
+ //将xml转换成map
+ Map map = WXPayUtil.xmlToMap(content.toString());
+ String return_code = map.get("return_code");
+ //自定义参数 为json格式的字符串
+ //如果返回成功
+ if ("SUCCESS".equals(return_code)) {
+ //将自定义参数转换成JSONObject对象,处理业务逻辑
+ paymentCallback(map);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/xml; charset=utf-8");
+ PrintWriter out = null;
+ try {
+ out = response.getWriter();
+ out.print("\n" +
+ " \n" +
+ " \n" +
+ "\n");
+ out.close();
+ return null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 生成xml格式 添加参数时,按照abcd26个字母顺序添加
+ *
+ * @param tradeNo 微信单号
+ * @param out_refund_no 退款单号
+ * @param total_fee 总金额
+ * @param refund_fee 退款金额
+ * @param refund_desc 退款原因
+ * @return
+ */
+ private String createOutXMLParam(String tradeNo, String out_refund_no, String total_fee, String refund_fee, String refund_desc) {
+ HashMap map = new HashMap<>();
+ //随机字符串
+ String nonceStr = WXPayUtil.generateNonceStr();
+ map.put("appid", environment.getProperty("APPID"));
+ //商户id
+ map.put("mch_id", environment.getProperty("MCHID"));
+ //随机字符串
+ map.put("nonce_str", nonceStr);
+ //商户退款单号 一个订单唯一
+ map.put("out_refund_no", tradeNo);
+ //退款原因
+ map.put("refund_desc", refund_desc);
+ //退款金额
+ map.put("refund_fee", refund_fee);
+ //订单金额
+ map.put("total_fee", total_fee);
+ //微信订单号
+ map.put("transaction_id", out_refund_no);
+ String xml = "";
+ try {
+ String signature = WXPayUtil.generateSignature(map, environment.getProperty("KEY"));
+ map.put("sign", signature);
+ xml = WXPayUtil.mapToXml(map);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return xml;
+ }
+
+ /**
+ * 加载证书
+ *
+ * @param certPath 证书位置
+ * @throws Exception
+ */
+ private CloseableHttpClient initCert(String certPath) throws Exception {
+ String path = "apiclient_cert.p12";
+ //File file = new File(this.getClass().getResource("/").getPath()+path);
+ File file = new File("/www/wwwroot/msjd.project2.tingsun.net/" + path);
+ // 证书密码,默认为商户ID
+ String key = environment.getProperty("MCHID");
+ // 指定读取证书格式为PKCS12
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ // 读取本机存放的PKCS12证书文件
+ FileInputStream instream = new FileInputStream(file);
+ try {
+ // 指定PKCS12的密码(商户ID)
+ keyStore.load(instream, key.toCharArray());
+ } finally {
+ instream.close();
+ }
+ SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
+ SSLConnectionSocketFactory sslsf =
+ new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
+ SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+ return HttpClients.custom().setSSLSocketFactory(sslsf).build();
+ }
+
+ /**
+ * 修改退款订单
+ * @param orderId
+ * @param transactionId
+ * @return
+ * @throws Exception
+ */
+ /* public int addOrUpdate(Long orderId, String transactionId) throws Exception {
+ Order order = orderMapper.selectById(orderId);
+ String userId = StringUtils.valueOf(order.getUserId());
+ User user = userMapper.getUserVo(userId);
+ order.setPrepayId(transactionId);
+ orderMapper.updateById(order);
+ return 0;
+ }*/
+
+ /**
+ * 企业退款
+ *
+ * @return
+ */
+/* @GetMapping("/enterpriseCheckOut")
+ @ApiOperation(value = "企业退款", notes = "传入order")
+ public Object enterpriseCheckOut(HttpServletRequest servletRequest) {
+ String orderNumber = servletRequest.getParameter("orderNumber");
+ String openid = servletRequest.getParameter("openid");
+ String reason = "退款申请";
+ return enterpriseOut(orderNumber, openid, reason);
+ }
+
+
+ public Object enterpriseOut(String orderNumber, String openid, String reason) {
+ OrderVO orderInfo = orderService.selectOrderNumber(orderNumber);
+
+ String retreat = StringUtils.valueOf(map.get("retreat"));
+ if (StringUtils.validatorEmpty(retreat)) {
+ return new SuccessResponseData(ResponseConstants.NOT_EXISTING, "订单金额出错");
+ }
+ CloseableHttpClient httpClient = null;
+ try {
+ //证书的地址
+ ConfigListener.getConf().get("certPath");
+ httpClient = initCert(ConfigListener.getConf().get("certPath"));
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ }
+ //退款金额单位为分
+ Double value = Double.valueOf(retreat) * 100;
+ Integer refund_fee = value.intValue();
+ if (refund_fee <= 0) {
+ return new SuccessResponseData(ResponseConstants.NOT_EXISTING, "订单金额出错");
+ }
+ String result = "";
+ HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
+ AjaxResult successResponseData = new AjaxResult();
+ StringEntity postEntity = new StringEntity(creatXMLParam(orderInfo.getPrepayId(), refund_fee.toString(), reason, openid), "UTF-8");
+ httpPost.addHeader("Content-Type", "text/xml");
+ httpPost.setEntity(postEntity);
+ try {
+ HttpResponse response = null;
+ try {
+ response = httpClient.execute(httpPost);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ HttpEntity entity = response.getEntity();
+ try {
+ result = EntityUtils.toString(entity, "UTF-8");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } finally {
+ httpPost.abort();
+ }
+ return parseXml(result, successResponseData, orderInfo.getId(), Double.valueOf(retreat));
+ }*/
+
+
+ /**
+ * 生成xml格式 添加参数时,按照abcd26个字母顺序添加
+ *
+ * @param openid 用户openid
+ * @param partner_trade_no 商户退款单号
+ * @param amount 退款金额
+ * @param refund_desc 退款原因
+ * @return
+ */
+ private String creatXMLParam(String partner_trade_no, String amount, String refund_desc, String openid) {
+ String param = "";
+ //随机字符串
+ String nonceStr = WXPayUtil.generateNonceStr();
+ //退款金额
+ param += "amount=" + amount;
+ //校验用户姓名选项
+ param += "&check_name=" + "NO_CHECK";
+ //退款原因
+ param += "&desc=" + refund_desc;
+ param += "&mch_appid=" + environment.getProperty("APPID");
+ //商户id
+ param += "&mchid=" + environment.getProperty("MCHID");
+ //随机字符串
+ param += "&nonce_str=" + nonceStr;
+ //用户openid
+ param += "&openid=" + openid;
+ //商户退款单号 一个订单唯一
+ param += "&partner_trade_no=" + partner_trade_no;
+ //生成签名 添加key值
+ String stringSignTemp = param + "&key=" + environment.getProperty("KEY");
+ //签名 不参与签名 默认MD5算法
+ String sign = StringUtils.md5(stringSignTemp);
+ String xmlString = "\n" +
+ " " + amount + "\n" +
+ " " + "NO_CHECK" + "\n" +
+ " " + refund_desc + "\n" +
+ " " + environment.getProperty("APPID") + "\n" +
+ " " + environment.getProperty("MCHID") + "\n" +
+ " " + nonceStr + "\n" +
+ " " + openid + "\n" +
+ " " + partner_trade_no + "\n" +
+ " " + sign + "\n" +
+ " ";
+ return xmlString;
+ }
+
+ /**
+ * 解析xml字符串
+ *
+ * @param result 请求后的结果
+ * @param jsonObject json对象
+ * @return
+ */
+/* private AjaxResult parseXml(String result, AjaxResult jsonObject, Long id, Double refundMoney) {
+ try {
+ Map map = WXPayUtil.xmlToMap(result);
+ String return_code = map.get("return_code");
+ if ("FAIL".equals(return_code)) {
+ jsonObject.error(map.get("return_msg"));
+ } else {
+ orderService.checkOut(id, refundMoney);
+ jsonObject.success(map);
+ }
+ } catch (Exception e) {
+ jsonObject.error(e.getMessage());
+ e.printStackTrace();
+ }
+ return jsonObject;
+ }*/
+}
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/domain/XhpcRechargeOrder.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/domain/XhpcRechargeOrder.java
new file mode 100644
index 00000000..8b2e6c76
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/domain/XhpcRechargeOrder.java
@@ -0,0 +1,120 @@
+package com.xhpc.payment.domain;
+
+import com.ruoyi.common.core.web.domain.BaseEntity;
+
+import java.math.BigDecimal;
+
+
+/**
+ * @description 充值订单 xhpc_recharge_order
+ * @author
+ * @date 2021-07-22
+ */
+public class XhpcRechargeOrder extends BaseEntity {
+
+
+ /**
+ * 充值订单id
+ */
+ private Long rechargeOrderId;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 微信支付订单号
+ */
+ private String prepayId;
+
+ /**
+ * 支付宝订单编号
+ */
+ private String alipayNumber;
+
+ /**
+ * 充值金额
+ */
+ private BigDecimal amount;
+
+ /**
+ * 充值渠道(1微信 2支付宝)
+ */
+ private Integer type;
+
+
+ /**
+ * 状态(0待支付 1充值成功,2充值失败)
+ */
+ private Integer status;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ private Integer delFlag;
+
+ public Long getRechargeOrderId() {
+ return rechargeOrderId;
+ }
+
+ public void setRechargeOrderId(Long rechargeOrderId) {
+ this.rechargeOrderId = rechargeOrderId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public String getPrepayId() {
+ return prepayId;
+ }
+
+ public void setPrepayId(String prepayId) {
+ this.prepayId = prepayId;
+ }
+
+ public String getAlipayNumber() {
+ return alipayNumber;
+ }
+
+ public void setAlipayNumber(String alipayNumber) {
+ this.alipayNumber = alipayNumber;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public void setAmount(BigDecimal amount) {
+ this.amount = amount;
+ }
+
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+
+ public Integer getDelFlag() {
+ return delFlag;
+ }
+
+ public void setDelFlag(Integer delFlag) {
+ this.delFlag = delFlag;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+}
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/mapper/XhpcRechargeOrderMapper.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/mapper/XhpcRechargeOrderMapper.java
new file mode 100644
index 00000000..5daa3cca
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/mapper/XhpcRechargeOrderMapper.java
@@ -0,0 +1,42 @@
+package com.xhpc.payment.mapper;
+
+import com.xhpc.payment.domain.XhpcRechargeOrder;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 充值订单信息 数据层
+ *
+ * @author ruoyi
+ */
+public interface XhpcRechargeOrderMapper {
+
+ /**
+ * 新增 充值订单信息
+ *
+ * @param xhpcRechargeOrder 充值订单信息
+ * @return 结果
+ */
+ public int insert(XhpcRechargeOrder xhpcRechargeOrder);
+
+ /**
+ * 修改充值订单信息
+ *
+ * @param xhpcRechargeOrder 充值订单信息
+ * @return 结果
+ */
+ public int update(XhpcRechargeOrder xhpcRechargeOrder);
+
+
+ /**
+ * 查询充值订单详情
+ *
+ * @param rechargeOrderId 充值订单id
+ * @return 结果
+ */
+ public Map info(@Param("rechargeOrderId") Long rechargeOrderId);
+
+
+}
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/IXhpcRechargeOrderService.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/IXhpcRechargeOrderService.java
new file mode 100644
index 00000000..7030514f
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/IXhpcRechargeOrderService.java
@@ -0,0 +1,37 @@
+package com.xhpc.payment.service;
+
+import com.xhpc.payment.domain.XhpcRechargeOrder;
+import java.util.Map;
+
+
+/**
+ * 充值订单信息 服务层
+ *
+ * @author ruoyi
+ */
+public interface IXhpcRechargeOrderService {
+
+ /**
+ * 更新 充值订单
+ *
+ * @param xhpcRechargeOrder 充值订单
+ */
+ public int update(XhpcRechargeOrder xhpcRechargeOrder);
+
+
+ /**
+ * 充值订单详情
+ *
+ * @param appUserId 充值订单id
+ * @return 结果
+ */
+ public Map info(Long appUserId);
+
+ /**
+ * 新增 充值订单
+ * @param openid
+ * @param amount
+ * @return
+ */
+ public XhpcRechargeOrder add(String openid,double amount);
+}
\ No newline at end of file
diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/impl/XhpcRechargeOrderServiceImpl.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/impl/XhpcRechargeOrderServiceImpl.java
new file mode 100644
index 00000000..02907185
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/service/impl/XhpcRechargeOrderServiceImpl.java
@@ -0,0 +1,58 @@
+package com.xhpc.payment.service.impl;
+
+import com.xhpc.payment.domain.XhpcRechargeOrder;
+import com.xhpc.payment.mapper.XhpcRechargeOrderMapper;
+import com.xhpc.payment.service.IXhpcRechargeOrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * 充值订单信息 服务层
+ *
+ * @author ruoyi
+ */
+@Service
+public class XhpcRechargeOrderServiceImpl implements IXhpcRechargeOrderService {
+
+ @Autowired
+ private XhpcRechargeOrderMapper xhpcRechargeOrderMapper;
+
+
+ /**
+ * 更新 充值订单
+ *
+ * @param xhpcRechargeOrder 充值订单
+ */
+ @Override
+ public int update(XhpcRechargeOrder xhpcRechargeOrder) {
+ return xhpcRechargeOrderMapper.update(xhpcRechargeOrder);
+ }
+
+
+ /**
+ * 充值订单详情
+ *
+ * @param appUserId 充值订单id
+ * @return 结果
+ */
+ @Override
+ public Map info(Long appUserId) {
+ return xhpcRechargeOrderMapper.info(appUserId);
+ }
+
+ /**
+ * 新增 充值订单
+ * @param openid
+ * @param amount
+ * @return
+ */
+ @Override
+ public XhpcRechargeOrder add(String openid,double amount) {
+ XhpcRechargeOrder xhpcRechargeOrder = new XhpcRechargeOrder();
+ xhpcRechargeOrderMapper.insert(xhpcRechargeOrder);
+ return xhpcRechargeOrder;
+ }
+
+}
\ No newline at end of file
diff --git a/xhpc-modules/xhpc-payment/src/main/resources/banner.txt b/xhpc-modules/xhpc-payment/src/main/resources/banner.txt
new file mode 100644
index 00000000..27cacb9c
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ __ _ _
+ (_) / _|(_)| |
+ _ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
+| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
+| | | |_| || (_) || |_| || | | | | || || __/
+|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
+ __/ |
+ |___/
\ No newline at end of file
diff --git a/xhpc-modules/xhpc-payment/src/main/resources/bootstrap.yml b/xhpc-modules/xhpc-payment/src/main/resources/bootstrap.yml
new file mode 100644
index 00000000..648ff1b1
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/resources/bootstrap.yml
@@ -0,0 +1,46 @@
+ppsvc:
+ server: 0.0.0.0
+ port: 8888
+
+# Tomcat
+server:
+ port: 9802
+
+# Spring
+spring:
+ application:
+ # 应用名称
+ name: xhpc-payment
+ profiles:
+ # 环境配置
+ active: dev
+ cloud:
+ nacos:
+ discovery:
+ # 服务注册地址
+ server-addr: 118.24.137.203:8848
+ config:
+ # 配置中心地址
+ server-addr: 118.24.137.203:8848
+ # 配置文件格式
+ file-extension: yml
+ # 共享配置
+ shared-configs:
+ - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+
+##获取微信openid地址
+WXGETJSCODE: "https://api.weixin.qq.com/sns/jscode2session?appid=wxb14ef93e9b7901f3&secret=b5c5672141b5930c30a1abee95a2dcbf&js_code="
+##阿里云身份证验证地址
+VERIFYCARD: "http://idenauthen.market.alicloudapi.com/idenAuthentication"
+#阿里云身份证验证地址appcode
+APPCODE: "APPCODE e26d9088b58e24af69411d5933cece47"
+#小程序appid
+APPID: "wxd0a48e00319ef8a7"
+#小程序绑定商户id
+MCHID: "1514355771"
+#商户后台设置的key
+KEY: "sichuanxianghuakejiyouxiangongsi"
+#微信小程序支付地址
+WXPAYUNIFIEDORDER: "https://api.mch.weixin.qq.com/pay/unifiedorder"
+#支付回调地址
+SERVERDOMAIN: "https://cdz.project2.tingsun.net/wx/paymentCallback"
\ No newline at end of file
diff --git a/xhpc-modules/xhpc-payment/src/main/resources/logback.xml b/xhpc-modules/xhpc-payment/src/main/resources/logback.xml
new file mode 100644
index 00000000..83ed4f2d
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+
+
+
+
+
+ ${log.path}/info.log
+
+
+
+ ${log.path}/info.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ INFO
+
+ ACCEPT
+
+ DENY
+
+
+
+
+ ${log.path}/error.log
+
+
+
+ ${log.path}/error.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ ERROR
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xhpc-modules/xhpc-payment/src/main/resources/mapper/XhpcRechargeOrderMapper.xml b/xhpc-modules/xhpc-payment/src/main/resources/mapper/XhpcRechargeOrderMapper.xml
new file mode 100644
index 00000000..21083fa3
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/resources/mapper/XhpcRechargeOrderMapper.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO xhpc_recharge_order
+
+
+ recharge_order_id,
+
+
+ user_id,
+
+
+ prepay_id,
+
+
+ alipay_number,
+
+
+ amount,
+
+
+ type,
+
+
+ status,
+
+
+ del_flag,
+
+
+ create_time,
+
+
+ create_by,
+
+
+ update_time,
+
+
+ update_by,
+
+
+ remark
+
+
+
+
+ #{rechargeOrderId},
+
+
+ #{userId},
+
+
+ #{prepayId},
+
+
+ #{alipayNumber},
+
+
+ #{amount},
+
+
+ #{type},
+
+
+ #{status},
+
+
+ #{delFlag},
+
+
+ #{createTime},
+
+
+ #{createBy},
+
+
+ #{updateTime},
+
+
+ #{updateBy},
+
+
+ #{remark}
+
+
+
+
+
+ UPDATE xhpc_recharge_order
+
+ user_id = #{userId},
+ prepay_id = #{prepayId},
+ alipay_number = #{alipayNumber},
+ amount = #{amount},
+ type = #{type},
+ status = #{status},
+ del_flag = #{delFlag},
+ create_time = #{createTime},
+ create_by = #{createBy},
+ update_time = #{updateTime},
+ update_by = #{updateBy},
+ remark = #{remark}
+
+ WHERE recharge_order_id = #{rechargeOrderId}
+
+
+
+
+
\ No newline at end of file
diff --git a/xhpc-modules/xhpc-payment/src/main/resources/svcmainlogic.xml b/xhpc-modules/xhpc-payment/src/main/resources/svcmainlogic.xml
new file mode 100644
index 00000000..9aee48b3
--- /dev/null
+++ b/xhpc-modules/xhpc-payment/src/main/resources/svcmainlogic.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+