欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java接入微信支付超級詳細保姆級教程

 更新時間:2024年12月26日 11:11:00   作者:小鯊魚Vicky  
這篇文章主要給大家介紹了關(guān)于Java接入微信支付的相關(guān)資料,包括l 準(zhǔn)備開發(fā)所需的賬號和配置信息、準(zhǔn)備環(huán)境、設(shè)置開發(fā)參數(shù)以及實現(xiàn)支付接口,回調(diào)地址的設(shè)置和異步回調(diào)通知的處理也是文章的重點內(nèi)容,需要的朋友可以參考下

本文介紹了“二維碼付款”的代碼。其他微信支付方式的代碼都在源碼中。

一、準(zhǔn)備開發(fā)所需的賬號以及配置信息

首先想要接入微信支付我們需要兩個玩意:

一是公眾號/小程序/企業(yè)微信(開發(fā)用的)這個是為了獲取 APPID

一是微信支付商戶(收錢用的) 獲取 api_key mch_id

1、前往:https://mp.weixin.qq.com/ (微信公眾平臺)注冊一個應(yīng)用,類型只能是:公眾號/小程序/企業(yè)微信,注冊完成需要完成”微信認證“(微信需要收取300元)。

2、前往:https://pay.weixin.qq.com(微信支付商戶平臺)注冊一個商戶,支付成功后的錢就會在這個賬號里面。

? 1、APPID:應(yīng)用id也就是 公眾號/小程序的ID

? 2、Api_key: 對應(yīng)的APIv2密鑰

? 3、mch_Id:商戶ID (收錢的商家ID)對應(yīng)的是 【微信支付商戶號】

4.將申請的下來的APPID綁定到商戶號下,添加成功后再次到工作號里面

【廣告與服務(wù)—>微信支付】這個時候會看到關(guān)聯(lián)申請,同意就可以了。到這一步前置工作就完成了

二、準(zhǔn)備環(huán)境

項目采用SpringBoot

微信支付有兩種版本:V3和V2,本文的接入版本為V2

1、導(dǎo)入jar包

1.1微信支付jar包

<dependency>
  <groupId>com.github.wxpay</groupId>
  <artifactId>wxpay-sdk</artifactId>
  <version>0.0.3</version>
</dependency>

1.2導(dǎo)入hutool工具類jar包

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.12</version>
</dependency>

2、設(shè)置開發(fā)參數(shù)

如果自己就是商戶 那么可以將參數(shù)設(shè)置到配置文件application.yml中,如果是多商戶則建立商戶收款配置表 將信息維護到數(shù)據(jù)庫中
在application.yml,設(shè)置好開發(fā)參數(shù)

pay:
  appid: wx123456789a439 #微信公眾號appid
  api_key: gwxkjvfewvfabvcrxgrawvgs924ceaxj #公眾號設(shè)置的api密鑰
  mch_id: 1603596731 #微信商戶平臺 商戶id

本文是多商戶

  • 數(shù)據(jù)庫參考

  • 微信支付工具類

package com.manage.common.utils;

import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;

/**
 * 微信支付工具類
 *
 */
