最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot微信掃碼支付的實現(xiàn)示例

 更新時間:2021年01月26日 10:46:42   作者:代碼中的余溫  
這篇文章主要介紹了SpringBoot微信掃碼支付的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、首先導入生成二維碼和微信支付環(huán)境

    <!-- 生成二維碼工具 -->
    <dependency>
      <groupId>com.google.zxing</groupId>
      <artifactId>core</artifactId>
      <version>3.2.1</version>
    </dependency>
    <dependency>
      <groupId>com.google.zxing</groupId>
      <artifactId>javase</artifactId>
      <version>3.2.0</version>
    </dependency>
    <!-- 微信支付所需sdk -->
    <dependency>
      <groupId>com.github.wxpay</groupId>
      <artifactId>wxpay-sdk</artifactId>
      <version>0.0.3</version>
    </dependency>

二、在application.yml文件配置微信所有需的基本配置

1.導入

代碼如下(示例):

# 服務器域名地址
server:
 service-domain: //這里寫你的域名地址
#微信app支付
pay:
 wxpay:
  app:
   appID: 微信appid
   mchID: 商戶號
   key: //這個key實在微信支付公眾品臺自己定義的key 要求36位
   certPath: static/cert/wxpay/apiclient_cert.p12 # 從微信商戶平臺下載的安全證書存放的路徑、我放在resources下面,切記一定要看看target目錄下的class文件下有沒有打包apiclient_cert.p12文件
   payNotifyUrl: # 微信支付成功的異步通知接口 這里引入你的回調接口。
   //這里直接寫https://域名:端口/接口地址,注意一定是線上的接口,因為微信訪問不到你本地的接口

2.創(chuàng)建MyWXPayConfig類引入配置信息

代碼如下(示例):

package com.example.gasstation.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.InputStream;

@Data
@Component
@ConfigurationProperties(prefix = "pay.wxpay.app")
public class MyWXPayConfig implements WXPayConfig{

  /**
   * appID
   */
  private String appID;

  /**
   * 商戶號
   */
  private String mchID;

  /**
   * API 密鑰
   */
  private String key;

  /**
   * API證書絕對路徑 (本項目放在了 resources/cert/wxpay/apiclient_cert.p12")
   */
  private String certPath;

  /**
   * HTTP(S) 連接超時時間,單位毫秒
   */
  private int httpConnectTimeoutMs = 8000;

  /**
   * HTTP(S) 讀數(shù)據(jù)超時時間,單位毫秒
   */
  private int httpReadTimeoutMs = 10000;

  /**
   * 微信支付異步通知地址
   */
  private String payNotifyUrl;

  /**
   * 微信退款異步通知地址
   */
  private String refundNotifyUrl;

  /**
   * 統(tǒng)一下單url
   */
  private final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

 /** 這里實現(xiàn)了一個service層**/
  @Override
  public InputStream getCertStream() {
    InputStream certStream =getClass().getClassLoader().getResourceAsStream(certPath);
    return certStream;
  }
  //在同層級下面新建WXPayConfig service層
  package com.example.gasstation.config;
 import java.io.InputStream;
 public interface WXPayConfig {
   InputStream getCertStream();//不要問我為啥不另起一行,因為我懶
 }
}

三、引入 WxPayServiceImpl 實現(xiàn)類

package com.example.gasstation.server.impl;

import com.example.gasstation.config.MyWXPayConfig;
import com.example.gasstation.entity.Result;
import com.example.gasstation.mapper.PayMapper;
import com.example.gasstation.model.Money_transfer;
import com.example.gasstation.model.Pay;
import com.example.gasstation.server.WxPayService;
import com.example.gasstation.util.HttpClientUtil;
import com.example.gasstation.util.WXPayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

@Service
public class WxPayServiceImpl implements WxPayService {

  @Autowired
  private MyWXPayConfig wxPayAppConfig;

