JAVA實(shí)現(xiàn)微信APPV3支付保姆級(jí)教程
前言
現(xiàn)在Java微信支付文章五花八門 看不懂 看的懵 摻雜業(yè)務(wù)邏輯不知名的返回封裝 爆紅一片 不妨看看這篇
由于微信更新了0.4.9版本 部分使用微信支付會(huì)解析報(bào)錯(cuò) 原因是微信內(nèi)置了Jackson2.13.xxx依賴會(huì)與springboot這個(gè)Jackson產(chǎn)生沖突 可能會(huì)無(wú)法升級(jí)依賴 因?yàn)樯?jí)了也會(huì)使用老版本依賴
解決方法需要把微信支付解析 驗(yàn)簽等方法分離重寫 目前沒(méi)時(shí)間寫文章
1.加入Maven依賴
<!-- 微信支付V3 目前新版本--> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.7</version> </dependency>
2.創(chuàng)建WxV3PayConfig.java配置類
/** * implements WXPayConfig */ @Data public class WxV3PayConfig { //平臺(tái)證書序列號(hào) public static String mchSerialNo = "xxxxxxxxxxxxxx"; //appID public static String APP_ID = "xxxxxxxxxxxxxx"; //商戶id public static String Mch_ID = "xxxxxxxxxxxxxx"; // API V3密鑰 public static String apiV3Key = "xxxxxxxxxxxxxx"; // 商戶API V3私鑰 public static String privateKey = " -----BEGIN PRIVATE KEY----- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -----END PRIVATE KEY-----"; }
3.創(chuàng)建WXPaySignatureCertificateUtil.java 工具類
復(fù)制粘貼即可
/*** * *包都在這 * * * */ import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier; import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import lombok.SneakyThrows; import org.apache.http.impl.client.CloseableHttpClient; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; public class WXPaySignatureCertificateUtil { /** * 證書驗(yàn)證 * 自動(dòng)更新的簽名驗(yàn)證器 */ public static CloseableHttpClient checkSign() throws IOException { //驗(yàn)簽 CloseableHttpClient httpClient = null; PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WxV3PayConfig.privateKey.getBytes("utf-8"))); httpClient = WechatPayHttpClientBuilder.create() .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey) .withValidator(new WechatPay2Validator(WXPaySignatureCertificateUtil.getVerifier(WxV3PayConfig.mchSerialNo))) .build(); return httpClient; } /** * 保存微信平臺(tái)證書 */ private static final ConcurrentHashMap<String, AutoUpdateCertificatesVerifier> verifierMap = new ConcurrentHashMap<>(); /** * 功能描述:獲取平臺(tái)證書,自動(dòng)更新 * 注意:這個(gè)方法內(nèi)置了平臺(tái)證書的獲取和返回值解密 */ static AutoUpdateCertificatesVerifier getVerifier(String mchSerialNo) { AutoUpdateCertificatesVerifier verifier = null; if (verifierMap.isEmpty() || !verifierMap.containsKey(mchSerialNo)) { verifierMap.clear(); try { //傳入證書 PrivateKey privateKey = getPrivateKey(); //刷新 PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey); WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer); verifier = new AutoUpdateCertificatesVerifier(credentials , WxV3PayConfig.apiV3Key.getBytes("utf-8")); verifierMap.put(verifier.getValidCertificate().getSerialNumber()+"", verifier); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else { verifier = verifierMap.get(mchSerialNo); } return verifier; } /** * 生成帶簽名支付信息 * * @param timestamp 時(shí)間戳 * @param nonceStr 隨機(jī)數(shù) * @param prepayId 預(yù)付單 * @return 支付信息 * @throws Exception */ public static String appPaySign(String timestamp, String nonceStr, String prepayId) throws Exception { //上傳私鑰 PrivateKey privateKey = getPrivateKey(); String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId) .collect(Collectors.joining("\n", "", "\n")); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(privateKey); sign.update(signatureStr.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(sign.sign()); } /** * 生成帶簽名支付信息 * * @param timestamp 時(shí)間戳 * @param nonceStr 隨機(jī)數(shù) * @param prepayId 預(yù)付單 * @return 支付信息 * @throws Exception */ public static String jsApiPaySign(String timestamp, String nonceStr, String prepayId) throws Exception { //上傳私鑰 PrivateKey privateKey = getPrivateKey(); String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, "prepay_id="+prepayId) .collect(Collectors.joining("\n", "", "\n")); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(privateKey); sign.update(signatureStr.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(sign.sign()); } /** * 獲取私鑰。 * 證書路徑 本地使用如: D:\\微信平臺(tái)證書工具\(yùn)\7.9\\apiclient_key.pem * 證書路徑 線上使用如: /usr/apiclient_key.pem * String filename 私鑰文件路徑 (required) * @return 私鑰對(duì)象 */ public static PrivateKey getPrivateKey() throws IOException { String content = new String(Files.readAllBytes(Paths.get("D:\\微信平臺(tái)證書工具\(yùn)\7.9\\apiclient_key.pem")), "utf-8"); try { String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePrivate( new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("當(dāng)前Java環(huán)境不支持RSA", e); } catch (InvalidKeySpecException e) { throw new RuntimeException("無(wú)效的密鑰格式"); } } /** * 功能描述: 驗(yàn)證簽名 * 注意:使用微信支付平臺(tái)公鑰驗(yàn)簽 * Wechatpay-Signature 微信返簽名 * Wechatpay-Serial 微信平臺(tái)證書序列號(hào) * * @return java.lang.String * @author 影子 */ @SneakyThrows public static boolean verifySign(HttpServletRequest request,String body) { boolean verify = false; try { String wechatPaySignature = request.getHeader("Wechatpay-Signature"); String wechatPayTimestamp = request.getHeader("Wechatpay-Timestamp"); String wechatPayNonce = request.getHeader("Wechatpay-Nonce"); String wechatPaySerial = request.getHeader("Wechatpay-Serial"); //組裝簽名串 String signStr = Stream.of(wechatPayTimestamp, wechatPayNonce, body) .collect(Collectors.joining("\n", "", "\n")); //獲取平臺(tái)證書 AutoUpdateCertificatesVerifier verifier = getVerifier(wechatPaySerial); //獲取失敗 驗(yàn)證失敗 if (verifier != null) { Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(verifier.getValidCertificate()); //放入簽名串 signature.update(signStr.getBytes(StandardCharsets.UTF_8)); verify = signature.verify(Base64.getDecoder().decode(wechatPaySignature.getBytes())); } } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return verify; } }
創(chuàng)建WXPayConstants.java類
/** * 常量 */ public class WXPayConstants { public static final String DOMAIN_API = "https://api.mch.weixin.qq.com/v3"; //app下單 public static final String PAY_TRANSACTIONS_APP = "/pay/transactions/app"; //微信支付回調(diào) public static final String WECHAT_PAY_NOTIFY_URL = "https://xxx.xxxx.com/deal/api/appPayment/weChatPayNotify"; //申請(qǐng)退款 public static final String REFUND_DOMESTIC_REFUNDS = "/refund/domestic/refunds"; //微信退款回調(diào) public static final String WECHAT_REFUNDS_NOTIFY_URL = "https://xxx.xxxx.com/api/appPayment/weChatPayRefundsNotify"; //關(guān)閉訂單 public static final String PAY_TRANSACTIONS_OUT_TRADE_NO = "/pay/transactions/out-trade-no/{}/close"; }
這里以APP支付和退款為例
創(chuàng)建WechatPaymentService.java
/** * @author 影子 */ public interface WechatPaymentService { /** * 微信商品支付 * @param payParam * @return */ public Map<String, Object>weChatDoUnifiedOrder() throws Exception; /** * 微信支付回調(diào)通知 * @param * @return */ public Map<String, Object> weChatNotificationHandler(HttpServletRequest request, HttpServletResponse response); /** *微信關(guān)閉訂單 * @param outTradeNo * @return */ public Map<String, Object> closeOrder(String outTradeNo); /** * 申請(qǐng)退款 * @param * @return */ public Map<String, Object> weChatPayRefundsNotify(HttpServletRequest request); /** * 微信退款 * @param outTradeNo 訂單號(hào) * @return */ public Map<String, Object> weChatRefunds(String outTradeNo); }
創(chuàng)建WeChatPaymentServiceImpl.java
/* * *改了七八遍 照顧找包困難的朋友吧 * */ import com.alibaba.fastjson.JSONObject; import com.alipay.api.internal.util.file.ByteArrayOutputStream; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.wxpay.sdk.WXPayUtil; import com.wechat.pay.contrib.apache.httpclient.notification.Notification; import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler; import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; public class WeChatPaymentServiceImpl implements WechatPaymentService { /** * V3微信支付統(tǒng)一下單 * * @param payParam * @return * */ @Override public Map<String, Object>weChatDoUnifiedOrder() { Map<String,Object> map =new HashMap<>(); //支付總金額 BigDecimal totalPrice = BigDecimal.ZERO; totalPrice = totalPrice.add(BigDecimal.valueOf(600)); //轉(zhuǎn)換金額保留兩位小數(shù)點(diǎn) Integer money=new BigDecimal(String.valueOf(totalPrice)).movePointRight(2).intValue(); try { //驗(yàn)證證書 CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(); //app下單 HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API+WXPayConstants.PAY_TRANSACTIONS_APP); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode rootNode = objectMapper.createObjectNode(); rootNode.put("mchid", "商戶id") .put("appid", "APPID") .put("description","描述") .put("notify_url", WXPayConstants.WECHAT_PAY_NOTIFY_URL)//回調(diào) .put("out_trade_no", "訂單號(hào)"); rootNode.putObject("amount") .put("total","總金額"); objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); //完成簽名并執(zhí)行請(qǐng)求 CloseableHttpResponse response = httpClient.execute(httpPost); //獲取返回狀態(tài) int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { //處理成功 String result = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONObject object = JSONObject.parseObject(result); //獲取預(yù)付單 String prepayId = object.getString("prepay_id"); //生成簽名 Long timestamp = System.currentTimeMillis() / 1000; //隨機(jī)字符串 這個(gè)是微信支付maven自帶的 也可以用其它的 String nonceStr = WXPayUtil.generateNonceStr(); //生成帶簽名支付信息 String paySign = WXPaySignatureCertificateUtil.appPaySign(String.valueOf(timestamp), nonceStr, prepayId); Map<String, String> param = new HashMap<>(); param.put("appid", WxV3PayConfig.APP_ID); param.put("partnerid", WxV3PayConfig.Mch_ID); param.put("prepayid", prepayId); param.put("package", "Sign=WXPay"); param.put("noncestr", nonceStr); param.put("timestamp", String.valueOf(timestamp)); param.put("sign", paySign); map.put("code",200); map.put("message", "下單成功"); map.put("data", param); return map; } map.put("code",200); map.put("message", "下單失敗"); map.put("data", response); return map; } catch (Exception e) { e.printStackTrace(); } } /** * 微信支付回調(diào)通知 * @return */ @Override public Map<String, Object> weChatNotificationHandler(HttpServletRequest request, HttpServletResponse response){ Map<String,Object> map = new HashMap<>(); try { BufferedReader br = request.getReader(); String str = null; StringBuilder sb = new StringBuilder(); while ((str = br.readLine())!=null) { sb.append(str); } // 構(gòu)建request,傳入必要參數(shù) NotificationRequest requests = new NotificationRequest.Builder() .withSerialNumber(request.getHeader("Wechatpay-Serial")) .withNonce(request.getHeader("Wechatpay-Nonce")) .withTimestamp(request.getHeader("Wechatpay-Timestamp")) .withSignature(request.getHeader("Wechatpay-Signature")) .withBody(String.valueOf(sb)) .build(); //驗(yàn)簽 NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifier(WxV3PayConfig.mchSerialNo), WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8)); //解析請(qǐng)求體 Notification notification = handler.parse(requests); String decryptData = notification.getDecryptData(); //解析 JSONObject jsonObject = JSONObject.parseObject(decryptData); //支付狀態(tài)交易狀態(tài),枚舉值: SUCCESS:支付成功 REFUND:轉(zhuǎn)入退款 NOTPAY:未支付 CLOSED:已關(guān)閉 REVOKED:已撤銷(付款碼支付) // USERPAYING:用戶支付中(付款碼支付) PAYERROR:支付失敗(其他原因,如銀行返回失敗) String trade_state = String.valueOf(jsonObject.get("trade_state")); if (trade_state.equals("SUCCESS")) { //訂單號(hào) String orderNumber = String.valueOf(jsonObject.get("out_trade_no")); //微信支付微信生成的訂單號(hào) String transactionId = String.valueOf(jsonObject.get("transaction_id")); //省略查詢訂單 //此處處理業(yè)務(wù) map.put("code","SUCCESS"); map.put("message","成功"); //消息推送成功 return map; } map.put("code","RESOURCE_NOT_EXISTS"); map.put("message", "訂單不存在"); return map; }catch (Exception e) { e.printStackTrace(); } map.put("code","FAIL"); map.put("message", "失敗"); return map; } /** * 關(guān)閉訂單 * @param outTradeNo 訂單號(hào) * @return */ @Override public Map<String, Object> closeOrder(String outTradeNo) { Map<String,Object> map = new HashMap<>(); try { //驗(yàn)證證書 CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(); //關(guān)閉訂單 String url = StrFormatter.format(WXPayConstants.DOMAIN_API+WXPayConstants.PAY_TRANSACTIONS_OUT_TRADE_NO, outTradeNo); HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); //2.添加商戶id ObjectMapper objectMapper = new ObjectMapper(); ObjectNode rootNode = objectMapper.createObjectNode(); rootNode.put("mchid", WxV3PayConfig.Mch_ID); objectMapper.writeValue(bos, rootNode); //3.調(diào)起微信關(guān)單接口 httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); //完成簽名并執(zhí)行請(qǐng)求 CloseableHttpResponse response = httpClient.execute(httpPost); System.out.println(response.getStatusLine().getStatusCode() == 204); //無(wú)數(shù)據(jù)(Http狀態(tài)碼為204) 微信返回結(jié)果無(wú)數(shù)據(jù) 狀態(tài)碼為204 成功 if (response.getStatusLine().getStatusCode() == 204) { //code 退款碼請(qǐng)前往微信支付文檔查詢 map.put("code",200); map.put("message", "關(guān)閉訂單成功!"); return map; } } catch (Exception e) { log.error("關(guān)單失敗:" + outTradeNo + e); } return null; } /** * 微信退款 * @param outTradeNo 訂單號(hào) * @return */ @Override public Map<String, Object> weChatRefunds(String outTradeNo) { Map<String,Object> map = new HashMap<>(); //退款總金額 BigDecimal totalPrice = BigDecimal.ZERO; totalPrice = totalPrice.add(BigDecimal.valueOf(600)); //轉(zhuǎn)換金額 Integer money=new BigDecimal(String.valueOf(totalPrice)).movePointRight(2).intValue(); try { //驗(yàn)證證書 CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(); //申請(qǐng)退款接口 HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API+WXPayConstants.REFUND_DOMESTIC_REFUNDS); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type","application/json; charset=utf-8"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode rootNode = objectMapper.createObjectNode(); //微信支付訂單號(hào) rootNode.put("transaction_id", "微信支付訂單號(hào)") //退款訂單號(hào) .put("out_refund_no","生成退款訂單號(hào)") .put("notify_url","退款回調(diào)"); //退款金額 rootNode.putObject("amount") .put("refund", "100.00") //原訂單金額 .put("total", "100.00") .put("currency","CNY"); objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); CloseableHttpResponse response = httpClient.execute(httpPost); //退款成功返回消息 String bodyAsString = EntityUtils.toString(response.getEntity()); JSONObject jsonObject = JSONObject.parseObject(bodyAsString); if (jsonObject.get("status").equals("SUCCESS") || jsonObject.get("status").equals("PROCESSING")) { //code返回 map.put("code",200); map.put("message", "退款成功"); return map; } }catch (Exception e) { e.printStackTrace(); } map.put("code",500); map.put("message", "申請(qǐng)退款失?。?); map.put("data", jsonObject); return map; } /** * 申請(qǐng)退款回調(diào) * @param request * @return */ @Override public Map<String,Object> weChatPayRefundsNotify(HttpServletRequest request) { Map<String,Object> map = new HashMap<>(); try { BufferedReader br = request.getReader(); String str = null; StringBuilder sb = new StringBuilder(); while ((str = br.readLine())!=null) { sb.append(str); } // 構(gòu)建request,傳入必要參數(shù) NotificationRequest requests = new NotificationRequest.Builder() .withSerialNumber(request.getHeader("Wechatpay-Serial")) .withNonce(request.getHeader("Wechatpay-Nonce")) .withTimestamp(request.getHeader("Wechatpay-Timestamp")) .withSignature(request.getHeader("Wechatpay-Signature")) .withBody(String.valueOf(sb)) .build(); //驗(yàn)簽 NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifier(WxV3PayConfig.mchSerialNo), WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8)); //解析請(qǐng)求體 Notification notification = handler.parse(requests); String decryptData = notification.getDecryptData(); //解析 JSONObject jsonObject = JSONObject.parseObject(decryptData); String refund_status = String.valueOf(jsonObject.get("refund_status")); if (refund_status.equals("SUCCESS")) { //訂單號(hào) String orderNumber = String.valueOf(jsonObject.get("out_trade_no")); //微信支付訂單號(hào) String transactionId = String.valueOf(jsonObject.get("transaction_id")); //這里是處理業(yè)務(wù)邏輯 //code 退款碼請(qǐng)前往微信支付文檔查詢 map.put("code","RESOURCE_NOT_EXISTS"); map.put("message", "訂單不存在"); return map; } }catch (Exception e) { e.printStackTrace(); } map.put("code","USER_ACCOUNT_ABNORMAL"); map.put("message", "退款請(qǐng)求失敗"); return map; } }
代碼可復(fù)制粘貼使用 無(wú)業(yè)務(wù)邏輯代碼 支付代碼簡(jiǎn)潔
如果更換支付類型如:APP、二維碼支付、掃碼支付、JSAPI支付
請(qǐng)看以下示例二維碼支付代碼
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3"+"/pay/transactions/native");
HttpPost httpPost = new HttpPost("這里更換")
整體不變只需要微信返回正確狀態(tài)碼內(nèi)處理即可 如以下返回為 二維碼支付參數(shù)
//完成簽名并執(zhí)行請(qǐng)求 CloseableHttpResponse response = httpClient.execute(httpPost); //獲取返回狀態(tài) int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { //處理成功 String result = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONObject object = JSONObject.parseObject(result); map.put("code",200); map.put("message", "下單成功"); map.put("data", object); return map; } map.put("code",500); map.put("message", "下單失敗"); map.put("data", response); return map;
修改方式 根據(jù)官方文檔返回參數(shù)類型為準(zhǔn)
你學(xué)廢了嗎?
總結(jié)
到此這篇關(guān)于JAVA實(shí)現(xiàn)微信APPV3支付保姆級(jí)教程的文章就介紹到這了,更多相關(guān)Java微信APPV3支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析Java中Apache BeanUtils和Spring BeanUtils的用法
這篇文章主要介紹了Java中Apache BeanUtils和Spring BeanUtils的用法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11基于Java驗(yàn)證jwt token代碼實(shí)例
這篇文章主要介紹了基于Java驗(yàn)證jwt token代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12SpringBoot+Vue項(xiàng)目打包部署完整步驟教程
這篇文章主要介紹了SpringBoot+Vue項(xiàng)目打包部署的相關(guān)資料,包括Vue項(xiàng)目的打包設(shè)置、SpringBoot的配置修改、跨域問(wèn)題處理、使用Nginx配置反向代理以及最終的項(xiàng)目啟動(dòng),教程假定開發(fā)者已具備完整的前后端分離項(xiàng)目和配置好環(huán)境的服務(wù)器,需要的朋友可以參考下2024-10-10聽說(shuō)用了YYYY-MM-dd的程序員,前些天都在加班改Bug
這篇文章主要介紹了YYYY-MM-dd的實(shí)用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01swing中Tree與滾動(dòng)條用法實(shí)例分析
這篇文章主要介紹了swing中Tree與滾動(dòng)條用法,以實(shí)例形式分析了java基于swing實(shí)現(xiàn)圖形界面的使用技巧,需要的朋友可以參考下2015-09-09java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹
這篇文章主要介紹了java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹的相關(guān)資料,對(duì)于初學(xué)者還是有必要了解下,細(xì)致說(shuō)明他們是什么,需要的朋友可以參考下2016-11-11