public class WxChatPayCommonUtil {
        /**
         * 發(fā)送 http 請求
         * @param requestUrl    請求路徑
         * @param requestMethod 請求方式(GET/POST/PUT/DELETE/...)
         * @param outputStr     請求參數(shù)體
         * @return 結(jié)果信息
         */
        public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
            try {
                URL url = new URL(requestUrl);
                HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setUseCaches(false);
                // 設(shè)置請求方式(GET/POST)
                conn.setRequestMethod(requestMethod);
                conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
                // 當(dāng)outputStr不為null時向輸出流寫數(shù)據(jù)
                if (null != outputStr) {
                    OutputStream outputStream = conn.getOutputStream();
                    // 注意編碼格式
                    outputStream.write(outputStr.getBytes("UTF-8"));
                    outputStream.close();
                }
                // 從輸入流讀取返回內(nèi)容
                InputStream inputStream = conn.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                String str = null;
                StringBuffer buffer = new StringBuffer();
                while ((str = bufferedReader.readLine()) != null) {
                    buffer.append(str);
                }
                // 釋放資源
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
                inputStream = null;
                conn.disconnect();
                return buffer.toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 獲取ip
         * @param request 請求
         * @return ip 地址
         */
        public static String getIp(HttpServletRequest request) {
            if (request == null) {
                return "";
            }
            String ip = request.getHeader("X-Requested-For");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Forwarded-For");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }

        /**
         * 從流中讀取微信返回的xml數(shù)據(jù)
         * @param httpServletRequest
         * @return
         * @throws IOException
         */
        public static String readXmlFromStream(HttpServletRequest httpServletRequest) throws IOException {
            InputStream inputStream = httpServletRequest.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            final StringBuffer sb = new StringBuffer();
            String line = null;
            try {
                while ((line = bufferedReader.readLine()) != null) {
                    sb.append(line);
                }
            } finally {
                bufferedReader.close();
                inputStream.close();
            }

            return sb.toString();
        }

        /**
         * 設(shè)置返回給微信服務(wù)器的xml信息
         * @param returnCode
         * @param returnMsg
         * @return
         */
        public static String setReturnXml(String returnCode, String returnMsg) {
            return "<xml><return_code><![CDATA[" + returnCode + "]]></return_code><return_msg><![CDATA[" + returnMsg + "]]></return_msg></xml>";
        }
}
  • 微信支付接口地址
package com.manage.common.utils;

/**
 * 微信支付接口地址
 *
 */
public class WeChatPayUrl {
    //統(tǒng)一下單預(yù)下單接口url
    public static final String Uifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    //訂單狀態(tài)查詢接口URL
    public static final String Orderquery = "https://api.mch.weixin.qq.com/pay/orderquery";
    //訂單申請退款
    public static final String Refund = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    //付款碼 支付
    public static final String MicroPay = "https://api.mch.weixin.qq.com/pay/micropay";
    //微信網(wǎng)頁授權(quán) 獲取“code”請求地址
    public static final String GainCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";

}
  • 錢 工具類
package com.manage.common.utils;

import com.manage.common.object.YouNumberUtil;

import java.math.BigDecimal;

/**
 * 錢 工具類
 *
 * Created by YouHan on 2019-06-28 09:12:00
 * Copyright ? 2019 YouHan All rights reserved.
 */
public class MoneyUtils {
    public static final String YUAN = "元";
    public static final String FEN = "分";

    /**
     * 元轉(zhuǎn)分
     *
     * @param s
     * @return java.lang.Integer
     * @date 2020/9/10 9:03
     * @author YouHan
     */
    public static Integer yuanToFen(String s) {
        if (!YouNumberUtil.isNumber(s)) {
            return 0;
        }

        return new BigDecimal(s).multiply(new BigDecimal(100)).intValue();
    }

    /**
     * 處理分
     *
     * @param s
     * @return java.lang.Integer
     * @author YouHan
     * @date 2022/7/23
     */
    public static Integer handleFen(String s) {
        if (!YouNumberUtil.isNumber(s)) {
            return 0;
        }

        return new BigDecimal(s).intValue();
    }

    /**
     * 分轉(zhuǎn)元
     *      可以為正負小數(shù)(這里保留2位小數(shù))
     *
     * @param s
     * @return java.lang.String
     * @date 2020/9/10 9:01
     * @author YouHan
     */
    public static String fenToYuan(String s) {
        if (!YouNumberUtil.isNumber(s) || "0".equals(s) || "-0".equals(s)) {
            return "0.00";
        }

        return new BigDecimal(s)
                .divide(new BigDecimal(100))
                .setScale(2, BigDecimal.ROUND_DOWN)
                .toString();
    }

    /**
     * 處理元
     *      可以為正負小數(shù)(這里保留2位小數(shù))
     *
     * @param s
     * @return java.lang.String
     * @author YouHan
     * @date 2022/7/23
     */
    public static String handleYuan(String s) {
        if (!YouNumberUtil.isNumber(s) || "0".equals(s) || "-0".equals(s)) {
            return "0.00";
        }

        return new BigDecimal(s)
                .setScale(2, BigDecimal.ROUND_DOWN)
                .toString();
    }

    public static void main(String[] args) {
        System.out.println(yuanToFen("10.00"));
    }
}
  • 數(shù)字 client
package com.manage.common.object;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * String client
 *
 * Created by YouHan on 2019-09-11 08:57:56
 * Copyright ? 2019 YouHan All rights reserved.
 */
public class YouStringUtil {

	/**
	 * 下劃線
	 */
	public static final Pattern LINE = Pattern.compile("_(\\w)");

	/**
	 * 駝峰
	 */
	public static final Pattern HUMP = Pattern.compile("[A-Z]");

	/**
	 * 添加內(nèi)容
	 *
	 * @param content
	 * @param length
	 * @return java.lang.String
	 * @author YouHan
	 * @date 2021/6/17 9:59
	 */
	public static String appendContent(String content, int length) {
		if (length <= 0) {
			return "";
		}

		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < length; i ++) {
			sb.append(content);
		}

		return sb.toString();
	}

	/**
	 * 添加前綴內(nèi)容
	 *
	 * @param s
	 * @param content
	 * @param length
	 * @return java.lang.String
	 * @date 2019-08-12 09:53
	 * @author YouHan
	 */
	public static String appendPrefixContent(String s, String content, int length) {

		if (length <= 0) {
			return null;
		}

		StringBuilder sb = new StringBuilder(s);
		for (int i = 0; i < length; i ++) {
			sb.append(content, 0, content.length());
		}

		return sb.toString();
	}

	/**
	 * 添加后綴內(nèi)容
	 *
	 * @param s
	 * @param content
	 * @param length
	 * @return java.lang.String
	 * @date 2019-08-12 09:56
	 * @author YouHan
	 */
	public static String appendSuffixContent(String s, String content, int length) {
		if (length <= 0) {
			return null;
		}

		StringBuilder sb = new StringBuilder(s);

		for (int i = 0; i < length; i ++) {
			sb.append(content);
		}

		return sb.toString();
	}

	/**
	 * Set 轉(zhuǎn) String
	 *
	 * @param stringSet
	 * @return java.lang.String
	 * @author YouHan
	 * @date 2021/6/3 9:26
	 */
	public static String setToString(Set<String> stringSet) {
		return setToString(stringSet, null);
	}

	/**
	 * Set 轉(zhuǎn) String
	 *
	 * @param stringSet
	 * @param regex
	 * @return java.lang.String
	 * @date 2021/6/3 9:21
	 * @author YouHan
	 */
	public static String setToString(Set<String> stringSet, String regex) {
		// 參數(shù)校驗
		if (CollectionUtils.isEmpty(stringSet)) {
			return null;
		}
		if (StringUtils.isBlank(regex)) {
			regex = ",";
		}

		// List to String
		StringBuilder sb = new StringBuilder(stringSet.size());
		for (String s : stringSet) {
			sb.append(s).append(regex);
		}

		// 返回結(jié)果
		return sb.substring(0, sb.length() - 1);
	}

	/**
	 *  字符串列表轉(zhuǎn)字符串
	 *
	 * @author YouHan
	 * @generatedDate: 2018/10/9 17:25
	 * @param stringList 要轉(zhuǎn)換的字符串列表
	 * @return
	 */
	public static String listToString(List<String> stringList) {
		return listToString(stringList, null);
	}

	/**
	 *  字符串列表轉(zhuǎn)字符串
	 *
	 * @author YouHan
	 * @generatedDate: 2018/10/9 17:25
	 * @param stringList 要轉(zhuǎn)換的字符串列表
	 * @return
	 */
	public static String listToString(List<String> stringList, String regex) {
		// 參數(shù)校驗
		if (CollectionUtils.isEmpty(stringList)) {
			return null;
		}
		if (StringUtils.isBlank(regex)) {
			regex = ",";
		}

		// List to String
		StringBuilder sb = new StringBuilder(stringList.size());
		for (String s : stringList) {
			sb.append(s).append(regex);
		}

		// 返回結(jié)果
		return sb.substring(0, sb.length() - 1);
	}

	/**
	 * 字符串轉(zhuǎn)列表
	 *
	 * @param s
	 * @return java.client.List<java.lang.String>
	 * @date 2019-09-11 09:11
	 * @author YouHan
	 */
	public static List<String> stringToList(String s) {
		/**
		 * 參數(shù)校驗
		 */
		if (StringUtils.isBlank(s)) {
			return null;
		}

		return stringToList(s, null);
	}

	/**
	 * 字符串轉(zhuǎn)列表
	 *
	 * @param s
	 * @param regex 分割規(guī)則,默認為逗號
	 * @return java.client.List<java.lang.String>
	 * @date 2019-09-11 09:11
	 * @author YouHan
	 */
	public static List<String> stringToList(String s, String regex) {
		/**
		 * 參數(shù)校驗
		 */
		if (StringUtils.isBlank(s)) {
			return null;
		}

		/**
		 * 默認逗號隔開
		 */
		if (StringUtils.isBlank(regex)) {
			regex = ",";
		}

		/**
		 * 去除首尾空格
		 */
		String blankString = " ";
		while (s.startsWith(blankString)) {
			s = s.substring(1);
		}
		while (s.endsWith(blankString)) {
			s = s.substring(0, s.length() -1);
		}

		/**
		 * 返回結(jié)果列表
		 */
		List<String> resultList = new ArrayList<>();

		/**
		 * 只有單個元素
		 */
		if (!s.contains(regex)) {
			resultList.add(s);
			return resultList;
		}

		String[] strings = s.split(regex);
		for (String e : strings) {
			resultList.add(e);
		}

		return resultList;
	}

	/**
	 * 過濾逗號
	 * @param s
	 * @return
	 */
	public static String filterCommaString(String s) {
		// 數(shù)據(jù)為空校驗
		if (StringUtils.isEmpty(s)) {
			return null;
		}

		// 去除 并列逗號
		s = s.replace(",,", ",");

		// 去除 首逗號
		if (s.startsWith(",")) {
			s = s.substring(1, s.length() - 1);
		}

		// 去除 尾逗號
		if (s.endsWith(",")) {
			s = s.substring(0, s.length() - 1);
		}

		return s;
	}

	/**
	 * 是否包含中文(包括中文標(biāo)點符號和空格)
	 *
	 * @param s
	 * @return boolean
	 * @date 2020/9/9 13:30
	 * @author YouHan
	 */
	public static Boolean isContainChinese(String s) {
		/**
		 * 參數(shù)校驗
		 */
		if (StringUtils.isBlank(s)) {
			return false;
		}

		if (s.contains(" ")) {
			return true;
		}

		/**
		 * 中文正則表達式
		 */
		String regex = "[\u4e00-\u9fa5]";

		if (s.matches(regex)) {
			return Boolean.TRUE;
		}

		/**
		 * 中文標(biāo)點符號處理
		 */
		char[] chars = s.toCharArray();
		for (char c : chars) {
			if (isChinesePunctuation(c)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 過濾中文(包括標(biāo)點符號和空格)
	 *
	 * @param s
	 * @return java.lang.String
	 * @date 2020/9/9 14:08
	 * @author YouHan
	 */
	public static String filterChinese(String s) {
		/**
		 * 參數(shù)校驗
		 */
		if (StringUtils.isBlank(s)) {
			return "";
		}

		s = s.replace(" ", "");

		if (!isContainChinese(s)) {
			return s;
		}

		/**
		 * 過濾中文字符
		 */
		char[] chars = s.toCharArray();
		StringBuilder sb = new StringBuilder(chars.length);
		for (char c : chars) {
			if (isContainChinese(String.valueOf(c))) {
				continue;
			}
			sb.append(c);
		}

		return sb.toString();
	}

	/**
	 * 判斷是否為中文標(biāo)點符號
	 *
	 * @param c
	 * @return java.lang.Boolean
	 * @date 2020/9/9 13:43
	 * @author YouHan
	 */
	public static boolean isChinesePunctuation(char c) {
		Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
		if (ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
				|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
				|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
				|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS
				|| ub == Character.UnicodeBlock.VERTICAL_FORMS) {
			return true;
		}

		return false;
	}

	/**
	 * 獲取 UUID
	 *
	 * @param
	 * @return java.lang.String
	 * @date 2021/4/9 14:08
	 * @author YouHan
	 */
	public static String getUUID() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 安全比較(可防止時序攻擊 timing attack)
	 */
	public static boolean safeEqual(String a, String b) {
		if (StringUtils.isBlank(a) || StringUtils.isBlank(b)) {
			return false;
		}
		if (a.length() != b.length()) {
			return false;
		}
		int equal = 0;
		for (int i = 0; i < a.length(); i++) {
			equal |= a.charAt(i) ^ b.charAt(i);
		}
		return equal == 0;
	}

	/**
	 * 駝峰轉(zhuǎn)下劃線
	 *
	 * @param s
	 * @return java.lang.String
	 * @date 2021/5/6 22:20
	 * @author YouHan
	 */
	public static String humpToLine(String s) {
		Matcher matcher = HUMP.matcher(s);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
		}
		if (sb.toString().startsWith("_")) {
			sb.deleteCharAt(0);
		}

		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 下劃線轉(zhuǎn)駝峰
	 *
	 * @param s
	 * @return java.lang.String
	 * @date 2021/5/6 22:21
	 * @author YouHan
	 */
	public static String lineToHump(String s) {
		s = s.toLowerCase();
		Matcher matcher = LINE.matcher(s);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 生成加密的內(nèi)容
	 *
	 * @param s
	 * @return java.lang.String
	 * @author YouHan
	 * @date 2021/6/17 10:10
	 */
	public static String hide(String s) {
		/**
		 * 1
		 * 1*
		 * 1**
		 * 1***
		 * 1***5
		 * 12***6
		 * 12***67
		 * 123***78
		 * 123***789
		 * 123****890
		 * 123*****8901
		 */
		if (s.isEmpty() || s.length() == 1) {
			return s;
		}

		if (s.length() == 2) {
			return s.substring(0, 1) + "*";
		}

		if (s.length() == 3 || s.length() == 4) {
			return s.substring(0, 1) + appendContent("*", s.length() - 1);
		}

		if (s.length() == 5) {
			return s.substring(0, 1) + "***" + s.substring(4);
		}

		if (s.length() == 6 || s.length() == 7) {
			return s.substring(0, 2) + appendContent("*", 3) + s.substring(5);
		}

		if (s.length() == 8) {
			return s.substring(0, 3) + "***" + s.substring(6);
		}

		return s.substring(0, 3) + appendContent("*", s.length() - 6) + s.substring(s.length() - 3);
	}
}
  • String client
package com.manage.common.object;

import org.apache.commons.lang3.StringUtils;

import java.util.concurrent.ThreadLocalRandom;

/**
 * 數(shù)字 client
 *
 * Created by YouHan on 2020-09-09 13:28:40
 * Copyright ? 2021 YouHan All rights reserved.
 */
public class YouNumberUtil {
    /**
     * 整數(shù)正則表達式
     */
    public static final String INTEGER_REGEX = "^[-\\+]?[\\d]*$";

    /**
     * 數(shù)字正則表達式
     */
    public static final String NUMBER_REGEX = "^-?\\d+(\\.\\d+)?$";

    /**
     * 是否是整數(shù)
     *
     * @param s
     * @return java.lang.Boolean
     * @date 2020/9/12 8:38
     * @author YouHan
     */
    public static boolean isInteger(String s) {
        if (StringUtils.isBlank(s)) {
            return false;
        }

        return s.matches(INTEGER_REGEX);
    }

    /**
     * 判斷給定字符串是否為十六進制數(shù)
     *
     * @param value 值
     * @return 是否為十六進制
     */
    public static boolean isHex(String value) {
        final int index = (value.startsWith("-") ? 1 : 0);
        if (value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index)) {
            try {
                Long.decode(value);
            } catch (NumberFormatException e) {
                return false;
            }
            return true;
        }

        return false;
    }

    /**
     * 是否是數(shù)字(包括小數(shù))
     *
     * @param s
     * @return java.lang.Boolean
     * @date 2020/9/9 14:01
     * @author YouHan
     */
    public static boolean isNumber(String s) {
        if (StringUtils.isBlank(s)) {
            return false;
        }

        return s.matches(NUMBER_REGEX);
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n 十進制數(shù)
     * @return java.lang.String
     * @date 2019/4/8 09:22
     * @author YouHan
     */
    public static String intToHex(Integer n) {
        if (null == n) {
            return null;
        }

        return String.format("%X", n);
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n 十進制數(shù)
     * @return java.lang.String
     * @date 2019/4/8 09:22
     * @author YouHan
     */
    public static String longToHex(Long n) {
        if (null == n) {
            return null;
        }

        return String.format("%X", n);
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n
     * @param length
     * @return java.lang.String
     * @date 2019-08-12 09:56
     * @author YouHan
     */
    public static String intToHexPrefix(Integer n, Integer length) {
        if (null == n) {
            return null;
        }
        if (null == length || length <= 0) {
            return null;
        }

        String result = String.format("%X", n);
        if (result.length() < length) {
            result = YouStringUtil.appendPrefixContent(result, "0", length - result.length());
        }

        return result;
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n
     * @param length
     * @return java.lang.String
     * @date 2019-08-12 09:56
     * @author YouHan
     */
    public static String longToHexPrefix(Long n, Integer length) {
        if (null == n) {
            return null;
        }
        if (null == length || length <= 0) {
            return null;
        }

        String result = String.format("%X", n);
        if (result.length() < length) {
            result = YouStringUtil.appendPrefixContent(result, "0", length - result.length());
        }

        return result;
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n 十進制數(shù)
     * @return java.lang.String
     * @date 2019/4/8 09:22
     * @author YouHan
     */
    public static String intToHexSuffix(Integer n, Integer length) {
        if (null == n) {
            return null;
        }
        if (null == length || length <= 0) {
            return null;
        }

        String result = String.format("%X", n);
        if (result.length() < length) {
            result = YouStringUtil.appendSuffixContent(result, "0", length - result.length());
        }

        return result;
    }

    /**
     * 十進制轉(zhuǎn)十六進制
     *
     * @param n 十進制數(shù)
     * @return java.lang.String
     * @date 2019/4/8 09:22
     * @author YouHan
     */
    public static String longToHexSuffix(Long n, Integer length) {
        if (null == n) {
            return null;
        }
        if (null == length || length <= 0) {
            return null;
        }

        String result = String.format("%X", n);
        if (result.length() < length) {
            result = YouStringUtil.appendSuffixContent(result, "0", length - result.length());
        }

        return result;
    }

    /**
     * 十六進制轉(zhuǎn)十進制
     *
     * @param hex
     * @return java.lang.Integer
     * @date 2019/4/8 09:49
     * @author YouHan
     */
    public static Integer hexToInt(String hex) {
        Long n = hexToLong(hex);
        if (null == n) {
            return null;
        }

        // 超出整數(shù)最大值,不予處理
        if (Integer.MAX_VALUE < n) {
            return null;
        }

        return Integer.valueOf(String.valueOf(n));
    }

    /**
     * 十六進制轉(zhuǎn)十進制
     *
     * @param hex
     * @return java.lang.Integer
     * @date 2019/4/8 09:49
     * @author YouHan
     */
    public static Long hexToLong(String hex) {
        if (StringUtils.isBlank(hex)) {
            return null;
        }

        // 去除前綴為 0 的 十六進制
        if (hex.length() > 1 && hex.startsWith("0")) {
            hex = hex.substring(1);
        }

        return Long.valueOf(hex, 16);
    }

    /**
     * 字符串轉(zhuǎn)十六進制
     *
     * @param s
     * @return
     */
    public static String stringToHex(String s) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = s.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString().trim();
    }

    /**
     * 十六進制轉(zhuǎn)字符串
     *
     * @param s
     * @return
     */
    public static String hexToString(String s) {
        String str = "0123456789ABCDEF";
        char[] hexs = s.toCharArray();
        byte[] bytes = new byte[s.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }

        return new String(bytes);
    }

    /**
     * 去除末尾多余的 0
     *
     * @param s
     * @return java.lang.String
     * @author YouHan
     * @date 2021/7/2 15:39
     */
    public static String stripTrailingZeros(String s) {
        if (StringUtils.isBlank(s)) {
            return "0";
        }

        if (!isNumber(s)) {
            return "0";
        }

        if (!s.contains(".")) {
            return s;
        }

        while (s.endsWith("0")) {
            s = s.substring(0, s.length() - 1);
        }
        if (s.endsWith(".")) {
            s = s.substring(0, s.length() - 1);
        }

        return s;
    }

    /**
     * int 轉(zhuǎn) String
     * 1024以內(nèi)高效,超出后,正常轉(zhuǎn)換
     */
    static int cacheSize = 1024;
    static String[] caches = new String[cacheSize];

    static {
        for (int i = 0; i < cacheSize; i++) {
            caches[i] = String.valueOf(i);
        }
    }

    public static String int2String(int data) {
        if (data < cacheSize) {
            return caches[data];
        }
        return String.valueOf(data);
    }

    /**
     * 獲取幾位的 int 隨機數(shù)
     *
     * @param length
     * @return int
     * @author YouHan
     * @date 2021/12/19
     */
    public static int getRandomInt(int length) {
        return (int) ((Math.random() * 9 + 1) * 10 * length);
    }

    /**
     * 獲取幾位的 long 隨機數(shù)
     *
     * @param length
     * @return long
     * @author YouHan
     * @date 2021/12/19
     */
    public static long getRandomLong(long length) {
        return (long) ((Math.random() * 9 + 1) * 10 * length);
    }

    /**
     * 獲取隨機數(shù)
     *
     * @param
     * @return java.client.concurrent.ThreadLocalRandom
     * @author YouHan
     * @date 2021/6/3 10:29
     */
    public static ThreadLocalRandom getRandom() {
        return ThreadLocalRandom.current();
    }

    /**
     * 獲取緩存穿透時間(單位秒),最長不超過 5 分鐘
     *
     * @param
     * @return java.lang.Long
     * @date 2021/4/26 9:50
     * @author YouHan
     */
    public static Long getCachePenetrationTime() {
        return Long.valueOf(int2String(getRandom().nextInt(300)));
    }

    /**
     * 獲取數(shù)據(jù)庫緩存時間(單位秒),最長不超過 1 小時
     *
     * @param
     * @return java.lang.Long
     * @date 2021/4/26 9:50
     * @author YouHan
     */
    public static Long getDBCacheTime() {
        return Long.valueOf(int2String(getRandom().nextInt(3600)));
    }

    /**
     * 十六進制高低位轉(zhuǎn)換
     *
     * @param hexString
     * @return java.lang.String
     * @author YouHan
     * @date 2021/12/11
     */
    public static String hexHighLowPositionConvert(String hexString) {
        if (StringUtils.isBlank(hexString) || hexString.length() % 2 != 0) {
            return null;
        }

        StringBuilder result = new StringBuilder();
        for (int i = hexString.length() - 2; i >= 0; i = i - 2) {
            result.append(hexString.substring(i, i + 2));
        }

        return result.toString();
    }

    public static void main(String[] args) {
        System.out.println(Long.MAX_VALUE);
    }
}
  • 上業(yè)務(wù)代碼

Controller

/**
	 * 調(diào)用統(tǒng)一下單接口,并組裝生成支付所需參數(shù)對象.
	 *
	 * @param orderInfoVO 統(tǒng)一下單請求參數(shù)
	 */
	@Operation(summary = "調(diào)用統(tǒng)一下單接口")
	@PostMapping("/unifiedOrder")
	public AjaxResult unifiedOrder(HttpServletRequest request, @RequestBody OrderInfoVO orderInfoVO) {
		return orderInfoService.unifiedOrder(request, orderInfoVO);
	}

Service

AjaxResult unifiedOrder(HttpServletRequest request, OrderInfoVO orderInfoVO);

ServiceImpl

	@Override
    public AjaxResult unifiedOrder(HttpServletRequest request, OrderInfoVO orderInfoVO) {
		//根據(jù)typeId查詢支付金額  根據(jù)自己的業(yè)務(wù)邏輯自行處理
        SysFunctionType sysFunctionType = sysFunctionTypeMapper.selectFunctionTypeById(orderInfoVO.getTypeId());
        //通過customId 查詢用戶信息  根據(jù)自己的業(yè)務(wù)邏輯自行處理
        SysCustom sysCustom = sysCustomMapper.selectSysCustomById(orderInfoVO.getCustomId());
        //根據(jù)自己的業(yè)務(wù)邏輯自行處理 OrderInfo為我自己業(yè)務(wù)中的實體類
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderInfoVO.getOrderId());
        //支付類型
        orderInfo.setPaymentType(orderInfoVO.getPayType());
        //交易類型
        orderInfo.setTradeType("NATIVE");
        //支付金額(BigDecimal 例子:10.00)
        orderInfo.setPaymentPrice(sysFunctionType.getPrice());
        orderInfo.setName(sysCustom.getName()+"體檢報告");
        String body = orderInfo.getName();
        body = body.length() > 40 ? body.substring(0,39) : body;
        //更新編號防止不同終端微信報重復(fù)訂單號
        orderInfo.setOrderNo(IdUtil.getSnowflake(0,0).nextIdStr());
        //公眾號
        req.put("appid", payConfig.getAppId());
        // 商戶號
        req.put("mch_id", payConfig.getMchId());
        // 32位隨機字符串
        req.put("nonce_str", WXPayUtil.generateNonceStr());
        // 商品描述
        req.put("body", body); 
        // 商戶訂單號
        req.put("out_trade_no", orderInfo.getOrderNo());
        // 標(biāo)價金額(分)
        req.put("total_fee", String.valueOf(MoneyUtils.yuanToFen(String.valueOf(orderInfo.getPaymentPrice()))));
        // 終端IP
        req.put("spbill_create_ip", request.getRemoteAddr());
        // 回調(diào)地址+攜帶的返回參數(shù)  domain 為配置的域名[不可為ip地址]
        req.put("notify_url", domain+"/system/order/info/notify-order-wx"+"/"+sysDevice.getTenantId()+"/"+orderInfo.getId()+"/"+orderInfoVO.getTypeId());  
        // 交易類型
        req.put("trade_type", "NATIVE");
        // 簽名
        req.put("attach", String.valueOf(orderInfo.getTenantId()));
            try {
            	// 簽名
                req.put("sign", WXPayUtil.generateSignature(req, payConfig.getMchKey(), WXPayConstants.SignType.MD5));  
                String xmlBody = WXPayUtil.generateSignedXml(req, payConfig.getMchKey());
                System.err.println(String.format("微信支付預(yù)下單請求 xml 格式:\n%s", xmlBody));
                String result = WxChatPayCommonUtil.httpsRequest(WeChatPayUrl.Uifiedorder, "POST", xmlBody);
                this.updateOrderInfo(orderInfo);
                System.err.println(String.format("%s", result));
                Map<String, String> WxResultMap = WXPayUtil.xmlToMap(result);
                WxResultMap.put("orderNo",orderInfo.getOrderNo());
                if (ObjectUtil.isNotEmpty(WxResultMap.get("return_code")) && WxResultMap.get("return_code").equals("SUCCESS")) {
                    if (WxResultMap.get("result_code").equals("SUCCESS")) {
                        System.out.println("預(yù)下單成功");
                        System.out.println("QrCode:"+WxResultMap.get("code_url"));
                        return AjaxResult.success(WxResultMap);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
	}

參數(shù)疑惑解釋:
?notify_url:此參數(shù)為回調(diào)通知地址(公網(wǎng)必須可以訪問),當(dāng)這筆訂單用戶支付成功之后,”微信“會異步請求你這個地址告訴你 某個訂單支付成功了。后面會講到這個怎么寫這個接口 包括如何在本地環(huán)境進行測試。

完成上面的代碼,簡單的一個支付后端接口實現(xiàn)就完成了。

3:題外篇 回調(diào)地址

異步回調(diào)通知官方文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8

簡單來說就是:

在一筆訂單支付成功之后微信會告訴你的服務(wù)器這筆訂單支付成功了,然后你就需要根據(jù)你的項目業(yè)務(wù)邏輯進行處理,改變數(shù)據(jù)庫的支付結(jié)果,然后發(fā)貨。所以你需要寫一個接口放到你們項目中,讓微信來調(diào)用你的接口就行了。

回調(diào)的接口地址必須是公網(wǎng)可以進行訪問的,如果開發(fā)中您的項目公網(wǎng)沒有辦法訪問的話,微信是無法調(diào)用的。所以我們需要弄一個內(nèi)網(wǎng)穿透 花生殼:https://hsk.oray.com/(免費)

這個時候把域名地址配置到 application.yml

company:
  domain: https://33q716k372.imdo.co

4.回調(diào)方法

Controller

/**
	 * 支付回調(diào)(微信)
	 *
	 * @param xmlData  微信XML數(shù)據(jù)
	 * @param tenantId 商家id
	 * @param orderId  訂單id
	 * @param typeId   類型id
	 * @return 返回支付結(jié)果
	 */
	@Operation(summary = "支付回調(diào)(微信)")
	@PostMapping("/notify-order-wx/{tenantId}/{orderId}/{typeId}")
	public String notifyOrderWx(HttpServletRequest request, HttpServletResponse response,
								@RequestBody String xmlData, @PathVariable("tenantId") Long tenantId,
								@PathVariable("orderId") Long orderId,
								@PathVariable("typeId") Long typeId) throws IOException {
		log.info("支付回調(diào)(微信):" + xmlData);
		if(tenantId == null || orderId == null || typeId == null){
			System.out.println("驗簽失敗");
			response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
		}
		String resXml = "";
		try {
			//通過商家id查詢支付配置
			PayConfig payConfig = payConfigService.selectPayConfigByTenantId(tenantId,"1");
			Map<String, Object> ResultMap = orderInfoService.WeChatPayCallback(xmlData, payConfig.getMchKey());
			Map<String, String> WxResultMapData = new HashMap<>();
			if (ResultMap.get("Verify").equals("YES")) {
				//驗簽成功
				System.out.println("驗簽成功");
				WxResultMapData = (Map<String, String>) ResultMap.get("data");
				System.out.println("WxResultMapData:" + JSONUtil.toJsonStr(WxResultMapData));
				log.info("收到微信回調(diào):{}", JSONUtil.toJsonStr(WxResultMapData));
				OrderInfo orderInfo = orderInfoService.selectOrderInfoByOrderNo(WxResultMapData.get("out_trade_no"));
				System.out.println("通知微信驗簽成功");
				//自信業(yè)務(wù)邏輯處理
				orderInfoService.notifyOrder(orderInfo,tenantId,orderId,typeId,WxResultMapData);
				resXml = String.valueOf(ResultMap.get("returnWeChat"));
			} else if (ResultMap.get("Verify").equals("NO")) {
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[" + WxResultMapData.get("err_code_des") + "]]></return_msg>" + "</xml> ";
			}
		}catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
			out.write(resXml.getBytes());
			out.flush();
			out.close();
		}
		return WxPayNotifyResponse.success("成功");
	}

Service

public Map<String, Object> WeChatPayCallback(String xmlData, String apiKey);

ServiceImpl

@Override
    public Map<String, Object> WeChatPayCallback(String xmlData, String apiKey) {
        Map<String, Object> ResultMap = new HashMap<String, Object>();
        //解析到微信返回過來的xml數(shù)據(jù)
        try {
            //xml轉(zhuǎn)Map
            Map<String, String> WxResultMap = WXPayUtil.xmlToMap(xmlData);
            //驗證簽名
            boolean SignStatus = WXPayUtil.isSignatureValid(WxResultMap, apiKey);
            if (SignStatus) {
                //驗證成功
                //要返回給微信的xml數(shù)據(jù)
                String returnWeChat = WxChatPayCommonUtil.setReturnXml("SUCCESS", "OK");
                ResultMap.put("Verify", "YES");
                ResultMap.put("returnWeChat", returnWeChat);
                ResultMap.put("data", WxResultMap);
            } else {
                //驗證失敗(表示可能接口被他人調(diào)用  需要留意)
                ResultMap.put("Verify", "NO");
                ResultMap.put("msg", "驗簽失敗。");
            }
            return ResultMap;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

總結(jié) 

到此這篇關(guān)于Java接入微信支付的文章就介紹到這了,更多相關(guān)Java接入微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot實現(xiàn)TCP連接并進行數(shù)據(jù)互傳的方法

    SpringBoot實現(xiàn)TCP連接并進行數(shù)據(jù)互傳的方法

    本文詳細介紹了微服務(wù)架構(gòu)中的翻譯組件使用場景,以及多種開源翻譯組件的解決方案,文中分析了國內(nèi)外多個翻譯服務(wù)如百度翻譯、谷歌翻譯等,以及如何在微服務(wù)項目中集成這些翻譯組件,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    PDF轉(zhuǎn)文本的插件常用的有pdfbox ,itextpdf 和 spire.pdf,本文主要介紹如何使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片,需要的可以參考一下
    2025-01-01
  • JavaWeb倉庫管理系統(tǒng)詳解

    JavaWeb倉庫管理系統(tǒng)詳解

    這篇文章主要為大家詳細介紹了JavaWeb倉庫管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Spring和SpringBoot有哪些區(qū)別

    Spring和SpringBoot有哪些區(qū)別

    相信對于用了 SpringBoot很久的同學(xué)來說,還不是很理解 SpringBoot到底和 Spring有什么區(qū)別,看完文章中的比較,或許你有了不同的答案和看法。
    2020-10-10
  • springboot日志切面通用類實例詳解

    springboot日志切面通用類實例詳解

    這篇文章主要介紹了springboot日志切面通用類,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • SpringCloudStream原理和深入使用小結(jié)

    SpringCloudStream原理和深入使用小結(jié)

    Spring?Cloud?Stream是一個用于構(gòu)建與共享消息傳遞系統(tǒng)連接的高度可擴展的事件驅(qū)動型微服務(wù)的框架,本文給大家介紹SpringCloudStream原理和深入使用,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • SpringBoot lombok(注解@Getter @Setter)詳解

    SpringBoot lombok(注解@Getter @Setter)詳解

    通過使用Lombok庫,SpringBoot應(yīng)用可以自動化生成常用的方法如setter和getter,顯著降低了代碼冗余并提高了開發(fā)效率,Lombok的@Getter和@Setter注解用于自動生成屬性的訪問和修改方法,而@Data注解則提供了一個全面的解決方案
    2024-11-11
  • springboot2如何集成ElasticSearch6.4.3

    springboot2如何集成ElasticSearch6.4.3

    這篇文章主要介紹了springboot2如何集成ElasticSearch6.4.3問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • MyBatis-Plus MetaObjectHandler的原理及使用

    MyBatis-Plus MetaObjectHandler的原理及使用

    MyBatis-Plus的MetaObjectHandler接口允許開發(fā)者自動填充實體類字段,如創(chuàng)建時間、更新時間等公共字段,減少代碼重復(fù),提高數(shù)據(jù)一致性和完整性,感興趣的可以了解一下
    2024-10-10
  • java中的Integer的toBinaryString()方法實例

    java中的Integer的toBinaryString()方法實例

    這篇文章主要介紹了java中的Integer的toBinaryString()方法實例,有需要的朋友可以參考一下
    2013-12-12

最新評論