微信第三方支付接口java調用詳細文檔


1.顯示支付二維碼

  1. 支付流程
    首先用戶選好商品后
    跳到結算頁面

在點擊支付提交時應先將表單的數據保存到數據庫(一般都會有訂單表一二級)
經過后台保存數據后再轉發到前台(二維碼是后台調用微信生成的)
看到掃碼頁面

當用戶掃碼成功后 更改訂單狀態為已支付(一般情況 根據業務定)

開始
首先第一步

  1. 當用戶選好商品后 點擊 支付按鈕時發送一個請求到后台控制層

讓后跳到掃碼頁面顯示商品信息頁面

這個頁面應該有一個標簽

<img src=”請求的控制類地址” />

注意下面寫的方法 就是輸出一個二維碼
跳到二維碼頁面img標簽會去訪問src這個路徑方法
讓后開始准備

一般會吧微信支付用到的參數封裝成一個類,或者properties,xml,yml等等這樣的文件(在企業中基本都是后者)這里使用類 方便一些
在這里插入圖片描述
導入要使用的jar包和工具類
在這里插入圖片描述
在這里插入圖片描述
在控制類中加入以下幾個工具方法(也可以封裝成工具類)

/** * 獲取本機IP地址 * @return IP */
	private static String getRemortIP(HttpServletRequest request) {  
        if (request.getHeader("x-forwarded-for") == null) {  
            return request.getRemoteAddr();  
        }  
        return request.getHeader("x-forwarded-for");  
    }


/** * 微信支付簽名算法sign */
    private String getSign(Map<String,Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + WeixinPayConfig.key);
        String sign = Md5Util.string2MD5(sb.toString());
        return sign;
    }
    

/** * 通過返回IO流獲取支付地址 * @param in * @return */
	private String getElementValue(InputStream in,String key){
		SAXReader reader = new SAXReader();
        Document document=null;
		try {
			document = reader.read(in);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        Element root = document.getRootElement();
        List<Element> childElements = root.elements();
        for (Element child : childElements) {
        	System.out.println(child.getName()+":"+child.getStringValue());
        	if(key.equals(child.getName())){
        		return child.getStringValue();
        	}
        }
        return null;
	}
	

/** * 類型轉換 * @author chenp * @param matrix * @return */  
	 public static BufferedImage toBufferedImage(BitMatrix matrix) {  
      int width = matrix.getWidth();  
      int height = matrix.getHeight();  
      BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);  
      for (int x = 0; x < width; x++) {  
          for (int y = 0; y < height; y++) {  
              image.setRGB(x, y, matrix.get(x, y) == true ? 0xff000000 : 0xFFFFFFFF);  
          }  
      }  
      return image;  
	 }
	

以上方法都要用到 可以封住成一個工具類 由於是演示這里直接放在當前類中了

上面這些弄完后就可以開工了

  1. 首先要測試參數
  2. 把剛剛復制的 通過返回IO流獲取支付地址getElementValue這個方法里的代碼注掉

在這里插入圖片描述

