Quellcode durchsuchen

增加支付接口

houweiyu vor 4 Jahren
Ursprung
Commit
f899f9ef83

+ 8 - 0
dinner-core/pom.xml

@@ -14,5 +14,13 @@
 
 
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
+    <dependencies>
+            <dependency>
+                <groupId>dom4j</groupId>
+                <artifactId>dom4j</artifactId>
+                <version>1.6.1</version>
+            </dependency>
+    </dependencies>
+
 
 
 </project>
 </project>

+ 169 - 0
dinner-core/src/main/java/com/fdage/base/dto/WechatRefundApiResult.java

@@ -0,0 +1,169 @@
+package com.fdage.base.dto;
+
+public class WechatRefundApiResult {
+	private String return_code;
+	private String return_msg;
+	
+	private String result_code;
+	private String err_code;
+	private String err_code_des;
+	private String appid;
+	private String mch_id;
+	private String device_info;
+	private String nonce_str;
+	private String sign;
+	private String transaction_id;
+	private String out_trade_no;
+	private String out_refund_no;
+	private String refund_id;
+	private String refund_channel;
+	private String refund_fee;
+	private String settlement_refund_fee;
+	private String total_fee;
+	private String settlement_total_fee;
+	private String fee_type;
+	private String cash_fee;
+	private String cash_refund_fee;
+	private String refund_status;
+	
+	public String getRefund_status() {
+		return refund_status;
+	}
+	public void setRefund_status(String refund_status) {
+		this.refund_status = refund_status;
+	}
+	public String getReturn_code() {
+		return return_code;
+	}
+	public void setReturn_code(String return_code) {
+		this.return_code = return_code;
+	}
+	public String getReturn_msg() {
+		return return_msg;
+	}
+	public void setReturn_msg(String return_msg) {
+		this.return_msg = return_msg;
+	}
+	public String getResult_code() {
+		return result_code;
+	}
+	public void setResult_code(String result_code) {
+		this.result_code = result_code;
+	}
+	public String getErr_code() {
+		return err_code;
+	}
+	public void setErr_code(String err_code) {
+		this.err_code = err_code;
+	}
+	public String getErr_code_des() {
+		return err_code_des;
+	}
+	public void setErr_code_des(String err_code_des) {
+		this.err_code_des = err_code_des;
+	}
+	public String getAppid() {
+		return appid;
+	}
+	public void setAppid(String appid) {
+		this.appid = appid;
+	}
+	public String getMch_id() {
+		return mch_id;
+	}
+	public void setMch_id(String mch_id) {
+		this.mch_id = mch_id;
+	}
+	public String getDevice_info() {
+		return device_info;
+	}
+	public void setDevice_info(String device_info) {
+		this.device_info = device_info;
+	}
+	public String getNonce_str() {
+		return nonce_str;
+	}
+	public void setNonce_str(String nonce_str) {
+		this.nonce_str = nonce_str;
+	}
+	public String getSign() {
+		return sign;
+	}
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+	public String getTransaction_id() {
+		return transaction_id;
+	}
+	public void setTransaction_id(String transaction_id) {
+		this.transaction_id = transaction_id;
+	}
+	public String getOut_trade_no() {
+		return out_trade_no;
+	}
+	public void setOut_trade_no(String out_trade_no) {
+		this.out_trade_no = out_trade_no;
+	}
+	public String getOut_refund_no() {
+		return out_refund_no;
+	}
+	public void setOut_refund_no(String out_refund_no) {
+		this.out_refund_no = out_refund_no;
+	}
+	public String getRefund_id() {
+		return refund_id;
+	}
+	public void setRefund_id(String refund_id) {
+		this.refund_id = refund_id;
+	}
+	public String getRefund_channel() {
+		return refund_channel;
+	}
+	public void setRefund_channel(String refund_channel) {
+		this.refund_channel = refund_channel;
+	}
+	public String getRefund_fee() {
+		return refund_fee;
+	}
+	public void setRefund_fee(String refund_fee) {
+		this.refund_fee = refund_fee;
+	}
+	public String getSettlement_refund_fee() {
+		return settlement_refund_fee;
+	}
+	public void setSettlement_refund_fee(String settlement_refund_fee) {
+		this.settlement_refund_fee = settlement_refund_fee;
+	}
+	public String getTotal_fee() {
+		return total_fee;
+	}
+	public void setTotal_fee(String total_fee) {
+		this.total_fee = total_fee;
+	}
+	public String getSettlement_total_fee() {
+		return settlement_total_fee;
+	}
+	public void setSettlement_total_fee(String settlement_total_fee) {
+		this.settlement_total_fee = settlement_total_fee;
+	}
+	public String getFee_type() {
+		return fee_type;
+	}
+	public void setFee_type(String fee_type) {
+		this.fee_type = fee_type;
+	}
+	public String getCash_fee() {
+		return cash_fee;
+	}
+	public void setCash_fee(String cash_fee) {
+		this.cash_fee = cash_fee;
+	}
+	public String getCash_refund_fee() {
+		return cash_refund_fee;
+	}
+	public void setCash_refund_fee(String cash_refund_fee) {
+		this.cash_refund_fee = cash_refund_fee;
+	}
+	
+	
+}

