微信支付一篇就够了(app,小程序,公众号)

目录

前言

介绍

代码

小结


前言

当前开发的主流项目涉及到实体商品,虚拟商品等付费服务的基本都会用到微信支付,本篇对于对接微信商户平台的三大主流支付方式的Java对接方式列举一下。

介绍

官方文档给到:

微信扫码支付:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

微信公众号支付:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

微信H5支付:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1

微信小程序支付:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1

微信官方提供了一套Java、.NET、PHP等三个版本的开发SDK

地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

其实这几种支付方式所调用api接口参数和方式都大同小异,详细的参数介绍可以直接访问官方文档查看,下面直接列实战代码复制即用。

代码

业务层代码

//上面可以写你的业务代码(一般在ServiceImpl层)
 String unifiedorder = WeiXinUtil.getUnifiedorder("用户openid", "商品名","支付金额", "订单号", "下单方式eg: xcx");// 统一下单
 Map<String, String> map = PayUtil.doXMLParse(unifiedorder);//解析xml转map
 SortedMap<Object, Object> param = WeiXinUtil.prepayIdApp(map);//调取支付,最后返回的param直接给到前端去拉取支付就可以了

工具类(官方给到的sdk里包含)

WeiXinUtil :

package com.ruoyi.web.jewelry.WxPay;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.ruoyi.web.util.AlipayConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.core.io.ClassPathResource;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.*;
import static com.ruoyi.web.jewelry.WxPay.PayUtil.mapToXml;
import static com.ruoyi.web.util.AlipayConstant.*;

/**
 * @Description 
 * @Author 
 * @Date 
 */
@Slf4j
public class WeiXinUtil {

    /**
     * 商户号
     */
    private final static String mchId = "";

    //p12文件地址
    public final static String certUrlPath = "";

