java微信掃碼支付模式一線下支付功能實(shí)現(xiàn)
一、準(zhǔn)備工作
無(wú)數(shù)人來(lái)追問(wèn)模式一的開發(fā),所以在這就貼出來(lái),僅供參考。關(guān)于模式一和模式二的區(qū)別,我有解釋過(guò)很多次,無(wú)非就是模式一的二維碼是針對(duì)商品的,模式二的二維碼是針對(duì)訂單的,其他具體細(xì)節(jié)我就不費(fèi)口舌了,各位可以自行去官方查看文檔,然后是選模式一還是模式二就得看自己的業(yè)務(wù)了。
1.1、有關(guān)配置參數(shù)
還是之前那四樣,APP_ID和APP_SECRET可以在公眾平臺(tái)找著,MCH_ID和API_KEY則在商戶平臺(tái)找到,特別是API_KEY要在商戶平臺(tái)設(shè)置好,這個(gè)東東關(guān)系到參數(shù)校驗(yàn)的正確與否,所以一定要設(shè)置正確。掃碼支付模式一其實(shí)與掃碼支付模式二類似,實(shí)際只會(huì)用到APP_ID、MCH_ID和API_KEY,其他的都不用。模式一的官方文檔地址在這:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
1.2、有關(guān)概念
在這里我想先修正一個(gè)概念,在之前模式二開發(fā)過(guò)程中我曾提到了一個(gè)“支付回調(diào)地址”這樣的概念,其作用實(shí)際就是客戶在掃描完成支付后,微信服務(wù)器要訪問(wèn)我們提供的這個(gè)地址,給我們發(fā)送支付結(jié)果,以便我們核實(shí)訂單進(jìn)行發(fā)貨,這是其他支付工具比較普遍的概念和叫法。不過(guò)后來(lái)我翻了一下微信官網(wǎng)的文檔,發(fā)現(xiàn)在模式一開發(fā)中,他們把這個(gè)叫做“異步通知url”而不是什么“支付回調(diào)地址”,但本質(zhì)這指的是一個(gè)意思??墒菫槭裁次乙谶@提到這個(gè)東東呢?這是因?yàn)樵谀J揭恢校瑢?shí)際上還有另外一個(gè)所謂的“支付回調(diào)”稱之為“掃碼支付回調(diào)URL”,這東東與上面的“異步通知url”可就不一樣了,簡(jiǎn)單理解可以認(rèn)為是咱們的服務(wù)器上一個(gè)用來(lái)輔助完成下單的接口。模式一的開發(fā)同時(shí)需要“掃碼支付回調(diào)URL”與“異步通知url”兩個(gè)接口配合才能完成,所以這里大家要辨別好了。
“異步通知url”在調(diào)用統(tǒng)一下單接口時(shí)進(jìn)行設(shè)置,可以動(dòng)態(tài)設(shè)置,只要這個(gè)接口按照有關(guān)規(guī)則接收參數(shù)響應(yīng)參數(shù)即可。而“掃碼支付回調(diào)URL”則較為固定,它在微信公眾平臺(tái)設(shè)置,設(shè)置后需要10分鐘左右才能生效,大家登錄微信公眾平臺(tái)后,選擇微信支付,在開發(fā)配置選項(xiàng)卡下面就可以找著:

這里咱們要設(shè)置一個(gè)自己服務(wù)器的地址(再說(shuō)一遍公網(wǎng)地址,就是讓微信服務(wù)器能找著你)。
1.3、開發(fā)環(huán)境
我這里以最基本的Servlet 3.0作為示例環(huán)境。關(guān)于引用第三方的jar包,相比較于模式二開發(fā),除了用到了xml操作的jdom,以外就一個(gè)Google ZXing的二維碼包和log4j包。如下圖:

為了方便調(diào)試,建議各位先在這個(gè)環(huán)境下調(diào)通了再移植到真實(shí)項(xiàng)目當(dāng)中去。
二、開發(fā)實(shí)戰(zhàn)
在動(dòng)手之前,我建議大家先去官方文檔那好好看看那個(gè)時(shí)序圖,理解了那個(gè)時(shí)序圖,寫代碼也就不是什么難事了,當(dāng)然如果看圖你沒(méi)辦法理解,也可以結(jié)合我下面的代碼來(lái)試著理解。
2.1、二維碼生成
首先是二維碼,二維碼中的內(nèi)容為鏈接,形式為:
weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
具體可以參考官方文檔模式一生成二維碼規(guī)則。接下來(lái)我們需要將該鏈接生成二維碼,我這里使用了Google ZXing來(lái)生成二維碼。
package com.wqy;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.wqy.util.PayCommonUtil;
import com.wqy.util.PayConfigUtil;
/**
* Servlet implementation class Pay1
*/
@WebServlet("/Pay1")
public class Pay1 extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(Pay1.class);
public static int defaultWidthAndHeight=200;
/**
* @see HttpServlet#HttpServlet()
*/
public Pay1() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
String nonce_str = PayCommonUtil.getNonce_str();
long time_stamp = System.currentTimeMillis() / 1000;
String product_id = "hd_goodsssss_10";
String key = PayConfigUtil.API_KEY; // key
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
packageParams.put("appid", PayConfigUtil.APP_ID);
packageParams.put("mch_id", PayConfigUtil.MCH_ID);
packageParams.put("time_stamp", String.valueOf(time_stamp));
packageParams.put("nonce_str", nonce_str);
packageParams.put("product_id", product_id);
String sign = PayCommonUtil.createSign("UTF-8", packageParams,key);//MD5哈希
packageParams.put("sign", sign);
//生成參數(shù)
String str = ToUrlParams(packageParams);
String payurl = "weixin://wxpay/bizpayurl?" + str;
logger.info("payurl:"+payurl);
//生成二維碼
Map<EncodeHintType, Object> hints=new HashMap<EncodeHintType, Object>();
// 指定糾錯(cuò)等級(jí)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// 指定編碼格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(payurl,BarcodeFormat.QR_CODE, defaultWidthAndHeight, defaultWidthAndHeight, hints);
OutputStream out = response.getOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "png", out);//輸出二維碼
out.flush();
out.close();
} catch (WriterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String ToUrlParams(SortedMap<Object, Object> packageParams){
//實(shí)際可以不排序
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 (null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.deleteCharAt(sb.length()-1);//刪掉最后一個(gè)&
return sb.toString();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2.2、掃描支付回調(diào)url接口
當(dāng)客戶用微信掃了上面的二位碼之后,微信服務(wù)器就會(huì)訪問(wèn)此接口,在這里我們要完成統(tǒng)一下單獲取交易會(huì)話標(biāo)識(shí),處理的主要流程如下:
1)、接收微信服務(wù)器發(fā)送過(guò)來(lái)的參數(shù),對(duì)參數(shù)進(jìn)行簽名校驗(yàn);
2)、取出參數(shù)product_id,這是二維碼上唯一能夠透?jìng)鬟^(guò)來(lái)的參數(shù),其他參數(shù)可參照官方文檔模式一3.1 輸入?yún)?shù);
3)、根據(jù)product_id處理自己的業(yè)務(wù),比如計(jì)算支付金額,生成訂單號(hào)等;
4)、調(diào)用統(tǒng)一下單接口獲取交易會(huì)話標(biāo)識(shí)prepay_id;
4.1)、準(zhǔn)備好相關(guān)參數(shù)(如appid、mch_id、支付金額、訂單號(hào)、商品描述等),調(diào)用微信統(tǒng)一下單接口(與模式二調(diào)用統(tǒng)一下單接口類似),留意一下這里要加上上面提到的“異步通知url”,也就是后面會(huì)說(shuō)道的異步通知url接口,具體參數(shù)參考官方文檔統(tǒng)一下單請(qǐng)求參數(shù);
4.2)、接收統(tǒng)一下單接口返回的參數(shù),對(duì)參數(shù)進(jìn)行驗(yàn)簽;
4.3)、取出參數(shù)prepay_id,這是交易會(huì)話標(biāo)識(shí),極其重要,其他參數(shù)可參考官方文檔統(tǒng)一下單返回結(jié)果;
5)、準(zhǔn)備好相關(guān)參數(shù)(如appid、mch_id、return_code、prepay_id等),響應(yīng)最開始的支付回調(diào)(如果上面步驟如果錯(cuò)誤,如驗(yàn)簽失敗則可以返回錯(cuò)誤參數(shù)給微信服務(wù)器),具體參數(shù)可參照官方文檔模式一3.2 輸出參數(shù)。
package com.wqy;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.wqy.util.HttpUtil;
import com.wqy.util.PayCommonUtil;
import com.wqy.util.PayConfigUtil;
/**
* Servlet implementation class Notify1
*/
@WebServlet("/Notify1")
public class Notify1 extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(Notify1.class);
/**
* @see HttpServlet#HttpServlet()
*/
public Notify1() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// 讀取xml
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
SortedMap<Object, Object> packageParams = PayCommonUtil.xmlConvertToMap(sb.toString());
logger.info(packageParams);
// 賬號(hào)信息
String key = PayConfigUtil.API_KEY; // key
String resXml="";//反饋給微信服務(wù)器
// 驗(yàn)簽
if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {
//appid openid mch_id is_subscribe nonce_str product_id sign
//統(tǒng)一下單
String openid = (String)packageParams.get("openid");
String product_id = (String)packageParams.get("product_id");
//解析product_id,計(jì)算價(jià)格等
String out_trade_no = String.valueOf(System.currentTimeMillis()); // 訂單號(hào)
String order_price = "1"; // 價(jià)格 注意:價(jià)格的單位是分
String body = product_id; // 商品名稱 這里設(shè)置為product_id
String attach = "XXX店"; //附加數(shù)據(jù)
String nonce_str0 = PayCommonUtil.getNonce_str();
// 獲取發(fā)起電腦 ip
String spbill_create_ip = PayConfigUtil.CREATE_IP;
String trade_type = "NATIVE";
SortedMap<Object,Object> unifiedParams = new TreeMap<Object,Object>();
unifiedParams.put("appid", PayConfigUtil.APP_ID); // 必須
unifiedParams.put("mch_id", PayConfigUtil.MCH_ID); // 必須
unifiedParams.put("out_trade_no", out_trade_no); // 必須
unifiedParams.put("product_id", product_id);
unifiedParams.put("body", body); // 必須
unifiedParams.put("attach", attach);
unifiedParams.put("total_fee", order_price); // 必須
unifiedParams.put("nonce_str", nonce_str0); // 必須
unifiedParams.put("spbill_create_ip", spbill_create_ip); // 必須
unifiedParams.put("trade_type", trade_type); // 必須
unifiedParams.put("openid", openid);
unifiedParams.put("notify_url", PayConfigUtil.NOTIFY_URL);//異步通知url
String sign0 = PayCommonUtil.createSign("UTF-8", unifiedParams,key);
unifiedParams.put("sign", sign0); //簽名
String requestXML = PayCommonUtil.getRequestXml(unifiedParams);
logger.info(requestXML);
//統(tǒng)一下單接口
String rXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
//統(tǒng)一下單響應(yīng)
SortedMap<Object, Object> reParams = PayCommonUtil.xmlConvertToMap(rXml);
logger.info(reParams);
//驗(yàn)簽
if (PayCommonUtil.isTenpaySign("UTF-8", reParams, key)) {
// 統(tǒng)一下單返回的參數(shù)
String prepay_id = (String)reParams.get("prepay_id");//交易會(huì)話標(biāo)識(shí) 2小時(shí)內(nèi)有效
String nonce_str1 = PayCommonUtil.getNonce_str();
SortedMap<Object,Object> resParams = new TreeMap<Object,Object>();
resParams.put("return_code", "SUCCESS"); // 必須
resParams.put("return_msg", "OK");
resParams.put("appid", PayConfigUtil.APP_ID); // 必須
resParams.put("mch_id", PayConfigUtil.MCH_ID);
resParams.put("nonce_str", nonce_str1); // 必須
resParams.put("prepay_id", prepay_id); // 必須
resParams.put("result_code", "SUCCESS"); // 必須
resParams.put("err_code_des", "OK");
String sign1 = PayCommonUtil.createSign("UTF-8", resParams,key);
resParams.put("sign", sign1); //簽名
resXml = PayCommonUtil.getRequestXml(resParams);
logger.info(resXml);
}else{
logger.info("簽名驗(yàn)證錯(cuò)誤");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[簽名驗(yàn)證錯(cuò)誤]]></return_msg>" + "</xml> ";
}
}else{
logger.info("簽名驗(yàn)證錯(cuò)誤");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[簽名驗(yàn)證錯(cuò)誤]]></return_msg>" + "</xml> ";
}
//------------------------------
//處理業(yè)務(wù)完畢
//------------------------------
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
至此,用戶的微信單就會(huì)顯示出要支付的金額及商品描述等,接下來(lái)就是等待客戶完成支付。
2.3、異步通知url接口
當(dāng)用戶在微信上完成支付操作后,微信服務(wù)器就會(huì)異步通知這個(gè)接口,給我們發(fā)送最終的支付結(jié)果,以便我們核實(shí)訂單進(jìn)行發(fā)貨等操作,注意這個(gè)接口和模式二的開發(fā)是一模一樣的。大概流程如下:
1)、接收微信服務(wù)器發(fā)送過(guò)來(lái)的參數(shù),對(duì)參數(shù)進(jìn)行簽名校驗(yàn);
2)、取出參數(shù)result_code、訂單號(hào)out_trade_no、訂單金額total_fee及其他業(yè)務(wù)相關(guān)的參數(shù),具體參數(shù)可參照官方文檔支付結(jié)果通用通知的通知參數(shù);
3)、處理業(yè)務(wù),如校驗(yàn)訂單號(hào)及訂單金額、修改訂單狀態(tài)等;
4)、準(zhǔn)備好相關(guān)參數(shù)(return_code和return_msg),應(yīng)答微信服務(wù)器。
注意,如果微信收到商戶的應(yīng)答不是成功或超時(shí),微信認(rèn)為通知失敗,微信會(huì)通過(guò)一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)
package com.wqy;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.SortedMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.wqy.util.PayCommonUtil;
import com.wqy.util.PayConfigUtil;
/**
* Servlet implementation class Re_notify
*/
@WebServlet("/Re_notify")
public class Re_notify extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(Re_notify.class);
/**
* @see HttpServlet#HttpServlet()
*/
public Re_notify() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// 讀取參數(shù)
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
SortedMap<Object, Object> packageParams = PayCommonUtil.xmlConvertToMap(sb.toString());
logger.info(packageParams);
// 賬號(hào)信息
String key = PayConfigUtil.API_KEY; // key
String resXml = ""; // 反饋給微信服務(wù)器
// 判斷簽名是否正確
if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {
// ------------------------------
// 處理業(yè)務(wù)開始
// ------------------------------
if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
// 這里是支付成功
////////// 執(zhí)行自己的業(yè)務(wù)邏輯////////////////
String mch_id = (String) packageParams.get("mch_id");
String openid = (String) packageParams.get("openid");
String is_subscribe = (String) packageParams.get("is_subscribe");
String out_trade_no = (String) packageParams.get("out_trade_no");
String total_fee = (String) packageParams.get("total_fee");
logger.info("mch_id:" + mch_id);
logger.info("openid:" + openid);
logger.info("is_subscribe:" + is_subscribe);
logger.info("out_trade_no:" + out_trade_no);
logger.info("total_fee:" + total_fee);
////////// 執(zhí)行自己的業(yè)務(wù)邏輯////////////////
logger.info("支付成功");
// 通知微信.異步確認(rèn)成功.必寫.不然會(huì)一直通知后臺(tái).八次之后就認(rèn)為交易失敗了.
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
logger.info("支付失敗,錯(cuò)誤信息:" + packageParams.get("err_code"));
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[報(bào)文為空]]></return_msg>" + "</xml> ";
}
} else {
logger.info("簽名驗(yàn)證錯(cuò)誤");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[簽名驗(yàn)證錯(cuò)誤]]></return_msg>" + "</xml> ";
}
// ------------------------------
// 處理業(yè)務(wù)完畢
// ------------------------------
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
三、測(cè)試結(jié)果
3.1、生成的支付二維碼鏈接

3.2、支付回調(diào)url接口接收到的參數(shù)

3.3、發(fā)起統(tǒng)一下單請(qǐng)求參數(shù)

3.4、統(tǒng)一下單返回參數(shù)

3.5、支付回調(diào)url接口最終的響應(yīng)參數(shù)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)大文件的切割與合并操作示例
這篇文章主要介紹了Java實(shí)現(xiàn)大文件的切割與合并操作,結(jié)合實(shí)例形式分析了java基于io及util操作大文件按指定個(gè)數(shù)分割與合并相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
JMeter中的后端監(jiān)聽器的實(shí)現(xiàn)
本文主要介紹了JMeter中的后端監(jiān)聽器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
通過(guò)Java實(shí)現(xiàn)獲取表的自增主鍵值
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)Java實(shí)現(xiàn)獲取表的自增主鍵值,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下2023-06-06
Java設(shè)計(jì)模式之23種設(shè)計(jì)模式詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之23種設(shè)計(jì)模式詳解,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問(wèn)題,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
從零開始在Centos7上部署SpringBoot項(xiàng)目
本文主要介紹了從零開始在Centos7上部署SpringBoot項(xiàng)目,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