  @Autowired
  private PayMapper payMapper;
  @Override
  public String save(String orderNo, double amount, String body,Integer uid) {
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式
    // 1. 生成訂單
    // 訂單號,流水號,金額,付款狀態(tài),創(chuàng)建時間
    String product_id = WXPayUtils.generateUUID();
    Pay pay = new Pay();//這里新建一個實體類 用處存入數(shù)據(jù)庫
    pay.setTradeNo(product_id);
    pay.setOutTradeNo(orderNo);
    pay.setBody(body);
    pay.setPaystatus(1);
    pay.setUid(uid);
    pay.setTotalAmount(amount);
    pay.setGmtCreate(df.format(new Date()));
    pay.setTradeStatus("0");
    pay.setAppId(wxPayAppConfig.getAppID());
    // 生成預支付訂單,保存到數(shù)據(jù)庫
    payMapper.insert(pay);
    // 調用統(tǒng)一下單方法,返回 codeUrl 地址
    String codeUrl = unifiedOrder(product_id,orderNo,amount,body);

    return codeUrl;
  }

  private String unifiedOrder(String product_id, String orderNo, double amount, String body){
    // 生成簽名
    try{
      SortedMap<String, String> params = new TreeMap<>();
      params.put("appid",wxPayAppConfig.getAppID());
      params.put("mch_id",wxPayAppConfig.getMchID());
      params.put("nonce_str", WXPayUtils.generateUUID());
      params.put("body",body);           // 商品描述
      params.put("out_trade_no",orderNo);      // 商戶訂單號
      params.put("total_fee",String.valueOf((int)(amount*100)));       // 標價金額(單位為分)
      params.put("spbill_create_ip", "這里寫服務器IP");  // 終端IP

      params.put("notify_url", wxPayAppConfig.getPayNotifyUrl());  // 異步接收微信支付結果通知的回調地址
      params.put("trade_type","NATIVE");         // 交易類型
      params.put("product_id",product_id);        // 微信支付要求NATIVE支付,此參數(shù)必填


      // sign 簽名
      String sign = WXPayUtils.createSign(params, wxPayAppConfig.getKey());
      params.put("sign",sign);
      System.out.println(sign);

      // map轉xml
      String payXml = WXPayUtils.mapToXml(params);
      System.out.println(payXml);

      // 統(tǒng)一下單
      String s = HttpClientUtil.doPost(wxPayAppConfig.getUNIFIED_ORDER_URL(), payXml, 10000);
      if(null == s){
        return null;
      }
      Map<String, String> unifiedOrderMap = WXPayUtils.xmlToMap(s);
      System.out.println(unifiedOrderMap.toString());
      if(unifiedOrderMap != null){
        // 前臺添加定時器,進行輪詢操作,直到支付完畢
        return unifiedOrderMap.get("code_url");
      }
    } catch (Exception e){
      e.printStackTrace();
    }
    return null;
  }
}

四、引入WxPayService層

package com.example.gasstation.server;

import com.example.gasstation.model.Money_transfer;

public interface WxPayService {

  String save(String orderNo, double amount, String body,Integer uid);

  boolean callBackPayUpdate(String outTradeNo,String totalFee);
}

五、引入Util類

package com.example.gasstation.util;

import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.*;

/**
 * @Author qjp
 */