    /**
     * @param openid
     * @param ProductName
     * @param money
     * @Description 
     * @Return java.lang.String
     * @Author 
     * @Date 
     **/

//    统一下单》》
    public static String getUnifiedorder(String openid, String ProductName, Double money, String OrderId , String FromType,Integer classType) throws Exception {
        System.out.println("FromType>;"+FromType);
        SortedMap<Object, Object> params = new TreeMap<>();
        if ("APP".equals(FromType)){
            params.put("appid","appid");//app id
        }else if ("XCX".equals(FromType)){
            params.put("appid", "xcxid");//小程序appid/app id
        }else if ("GZH".equals(FromType)){
            params.put("appid", GongzhonghaoappId);//公众号appid
        }
        params.put("body", ProductName);//商品名称
        params.put("mch_id", WXMerchantId);//商户mch_id
        params.put("nonce_str", PayUtil.makeUUID(32));//随机字符串
        //http://8.142.102.62:8083
        //http://8e049480514d.ngrok.io
        if (1==classType)
        params.put("notify_url","http://localhost:9099/huidiao");直购商品回调地址
       else
            params.put("notify_url","http://localhost:9099/huidiao");手续费回调地址

        System.out.println("走的回调地址:"+params.get("notify_url"));
        if ("XCX".equals(FromType)) {
            params.put("openid", openid);//微信用户唯一标识>>>小程序支付时必填
        }
        if ("GZH".equals(FromType)) {
            params.put("openid", openid);//微信用户唯一标识>>>公众号
        }
//        params.put("out_trade_no", PayUtil.generateOrderNo());//商品订单号
        params.put("out_trade_no", "WX_"+OrderId);//商品订单号
        params.put("spbill_create_ip", PayUtil.getLocalIp());//服务部署的ip
        params.put("total_fee", PayUtil.moneyToIntegerStr(money));//费用的参数转型
        if ("APP".equals(FromType)){
            params.put("trade_type", "APP");//对接类型
        }else{
            params.put("trade_type", "JSAPI");//对接类型
        }
        params.put("sign", PayUtil.createSign("UTF-8", params));//MD5签名   (传入key:商户密钥)
        //转换成xml
        String xmlData = PayUtil.getRequestXml(params);
        //请求微信后台,获取支付id
        System.out.println("xmlData:"+xmlData);
        String resXml = HttpUtil.doPost("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlData);
        return resXml;
    }

    //    小程序调取支付
    public static SortedMap<Object, Object> prepayId(Map<String, String> map) {
        System.out.println("小程序支付map》》:"+map);
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("appId","");//微信小程序appid
        parameters.put("timeStamp", PayUtil.create_timestamp());
        parameters.put("nonceStr", map.get("nonce_str"));
        parameters.put("package", "prepay_id=" + map.get("prepay_id"));
        parameters.put("signType", "MD5");
        String sign = PayUtil.createSign("UTF-8", parameters,"");//商户秘钥
        parameters.put("prepayId", map.get("prepay_id"));
        parameters.put("paySign", sign);
        parameters.put("resultCode", "SUCCESS");
        parameters.put("mchId","");//微信支付商户号
        return parameters;
    }
    public static SortedMap<Object, Object> GzhprepayId(Map<String, String> map) {
        System.out.println("公众号支付map》》:"+map);
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("appId",GongzhonghaoappId);//公众号appid
        parameters.put("timeStamp", PayUtil.create_timestamp());
        parameters.put("nonceStr", map.get("nonce_str"));
        parameters.put("package", "prepay_id=" + map.get("prepay_id"));
        parameters.put("signType", "MD5");
        String sign = PayUtil.createSign("UTF-8", parameters,WXMerchantSecret);//商户秘钥
        parameters.put("prepayId", map.get("prepay_id"));
        parameters.put("paySign", sign);
        parameters.put("resultCode", "SUCCESS");
        parameters.put("mchId",WXMerchantId);//微信支付商户号
        return parameters;
    }

    //    app调取支付
    public static SortedMap<Object, Object> prepayIdApp(Map<String, String> map) {
        System.out.println("map>>:"+map);
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("appid","");//微信appid
        parameters.put("partnerid", "");//微信支付商户号
        parameters.put("prepayid", map.get("prepay_id"));//预支付交易会话ID
        parameters.put("package", "Sign=WXPay");
        parameters.put("noncestr", map.get("nonce_str"));
        parameters.put("timestamp", PayUtil.create_timestamp());
        String sign = PayUtil.createSign("UTF-8", parameters);//商户秘钥
        System.out.println("map.get(\"prepay_id\")>>>"+map.get("prepay_id"));
        parameters.put("sign", sign);//签名
        return parameters;
    }


    /**
     * 验证回调签名
     *
     * @return
     */
    public static boolean isTenpaySign(Map<String, String> map) {
        String characterEncoding = "utf-8";
        String charset = "utf-8";
        String signFromAPIResponse = map.get("sign");
        if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
            System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
            return false;
        }
//        log.debug("服务器回包里面的签名是:" + signFromAPIResponse);
        //过滤空 设置 TreeMap
        SortedMap<String, String> packageParams = new TreeMap();

        for (String parameter : map.keySet()) {
            String parameterValue = map.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }

        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();

        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        // TODO: 2019/1/25 微信支付的key
        sb.append("key=" +WXMerchantSecret);

        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        //算出签名
        String resultSign = "";
        String tobesign = sb.toString();

        if (null == charset || "".equals(charset)) {
            resultSign = MD5Util.passmd5(tobesign).toUpperCase();
        } else {
            try {
                resultSign = MD5Util.passmd5(tobesign).toUpperCase();
            } catch (Exception e) {
                resultSign = MD5Util.passmd5(tobesign).toUpperCase();
            }
        }

        String tenpaySign = packageParams.get("sign").toUpperCase();
        return tenpaySign.equals(resultSign);
    }