+ 4 - 3
dinner-core/src/main/java/com/fdage/base/service/impl/TmOrderServiceImpl.java

@@ -1,14 +1,14 @@
 package com.fdage.base.service.impl;
 package com.fdage.base.service.impl;
 
 
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.fdage.base.entity.TmOrder;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdage.base.dao.TmOrderDao;
 import com.fdage.base.dao.TmOrderDao;
+import com.fdage.base.entity.TmOrder;
 import com.fdage.base.enums.IdPreEnum;
 import com.fdage.base.enums.IdPreEnum;
 import com.fdage.base.service.ITmOrderService;
 import com.fdage.base.service.ITmOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdage.base.utils.DataUtils;
 import fdage.back.sdk.base.enums.ResultCodeEnum;
 import fdage.back.sdk.base.enums.ResultCodeEnum;
 import fdage.back.sdk.base.exception.CommonBaseException;
 import fdage.back.sdk.base.exception.CommonBaseException;
 import fdage.back.sdk.base.uuid.SnowFlakeUUidUtils;
 import fdage.back.sdk.base.uuid.SnowFlakeUUidUtils;
@@ -40,6 +40,7 @@ public class TmOrderServiceImpl extends ServiceImpl<TmOrderDao, TmOrder> impleme
             return tmOrder;
             return tmOrder;
         }
         }
         tmOrder.setId(SnowFlakeUUidUtils.generaUUid(null , null , IdPreEnum.ORDER_PRE.getPre()));
         tmOrder.setId(SnowFlakeUUidUtils.generaUUid(null , null , IdPreEnum.ORDER_PRE.getPre()));
+        tmOrder.setOrderNo(DataUtils.generateOrderNumber());
         tmOrder.setIsDelete(0);
         tmOrder.setIsDelete(0);
         tmOrder.setCreateTime(LocalDateTime.now());
         tmOrder.setCreateTime(LocalDateTime.now());
         tmOrder.setUpdateTime(LocalDateTime.now());
         tmOrder.setUpdateTime(LocalDateTime.now());

+ 29 - 0
dinner-core/src/main/java/com/fdage/base/utils/DataUtils.java

@@ -26,6 +26,7 @@ import java.net.ConnectException;
 import java.net.URL;
 import java.net.URL;
 import java.security.MessageDigest;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.*;
 
 
 import static com.google.zxing.client.j2se.MatrixToImageConfig.BLACK;
 import static com.google.zxing.client.j2se.MatrixToImageConfig.BLACK;
@@ -377,6 +378,34 @@ public class DataUtils {
         }
         }
     }
     }
 
 
+
+    /**
+     * 获取随机字符串
+     *
+     * @param num
+     * @return
+     */
+    public static String getRandomString(Integer num) {
+        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+        Random random = new Random();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < num; i++) {
+            int number = random.nextInt(base.length());
+            sb.append(base.charAt(number));
+        }
+        return sb.toString();
+    }
+
+    public static String timeToStr(Long time, String pattern) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
+        if (time.toString().length() < 13) {
+            time = time * 1000L;
+        }
+        Date date = new Date(time);
+        String value = dateFormat.format(date);
+        return value;
+    }
+
    /* public static void main(String[] args) throws Exception{
    /* public static void main(String[] args) throws Exception{
         createQRCode("https://www.4dkankan.com/spc.html?m=t-pnj0IJX", "C:/Users/4dage/Desktop/logo-file/t-pnj0IJX1.png", null);
         createQRCode("https://www.4dkankan.com/spc.html?m=t-pnj0IJX", "C:/Users/4dage/Desktop/logo-file/t-pnj0IJX1.png", null);
     }*/
     }*/

+ 29 - 0
dinner-core/src/main/java/com/fdage/base/utils/MD5.java

@@ -0,0 +1,29 @@
+package com.fdage.base.utils;
+
+import java.security.MessageDigest;
+
+public class MD5 {
+    private MD5() {
+    }
+
+    /*  * 生成 MD5
+  *
+          * @param data 待处理数据
+  * @return MD5结果
+  */
+    public static String getMessageDigest(String data) {
+        StringBuilder sb = new StringBuilder();
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] array = md.digest(data.getBytes("UTF-8"));
+
+            for (byte item : array) {
+                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+            }
+        } catch (Exception e) {
+            return null;
+        }
+        return sb.toString().toUpperCase();
+    }
+
+}

+ 45 - 0
dinner-core/src/main/java/com/fdage/base/utils/WechatConfig.java

