1新增支付服务
This commit is contained in:
parent
22794224a6
commit
3456fbdd43
@ -112,6 +112,17 @@
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.3.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -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";
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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<String, String> 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<String,String> 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<String, Object> getMapFromXML(String strXML) throws Exception {
|
||||
try {
|
||||
Map<String, Object> data = new HashMap<String, Object>();
|
||||
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<String,Object> 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<String, String> paraFilter(Map<String, String> sArray) {
|
||||
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
|
||||
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<String, String> params) {
|
||||
List<String> keys = new ArrayList<String>(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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, String> xmlToMap(String strXML) throws Exception {
|
||||
try {
|
||||
Map<String, String> data = new HashMap<String, String>();
|
||||
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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
|
||||
Set<String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@
|
||||
<module>xhpc-power-pile</module>
|
||||
<module>xhpc-charging-station</module>
|
||||
<module>xhpc-user</module>
|
||||
<module>xhpc-payment</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>xhpc-modules</artifactId>
|
||||
|
||||
33
xhpc-modules/xhpc-payment/.gitignore
vendored
Normal file
33
xhpc-modules/xhpc-payment/.gitignore
vendored
Normal file
@ -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/
|
||||
118
xhpc-modules/xhpc-payment/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
118
xhpc-modules/xhpc-payment/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
xhpc-modules/xhpc-payment/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -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
|
||||
310
xhpc-modules/xhpc-payment/mvnw
vendored
Normal file
310
xhpc-modules/xhpc-payment/mvnw
vendored
Normal file
@ -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 "$@"
|
||||
182
xhpc-modules/xhpc-payment/mvnw.cmd
vendored
Normal file
182
xhpc-modules/xhpc-payment/mvnw.cmd
vendored
Normal file
@ -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%
|
||||
96
xhpc-modules/xhpc-payment/pom.xml
Normal file
96
xhpc-modules/xhpc-payment/pom.xml
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>xhpc-modules</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>xhpc-payment</artifactId>
|
||||
|
||||
<description>
|
||||
账号服务
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Mysql Connector -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Common DataSource -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datasource</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Common DataScope -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datascope</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 支付宝sdk -->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>${alipay.sdk}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, String> sign = createSign(result, 1, orderInfo.getId(), environment.getProperty("KEY"), doubleValue, remarks);
|
||||
Map<String, String> sign = createSign(result, 1);
|
||||
responseData.success(sign);
|
||||
return responseData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*
|
||||
* @param result xml格式字符串
|
||||
* @param pageType 页面类型 1-APP 2-PC
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> createSign(String result, Integer pageType) {
|
||||
try {
|
||||
Map<String, String> 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<String, String> 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 = "<xml>\n" +
|
||||
" <appid>" + appid + "</appid>\n" +
|
||||
" <attach>" + attach + "</attach>\n" +
|
||||
" <body>" + body + "</body>\n" +
|
||||
" <mch_id>" + mch_id + "</mch_id>\n" +
|
||||
" <nonce_str>" + nonce_str + "</nonce_str>\n" +
|
||||
" <notify_url>" + notify_url + "</notify_url>\n";
|
||||
if ("JSAPI".equals(trade_type)) {
|
||||
xmlString += " <openid>" + openid + "</openid>\n";
|
||||
}
|
||||
xmlString +=
|
||||
" <out_trade_no>" + out_trade_no + "</out_trade_no>\n" +
|
||||
" <spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>\n" +
|
||||
" <time_expire>" + timeExpire + "</time_expire>\n" +
|
||||
" <total_fee>" + total_fee + "</total_fee>\n" +
|
||||
" <trade_type>" + trade_type + "</trade_type>\n" +
|
||||
" <sign>" + sign + "</sign>\n" +
|
||||
"</xml> ";
|
||||
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<String, String> 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<String, String> 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("<xml>\n" +
|
||||
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
|
||||
" <return_msg><![CDATA[OK]]></return_msg>\n" +
|
||||
"</xml>\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<String, String> 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 = "<xml>\n" +
|
||||
" <amount>" + amount + "</amount>\n" +
|
||||
" <check_name>" + "NO_CHECK" + "</check_name>\n" +
|
||||
" <desc>" + refund_desc + "</desc>\n" +
|
||||
" <mch_appid>" + environment.getProperty("APPID") + "</mch_appid>\n" +
|
||||
" <mchid>" + environment.getProperty("MCHID") + "</mchid>\n" +
|
||||
" <nonce_str>" + nonceStr + "</nonce_str>\n" +
|
||||
" <openid>" + openid + "</openid>\n" +
|
||||
" <partner_trade_no>" + partner_trade_no + "</partner_trade_no>\n" +
|
||||
" <sign>" + sign + "</sign>\n" +
|
||||
"</xml> ";
|
||||
return xmlString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析xml字符串
|
||||
*
|
||||
* @param result 请求后的结果
|
||||
* @param jsonObject json对象
|
||||
* @return
|
||||
*/
|
||||
/* private AjaxResult parseXml(String result, AjaxResult jsonObject, Long id, Double refundMoney) {
|
||||
try {
|
||||
Map<String, String> 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;
|
||||
}*/
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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<String, Object> info(@Param("rechargeOrderId") Long rechargeOrderId);
|
||||
|
||||
|
||||
}
|
||||
@ -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<String, Object> info(Long appUserId);
|
||||
|
||||
/**
|
||||
* 新增 充值订单
|
||||
* @param openid
|
||||
* @param amount
|
||||
* @return
|
||||
*/
|
||||
public XhpcRechargeOrder add(String openid,double amount);
|
||||
}
|
||||
@ -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<String, Object> 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;
|
||||
}
|
||||
|
||||
}
|
||||
10
xhpc-modules/xhpc-payment/src/main/resources/banner.txt
Normal file
10
xhpc-modules/xhpc-payment/src/main/resources/banner.txt
Normal file
@ -0,0 +1,10 @@
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
_ __ _ _
|
||||
(_) / _|(_)| |
|
||||
_ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
|
||||
| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
|
||||
| | | |_| || (_) || |_| || | | | | || || __/
|
||||
|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
|
||||
__/ |
|
||||
|___/
|
||||
46
xhpc-modules/xhpc-payment/src/main/resources/bootstrap.yml
Normal file
46
xhpc-modules/xhpc-payment/src/main/resources/bootstrap.yml
Normal file
@ -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"
|
||||
74
xhpc-modules/xhpc-payment/src/main/resources/logback.xml
Normal file
74
xhpc-modules/xhpc-payment/src/main/resources/logback.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/xphc-power-pile"/>
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.xhpc" level="info"/>
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn"/>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info"/>
|
||||
<appender-ref ref="file_error"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xhpc.payment.mapper.XhpcRechargeOrderMapper">
|
||||
|
||||
<resultMap type="com.xhpc.payment.domain.XhpcRechargeOrder" id="XhpcRechargeOrderResult">
|
||||
<result column="recharge_order_id" property="rechargeOrderId" />
|
||||
<result column="user_id" property="userId" />
|
||||
<result column="prepay_id" property="prepayId" />
|
||||
<result column="alipay_number" property="alipayNumber" />
|
||||
<result column="amount" property="amount" />
|
||||
<result column="type" property="type" />
|
||||
<result column="status" property="status" />
|
||||
<result column="del_flag" property="delFlag" />
|
||||
<result column="create_time" property="createTime" />
|
||||
<result column="create_by" property="createBy" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
<result column="update_by" property="updateBy" />
|
||||
<result column="remark" property="remark" />
|
||||
</resultMap>
|
||||
|
||||
<insert id="insert" parameterType="com.xhpc.user.domain.XhpcAppUser">
|
||||
INSERT INTO xhpc_recharge_order
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="null != rechargeOrderId and '' != rechargeOrderId">
|
||||
recharge_order_id,
|
||||
</if>
|
||||
<if test="null != userId and '' != userId">
|
||||
user_id,
|
||||
</if>
|
||||
<if test="null != prepayId and '' != prepayId">
|
||||
prepay_id,
|
||||
</if>
|
||||
<if test="null != alipayNumber and '' != alipayNumber">
|
||||
alipay_number,
|
||||
</if>
|
||||
<if test="null != amount and '' != amount">
|
||||
amount,
|
||||
</if>
|
||||
<if test="null != type and '' != type">
|
||||
type,
|
||||
</if>
|
||||
<if test="null != status and '' != status">
|
||||
status,
|
||||
</if>
|
||||
<if test="null != delFlag and '' != delFlag">
|
||||
del_flag,
|
||||
</if>
|
||||
<if test="null != createTime and '' != createTime">
|
||||
create_time,
|
||||
</if>
|
||||
<if test="null != createBy and '' != createBy">
|
||||
create_by,
|
||||
</if>
|
||||
<if test="null != updateTime and '' != updateTime">
|
||||
update_time,
|
||||
</if>
|
||||
<if test="null != updateBy and '' != updateBy">
|
||||
update_by,
|
||||
</if>
|
||||
<if test="null != remark and '' != remark">
|
||||
remark
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="null != rechargeOrderId and '' != rechargeOrderId">
|
||||
#{rechargeOrderId},
|
||||
</if>
|
||||
<if test="null != userId and '' != userId">
|
||||
#{userId},
|
||||
</if>
|
||||
<if test="null != prepayId and '' != prepayId">
|
||||
#{prepayId},
|
||||
</if>
|
||||
<if test="null != alipayNumber and '' != alipayNumber">
|
||||
#{alipayNumber},
|
||||
</if>
|
||||
<if test="null != amount and '' != amount">
|
||||
#{amount},
|
||||
</if>
|
||||
<if test="null != type and '' != type">
|
||||
#{type},
|
||||
</if>
|
||||
<if test="null != status and '' != status">
|
||||
#{status},
|
||||
</if>
|
||||
<if test="null != delFlag and '' != delFlag">
|
||||
#{delFlag},
|
||||
</if>
|
||||
<if test="null != createTime and '' != createTime">
|
||||
#{createTime},
|
||||
</if>
|
||||
<if test="null != createBy and '' != createBy">
|
||||
#{createBy},
|
||||
</if>
|
||||
<if test="null != updateTime and '' != updateTime">
|
||||
#{updateTime},
|
||||
</if>
|
||||
<if test="null != updateBy and '' != updateBy">
|
||||
#{updateBy},
|
||||
</if>
|
||||
<if test="null != remark and '' != remark">
|
||||
#{remark}
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.xhpc.user.domain.XhpcInternetUser">
|
||||
UPDATE xhpc_recharge_order
|
||||
<set>
|
||||
<if test="null != userId and '' != userId">user_id = #{userId},</if>
|
||||
<if test="null != prepayId and '' != prepayId">prepay_id = #{prepayId},</if>
|
||||
<if test="null != alipayNumber and '' != alipayNumber">alipay_number = #{alipayNumber},</if>
|
||||
<if test="null != amount and '' != amount">amount = #{amount},</if>
|
||||
<if test="null != type and '' != type">type = #{type},</if>
|
||||
<if test="null != status and '' != status">status = #{status},</if>
|
||||
<if test="null != delFlag and '' != delFlag">del_flag = #{delFlag},</if>
|
||||
<if test="null != createTime and '' != createTime">create_time = #{createTime},</if>
|
||||
<if test="null != createBy and '' != createBy">create_by = #{createBy},</if>
|
||||
<if test="null != updateTime and '' != updateTime">update_time = #{updateTime},</if>
|
||||
<if test="null != updateBy and '' != updateBy">update_by = #{updateBy},</if>
|
||||
<if test="null != remark and '' != remark">remark = #{remark}</if>
|
||||
</set>
|
||||
WHERE recharge_order_id = #{rechargeOrderId}
|
||||
</update>
|
||||
|
||||
<select id="info" parameterType="java.lang.Long" resultType="java.util.Map">
|
||||
select *
|
||||
from xhpc_recharge_order
|
||||
WHERE del_flag = 0 and recharge_order_id = #{rechargeOrderId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
|
||||
<util:map id="serviceLogics">
|
||||
|
||||
<entry key="01" value-ref="RegisterLogic"/>
|
||||
<entry key="03" value-ref="HBLogic"/>
|
||||
<entry key="05" value-ref="RateModelValidateLogic"/>
|
||||
<entry key="09" value-ref="RateModelRequestLogic"/>
|
||||
</util:map>
|
||||
</beans>
|
||||
Loading…
x
Reference in New Issue
Block a user