    /**
     * @param request 微信返回request
     * @return String 通知微信
     * @MethodName: notifyWeiXinPay
     * @Description: 微信支付回调校验
     * @author 
     * @date 
     */
    public static Boolean notifyWeiXinPay(HttpServletRequest request) throws Exception {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        String resultXml = new String(outSteam.toByteArray(), "utf-8");
        Map<String, String> params = XMLUtil.parseMap(resultXml);
        outSteam.close();
        inStream.close();

        Map<String, String> return_data = new HashMap<>();
        if (!isTenpaySign(params)) {
            // 支付失败
            log.debug("支付回调校验失败==>{}", JSONObject.toJSONString(params));
            return false;
        }
        log.info("===============付款成功==============");
        return true;
    }

    /**
     * xml -> map
     *
     * @param strXML
     * @return
     * @throws Exception
     * @content 说明:
     * @auther 
     * @time 2020年8月15日 上午10:30:43
     * @git 
     * @filename 
     * @result Map<String, String>
     */
    private static Map<String, String> xmlToMap(String strXML) throws Exception {
        Map<String, String> data = new HashMap<String, String>();
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        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) {

        }
        return data;
    }

    /**
     * 微信退款  ->  https://api.mch.weixin.qq.com/secapi/pay/refund
     *
     * @param out_trade_no >>> 订单号
     * @param price        >>> 退款金额
     * @return true 调用成功 false 调用失败
     * @content 说明:
     * @auther 
     * @time 
     * @git 
     * @filename 
     * @result boolean
     */
    public static boolean payRefund(String out_trade_no, double price) {
        return payRefund(out_trade_no, price, null);
    }

    /**
     * 微信退款 ->  https://api.mch.weixin.qq.com/secapi/pay/refund
     *
     * @param out_trade_no >>> 订单号
     * @param price        >>> 退款金额
     * @param refund_desc  >>> 退款说明
     * @return true 调用成功 false 调用失败
     * @content 说明:
     * @auther 
     * @time 
     * @git
     * @filename 
     * @result boolean
     */
    public static boolean payRefund(String out_trade_no, double price, String refund_desc) {
        Map map = new HashMap<String, String>();
        map.put("appid", "");
        map.put("mch_id", "");
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        map.put("out_trade_no", out_trade_no);
        map.put("out_refund_no", out_trade_no);
        map.put("total_fee", ((int) (price * 100)) + "");
        map.put("refund_fee", ((int) (price * 100)) + "");
        if (refund_desc != null) {
            map.put("refund_desc", refund_desc);
        }
        try {
            map.put("sign", WXPayUtil.generateSignature(map, ""));
        } catch (Exception e) {
            System.out.println("签名错误!");
        }
        // https://api.mch.weixin.qq.com/secapi/pay/refund 申请退款
        try {
            CloseableHttpResponse response = Post("https://api.mch.weixin.qq.com/secapi/pay/refund", mapToXml(map));
            if (response != null) {
                /*String str = new String(response.getEntity().getContent().readAllBytes(), "utf-8");
                System.out.println(str);
                Map result = xmlToMap(str);
                if ("SUCCESS".equals(result.get("return_code"))) {
                    if ("SUCCESS".equals(result.get("result_code"))) {
                        return true;
                    }
                } else {
                    return false;
                }*/
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("请求错误");
        }
        return false;
    }

    private static CloseableHttpResponse Post(String url, String outputEntity) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(new StringEntity(outputEntity, "UTF-8"));
        if (certUrlPath != null) {
            // 加载含有证书的http请求
            return HttpClients.custom().setSSLSocketFactory(initCert()).build().execute(httpPost);
        } else {
            return HttpClients.custom().build().execute(httpPost);
        }
    }

    /**
     * 加载证书
     */
    private static SSLConnectionSocketFactory initCert() throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        ClassPathResource resource = new ClassPathResource(certUrlPath);
        keyStore.load(resource.getInputStream(), mchId.toCharArray());
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
        @SuppressWarnings("deprecation")
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        return sslsf;
    }

}

PayUtil :

package com.ruoyi.web.jewelry.WxPay;
import org.jdom2.input.SAXBuilder;
import org.springframework.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;
import static com.ruoyi.web.util.AlipayConstant.WXMerchantSecret;