@@ -0,0 +1,45 @@
+package com.fdage.base.utils;
+
+import fdage.back.sdk.utils.ResourceUtil;
+import lombok.extern.log4j.Log4j2;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContexts;
+
+import javax.net.ssl.SSLContext;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.KeyStore;
+
+@SuppressWarnings("deprecation")
+@Log4j2
+public class WechatConfig {
+
+    private static SSLConnectionSocketFactory sslcsf;
+
+    public static SSLConnectionSocketFactory getSslcsf() {
+        if (null == sslcsf) {
+            setSsslcsf();
+        }
+        return sslcsf;
+    }
+
+    private static void setSsslcsf() {
+        try {
+            KeyStore keyStore = KeyStore.getInstance("PKCS12");
+            Thread.currentThread().getContextClassLoader();
+            log.info("wx.certName:" + ResourceUtil.getConfigByName("wx.certName"));
+//            InputStream instream = new WechatRefundApiResult().getClass().getResourceAsStream(ResourceUtil.getConfigByName("wx.certName"));
+            InputStream instream = new FileInputStream(ResourceUtil.getConfigByName("wx.certName"));
+            try {
+                keyStore.load(instream, ResourceUtil.getConfigByName("wx.mchId").toCharArray());
+            } finally {
+                instream.close();
+            }
+            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, ResourceUtil.getConfigByName("wx.mchId").toCharArray()).build();
+            sslcsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+}

+ 295 - 0
dinner-core/src/main/java/com/fdage/base/utils/WechatUtil.java

@@ -0,0 +1,295 @@
+package com.fdage.base.utils;
+
+
+import com.fdage.base.dto.WechatRefundApiResult;
+import com.fdage.controller.app.MapUtils;
+import fdage.back.sdk.utils.ResourceUtil;
+import lombok.extern.log4j.Log4j2;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * <p>Title: 微信退款工具类</p>
+ * <p>Description: 微信退款工具类,通过充值客户端的不同初始化不同的工具类,得到相应微信退款相关的appid和muchid</p>
+ *
+ * @author xubo
+ * @date 2017年6月6日  下午5:05:03
+ */
+@Log4j2
+public class WechatUtil {
+    /**
+     * 充值客户端类型--微信公众号
+     */
+    public static Integer CLIENTTYPE_WX = 2;
+    /**
+     * 充值客户端类型--app
+     */
+    public static Integer CLIENTTYPE_APP = 1;
+
+    /**
+     * 方法描述:微信退款逻辑
+     * 创建时间:2017年4月12日  上午11:04:25
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    public static WechatRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
+        //初始化请求微信服务器的配置信息包括appid密钥等
+        //转换金钱格式
+        BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
+        BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
+        //构建请求参数
+        Map<Object, Object> params = buildRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        //请求微信
+        String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
+        WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
+        return result;
+    }
+
+    /**
+     * 方法描述:得到请求微信退款请求的参数
+     * 创建时间:2017年6月8日  上午11:27:02
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    private static Map<Object, Object> buildRequsetMapParam(String out_trade_no, BigDecimal bdOrderMoney, BigDecimal bdRefundMoney) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        //微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
+        //微信支付分配的商户号
+        params.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
+        //随机字符串,不长于32位。推荐随机数生成算法
+        params.put("nonce_str", DataUtils.getRandomString(16));
+        //商户侧传给微信的订单号
+        params.put("out_trade_no", out_trade_no);
+        //商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+        params.put("out_refund_no", getBundleId());
+        //订单总金额,单位为分,只能为整数
+        params.put("total_fee", bdOrderMoney.multiply(new BigDecimal(100)).intValue());
+        //退款总金额,订单总金额,单位为分,只能为整数
+        params.put("refund_fee", bdRefundMoney.multiply(new BigDecimal(100)).intValue());
+        //操作员帐号, 默认为商户号
+        params.put("op_user_id", ResourceUtil.getConfigByName("wx.mchId"));
+        //签名前必须要参数全部写在前面
+        params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
+        return params;
+    }
+
+    /**
+     * 请求微信https
+     **/
+    public static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
+        log.info("*******退款(WX Request:" + mapToXml);
+        HttpPost httPost = new HttpPost(ResourceUtil.getConfigByName("wx.refundUrl"));
+        httPost.addHeader("Connection", "keep-alive");
+        httPost.addHeader("Accept", "*/*");
+        httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
+        httPost.addHeader("Host", "api.mch.weixin.qq.com");
+        httPost.addHeader("X-Requested-With", "XMLHttpRequest");
+        httPost.addHeader("Cache-Control", "max-age=0");
+        httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
+        httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
+        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
+        CloseableHttpResponse response = null;
+        try {
+            response = httpClient.execute(httPost);
+            HttpEntity entity = response.getEntity();
+            String xmlStr = EntityUtils.toString(entity, "UTF-8");
+            log.info("*******退款(WX Response:" + xmlStr);
+            return xmlStr;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return null;
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+            }
+        }
+    }
+
+    /**
+     * 方法描述:微信查询退款逻辑
+     * 创建时间:2017年4月12日  上午11:04:25
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    public Map<String, Object> wxRefundquery(String out_trade_no, String out_refund_no) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        //微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
+        //微信支付分配的商户号
+        params.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
+        //随机字符串,不长于32位。推荐随机数生成算法
+        params.put("nonce_str", DataUtils.getRandomString(16));
+        //商户侧传给微信的订单号
+        params.put("out_trade_no", out_trade_no);
+        //签名前必须要参数全部写在前面
+        //签名
+        params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        HttpPost httPost = new HttpPost(ResourceUtil.getConfigByName("wx.refundqueryUrl"));
+        httPost.addHeader("Connection", "keep-alive");
+        httPost.addHeader("Accept", "*/*");
+        httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
+        httPost.addHeader("Host", "api.mch.weixin.qq.com");
+        httPost.addHeader("X-Requested-With", "XMLHttpRequest");
+        httPost.addHeader("Cache-Control", "max-age=0");
+        httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
+        httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
+        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(WechatConfig.getSslcsf()).build();
+        CloseableHttpResponse response = null;
+        try {
+            response = httpClient.execute(httPost);
+            HttpEntity entity = response.getEntity();
+            String xmlStr = EntityUtils.toString(entity, "UTF-8");
+            System.out.println(xmlStr);
+            Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
+            return result;
+            //将信息保存到数据库
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return null;
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+            }
+        }
+    }
+
+    /**
+     * 支付交易ID
+     */
+    public static String getBundleId() {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
+        String tradeno = dateFormat.format(new Date());
+        String str = "000000" + (int) (Math.random() * 1000000);
+        tradeno = tradeno + str.substring(str.length() - 6);
+        return tradeno;
+    }
+
+    /**
+     * 方法描述:根据签名加密请求参数
+     * 创建时间:2017年6月8日  上午11:28:52
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    public static String arraySign(Map<Object, Object> params, String paySignKey) {
+        boolean encode = false;
+        Set<Object> keysSet = params.keySet();
+        Object[] keys = keysSet.toArray();
+        Arrays.sort(keys);
+        StringBuffer temp = new StringBuffer();
+        boolean first = true;
+        for (Object key : keys) {
+            if (first) {
+                first = false;
+            } else {
+                temp.append("&");
+            }
+            temp.append(key).append("=");
+            Object value = params.get(key);
+            String valueString = "";
+            if (null != value) {
+                valueString = value.toString();
+            }
+            if (encode) {
+                try {
+                    temp.append(URLEncoder.encode(valueString, "UTF-8"));
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                temp.append(valueString);
+            }
+        }
+        temp.append("&key=");
+        temp.append(paySignKey);
+        System.out.println(temp.toString());
+        String packageSign = MD5.getMessageDigest(temp.toString());
+        return packageSign;
+    }
+
+    /**
+     * 请求,只请求一次,不做重试
+     *
+     * @param url
+     * @param data
+     * @return
+     * @throws Exception
+     */
+    public static String requestOnce(final String url, String data) throws Exception {
+        BasicHttpClientConnectionManager connManager;
+        connManager = new BasicHttpClientConnectionManager(
+                RegistryBuilder.<ConnectionSocketFactory>create()
+                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                        .register("https", SSLConnectionSocketFactory.getSocketFactory())
+                        .build(),
+                null,
+                null,
+                null
+        );
+
+        HttpClient httpClient = HttpClientBuilder.create()
+                .setConnectionManager(connManager)
+                .build();
+
+        HttpPost httpPost = new HttpPost(url);
+
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setSocketTimeout(5000)
+                .setConnectTimeout(5000)
+                .setConnectionRequestTimeout(10000).build();
+
+        httpPost.setConfig(requestConfig);
+
+        StringEntity postEntity = new StringEntity(data, "UTF-8");
+        httpPost.addHeader("Content-Type", "text/xml");
+        httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + ResourceUtil.getConfigByName("wx.mchId"));
+        httpPost.setEntity(postEntity);
+
+        HttpResponse httpResponse = httpClient.execute(httpPost);
+        HttpEntity httpEntity = httpResponse.getEntity();
+        String reusltObj = EntityUtils.toString(httpEntity, "UTF-8");
+        log.info("请求结果:" + reusltObj);
+        return reusltObj;
+
+    }
+}