public class WXPayUtils {
  /**
   * XML格式字符串轉換為Map
   *
   * @param strXML XML字符串
   * @return XML數(shù)據(jù)轉換后的Map
   * @throws Exception
   */
  public static Map<String, String> xmlToMap(String strXML) throws Exception {
    try {
      Map<String, String> data = new HashMap<String, String>();
      DocumentBuilder documentBuilder = WXPayXmlUtil.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) {
        // do nothing
      }
      return data;
    } catch (Exception ex) {
      WXPayUtils.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
      throw ex;
    }

  }

  /**
   * 將Map轉換為XML格式的字符串
   *
   * @param data Map類型數(shù)據(jù)
   * @return XML格式的字符串
   * @throws Exception
   */
  public static String mapToXml(Map<String, String> data) throws Exception {
    Document document = WXPayXmlUtil.newDocument();
    Element root = document.createElement("xml");
    document.appendChild(root);
    for (String key: data.keySet()) {
      String value = data.get(key);
      if (value == null) {
        value = "";
      }
      value = value.trim();
      Element filed = document.createElement(key);
      filed.appendChild(document.createTextNode(value));
      root.appendChild(filed);
    }
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    DOMSource source = new DOMSource(document);
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    transformer.transform(source, result);
    String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
    try {
      writer.close();
    }
    catch (Exception ex) {
    }
    return output;
  }

  /**
   * 生成微信支付sign
   */
  public static String createSign(SortedMap<String, String> params, String key){
    StringBuilder sb = new StringBuilder();
    Set<Map.Entry<String, String>> es = params.entrySet();
    Iterator<Map.Entry<String, String>> it = es.iterator();
    while(it.hasNext()){
      Map.Entry<String, String> entry = it.next();
      String k = entry.getKey();
      String v = entry.getValue();
      if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)){
        sb.append(k + "=" + v + "&");
      }
    }
    sb.append("key=").append(key);
    String sign = MD5Util.MD5(sb.toString()).toUpperCase();

    return sign;
  }

  /**
   * 校驗簽名
   * @param params
   * @param key
   * @return
   */
  public static Boolean isCorrectSign(SortedMap<String, String> params, String key){
    String sign = createSign(params, key);
    String wxPaySign = params.get("sign").toUpperCase();

    return wxPaySign.equals(sign);
  }
  /**
   * 獲取有序map
   * @param map
   */
  public static SortedMap<String, String> getSortedMap(Map<String, String> map){
    SortedMap<String, String> sortedMap = new TreeMap<>();
    Iterator<String> it = map.keySet().iterator();
    while(it.hasNext()){
      String key = it.next();
      String value = map.get(key);
      String temp = "";
      if(null != value){
        temp = value.trim();
      }
      sortedMap.put(key, value);
    }
    return sortedMap;
  }

  /**
   * 日志
   * @return
   */
  public static Logger getLogger() {
    Logger logger = LoggerFactory.getLogger("wxpay java sdk");
    return logger;
  }

  /**
   * 獲取當前時間戳,單位秒
   * @return
   */
  public static long getCurrentTimestamp() {
    return System.currentTimeMillis()/1000;
  }

  /**
   * 獲取當前時間戳,單位毫秒
   * @return
   */
  public static long getCurrentTimestampMs() {
    return System.currentTimeMillis();
  }
  /**
   * 生成UUID(用來表示一筆訂單)
   * @return
   */
  public static String generateUUID(){
    String uuid = UUID.randomUUID().toString()
        .replaceAll("-","")
        .substring(0,32);
    return uuid;
  }
}

引入WXPayXmlUtil類

package com.example.gasstation.util;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;

public final class WXPayXmlUtil {
  public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    documentBuilderFactory.setXIncludeAware(false);
    documentBuilderFactory.setExpandEntityReferences(false);

    return documentBuilderFactory.newDocumentBuilder();
  }

  public static Document newDocument() throws ParserConfigurationException {
    return newDocumentBuilder().newDocument();
  }
}

六、引入WxPayController類

提示:到這里沒有報錯咱們已經(jīng)成功一半啦

@RestController
@RequestMapping("/wxPay")
public class WxPayController {

  @Autowired
  private WxPayService wxPayService;

  @Autowired
  private MyWXPayConfig wxPayConfig;

  @Autowired
  private WebMvcConfigurer webMvcConfigurer;