/**
 * @Description 
 * @Author 
 * @Date 
 */
public class PayUtil {
    /**
     * 获取当前机器的ip
     */
    public static String getLocalIp() {
        InetAddress ia = null;
        String localip = null;
        try {
            ia = ia.getLocalHost();
            localip = ia.getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return localip;
    }
    @SuppressWarnings("rawtypes")
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }
    /**
     *  创建签名Sign
     */
    @SuppressWarnings("rawtypes")
    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
        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();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" +WXMerchantSecret);//最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }


    /**
     * 创建签名Sign
     */
    @SuppressWarnings("rawtypes")
    public static String createSign(String characterEncoding, SortedMap<Object, Object> 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 = MD5Util.encrypt(sb.toString()).toUpperCase();
        return sign;
    }

    /**
     * 生成随机数
     */
    public static String makeUUID(int len) {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
    }
    /**
     * 生成订单号
     */
    public static String generateOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        return sdf.format(new Date()) + makeUUID(16);
    }
    /**
     * 解析xml
     */
    public static Map doXMLParse(String strxml) throws Exception {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        org.jdom2.Document doc = builder.build(in);
        org.jdom2.Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            org.jdom2.Element e = (org.jdom2.Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            m.put(k, v);
        }
        //关闭流
        in.close();
        return m;
    }
    /**
     * 获取子节点的xml
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                org.jdom2.Element e = (org.jdom2.Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }
    /**
     * 转换金额到整型
     */
    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);
    }
    /**
     * 微信下单,map to xml
     * @param params 参数
     * @return String
     */
    public static String mapToXml(Map<String, String> params) {
        StringBuilder xml = new StringBuilder();
        xml.append("<xml>");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key   = entry.getKey();
            String value = entry.getValue();
            // 略过空值
            if (StringUtils.isEmpty(value)) continue;
            xml.append("<").append(key).append("><![CDATA[");
            xml.append(entry.getValue());
            xml.append("]]></").append(key).append(">");
        }
        xml.append("</xml>");
        return xml.toString();
    }

    public static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

}
HttpUtil:
package com.ruoyi.web.jewelry.WxPay;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * HTTP请求工具类,用于处理HTTP请求
 *
 * @author 
 *
 */
public class HttpUtil {

	// 连接超时时间,默认10秒
	private int socketTimeout = 10000;
	// 传输超时时间,默认30秒
	private int connectTimeout = 30000;
	// HTTP请求器
	private static CloseableHttpClient httpClient;
	// 请求器的配置
	private static RequestConfig requestConfig;

	/**
	 * 连接超时
	 */
	private static int TIME_OUT = 5000;

	/**
	 * 读取数据超时
	 */
	private static int READ_OUT = 10000;

	/**
	 * 请求编码
	 */
	private static String ENCODING = "UTF-8";

	// private static Logger logger = Logger.getLogger(HttpUtil.class);
	/**
	 *
	 * @Title: HttpRecevie @author: LYQ @Description:
	 * 根据当前的请求对象,获得请求里的数据流 @Createtime: Sep 17, 2012 @param @param request
	 * 当前请求的对象 @param @return 设定文件 @return String 返回类型 @throws
	 */
	public static String HttpRecevie(HttpServletRequest request) {
		String re = null;
		try {
			// 读取请求内容
			BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
			String line = null;
			StringBuilder sb = new StringBuilder();
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			re = sb.toString();
			/***
			 * 注:以下代码是在action中必须写的。否则返回的数据可能有乱码
			 */
			// response.setCharacterEncoding("UTF-8");
			// response.setContentType("text/html;charset=UTF-8");
			// PrintWriter writer = response.getWriter();
			// String a = "你好";
			// writer.write(("{\"result\":" + a + "}"));
		} catch (IOException e) {
			System.err.println("HttpClientUtils:根据请求对象获取改请求对象里的内容出错:" + e.getMessage());
			return null;
		}
		return re;
	}