+ 218 - 0
dinner-core/src/main/java/com/fdage/base/utils/XmlUtil.java

@@ -0,0 +1,218 @@
+package com.fdage.base.utils;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * xml相关的工具类
+ *
+ * @author yang.y
+ */
+@SuppressWarnings("unchecked")
+public class XmlUtil {
+
+    /**
+     * xml字符串转换成bean对象
+     *
+     * @param xmlStr xml字符串
+     * @param clazz  待转换的class
+     * @return 转换后的对象
+     */
+    public static Object xmlStrToBean(String xmlStr, Class clazz) {
+        Object obj = null;
+        try {
+            // 将xml格式的数据转换成Map对象
+            Map<String, Object> map = xmlStrToMap(xmlStr);
+            // 将map对象的数据转换成Bean对象
+            obj = mapToBean(map, clazz);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return obj;
+    }
+
+    /**
+     * 将xml格式的字符串转换成Map对象
+     *
+     * @param xmlStr xml格式的字符串
+     * @return Map对象
+     * @throws Exception 异常
+     */
+    public static Map<String, Object> xmlStrToMap(String xmlStr) throws Exception {
+        if (StringUtils.isBlank(xmlStr)) {
+            return null;
+        }
+        Map<String, Object> map = new HashMap<String, Object>();
+        // 将xml格式的字符串转换成Document对象
+        Document doc = DocumentHelper.parseText(xmlStr);
+        // 获取根节点
+        Element root = doc.getRootElement();
+        // 获取根节点下的所有元素
+        List children = root.elements();
+        // 循环所有子元素
+        if (children != null && children.size() > 0) {
+            for (int i = 0; i < children.size(); i++) {
+                Element child = (Element) children.get(i);
+                map.put(child.getName(), child.getTextTrim());
+            }
+        }
+        return map;
+    }
+
+    public static void main(String[] args) throws Exception{
+        Map<String, Object> map = xmlStrToMap("<xml><return_code><![CDATA[SUCCESS]]></return_code>\n" +
+                "<return_msg><![CDATA[OK]]></return_msg>\n" +
+                "<appid><![CDATA[wx0509bd21546d1597]]></appid>\n" +
+                "<mch_id><![CDATA[1501483501]]></mch_id>\n" +
+                "<nonce_str><![CDATA[FZNQslBCVpcicpZx]]></nonce_str>\n" +
+                "<sign><![CDATA[D56A50C381099F15AD0F0A8EB56FCA81]]></sign>\n" +
+                "<result_code><![CDATA[SUCCESS]]></result_code>\n" +
+                "<prepay_id><![CDATA[wx131759151998816835d218301267760400]]></prepay_id>\n" +
+                "<trade_type><![CDATA[JSAPI]]></trade_type>\n" +
+                "</xml>");
+
+        System.out.println(map.get("return_code"));
+    }
+
+    /**
+     * 将xml格式字符串转换成Bean对象
+     * 多级子节点递归遍历
+     *
+     * @param xmlStr
+     * @param clazz
+     * @return
+     * @throws Exception
+     */
+    public static Object xmlStrToJavaBean(String xmlStr, Class clazz) {
+        if (StringUtils.isBlank(xmlStr)) {
+            return null;
+        }
+        Object obj = null;
+        Map<String, Object> map = new HashMap<String, Object>();
+        // 将xml格式的字符串转换成Document对象
+        Document doc;
+        try {
+            doc = DocumentHelper.parseText(xmlStr);
+
+            // 获取根节点
+            Element root = doc.getRootElement();
+            map = elementToMap(root, map);
+            // 将map对象的数据转换成Bean对象
+            obj = mapToBean(map, clazz);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return obj;
+    }
+
+    /**
+     * 递归遍历xml子节点,转换Map
+     *
+     * @param element
+     * @param map
+     * @return
+     */
+    public static Map<String, Object> elementToMap(Element element, Map<String, Object> map) {
+        if (element == null || map == null){
+            return null;
+        }
+        List children = element.elements();
+        if (children != null && children.size() > 0) {
+            for (int i = 0; i < children.size(); i++) {
+                Element child = (Element) children.get(i);
+                if (child.elements() != null && child.elements().size() > 0){
+                    elementToMap(child, map);
+                }
+                else{
+                    map.put(child.getName(), child.getTextTrim());
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 将Map对象通过反射机制转换成Bean对象
+     *
+     * @param map   存放数据的map对象
+     * @param clazz 待转换的class
+     * @return 转换后的Bean对象
+     * @throws Exception 异常
+     */
+    public static Object mapToBean(Map<String, Object> map, Class clazz) throws Exception {
+        Object obj = clazz.newInstance();
+        if (map != null && map.size() > 0) {
+            for (Map.Entry<String, Object> entry : map.entrySet()) {
+                String propertyName = entry.getKey();
+                Object value = entry.getValue();
+                String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
+                Field field = getClassField(clazz, propertyName);
+                if (field != null) {
+                    Class fieldTypeClass = field.getType();
+                    value = convertValType(value, fieldTypeClass);
+                    clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
+                }
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * 将Object类型的值,转换成bean对象属性里对应的类型值
+     *
+     * @param value          Object对象值
+     * @param fieldTypeClass 属性的类型
+     * @return 转换后的值
+     */
+    private static Object convertValType(Object value, Class fieldTypeClass) {
+        Object retVal = null;
+        if (Long.class.getName().equals(fieldTypeClass.getName())
+                || long.class.getName().equals(fieldTypeClass.getName())) {
+            retVal = Long.parseLong(value.toString());
+        } else if (Integer.class.getName().equals(fieldTypeClass.getName())
+                || int.class.getName().equals(fieldTypeClass.getName())) {
+            retVal = Integer.parseInt(value.toString());
+        } else if (Float.class.getName().equals(fieldTypeClass.getName())
+                || float.class.getName().equals(fieldTypeClass.getName())) {
+            retVal = Float.parseFloat(value.toString());
+        } else if (Double.class.getName().equals(fieldTypeClass.getName())
+                || double.class.getName().equals(fieldTypeClass.getName())) {
+            retVal = Double.parseDouble(value.toString());
+        } else {
+            retVal = value;
+        }
+        return retVal;
+    }
+
+    /**
+     * 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
+     *
+     * @param clazz     指定的class
+     * @param fieldName 字段名称
+     * @return Field对象
+     */
+    private static Field getClassField(Class clazz, String fieldName) {
+        if (Object.class.getName().equals(clazz.getName())) {
+            return null;
+        }
+        Field[] declaredFields = clazz.getDeclaredFields();
+        for (Field field : declaredFields) {
+            if (field.getName().equals(fieldName)) {
+                return field;
+            }
+        }
+
+        Class superClass = clazz.getSuperclass();
+        if (superClass != null) {// 简单的递归一下
+            return getClassField(superClass, fieldName);
+        }
+        return null;
+    }
+}

+ 2 - 0
dinner-core/src/main/java/com/fdage/controller/app/AppOrderController.java

@@ -149,4 +149,6 @@ public class AppOrderController extends BaseController {
         return Result.success();
         return Result.success();
     }
     }
 
 
+
+
 }
 }

+ 147 - 0
dinner-core/src/main/java/com/fdage/controller/app/AppPayController.java

@@ -0,0 +1,147 @@
+package com.fdage.controller.app;
+
+import com.fdage.base.entity.TmOrder;
+import com.fdage.base.service.impl.TmOrderServiceImpl;
+import com.fdage.base.utils.DataUtils;
+import com.fdage.base.utils.WechatUtil;
+import com.fdage.base.utils.XmlUtil;
+import com.fdage.controller.BaseController;
+import fdage.back.sdk.base.entity.Result;
+import fdage.back.sdk.utils.ResourceUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 2 * @Author: Abner
+ * 3 * @Date: 2021/2/20 11:22
+ * 4
+ */
+@Api(tags = "支付相关接口")
+@RestController
+@RequestMapping("/app/pay")
+@Log4j2
+public class AppPayController extends BaseController {
+
+
+    @Autowired
+    private TmOrderServiceImpl tmOrderService;
+
+    /**
+     * 获取支付的请求参数
+     */
+    @ApiOperation(value = "获取支付的请求参数")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "orderId", value = "订单号", paramType = "query", required = true, dataType = "String")
+    })
+    @PostMapping("prepay")
+    public Object payPrepay(@RequestParam(name = "orderId") String orderId) {
+
+        if(null == orderId){
+            return Result.failure("缺失订单id");
+        }
+
+        //
+        TmOrder orderInfo = tmOrderService.getById(orderId);
+
+        if (null == orderInfo) {
+            return Result.failure("订单不存在");
+        }
+
+        if (orderInfo.getPayStatus() != 0 && orderInfo.getPayStatus() != 1) {
+            return Result.failure("订单已支付,请不要重复操作");
+        }
+
+        String nonceStr = DataUtils.getRandomString(32);
+
+        //https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
+        Map<Object, Object> resultObj = new TreeMap();
+
+        try {
+            Map<Object, Object> parame = new TreeMap<Object, Object>();
+            parame.put("appid", ResourceUtil.getConfigByName("wx.appId"));
+            // 商家账号。
+            parame.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
+            String randomStr = DataUtils.getRandomNum(18).toUpperCase();
+            // 随机字符串
+            parame.put("nonce_str", randomStr);
+            // 商户订单编号
+            parame.put("out_trade_no", orderInfo.getOrderNo());
+            log.info("out_trade_no:" + orderInfo.getOrderNo());
+            Map orderGoodsParam = new HashMap();
+            orderGoodsParam.put("order_id", orderId);
+            // 商品描述
+            parame.put("body", "电商-支付");
+            //parame.put("body", orderInfo.getOrderNo());
+            //支付金额,微信接口金额单位是分,我们系统的金额单位是元,因此这里需要乘以100
+            parame.put("total_fee", orderInfo.getOrderPrice().multiply(new BigDecimal(100)).intValue());
+            // 回调地址
+            parame.put("notify_url", ResourceUtil.getConfigByName("wx.notifyUrl"));
+            // 交易类型APP
+            parame.put("trade_type", ResourceUtil.getConfigByName("wx.tradeType"));
+            parame.put("spbill_create_ip", getClientIp());
+
+            parame.put("openid", getContextUserInfo().getWxOpenId());
+            String sign = WechatUtil.arraySign(parame, ResourceUtil.getConfigByName("wx.paySignKey"));
+            // 数字签证
+            parame.put("sign", sign);
+
+            String xml = MapUtils.convertMap2Xml(parame);
+            log.info("xml:" + xml);
+            Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(ResourceUtil.getConfigByName("wx.uniformorder"), xml));
+            // 响应报文
+            String return_code = MapUtils.getString("return_code", resultUn);
+            String return_msg = MapUtils.getString("return_msg", resultUn);
+            //
+            if (return_code.equalsIgnoreCase("FAIL")) {
+                return Result.failure("支付失败," + return_msg);
+            } else if (return_code.equalsIgnoreCase("SUCCESS")) {
+                // 返回数据
+                String result_code = MapUtils.getString("result_code", resultUn);
+                String err_code_des = MapUtils.getString("err_code_des", resultUn);
+                if (result_code.equalsIgnoreCase("FAIL")) {
+                    String err_code = MapUtils.getString("err_code", resultUn);
+                    if(StringUtils.equals(err_code , "ORDERPAID")){
+                        //已经支付成功,则
+                        orderInfo.setPayStatus(2);
+                        tmOrderService.updateById(orderInfo);
+                    }
+                    return Result.failure("支付失败," + err_code_des);
+                } else if (result_code.equalsIgnoreCase("SUCCESS")) {
+                    String prepay_id = MapUtils.getString("prepay_id", resultUn);
+                    // 先生成paySign 参考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
+                    resultObj.put("appId", ResourceUtil.getConfigByName("wx.appId"));
+                    resultObj.put("timeStamp", DataUtils.timeToStr(System.currentTimeMillis() / 1000, "yyyy-MM-dd HH:mm:ss"));
+                    resultObj.put("nonceStr", nonceStr);
+                    resultObj.put("package", "prepay_id=" + prepay_id);
+                    resultObj.put("signType", "MD5");
+                    String paySign = WechatUtil.arraySign(resultObj, ResourceUtil.getConfigByName("wx.paySignKey"));
+                    resultObj.put("paySign", paySign);
+                    // 业务处理
+                    orderInfo.setPayId(prepay_id);
+                    // 付款中
+                    orderInfo.setPayStatus(0);
+                    tmOrderService.updateById(orderInfo);
+                    return Result.success(resultObj);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return Result.failure("下单失败,error=" + e.getMessage());
+        }
+        return Result.failure("下单失败");
+    }
+}

+ 300 - 0
dinner-core/src/main/java/com/fdage/controller/app/MapUtils.java

@@ -0,0 +1,300 @@
+package com.fdage.controller.app;
+
+import org.apache.commons.beanutils.PropertyUtilsBean;
+import org.apache.commons.lang.ArrayUtils;
+import org.springframework.util.Assert;
+
+import java.beans.PropertyDescriptor;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 获取map中值的工具类,自动进行类型转换
+ *
+ * @author DT_panda
+ */
+public class MapUtils {
+
+    public static String getString(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        return value.toString();
+    }
+
+    public static Integer getInteger(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        if (value instanceof Integer)
+            return (Integer) value;
+        if (value instanceof String)
+            return Integer.valueOf((String) value);
+        //Date 不支持变成为date类型
+        if (value instanceof Date)
+            throw new ClassCastException();
+        if (value instanceof Number)
+            return ((Number) value).intValue();
+        throw new ClassCastException();
+    }
+
+    public static Long getLong(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        if (value instanceof Long)
+            return (Long) value;
+        if (value instanceof Number)
+            return ((Number) value).longValue();
+        if (value instanceof String)
+            return Long.valueOf((String) value);
+        if (value instanceof Date) {
+            return (((Date) value).getTime());
+        }
+        if (value instanceof java.sql.Time) {
+            return ((java.sql.Time) value).getTime();
+        }
+        if (value instanceof Timestamp) {
+            return ((Timestamp) value).getTime();
+        }
+
+        throw new ClassCastException();
+    }
+
+    public static Double getDouble(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        if (value instanceof Double)
+            return (Double) value;
+        if (value instanceof Number)
+            return ((Number) value).doubleValue();
+        if (value instanceof String)
+            return Double.valueOf((String) value);
+        throw new ClassCastException();
+    }
+
+    public static BigDecimal getBigDecimal(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        if (value instanceof BigDecimal)
+            return (BigDecimal) value;
+        if (value instanceof Integer)
+            return new BigDecimal((Integer) value);
+        if (value instanceof Short)
+            return new BigDecimal((Short) value);
+        if (value instanceof Byte)
+            return new BigDecimal((Byte) value);
+        if (value instanceof Long)
+            return new BigDecimal((Long) value);
+        if (value instanceof Float)
+            return new BigDecimal((Float) value);
+        if (value instanceof Double)
+            return new BigDecimal((Double) value);
+        if (value instanceof Date) {
+            return new BigDecimal(((Date) value).getTime());
+        }
+        if (value instanceof java.sql.Time) {
+            return new BigDecimal(((java.sql.Time) value).getTime());
+        }
+        if (value instanceof Timestamp) {
+            return new BigDecimal(((Timestamp) value).getTime());
+        }
+        if (value instanceof String) {
+            if (!StringUtils.isNullOrEmpty((String) value))
+                return new BigDecimal((String) value);
+            else
+                return null;
+        }
+        throw new ClassCastException();
+    }
+
+    /**
+     * 将bean转化为map
+     *
+     * @param bean
+     * @return
+     */
+    public static Map<String, Object> getMap(Object bean) {
+        return beanToMap(bean);
+    }
+
+    /**
+     * 将map中key为likeKey的value前后加上字符'%',用于like查询
+     *
+     * @param map
+     * @param likeKey
+     */
+    public static void toLikeValue(Map<String, Object> map, String... likeKey) {
+        if (ArrayUtils.isEmpty(likeKey))
+            return;
+        for (String key : likeKey) {
+            if (map.containsKey(key))
+                map.put(key, "%" + map.get(key) + "%");
+        }
+    }
+
+    /**
+     * 获取日期
+     *
+     * @param key
+     * @param map
+     * @return
+     */
+    public static Date getDate(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        else {
+            if (value instanceof Date) {
+                return (Date) value;
+            } else if (value instanceof Timestamp) {
+                return new Date(((Timestamp) value).getTime());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取日期
+     *
+     * @param key
+     * @param map
+     * @return
+     */
+    public static java.util.Date getTimestamp(String key, Map<String, Object> map) {
+        if (map == null || key == null)
+            throw new IllegalArgumentException();
+        if (!map.containsKey(key))
+            return null;
+        Object value = map.get(key);
+        if (value == null)
+            return null;
+        else {
+            if (value instanceof Date) {
+                return (Date) value;
+            } else if (value instanceof Timestamp) {
+                Timestamp ts = (Timestamp) value;
+                return ts;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 如果value不为空 ,则放到map中
+     *
+     * @param map
+     * @param key
+     * @param value
+     */
+    public static void putIfValueNotNull(Map<String, Object> map, String key, Object value) {
+        Assert.notNull(map);
+        Assert.hasText(key);
+        if (value != null)
+            map.put(key, value);
+    }
+
+    /**
+     * 如果value不为空 ,则放到map中
+     *
+     * @param map
+     * @param key
+     * @param value
+     */
+    public static void putIfValueNotEmpty(Map<String, Object> map, String key, String value) {
+        Assert.notNull(map);
+        Assert.hasText(key);
+        if (!StringUtils.isNullOrEmpty(value))
+            map.put(key, value);
+    }
+
+    /**
+     * 将map中指定的key的value值进行处理
+     *
+     * @param key
+     * @param map
+     * @param helper
+     */
+    public static void convertMapValuePattern(String key, Map<String, Object> map, DealMapValueHelper helper) {
+        Assert.hasText(key);
+        Assert.notNull(map);
+        Assert.notNull(helper);
+        helper.dealValue(key, map);
+    }
+
+    /**
+     * 将javabean实体类转为map类型,然后返回一个map类型的值
+     *
+     * @return
+     */
+    public static Map<String, Object> beanToMap(Object beanObj) {
+        Map<String, Object> params = new HashMap<String, Object>(0);
+        try {
+            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
+            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(beanObj);
+            for (int i = 0; i < descriptors.length; i++) {
+                String name = descriptors[i].getName();
+                if (!"class".equals(name)) {
+                    params.put(name, propertyUtilsBean.getNestedProperty(beanObj, name));
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return params;
+    }
+
+    public static String convertMap2Xml(Map<Object, Object> paraMap) {
+        StringBuffer xmlStr = new StringBuffer();
+        if (paraMap != null) {
+            xmlStr.append("<xml>");
+            Set<Object> keySet = paraMap.keySet();
+            Iterator<Object> keyIte = keySet.iterator();
+            while (keyIte.hasNext()) {
+                String key = (String) keyIte.next();
+                String val = String.valueOf(paraMap.get(key));
+                xmlStr.append("<");
+                xmlStr.append(key);
+                xmlStr.append(">");
+                xmlStr.append(val);
+                xmlStr.append("</");
+                xmlStr.append(key);
+                xmlStr.append(">");
+            }
+            xmlStr.append("</xml>");
+        }
+        return xmlStr.toString();
+    }
+}
+