  /**
   * 微信支付 生成二維碼
   *
   * @param money
   * @return
   */
  @GetMapping("/pay")
  public void wxPay(Double money,String body,Integer uid ,HttpServletResponse response){
    Double amount = money;//金額
    SimpleDateFormat date = new SimpleDateFormat("yyyyMMddHHmmss");
    String orderNo = date.format(new Date()) + WXPayUtils.getCurrentTimestampMs();
    String url_code = wxPayService.save(orderNo, amount, body,uid);
    System.out.println("url_code:----------"+url_code);
    if(url_code == null){
      throw new NullPointerException();
    }

    try {
      // 生成二維碼配置
      Map<EncodeHintType, Object> hints = new HashMap<>();
      // 設置糾錯等級
      hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
      // 編碼類型
      hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

      BitMatrix bitMatrix = new MultiFormatWriter().encode(url_code, BarcodeFormat.QR_CODE, 400, 400, hints);
      OutputStream outputStream = response.getOutputStream();

      MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);

    } catch (Exception e){
      e.printStackTrace();
    }
  }

  /**
   * 微信支付回調接口
   */
  @RequestMapping("/callback")
  public void OrderCallBack(HttpServletRequest request, HttpServletResponse response) {
    InputStream inputStream = null;
    try {
      inputStream = request.getInputStream();
      // BufferedReader是包裝設計模式,性能更高
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
      StringBuffer stringBuffer = new StringBuffer();
      String line;
      while ((line = bufferedReader.readLine()) != null) {
        stringBuffer.append(line);
      }
      bufferedReader.close();
      inputStream.close();
      Map<String, String> callBackMap = WXPayUtils.xmlToMap(stringBuffer.toString());
      System.out.println(callBackMap.toString());

      SortedMap<String, String> sortedMap = WXPayUtils.getSortedMap(callBackMap);
      // 校驗簽名是否正確
      if (WXPayUtils.isCorrectSign(sortedMap, wxPayConfig.getKey())) {
        System.out.println("簽名校驗成功!");
        // 更新訂單狀態(tài)
        if ("SUCCESS".equals(sortedMap.get("result_code"))) {
          String outTradeNo = sortedMap.get("out_trade_no"); // 流水號
          String totalFee = sortedMap.get("total_fee"); // 交易金額
          if (wxPayService.callBackPayUpdate(outTradeNo, totalFee)) {  // 通知微信訂單處理成功
            response.setContentType("text/xml");
            response.setContentType("content-type");
            response.getWriter().println("<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>");
            //這里說明告訴微信你已經(jīng)成功啦,別給老子重復回調我的方法啦,這里有一個坑,
            response.setContentType("text/xml");
            response.getWriter().println("SUCCESS")
            //本身我就只有這兩句話,然后就導致微信一直回調我的方法,廢了半天的勁才搞好啦,
            //原因就是格式不對,給他返回的值他不認識,這里可以看一下微信的支付開發(fā)文檔,雖然文檔寫的很垃圾
          }
        }
        // 未成功,就都處理為失敗訂單
        response.setContentType("text/html");
        response.getWriter().println("fail");
      }
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

七、MD5加密

@Slf4j
public class MD5Util {
  
  public static String MD5(String source) {
    return encodeMd5(source.getBytes());
  }
  private static String encodeMd5(byte[] source) {
    try {
      return encodeHex(MessageDigest.getInstance("MD5").digest(source));
    } catch (NoSuchAlgorithmException e) {
      throw new IllegalStateException(e.getMessage(), e);
    }
  }

  private static String encodeHex(byte[] bytes) {
    StringBuffer buffer = new StringBuffer(bytes.length * 2);
    for (int i = 0; i < bytes.length; i++) {
      if(((int) bytes[i] & 0xff) < 0x10) {
        buffer.append("0");
      }
      buffer.append(Long.toString((int) bytes[i] & 0xff, 16));
    }
    return buffer.toString();
  }
}

總結

有什么不對的地方歡迎各位碼友指出問題,因為我也是第一次做這個微信掃碼支付
回調方法返回類型是void 你設置其他返回類型,就會跟你 給微信返的起沖突,就會導致報錯

到此這篇關于SpringBoot微信掃碼支付的實現(xiàn)示例的文章就介紹到這了,更多相關SpringBoot微信掃碼支付內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 詳解如何在Java項目中實現(xiàn)信號的連續(xù)接收

    詳解如何在Java項目中實現(xiàn)信號的連續(xù)接收

    在Java項目中,信號的連續(xù)接收是一項重要的任務,特別是在處理異步事件或者需要對外部事件做出響應時,本篇博客將介紹如何在Java項目中實現(xiàn)信號的連續(xù)接收,包括信號的監(jiān)聽、處理和停止等步驟,需要的朋友可以參考下
    2023-11-11
  • 一篇文章帶你了解Java基礎-抽象

    一篇文章帶你了解Java基礎-抽象

    這篇文章主要給大家介紹了關于Java抽象定義以及舉例的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-08-08
  • 一篇文章弄懂Mybatis中#和$的區(qū)別

    一篇文章弄懂Mybatis中#和$的區(qū)別

    mybatis為我們提供了兩種支持動態(tài)sql的語法#{}以及${},兩者都是動態(tài)的向sql語句中傳入需要的參數(shù),下面這篇文章主要給大家介紹了如何通過一篇文章弄懂Mybatis中#和$區(qū)別的相關資料,需要的朋友可以參考下
    2021-12-12
  • Spring Boot Jar 文件能直接運行的操作方法

    Spring Boot Jar 文件能直接運行的操作方法

    本文將深入探討 Spring Boot 的打包過程及其運行原理,揭示其 JAR 文件如何巧妙地集成依賴項、嵌入 Web 容器并實現(xiàn)自動配置,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • idea在工具欄中顯示快速創(chuàng)建包和類的圖標的詳細步驟

    idea在工具欄中顯示快速創(chuàng)建包和類的圖標的詳細步驟

    點擊需要創(chuàng)建包或者類的位置,在點擊對用的圖標就可以快速創(chuàng)建類或者包了,下面小編給大家介紹idea在工具欄中顯示快速創(chuàng)建包和類的圖標的詳細步驟,感興趣的朋友一起看看吧
    2024-02-02
  • Spring中使用JSR303請求約束判空的實現(xiàn)

    Spring中使用JSR303請求約束判空的實現(xiàn)

    這篇文章主要介紹了Spring中使用JSR303請求約束判空的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • JavaEE實現(xiàn)前后臺交互的文件上傳與下載

    JavaEE實現(xiàn)前后臺交互的文件上傳與下載

    這篇文章主要介紹了JavaEE實現(xiàn)前后臺交互的文件上傳與下載,分享相關技術,實現(xiàn)文件上傳下載功能,需要的朋友可以參考下
    2015-11-11
  • Java枚舉使用方法詳解

    Java枚舉使用方法詳解

    這篇文章主要為大家詳細介紹了Java枚舉的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 如何優(yōu)雅的進行Spring整合MongoDB詳解

    如何優(yōu)雅的進行Spring整合MongoDB詳解

    這篇文章主要給大家介紹了如何優(yōu)雅的進行Spring整合MongoDB的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-02-02
  • 使用spring+maven不同環(huán)境讀取配置方式

    使用spring+maven不同環(huán)境讀取配置方式

    這篇文章主要介紹了使用spring+maven不同環(huán)境讀取配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評論

阿克陶县| 依兰县| 乾安县| 威远县| 淮阳县| 新宁县| 临高县| 长沙县| 桑植县| 柳江县| 平昌县| 钟山县| 明光市| 临高县| 惠安县| 北川| 甘洛县| 蒲江县| 武夷山市| 明光市| 阿合奇县| 滨州市| 育儿| 双牌县| 化德县| 南江县| 灌云县| 武清区| 宁阳县| 紫阳县| 阳谷县| 德格县| 巴林左旗| 博兴县| 会东县| 井陉县| 彭泽县| 九龙坡区| 通化市| 团风县| 申扎县|