	/**
	 * @Title: HttpClientPost @author: LYQ @Description:
	 * 根据发送地址发送json数据到某一个url路径 @Createtime: Sep 17, 2012 @param @param url
	 * 访问路径 @param @param json 传递的json @param @return 设定文件 @return String
	 * 返回类型 @throws
	 */
	public static String HttpClientPost(String url, String json) {
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);
		StringBuilder result = new StringBuilder();
		try {
			StringEntity s = new StringEntity(json, "application/x-www-form-urlencoded", "UTF-8");
			s.setContentType("application/x-www-form-urlencoded");
			post.setEntity(s);
			HttpResponse res = client.execute(post);
			if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				Header[] headers = res.getAllHeaders();
				HttpEntity entity = res.getEntity();
				Header header = res.getFirstHeader("content-type");
				// 读取服务器返回的json数据(接受json服务器数据)
				InputStream inputStream = entity.getContent();
				InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
				BufferedReader reader = new BufferedReader(inputStreamReader);// 读字符串用的。
				String content = "";
				while (((content = reader.readLine()) != null)) {
					result.append(content);
				}
				// 关闭输入流
				reader.close();
			}
		} catch (Exception e) {
			System.err.println("HttpClientUtils:根据地址发送json数据出错:" + e.getMessage());
			e.printStackTrace();
			return null;
		}
		return result.toString();
	}

	/**
	 *
	 * @Title: HttpRequest @author: LYQ @Description:
	 * 这里用一句话描述这个方法的作用 @Createtime: Sep 17, 2012 @param @param
	 * reqUrl @param @param parameters @param @param recvEncoding @param @return
	 * 设定文件 @return String 返回类型 @throws
	 */
	public static String HttpRequest(String reqUrl, Map parameters, String recvEncoding, String methodType) {
		HttpURLConnection urlConnection = null;
		String responseContent = null;
		InputStream in = null;
		BufferedReader rd = null;
		try {
			StringBuffer params = new StringBuffer();
			if (parameters != null) {
				for (Iterator iter = parameters.entrySet().iterator(); iter.hasNext();) {
					Entry element = (Entry) iter.next();
					params.append(element.getKey().toString());
					params.append("=");
					params.append(URLEncoder.encode(element.getValue().toString(), HttpUtil.ENCODING));
					params.append("&");
				}
				if (params.length() > 0) {
					params = params.deleteCharAt(params.length() - 1);
				}
			}

			URL url = new URL(reqUrl);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.setRequestMethod(methodType); // GET POST
			urlConnection.setConnectTimeout(HttpUtil.TIME_OUT);// (单位:毫秒)
			urlConnection.setReadTimeout(HttpUtil.READ_OUT);// (单位:毫秒)
			urlConnection.setDoOutput(true);
			byte[] b = params.toString().getBytes();
			urlConnection.getOutputStream().write(b, 0, b.length);
			urlConnection.getOutputStream().flush();
			urlConnection.getOutputStream().close();

			in = urlConnection.getInputStream();
			rd = new BufferedReader(new InputStreamReader(in, recvEncoding));
			String tempLine = rd.readLine();
			StringBuffer temp = new StringBuffer();
			String crlf = System.getProperty("line.separator");
			while (tempLine != null) {
				temp.append(tempLine);
				temp.append(crlf);
				tempLine = rd.readLine();
			}
			responseContent = temp.toString();
			rd.close();
			in.close();
		} catch (IOException e) {
			System.out.println("HttpRequest:根据地址以post或者get方式携带参数请求出错:" + e.getMessage());
			responseContent = "";
		} finally {
			if (urlConnection != null) {
				urlConnection.disconnect();
			}
			try {
				if (in != null) {
					in.close();
				}
				if (rd != null) {
					rd.close();
				}
			} catch (IOException e) {
				responseContent = "";
			}
		}
		return responseContent;
	}

	/**
	 * @Title: HttpSend @author: LYQ @Description:
	 * 通过想指定地址发送xml,并收获返回的数据。 @Createtime: Sep 17, 2012 @param @param reqUrl
	 * 指定路径 @param @param xml 指定发送xml @param @return 设定文件 @return String
	 * 返回类型 @throws
	 */
	public static String HttpSend(String reqUrl, String xml) {
		String rel = "";
		try {
			URL my_url = new URL(reqUrl);
			URLConnection con = my_url.openConnection();
			con.setReadTimeout(HttpUtil.READ_OUT);
			con.setConnectTimeout(HttpUtil.TIME_OUT);
			con.setDoOutput(true);
			con.setRequestProperty("Pragma:", "no-cache");
			con.setRequestProperty("Cache-Control", "no-cache");
			con.setRequestProperty("Content-Type", "text/xml");
			OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
			out.write(new String(xml.getBytes("ISO-8859-1")));
			out.flush();
			out.close();
			BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
			StringBuffer result = new StringBuffer("");
			for (String line = br.readLine(); line != null; line = br.readLine()) {
				result.append(line);
			}
			rel = result.toString();
		} catch (Exception ex) {
			System.err.println("HttpSend:发送xml到指定目录出错:" + ex.getMessage());
			return null;
		}
		return rel;
	}

	/**
	 * @Title: HttpUrl @author: LYQ @Description:
	 * 根据url路径求情然后获取返回值,最简单的url请求。 @Createtime: Sep 17, 2012 @param @param url
	 * 请求路径 @param @param ecode 解析字符集 @param @return 设定文件 @return String
	 * 返回类型 @throws
	 */
	public static String HttpUrl(String url, String ecode) {
		StringBuffer ret = new StringBuffer();
		try {
			URL getUrl = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
			InputStream in = connection.getInputStream();
			connection.connect();
			BufferedReader reader = new BufferedReader(new InputStreamReader(in, ecode));
			String lines;
			while ((lines = reader.readLine()) != null) {
				ret.append(lines);
			}
			reader.close();
			connection.disconnect();
		} catch (Exception e) {
			System.err.println("HttpUrl:根据url路径请求地址出错:" + e.getMessage());
			return null;
		}
		return ret.toString();
	}
	/**
	 * 发送get请求
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public static String GetJson(String url) throws IOException {
		JSONObject jsonObject=null;
		DefaultHttpClient defaultHttpClient=new DefaultHttpClient();
		HttpGet httpGet=new HttpGet(url);
		HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
		HttpEntity httpEntity=httpResponse.getEntity();
		String result = "";
		if(httpEntity!=null){
			result= EntityUtils.toString(httpEntity,"UTF-8");
			//jsonObject=new JSONObject(result);
		}
		httpGet.releaseConnection();
		return result;
	}
	public static int getTIME_OUT() {
		return TIME_OUT;
	}

	public static void setTIME_OUT(int time_out) {
		TIME_OUT = time_out;
	}

	public static int getREAD_OUT() {
		return READ_OUT;
	}

	public static void setREAD_OUT(int read_out) {
		READ_OUT = read_out;
	}

	public static String getENCODING() {
		return ENCODING;
	}

	public static void setENCODING(String encoding) {
		ENCODING = encoding;
	}

	public static String requestCheckUpdateJson(String adress_Http) {
		String returnLine = "";
		try {
			URL my_url = new URL(adress_Http);
			HttpURLConnection connection = (HttpURLConnection) my_url.openConnection();
			connection.setConnectTimeout(1000 * 20);
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setRequestMethod("GET");
			connection.setUseCaches(false);
			connection.setInstanceFollowRedirects(true);
			connection.setRequestProperty("Content-Type", "application/json");
			connection.connect();
			BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
			String line = "";
			while ((line = reader.readLine()) != null) {
				returnLine += line;
			}
			reader.close();
			connection.disconnect();
			System.out.println("========返回的结果的为========" + returnLine);
		} catch (Exception e) {
			returnLine = "";
			System.out.println(e.getMessage());
		}
		return returnLine;
	}

	/**
	 * 向指定 URL 发送POST方法的请求
	 *
	 * @param url
	 *            发送请求的 URL
	 * @param param
	 *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
	 * @return 所代表远程资源的响应结果
	 */
	public static String sendPost(String url, String param) {
		PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			// 设置通用的请求属性

			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            // 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
			// 发送请求参数
			out.print(param);
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * 发送post请求
	 *
	 * @param @param
	 *            url
	 * @param @param
	 *            param
	 * @return void
	 * @throws 
	 *             
	 * @date 
	 */
	public static String doPost(String url, String param) {
		StringBuilder sb = new StringBuilder();
		InputStream is = null;
		BufferedReader br = null;
		PrintWriter out = null;
		try {
			URL uri = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) uri.openConnection();
			connection.setRequestMethod("POST");
			connection.setReadTimeout(5000);
			connection.setConnectTimeout(10000);
			connection.setRequestProperty("accept", "*/*");
//            connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            // 发送参数
			connection.setDoOutput(true);
			out = new PrintWriter(connection.getOutputStream());
			out.print(param);
			out.flush();
			// 接收结果
			is = connection.getInputStream();
			br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			String line;
			// 缓冲逐行读取
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			// System.out.println(sb.toString());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭流
			try {
				if (is != null) {
					is.close();
				}
				if (br != null) {
					br.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sb.toString();
	}

	/**
	 * 向指定URL发送GET方法的请求
	 *
	 * @param url
	 *            发送请求的URL
	 * @param param
	 *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
	 * @return URL 所代表远程资源的响应结果
	 */
	public static String sendGet(String url, String param) {
		String result = "";
		BufferedReader in = null;
		try {
			String urlNameString = url + "?" + param;
			URL realUrl = new URL(urlNameString);
			// 打开和URL之间的连接
			URLConnection connection = realUrl.openConnection();
			// 设置通用的请求属性
			connection.setRequestProperty("accept", "*/*");
			connection.setRequestProperty("connection", "Keep-Alive");
			connection.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			// 建立实际的连接
			connection.connect();
			// 获取所有响应头字段
			Map<String, List<String>> map = connection.getHeaderFields();
			// 遍历所有的响应头字段
			for (String key : map.keySet()) {
				System.out.println(key + "--->" + map.get(key));
			}
			// 定义 BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new InputStreamReader(
					connection.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			System.out.println("发送GET请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输入流
		finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		return result;
	}

	/**
	 *
	 * @param content
	 * @param url
	 * @param contentType
	 * @return
	 * @throws IOException
	 */
	public static String doPost(String content, String url, String contentType) throws IOException {
		StringBuilder result = new StringBuilder();
		URL postUrl = new URL(url);
		URLConnection con = postUrl.openConnection();
		con.setConnectTimeout(3000);
		con.setDoOutput(true);
		con.setRequestProperty("Pragma", "no-cache");
		con.setRequestProperty("Cache-Control", "no-cache");
		if (contentType != null) {
			con.setRequestProperty("Content-Type", contentType);
		}
		OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
		out.write(new String(content.getBytes("UTF-8")));
		out.flush();
		out.close();
		BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
		String line = "";
		for (line = br.readLine(); line != null; line = br.readLine()) {
			result = result.append(line);
		}
		return result.toString();
	}

}
MD5Util:
package com.ruoyi.web.jewelry.WxPay;
import lombok.extern.slf4j.Slf4j;
import java.security.MessageDigest;
/**
* @Description TODO  MD5加密工具类
* @param null
* @Return
* @Author 
* @Date 
**/
@Slf4j
public class MD5Util {
    public final static String encrypt(String s) {
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            log.error("generate md5 error, {}", s, e);
            return null;
        }
    }
    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };


    public static String passmd5(String source) {
        StringBuffer sb = new StringBuffer(32);
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(source.getBytes("utf-8"));

            for (int i = 0; i < array.length; i++) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
            }
        } catch (Exception e) {
            return null;
        }
        return sb.toString();
    }

    /**
     * 加密解密算法 执行一次加密,两次解密
     */
    public static String convertMD5(String inStr){

        char[] a = inStr.toCharArray();
        for (int i = 0; i < a.length; i++){
            a[i] = (char) (a[i] ^ 't');
        }
        String s = new String(a);
        return s;

    }

    public static void main(String[] args) {
        System.out.println(MD5Util.passmd5("987654321"));
    }

}
XMLUtil:
package com.ruoyi.web.jewelry.WxPay;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author
 */