請求的方法里面 有如下代碼

		 String orderNo=DateUtil.getCurrentDateStr(); // 生成訂單號(由項目定)
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID(配置文件里的屬性)
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號(配置文件里的屬性)
		map.put("device_info", WeixinPayConfig.device_info); // 設備號(配置文件里的屬性)
		map.put("notify_url", WeixinPayConfig.notify_url); // 異步通知地址(配置文件里的屬性)
		map.put("trade_type", "NATIVE"); // 交易類型(表示掃碼支付 詳情看微信公眾平台)
		map.put("out_trade_no", orderNo); // 商戶訂單號(由項目定)
		map.put("body", "測試商品"); // 商品描述(由項目定)
		map.put("total_fee", 100); // 標價金額(單位 '分')
		// map.put("spbill_create_ip", getRemortIP(request)); // 終端IP(正式環境下用)
		map.put("spbill_create_ip", "127.0.0.1"); // 終端IP(測試環境)
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串(StringUtil工具類提供)
		map.put("sign", getSign(map)); // 簽名(同類中的getSign方法提供)
		String xml=XmlUtil.genXml(map); //發送xml (XmlUtil工具類提供)
		System.out.println(xml);
		// 發現xml消息(由httpclient-4.5.2.jar,httpcore-4.4.9.jar提供)
		InputStream in=HttpClientUtil.sendXMLDataByPost(WeixinPayConfig.url, xml).getEntity().getContent(); 
		String code_url=getElementValue(in,""); // 獲取二維碼地址(同類中的getElementValue方法提供)
		```

讓后測試看到下面這段就說明成功了(控制台)
在這里插入圖片描述
如果錯誤了可以看一下錯誤原因

成功后在將getElementValue方法里剛剛注掉的代碼解注
在這里插入圖片描述

然后在訪問的方法里繼續添加代碼
在這里插入圖片描述

String orderNo=DateUtil.getCurrentDateStr(); // 生成訂單號(由項目定)
   	Map<String,Object> map=new HashMap<String,Object>();
   	map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID(配置文件里的屬性)
   	map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號(配置文件里的屬性)
   	map.put("device_info", WeixinPayConfig.device_info); // 設備號(配置文件里的屬性)
   	map.put("notify_url", WeixinPayConfig.notify_url); // 異步通知地址(配置文件里的屬性)
   	map.put("trade_type", "NATIVE"); // 交易類型(表示掃碼支付 詳情看微信公眾平台)
   	map.put("out_trade_no", orderNo); // 商戶訂單號(由項目定)
   	map.put("body", "測試商品"); // 商品描述(由項目定)
   	map.put("total_fee", 100); // 標價金額(單位 '分')
   	// map.put("spbill_create_ip", getRemortIP(request)); // 終端IP(正式環境下用)
   	map.put("spbill_create_ip", "127.0.0.1"); // 終端IP(測試環境)
   	map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串(StringUtil工具類提供)
   	map.put("sign", getSign(map)); // 簽名(同類中的getSign方法提供)
   	String xml=XmlUtil.genXml(map); //發送xml (XmlUtil工具類提供)
   	System.out.println(xml);
   	// 發現xml消息(由httpclient-4.5.2.jar,httpcore-4.4.9.jar提供)
   	InputStream in=HttpClientUtil.sendXMLDataByPost(WeixinPayConfig.url, xml).getEntity().getContent(); 
   	String code_url=getElementValue(in,"code_url"); // 獲取二維碼地址(同類中的getElementValue方法提供)
   	MultiFormatWriter multiFormatWriter = new MultiFormatWriter();  
       Map hints = new HashMap();  
       BitMatrix bitMatrix = null;  
       try {  
            bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 250, 250,hints);  
            BufferedImage image = toBufferedImage(bitMatrix);  
            //輸出二維碼圖片流 
            ImageIO.write(image, "png", response.getOutputStream());  
   	 } catch (WriterException e1) {  
   		 e1.printStackTrace();  
   	 }  

完成后 測試一下

出現二維碼就說明成功了
在這里插入圖片描述

2.異步請求處理

在1中生成的二維碼,用戶掃描支付后 將會調用公眾平台設置的回調地址
接下來根據回調地址來寫方法

然后先是拷貝方法 根1一樣 封住成工具類或者放在本類

/** * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。 * @return boolean */    
    public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {    
        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 + "&");    
            }    
        }    
        sb.append("key=" + API_KEY);    
            
        //算出摘要 
        String mysign = Md5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();    
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();    
            
        return tenpaySign.equals(mysign);    
    }  

然后回調地址的方法里寫

//讀取參數 
        InputStream inputStream ;    
        StringBuffer sb = new StringBuffer();    
        inputStream = req.getInputStream();    
        String s ;    
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));    
        while ((s = in.readLine()) != null){    
            sb.append(s);    
        }    
        in.close();    
        inputStream.close();  
        System.out.println("sb:"+sb.toString());
        
        //解析xml成map 
        Map<String, String> m = new HashMap<String, String>();    
        try {
			m = XmlUtil.doXMLParse(sb.toString());
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}    
            
        //過濾空 設置 TreeMap 
        SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();          
        Iterator<String> it = m.keySet().iterator();    
        while (it.hasNext()) {    
            String parameter = it.next();    
            String parameterValue = m.get(parameter);    
                
            String v = "";    
            if(null != parameterValue) {    
                v = parameterValue.trim();    
            } 
            packageParams.put(parameter, v);    
        }  
        
        // 微信支付的API密鑰 
        String key = WeixinPayConfig.key;
        
        if(isTenpaySign("UTF-8", packageParams, key)){ // 驗證通過
        	if("SUCCESS".equals((String)packageParams.get("result_code"))){  
        		System.out.println("驗證通過");
        	}else{
        		System.out.println("支付失敗");
        	}
        }else{
        	System.out.println("驗證未通過");
        }

在驗證通過后更改 訂單的狀態 為已支付

在編寫根據訂單查詢訂單狀態的方法
在二維碼頁面每隔多少秒就調用一次查看狀態
若為已支付狀態就可以跳轉頁面了

3.HTML在線支付

環境准備
加入
HMACSHA256Uitl.java 工具類

接口調用url
private static String url="https://api.mch.weixin.qq.com/pay/downloadfundflow";
使用到的工具方法

/** * 微信支付簽名算法sign */
    private static String getSign(Map<String,Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + WeixinPayConfig.key);
        // String sign = Md5Util.string2MD5(sb.toString());
        String sign=HMACSHA256Uitl.HMACSHA256(sb.toString().getBytes(), WeixinPayConfig.key.getBytes());
        return sign;
    }

然后編寫方法 因為是測試 這里使用的是main 實際根據業務更改

public static void main(String[] args) throws UnsupportedOperationException, ClientProtocolException, IOException {
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串
		map.put("bill_date", "20180419"); // 資金賬單日期
		map.put("account_type", "Basic"); // 資金賬戶類型
		map.put("sign", getSign(map)); // 簽名
		String xml=XmlUtil.genXml(map); 
		System.out.println(xml);
		InputStream in=HttpClientUtil.sendXMLDataByHttpsPost(url, xml).getEntity().getContent(); // 發現xml消息
		StringBuffer out=new StringBuffer();
		byte []b=new byte[4096];
		for(int n;(n=in.read(b))!=-1;){
			out.append(new String(b,0,n));
		}
		System.out.println(out.toString());
	}

運行結果
在這里插入圖片描述
出現以上結果就成功了

出現報錯的話 根據提示 更改參數即可

自行根據以上邏輯嵌入到頁面中即可

3.查詢訂單

創建參數

private static String url="https://api.mch.weixin.qq.com/pay/orderquery";

寫入配置文件里即可 由於是測試 這里寫在類中

再添加工具方法(getElementValue這個方法有重載 跟1,2里的不一樣)

/** * 通過返回IO流獲取支付地址 * @param in * @return */
	private static void getElementValue(InputStream in){
		SAXReader reader = new SAXReader();
        Document document=null;
		try {
			document = reader.read(in);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        Element root = document.getRootElement();
        List<Element> childElements = root.elements();
        for (Element child : childElements) {
        	System.out.println(child.getName()+":"+child.getStringValue());
        }
	}

這個和2,1中的方法是同一個

/** * 微信支付簽名算法sign */
    private static String getSign(Map<String,Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + WeixinPayConfig.key);
        String sign = Md5Util.string2MD5(sb.toString());
        return sign;
    }

這里直接寫的main方法 具體要求根據業務更改

public static void main(String[] args) throws UnsupportedOperationException, ClientProtocolException, IOException {
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		//map.put("transaction_id", "4200000087201804105653326283"); // 微信訂單號
		map.put("out_trade_no", "20180405055656553"); // 商戶訂單號(項目生成的訂單號)
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串
		map.put("sign", getSign(map)); // 簽名
		String xml=XmlUtil.genXml(map); 
		System.out.println(xml);
		InputStream in=HttpClientUtil.sendXMLDataByPost(url, xml).getEntity().getContent(); // 發現xml消息
		getElementValue(in);
	}

然后運行
在這里插入圖片描述
看見結果后 就成功了
如果有錯誤根據錯誤提示 排錯即可

4.關閉訂單

創建參數

private static String url="https://api.mch.weixin.qq.com/pay/closeorder";

寫入配置文件里即可 由於是測試 這里寫在類中

這里直接寫的main方法 具體要求根據業務更改(還是需要3里面的兩個方法)

public static void main(String[] args) throws UnsupportedOperationException, ClientProtocolException, IOException {
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		map.put("out_trade_no", "20180404022005421"); // 商戶訂單號
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串
		map.put("sign", getSign(map)); // 簽名
		String xml=XmlUtil.genXml(map); 
		System.out.println(xml);
		InputStream in=HttpClientUtil.sendXMLDataByPost(url, xml).getEntity().getContent(); // 發現xml消息
		getElementValue(in);
	}

然后運行

在這里插入圖片描述
看見結果后 就成功了
如果有錯誤根據錯誤提示 排錯即可

5.申請退款

首先 退款要用到安全證書
在微信公眾平台登陸后 在下面下載

在這里插入圖片描述
下載完后放在磁盤內

然后准備工作

將CertUtil.java 導入在工程內(更改里面的安全證書路徑,項目中要配置在配置文件中)

在這里插入圖片描述

接口調用url
private static String url="https://api.mch.weixin.qq.com/secapi/pay/refund";
使用到的工具方法

		/** * 通過返回IO流獲取支付地址 * @param in * @return */
	private static void getElementValue(InputStream in){
		SAXReader reader = new SAXReader();
        Document document=null;
		try {
			document = reader.read(in);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        Element root = document.getRootElement();
        List<Element> childElements = root.elements();
        for (Element child : childElements) {
        	System.out.println(child.getName()+":"+child.getStringValue());
        }
	}
	
	/** * 微信支付簽名算法sign */
    private static String getSign(Map<String,Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + WeixinPayConfig.key);
        String sign = Md5Util.string2MD5(sb.toString());
        return sign;
    }

然后編寫方法 因為是測試 這里使用的是main 實際根據業務更改

public static void main(String[] args) throws UnsupportedOperationException, ClientProtocolException, IOException {
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		map.put("transaction_id", "4200000094201804192059258077"); // 微信訂單號
		//map.put("out_trade_no", "20180419105343760"); // 商戶訂單號
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串
		map.put("out_refund_no", DateUtil.getCurrentDateStr()); // 商戶退款單號
		map.put("total_fee", 100); // 訂單金額
		map.put("refund_fee", 10); // 退款金額
		map.put("sign", getSign(map)); // 簽名
		String xml=XmlUtil.genXml(map); 
		System.out.println(xml);
		InputStream in=HttpClientUtil.sendXMLDataByHttpsPost(url, xml).getEntity().getContent(); // 發現xml消息
		getElementValue(in);
	}

運行程序查看結果

在這里插入圖片描述

出現以上結構就成功了

出現報錯的話 根據提示 更改參數即可

7 查詢退款

接口調用url
private static String url="https://api.mch.weixin.qq.com/pay/refundquery ";

使用到的工具方法

/** * 通過返回IO流獲取支付地址 * @param in * @return */
	private static void getElementValue(InputStream in){
		SAXReader reader = new SAXReader();
        Document document=null;
		try {
			document = reader.read(in);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        Element root = document.getRootElement();
        List<Element> childElements = root.elements();
        for (Element child : childElements) {
        	System.out.println(child.getName()+":"+child.getStringValue());
        }
	}
	
	/** * 微信支付簽名算法sign */
    private static String getSign(Map<String,Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + WeixinPayConfig.key);
        String sign = Md5Util.string2MD5(sb.toString());
        return sign;
    }

然后編寫方法 因為是測試 這里使用的是main 實際根據業務更改

public static void main(String[] args) throws UnsupportedOperationException, ClientProtocolException, IOException {
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("appid", WeixinPayConfig.appid); // 公眾賬號ID
		map.put("mch_id", WeixinPayConfig.mch_id); // 商戶號
		// map.put("transaction_id", "4200000094201804192059258077"); // 微信訂單號
		// map.put("out_trade_no", "20180419105343760"); // 商戶訂單號
		// map.put("out_refund_no", "20180427112536831"); // 商戶退款單號
		map.put("refund_id", "50000506552018042704327042706"); // 微信退款單號
		map.put("nonce_str", StringUtil.getRandomString(30)); // 隨機字符串
		// map.put("offset", 1); // 偏移量
		map.put("sign", getSign(map)); // 簽名
		String xml=XmlUtil.genXml(map); 
		System.out.println(xml);
		InputStream in=HttpClientUtil.sendXMLDataByPost(url, xml).getEntity().getContent(); // 發現xml消息
		getElementValue(in);
	}

運行程序查看結果

在這里插入圖片描述

出現以上結構就成功了

出現報錯的話 根據提示 更改參數即可

本文資料+工具類+Demo https://pan.baidu.com/s/1eXpUBxmkVagxg00-sAttFQ

如果對你有幫助的話,請賞下小弟唄
在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM