Java開發(fā)微信Navicat支付完整版
一:準(zhǔn)備工作
1:先去微信公眾平臺(tái)注冊(cè)一個(gè)公眾號(hào),選擇服務(wù)號(hào)
2:去微信商戶平臺(tái)注冊(cè)一個(gè)商戶號(hào),用于收款
3:在商戶號(hào)中配置對(duì)應(yīng)的公眾號(hào)的APPID
4:支付結(jié)果異步通知(需要重點(diǎn)注意)
注意:請(qǐng)先詳細(xì)查看官方文檔按步驟開發(fā),一切以官方文檔為主 微信Navicat支付官方文檔
5:測(cè)試的時(shí)候一定要使用內(nèi)網(wǎng)穿透軟件,否則回調(diào)時(shí)會(huì)報(bào)錯(cuò)
二:開發(fā)代碼
WeChatPayConfig:
public class WeChatPayConfig {
//公眾號(hào)APPID
private String APPID = "";
//商戶號(hào)KEY
private String KEY = "";
//商戶號(hào)ID
private String MCHID = "";
//支付完成后微信回調(diào)地址,需要外網(wǎng)能訪問要是域名,不能是127.0.0.1跟localhost
private String NOTIFY_URL = "";
}
WeChatPayServcie:
public interface WeChatPayServcie {
//微信支付下單
public Map<String,String> getWxpayUrl(Map<String, String> sourceMap);
//訂單查詢
public String orderQuery(String out_trade_no);
}
@Service
public class WeChatPayServiceImpl implements WeChatPayServcie {
/**
* 微信支付請(qǐng)求
* @param sourceMap
* @return
*/
public Map<String,String> getWxpayUrl(Map<String, String> sourceMap) {
SortedMap<String, Object> signParams = new TreeMap<String, Object>();
String nonce_str = UUID.randomUUID().toString().trim().replaceAll("-", "");
signParams.put("appid", PayConfig.APPID);
signParams.put("mch_id",PayConfig.MCHID);
signParams.put("nonce_str",sourceMap.get("nonce_str"));
signParams.put("product_id",sourceMap.get("prod_id"));
signParams.put("body",sourceMap.get("body"));
signParams.put("out_trade_no",sourceMap.get("out_trade_no"));
signParams.put("total_fee",sourceMap.get("total_fee"));
signParams.put("spbill_create_ip", WxUtil.getIp());
signParams.put("notify_url",PayConfig.NOTYFLY_URL);
signParams.put("trade_type","NATIVE");
String sign = WxUtil.createSign(signParams,PayConfig.KEY);
signParams.put("sign",sign);
String xmlPackage = WxUtil.parseMapXML(signParams);
Map<String, Object> resultMap = new HashMap();
try {
String result = HttpUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder",xmlPackage);
resultMap = WxUtil.parseXmlMap(result);
} catch (Exception e) {
e.printStackTrace();
}
String returnCode = (String) resultMap.get("return_code");
String returnMsg = (String) resultMap.get("return_msg");
if (returnCode.equalsIgnoreCase("FAIL")) {
throw new RuntimeException(returnMsg);
}
String result_code = (String) resultMap.get("result_code");
if (result_code.equalsIgnoreCase("FAIL")) {
throw new RuntimeException(resultMap.get("err_code_des"));
}
String code_url = (String) resultMap.get("code_url");
Map<String,String> map = new HashMap<>();
map.put("code_url",code_url);
map.put("out_trade_no",sourceMap.get("out_trade_no"));
return map;
}
/**
* 微信支付訂單查詢
* @param out_trade_no
* @return
*/
public String orderQuery(String out_trade_no) {
String nonce_str = UUID.randomUUID().toString().trim().replaceAll("-", "");
SortedMap<String, Object> signParams = new TreeMap<>();
signParams.put("appid", payConfig.getWeChatPorpetties().getAppId());
signParams.put("mch_id",payConfig.getWeChatPorpetties().getMchId());
signParams.put("out_trade_no",out_trade_no);
signParams.put("nonce_str",nonce_str);
String sign = WxUtil.createSign(signParams,payConfig.getWeChatPorpetties().getApiKey());
signParams.put("sign",sign);
String xmlPackage = WxUtil.parseMapXML(signParams);
Map<String, Object> resultMap = new HashMap();
try {
String result = HttpUtil.post("https://api.mch.weixin.qq.com/pay/orderquery",xmlPackage);
resultMap = WxUtil.parseXmlMap(result);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("渠道網(wǎng)絡(luò)異常");
}
String returnCode = (String) resultMap.get("return_code");
String returnMsg = (String) resultMap.get("return_msg");
if (returnCode.equalsIgnoreCase(PayContants.FAIL)) {
throw new RuntimeException(returnMsg);
}
String result_code = (String) resultMap.get("result_code");
if (result_code.equalsIgnoreCase(PayContants.FAIL)) {
throw new RuntimeException(resultMap.get("err_code_des"));
}
String trade_state = (String) resultMap.get("trade_state");
return trade_state;
}
}
WeChatPayController:
/**
* 微信支付接口
*/
@Controller
public class WxPayController {
@Autowired
WeChatPayServcie weChatPayServcie;
/**
* 微信支付下單
* payID可以不用傳自己生成32位以內(nèi)的隨機(jī)數(shù)就好,要保證不重復(fù)
* totalFee金額一定要做判斷,判斷這筆支付金額與數(shù)據(jù)庫是否一致
*/
@RequestMapping("pay")
@ResponseBody
public Map<String ,String> toWxpay(HttpServletRequest httpRequest,String payId, String totalFee, String body){
System.out.println("開始微信支付...");
Map<String, String> map = new HashMap<>();
String nonce_str = UUID.randomUUID().toString().trim().replaceAll("-", "");
//生成一筆支付記錄
//拼接支付參數(shù)
Map<String, String> paramMap = new HashMap<>();
paramMap.put("nonce_str", nonce_str);
paramMap.put("prod_id", payId);
paramMap.put("body", body);
paramMap.put("total_fee", totalFee);
paramMap.put("out_trade_no", payId);
//發(fā)送支付請(qǐng)求并獲取返回參數(shù)與二維碼,用于支付與調(diào)用查詢接口
Map<String, String> returnMap = weChatPayServcie.getWxpayUrl(paramMap);
httpRequest.setAttribute("out_trade_no", payId);
httpRequest.setAttribute("total_fee", totalFee);
//code_url就是二維碼URL,可以把這個(gè)URL放到草料二維碼中生成微信二維碼
httpRequest.setAttribute("code_url", returnMap.get("code_url"));
map.put("out_trade_no", payId);
map.put("total_fee", String.valueOf(bigDecimal));
map.put("code_url", returnMap.get("code_url"));
return map;
}
/**
* 查詢微信訂單
* ot_trade_no是支付
*/
@RequestMapping("query")
@ResponseBody
public Root<String> orderQuery(String out_trade_no){
return weixinPayServcie.orderQuery(queryCallbackForm.getOut_trade_no());
}
/**
* 微信支付回調(diào),這個(gè)地址就是Config中的NOTYFLY_URL
*/
@RequestMapping("callback")
public void notify_url(HttpServletRequest request, HttpServletResponse response) throws DocumentException, ServletException, IOException,Throwable {
System.out.print("微信支付回調(diào)獲取數(shù)據(jù)開始...");
String inputLine;
String notityXml = "";
try {
while ((inputLine = request.getReader().readLine()) != null) {
notityXml += inputLine;
}
request.getReader().close();
} catch (Exception e) {
WxUtil.sendXmlMessage(request,response, PayContants.FAIL);
throw new RuntimeException("回調(diào)數(shù)據(jù)xml獲取失??!");
}
if(StringUtils.isEmpty(notityXml)){
WxUtil.sendXmlMessage(request,response, PayContants.FAIL);
throw new RuntimeException("回調(diào)數(shù)據(jù)xml為空!");
}
Map<String ,Object> resultMap = XMLParse.parseXmlMap(notityXml);
String returnCode = (String) resultMap.get("return_code");
String returnMsg = (String) resultMap.get("return_msg");
if (returnCode.equalsIgnoreCase(PayContants.FAIL)) {
WxUtil.sendXmlMessage(request,response, PayContants.FAIL);
throw new RuntimeException(returnMsg);
}
String resultCode = (String) resultMap.get("result_code");
if (resultCode.equalsIgnoreCase(PayContants.FAIL)) {
WxUtil.sendXmlMessage(request,response, PayContants.FAIL);
throw new RuntimeException(resultMap.get("err_code_des"));
}
SortedMap<String ,Object> paramMap = new TreeMap<>();
paramMap.put("appid",resultMap.get("appid"));
paramMap.put("mch_id",resultMap.get("mch_id"));
paramMap.put("nonce_str",resultMap.get("nonce_str"));
paramMap.put("body",resultMap.get("body"));
paramMap.put("openid", resultMap.get("openid"));
paramMap.put("is_subscribe",resultMap.get("is_subscribe"));
paramMap.put("trade_type",resultMap.get("trade_type"));
paramMap.put("bank_type",resultMap.get("bank_type"));
paramMap.put("total_fee",resultMap.get("total_fee"));
paramMap.put("fee_type",resultMap.get("fee_type"));
paramMap.put("cash_fee",resultMap.get("cash_fee"));
paramMap.put("transaction_id",resultMap.get("transaction_id"));
paramMap.put("out_trade_no",resultMap.get("out_trade_no"));
paramMap.put("time_end",resultMap.get("time_end"));
paramMap.put("return_code",resultMap.get("return_code"));
paramMap.put("return_msg",resultMap.get("return_msg"));
paramMap.put("result_code",resultMap.get("result_code"));
String out_trade_no = (String) resultMap.get("out_trade_no");
String sign = SignUtil.createSign(paramMap,WxPayConfig.KEY);
String mySign =(String) resultMap.get("sign");
//回調(diào)一定要驗(yàn)證簽名以防數(shù)據(jù)被篡改
if(sign.equals(mySign)){
System.out.println("回調(diào)簽名驗(yàn)證成功!");
//修改業(yè)務(wù)邏輯,將那筆支付狀態(tài)改為已支付
}
WxUtil.sendXmlMessage(request,response, PayContants.SUCCESS);
}else{
WxUtil.sendXmlMessage(request,response, PayContants.FAIL);
throw new RuntimeException("簽名不一致!");
}
}
}
WxUtil:
package com.ys.commons.utils.pay;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//微信工具類
public class WxUtil {
//獲取當(dāng)前IP
public static String getIp() {
try {
String spbill_create_ip = InetAddress.getLocalHost().getHostAddress();
return spbill_create_ip;
} catch (UnknownHostException var2) {
var2.printStackTrace();
return "獲取IP失敗...";
}
}
//輸出xml格式
public static void sendXmlMessage(HttpServletRequest request, HttpServletResponse response, String content) {
try {
String contentXml = "<xml><return_code><![CDATA[" + content + "]]></return_code></xml>";
OutputStream os = response.getOutputStream();
BufferedWriter resBr = new BufferedWriter(new OutputStreamWriter(os));
resBr.write(contentXml);
resBr.flush();
resBr.close();
} catch (IOException var6) {
var6.printStackTrace();
}
}
//生成sign簽名
public static String createSign(SortedMap<String, Object> packageParams, String KEY) {
StringBuffer sb = new StringBuffer();
Set<Entry<String, Object>> es = packageParams.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Entry<String, Object> entry = (Entry)it.next();
String k = (String)entry.getKey();
String v = (String)entry.getValue();
if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + KEY);
String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
return sign;
}
//將map轉(zhuǎn)為xml
public static String parseMapXML(SortedMap<String, Object> map) {
String xmlResult = "";
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Iterator var3 = map.keySet().iterator();
while(var3.hasNext()) {
String key = (String)var3.next();
String value = "<![CDATA[" + map.get(key) + "]]>";
sb.append("<" + key + ">" + value + "</" + key + ">");
System.out.println();
}
sb.append("</xml>");
xmlResult = sb.toString();
return xmlResult;
}
//將xml轉(zhuǎn)為map
public static Map<String, Object> parseXmlMap(String xml) throws DocumentException {
Document document = DocumentHelper.parseText(xml);
Element root = document.getRootElement();
List<Element> elementList = root.elements();
Map<String, Object> map = new HashMap();
Iterator var5 = elementList.iterator();
while(var5.hasNext()) {
Element e = (Element)var5.next();
map.put(e.getName(), e.getText());
}
return map;
}
}
發(fā)送請(qǐng)求需要推薦一個(gè)非常好用的工具,里面各種常用的工具都封裝好了hutool,如果想直接復(fù)制代碼使用也需要引入此工具的maven庫
注意:此工具只支持JDK 1.7以上至此代碼已經(jīng)完成,有意見建議的都可以留言,后續(xù)會(huì)更新最完整最新版的PayPal支付,同時(shí)有需要的也可以看看博主的支付寶PC支付
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用Java把文本內(nèi)容轉(zhuǎn)換成網(wǎng)頁的實(shí)現(xiàn)方法分享
這篇文章主要介紹了使用Java把文本內(nèi)容轉(zhuǎn)換成網(wǎng)頁的實(shí)現(xiàn)方法分享,利用到了Java中的文件io包,需要的朋友可以參考下2015-11-11
SpringBoot是如何實(shí)現(xiàn)自動(dòng)配置的你知道嗎
這篇文章主要介紹了詳解SpringBoot自動(dòng)配置原理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2021-08-08
VScode 打造完美java開發(fā)環(huán)境最新教程
這篇文章主要介紹了VScode 打造完美java開發(fā)環(huán)境最新教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
關(guān)于mybatis一對(duì)一查詢一對(duì)多查詢遇到的問題
這篇文章主要介紹了關(guān)于mybatis一對(duì)一查詢,一對(duì)多查詢遇到的錯(cuò)誤,接下來是對(duì)文章進(jìn)行操作,要求查詢?nèi)课恼?,并關(guān)聯(lián)查詢作者,文章標(biāo)簽,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05
SpringBoot執(zhí)行異步任務(wù)Async介紹
這篇文章主要為大家介紹了SpringBoot執(zhí)行異步任務(wù)Async示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)圖文教程
這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)的相關(guān)資料,在多環(huán)境部署過程中、及線上運(yùn)維中可能會(huì)遇到臨時(shí)指定配置文件的情況,需要的朋友可以參考下2023-07-07