public class XMLUtil {

    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     *
     * @param strxml
     *
     * @return
     *
     * @throws JDOMException
     * @throws IOException
     */

    public static Map<String, String> parseMap(String strxml)
            throws JDOMException, IOException {
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        strxml=strxml.trim();
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
//        System.out.println("strxml:"+strxml);
        SortedMap<String, String> m = new TreeMap<String, String>();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
//        System.out.println("in:"+in);
        Document doc = builder.build(in);
//        System.out.println("doc:"+doc);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = XMLUtil.getChildrenText(children);
            }

            m.put(k, v);
        }
        // 关闭流

        in.close();
        return m;
    }

    /**
     * 获取子结点的xml
     *
     * @param children
     *
     * @return String
     */

    private static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(XMLUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }

    /**
     * 输出XML
     *
     * @param parameters
     *
     * @return
     */
    public static String parseXML(SortedMap parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"appkey".equals(k)) {
                sb.append("<" + k + ">" + v + "</" + k + ">\n");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 把map里的内容转成xml字符串
     *
     * @param param xml的map
     *
     * @return xml字符串
     */
    public static String GetMapToXML(Map<String, String> param) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : param.entrySet()) {
            sb.append("<" + entry.getKey() + ">");
            sb.append(entry.getValue());
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

}

其中用的的openid 分别来自:公众号:公众号授权获得(前端通过h5访问提供的地址去获取code给到后端去获取openid),小程序:小程序微信授权获得(前端授权code给到后端去获取openid),app:app微信授权获得(前端可以直接获取)这些获取openid的方式可以自行百度。

回调:

拉取完支付后微信官方回通过下单时填写的回调地址去调用接口,来实现一些支付成功后需要处理的需求逻辑。

//支付回调接口》》目的就是截取出来订单号 从而获取订单信息来操作后续逻辑 
public String weixinCallback(HttpServletRequest request) throws Exception {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        String resultXml = new String(outSteam.toByteArray(), "utf-8");
        Map<String, String> params = XMLUtil.parseMap(resultXml);
        outSteam.close();
        inStream.close();
        Map<String, String> return_data = new HashMap<>();
        if (!WeiXinUtil.isTenpaySign(params)) {
            // 支付失败
            System.err.println("支付回调校验失败==>" + JSONObject.toJSONString(params));
            return_data.put("return_code", "FAIL");
            return_data.put("return_msg", "return_code不正确");
            System.err.println("返回参数:" + XMLUtil.GetMapToXML(return_data));
            return XMLUtil.GetMapToXML(return_data);
        }
        System.err.println("===============付款成功==============");
        String regEx = "[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(params.get("out_trade_no"));
        System.out.println("out_trade_no" + m.replaceAll("").trim());
        String out_trade_no = m.replaceAll("").trim(); //TODO 这个就是订单号

//TODO 注意处理完业务要做到return 返回给到微信 不然会一直请求这个接口好几次
成功返回:
        return_data.put("return_code", "SUCCESS");
        return_data.put("return_msg", "OK");
        System.err.println("返回参数:" + XMLUtil.GetMapToXML(return_data));
        return XMLUtil.GetMapToXML(return_data);

小结

通常按照开发文档开发后运行还是报error多半是粗心导致 可能是参数错误,格式错误 ,确实没有按照官方文档来等等。没有那么多“灵异事件”,更多的是确实是自己错了。

附:要学会复盘能力,从失败中反思自己,使得下次躲掉坑。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值