通聯支付API集成(適用于SpringBoot)

目標:

  • 學習如何使用Java與通聯支付API進行交互

  • 實現一個簡單的支付下單和查詢訂單狀態的示例

所需材料:

  • 通聯支付API文檔

官方文檔icon-default.png?t=N7T8https://aipboss.allinpay.com/know/devhelp/main.php?pid=38#mid=313

  • 通聯支付加簽代碼SybUtil

package com.allinpay.common;import net.sf.json.JSONObject;
import org.apache.tomcat.util.codec.binary.Base64;import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;@SuppressWarnings("all")
public class SybUtil {/*** js轉化為實體** @param <T>* @param jsonstr* @param cls* @return*/public static <T> T json2Obj(String jsonstr, Class<T> cls) {JSONObject jo = JSONObject.fromObject(jsonstr);T obj = (T) JSONObject.toBean(jo, cls);return obj;}/*** md5** @param b* @return*/public static String md5(byte[] b) {try {MessageDigest md = MessageDigest.getInstance("MD5");md.reset();md.update(b);byte[] hash = md.digest();StringBuffer outStrBuf = new StringBuffer(32);for (int i = 0; i < hash.length; i++) {int v = hash[i] & 0xFF;if (v < 16) {outStrBuf.append('0');}outStrBuf.append(Integer.toString(v, 16).toLowerCase());}return outStrBuf.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();return new String(b);}}/*** 判斷字符串是否為空** @param s* @return*/public static boolean isEmpty(String s) {if (s == null || "".equals(s.trim()))return true;return false;}/*** 生成隨機碼** @param n* @return*/public static String getValidatecode(int n) {Random random = new Random();String sRand = "";n = n == 0 ? 4 : n;// default 4for (int i = 0; i < n; i++) {String rand = String.valueOf(random.nextInt(10));sRand += rand;}return sRand;}public static boolean validSign(TreeMap<String, String> param,String appkey, String signType) throws Exception {if (param != null && !param.isEmpty()) {if (!param.containsKey("sign"))return false;String sign = param.remove("sign");if ("MD5".equals(signType)) {// 如果是md5則需要把md5的key加入到排序param.put("key", appkey);}StringBuilder sb = new StringBuilder();for (Map.Entry<String, String> entry : param.entrySet()) {if (entry.getValue() != null && entry.getValue().length() > 0) {sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");}}if (sb.length() > 0) {sb.deleteCharAt(sb.length() - 1);}if ("MD5".equals(signType)) {return sign.toLowerCase().equals(md5(sb.toString().getBytes("UTF-8")).toLowerCase());} else {return rsaVerifyPublickey(sb.toString(), sign, appkey, "UTF-8");}}return false;}public static boolean rsaVerifyPublickey(String content, String sign,String publicKey, String charset) throws Exception {try {PublicKey pubKey = getPublicKeyFromX509("RSA",Base64.decodeBase64(publicKey.getBytes()));return rsaVerifyPublickey(content, sign, pubKey, charset);} catch (Exception e) {e.printStackTrace();throw new Exception("RSAcontent = " + content + ",sign=" + sign+ ",charset = " + charset, e);}}public static boolean rsaVerifyPublickey(String content, String sign,PublicKey pubKey, String charset) throws Exception {try {java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");signature.initVerify(pubKey);if (charset == null || "".equals(charset)) {signature.update(content.getBytes());} else {signature.update(content.getBytes(charset));}return signature.verify(Base64.decodeBase64(sign.getBytes()));} catch (Exception e) {throw e;}}public static String unionSign(TreeMap<String, String> params,String appkey,String signType) throws Exception {// TODO Auto-generated method stubparams.remove("sign");if ("MD5".equals(signType)) {// 如果是md5則需要把md5的key加入到排序params.put("key", appkey);}StringBuilder sb = new StringBuilder();for (Map.Entry<String, String> entry : params.entrySet()) {if (entry.getValue() != null && entry.getValue().length() > 0) {sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");}}if (sb.length() > 0) {sb.deleteCharAt(sb.length() - 1);}String sign = "";if ("MD5".equals(signType)) {System.out.println(sb.toString());sign = md5(sb.toString().getBytes("UTF-8"));// 記得是md5編碼的加簽params.remove("key");} else {sign = rsaSign(sb.toString(), appkey, "UTF-8");}return sign;}public static String rsaSign(String content, String privateKey,String charset) throws Exception {PrivateKey priKey = getPrivateKeyFromPKCS8("RSA",Base64.decodeBase64(privateKey.getBytes()));return rsaSign(content, priKey, charset);}public static String rsaSign(String content, byte[] privateKey,String charset) throws Exception {PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", privateKey);return rsaSign(content, priKey, charset);}public static String rsaSign(String content, PrivateKey priKey,String charset) throws Exception {java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");signature.initSign(priKey);if (charset == null || "".equals(charset)) {signature.update(content.getBytes());} else {signature.update(content.getBytes(charset));}byte[] signed = signature.sign();return new String(Base64.encodeBase64(signed));}public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,byte[] encodedKey) throws Exception {KeyFactory keyFactory = KeyFactory.getInstance(algorithm);return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));}public static PublicKey getPublicKeyFromX509(String algorithm,byte[] encodedKey) throws Exception {KeyFactory keyFactory = KeyFactory.getInstance(algorithm);return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));}
}
  • IDE(如IntelliJ IDEA或Eclipse)

  • JDK 8 或更高版本

  • 需要的maven
        <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.43</version></dependency><!-- SybUtil文件需要用到 --><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
  • ?輔助類
  1. 通聯支付需要的請求數據格式(Allinpay.java)
package com.allinpay.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.math.BigDecimal;@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Allinpay {private String cusid;private String appid;private int version;private BigDecimal trxamt;/*當指定為F02時,交易僅限分期交易。分期交易金額必須大于500元。*/// ?private String paytype;/*3  花唄分期3期6  花唄分期6期12  花唄分期12期3-cc 支付寶信用卡分期3期6-cc 支付寶信用卡分期6期12-cc 支付寶信用卡分期12期暫只支持支付寶花唄分期,支付寶信用卡分期,僅支持A01/A02*/// 可空參數private String fqnum;//訂單號,商戶唯一訂單號private String reqsn;/*商戶網站使用的編碼格式,支持UTF-8、GBK跟商戶網站的編碼一致*///private String charset;/*必須為https協議地址,且不允許帶參數頁面跳轉同步通知頁面路徑*/private String returl;// 異步通知地址// ?private String notify_url;// 商品描述,長度最大100private String body;//? 通知會原樣帶上, 訂單備注信息private String remark;// 隨機字符串,自己生成,最大32位private String randomstr;//訂單有效時間,以分為單位,默認為15private String validtime;// ? 支付限制(no_credit--指定不能使用信用卡支付)private String limit_pay;// 簽名類型,目前支持RSA2和RSAprivate String signtype;// 簽名 32位private String sign;// 關閉訂單的時候需要private String oldreqsn;}

?2.?由于本案列采用了多商家,所以暫時把配置也建成了一個類(PayConfig.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class PayConfig {private String cusid;private String appid;private String privateKey;}

?3.本案列設置了多方支付方式,所以還有一個支付載荷(PayLoad.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.math.BigDecimal;@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class PayLoad {private String orderId;private BigDecimal amount;private String payConfigKey;private String remark;private String title;private int payType;private String returnUrl;private String notifyUrl;}
  • ?H5支付下單代碼

    //這個是PayService的Impl實現層private final String order = "https://syb.allinpay.com/apiweb/h5unionpay/unionorder";private final String rsaPrivateKey = "xxx";@SneakyThrows@Overridepublic String h5Pay(PayLoad payLoad) {// String payConfigKey = payLoad.getPayConfigKey();PayConfig payConfig = new PayConfig().setAppid("xxx").setCusid("xxx").setPrivateKey(rsaPrivateKey);Allinpay allinpay = new Allinpay().setSigntype("RSA").setTrxamt(new BigDecimal(2)).setReqsn(payLoad.getOrderId()).setRandomstr(SybUtil.getValidatecode(8)).setBody(payLoad.getTitle()).setRemark(payLoad.getRemark()).setCharset("UTF-8").setAppid(payConfig.getAppid()).setCusid(payConfig.getCusid()).setReturl(payLoad.getReturnUrl());allinpay.setSign(URLEncoder.encode(SybUtil.unionSign(objectToTreeMap(allinpay), payConfig.getPrivateKey() , "RSA"), StandardCharsets.UTF_8));return order + "?" + treeMapToUrlParams(objectToTreeMap(allinpay));}//Controller代碼@SneakyThrows@GetMapping("pay")public String pay(HttpServletResponse response) {String paymentUrl = (String) payService.h5Pay(new PayLoad().setPayType(2).setPayConfigKey("").setReturnUrl("https://blog.csdn.net").setOrderId(IdUtil.getSnowflakeNextIdStr()).setAmount(new BigDecimal(2)).setRemark("測試支付備注").setTitle("測試H5支付"));String htmlResponse = "<!DOCTYPE html><html><head></head><body>"+ "<script>window.location.href='" + paymentUrl + "'</script>"+ "</body></html>";// 設置響應內容類型為HTMLresponse.setContentType("text/html;charset=UTF-8");return htmlResponse;}

  • 關閉訂單?

    // 關閉接口private final String close = "https://vsp.allinpay.com/apiweb/tranx/close";@SneakyThrows@Overridepublic String closeOrder(PayLoad payLoad) {PayConfig payConfig = new PayConfig().setAppid("xxx").setCusid("xxxx").setPrivateKey(rsaPrivateKey);Allinpay allinpay = new Allinpay().setCusid(payConfig.getCusid()).setAppid(payConfig.getAppid()).setRandomstr(SybUtil.getValidatecode(8)).setVersion(11).setOldreqsn(payLoad.getOrderId()).setSigntype("RSA");allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));return HttpUtil.post(close, BeanUtil.beanToMap(allinpay));}/*** 關閉訂單* @param outTradeNo 下單的訂單號,也就是你支付下單類Allinpay的reqsn* @return {@link String}***/@SneakyThrows@GetMapping("closeOrder/{outTradeNo}")public Map<String,String> closeOrder(@PathVariable Long outTradeNo) {return handleResult(payService.closeOrder(new PayLoad().setOrderId(outTradeNo.toString())));}
  • ?查詢訂單

    // 查詢接口private final String query = "https://vsp.allinpay.com/apiweb/tranx/query";@SneakyThrows@Overridepublic String query(PayLoad payLoad) {PayConfig payConfig = new PayConfig().setAppid("xxx").setCusid("xxxx").setPrivateKey(rsaPrivateKey);Allinpay allinpay = new Allinpay().setCusid(payConfig.getCusid()).setAppid(payConfig.getAppid()).setRandomstr(SybUtil.getValidatecode(8)).setVersion(11).setReqsn(payLoad.getOrderId()).setSigntype("RSA");allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));return HttpUtil.post(query, BeanUtil.beanToMap(allinpay));}/*** 查詢訂單* @param outTradeNo 下單的訂單號* @return {@link String}***/@SneakyThrows@GetMapping("query/{outTradeNo}")public Map<String, String> query(@PathVariable Long outTradeNo) {return handleResult(payService.query(new PayLoad().setOrderId(outTradeNo.toString())));}
  • 退款接口,這個是只能退當天的交易 (全額退實時返回退款結果)

    // 取消當天交易退款接口private final String cancelDayUrl = "https://vsp.allinpay.com/apiweb/tranx/cancel";@SneakyThrows@Overridepublic String cancelDay(PayLoad payLoad) {PayConfig payConfig = new PayConfig().setAppid("xxx").setCusid("xxxx").setPrivateKey(rsaPrivateKey);Allinpay allinpay = new Allinpay().setCusid(payConfig.getCusid()).setAppid(payConfig.getAppid()).setRandomstr(SybUtil.getValidatecode(8)).setVersion(11).setTrxamt(new BigDecimal(2)).setReqsn(payLoad.getOrderId()).setOldreqsn(payLoad.getOrderId()).setSigntype("RSA");allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));return HttpUtil.post(cancelDayUrl, BeanUtil.beanToMap(allinpay));}/*** 退款接口,只能退今天的,全額退款,實時返回退款結果* @return {@link String}*/@SneakyThrows@GetMapping("cancelDay/{outTradeNo}")public Map<String, String> cancelDay(@PathVariable Long outTradeNo) {return handleResult(payService.cancelDay(new PayLoad().setOrderId(outTradeNo.toString())));}
  • 退款接口 ,可以退部分

    // 退款接口private final String refundUrl = "https://vsp.allinpay.com/apiweb/tranx/refund";@SneakyThrows@Overridepublic String refund(PayLoad payLoad) {PayConfig payConfig = new PayConfig().setAppid("xxx").setCusid("xxxx").setPrivateKey(rsaPrivateKey);Allinpay allinpay = new Allinpay().setCusid(payConfig.getCusid()).setAppid(payConfig.getAppid()).setRandomstr(SybUtil.getValidatecode(8)).setVersion(11).setTrxamt(new BigDecimal(2)).setReqsn(payLoad.getOrderId()).setOldreqsn(payLoad.getOrderId()).setSigntype("RSA");allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));return HttpUtil.post(refundUrl, BeanUtil.beanToMap(allinpay));}// 可以和上面的接口進行整合處理/*** 退款接口,可以退部分* @return {@link String}*/@SneakyThrows@GetMapping("refund/{outTradeNo}")public Map<String, String> refund(@PathVariable Long outTradeNo) {return handleResult(payService.refund(new PayLoad().setOrderId(outTradeNo.toString())));}

提示:?可以和上面的接口進行整合處理

  • 其中簽名需要用到的轉map方法?

    private TreeMap<String, String> objectToTreeMap(Object obj) {TreeMap<String, String> treeMap = new TreeMap<>();Class<?> clazz = obj.getClass();while (clazz != null) {for (Field field : clazz.getDeclaredFields()) {field.setAccessible(true);try {Object fieldValue = field.get(obj);if (fieldValue != null) {treeMap.put(field.getName(), fieldValue.toString());}} catch (IllegalAccessException e) {log.error("Error accessing field " + field.getName() + ": " + e.getMessage());}}clazz = clazz.getSuperclass();}return treeMap;}
  • ?其中map轉路徑參數方法

  private static String treeMapToUrlParams(TreeMap<String, String> treeMap) {StringBuilder sb = new StringBuilder();for (Map.Entry<String, String> entry : treeMap.entrySet()) {String key = entry.getKey();String value = entry.getValue();if (sb.length() > 0) {sb.append("&");}sb.append(key).append("=").append(value);}return sb.toString();}
  • 其中通聯返回驗簽代碼

    /*** 驗簽* @param result* @return {@link Map}<{@link String},{@link String}>* @throws Exception*/@SuppressWarnings({ "rawtypes", "all" })public static Map<String,String> handleResult(String result) throws Exception{Map map = SybUtil.json2Obj(result, Map.class);if(map == null){throw new Exception("返回數據錯誤");}if("SUCCESS".equals(map.get("retcode"))) {TreeMap tmap = new TreeMap();tmap.putAll(map);if(SybUtil.validSign(tmap,"xxxxx","RSA")){return map;}else{throw new Exception("驗證簽名失敗");}// 驗簽成功,返回數據}else{throw new Exception(map.get("retmsg").toString());}}

提示:如果不考慮多商戶,多支付通道,可以再方法中Allinpay類直接填參數請求,不用通過PayLoad和PayConfig類??

  • 完整代碼克隆地址:

git clone https://gitee.com/byte1026/allin-pay.git

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/14047.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14047.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/14047.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【軟考中級 軟件設計師】計算機網絡和安全

計算機網絡和安全是軟件設計師&#xff08;軟考中級&#xff09;考試中的重要組成部分&#xff0c;它涵蓋了網絡基礎、網絡協議、網絡架構、網絡安全等多個方面。以下是一些核心概念和要點&#xff0c; 計算機網絡基礎 OSI七層模型&#xff1a;物理層、數據鏈路層、網絡層、傳…

LLM答案抽取|xFinder:針對大型語言模型的穩健且精確的答案提取

【摘要】大型語言模型&#xff08;LLM&#xff09;的不斷進步使人們越來越關注開發公平可靠的方法來評估其性能的關鍵問題。特別是測試集泄漏、提示格式過擬合等主觀或非主觀作弊現象的出現&#xff0c;給法學碩士的可靠評估帶來了重大挑戰。由于評估框架通常利用正則表達式 (R…

《最新出爐》系列初窺篇-Python+Playwright自動化測試-39-highlight() 方法之追蹤定位

1.簡介 在之前的文章中宏哥講解和分享了&#xff0c;為了看清自動化測試的步驟&#xff0c;通過JavaScript添加高亮顏色&#xff0c;就可以清楚的看到執行步驟了。在學習和實踐Playwright的過程中&#xff0c;偶然發現了使用Playwright中的highlight()方法也突出顯示Web元素。…

eNSP-集線器(hub)連接局域網

一、拓撲結構搭建 二、主機配置 pc1、pc2、pc3 三、測試 Hub相當于大家共享一條線路(類似于電線搭電)&#xff0c;線路上的所有的設備都會接收同樣的信息。

路由器不能端口映射什么原因?如何設置內網映射?

近期有小伙伴發來求助信息&#xff0c;他以前開游戲服務器和別人一起玩&#xff0c;那個時候端口映射還好&#xff0c;不知道哪一天開始突然不行了&#xff0c;已經是公網了&#xff0c;光貓是橋接的狀態&#xff0c;連路由器都換了&#xff0c;就是不能端口映射開服務器&#…

VAE-變分自編碼器(Variational Autoencoder,VAE)

變分自編碼器&#xff08;Variational Autoencoder&#xff0c;VAE&#xff09;是一種生成模型&#xff0c;結合了概率圖模型與神經網絡技術&#xff0c;廣泛應用于數據生成、表示學習和數據壓縮等領域。以下是對VAE的詳細解釋和理解&#xff1a; 基本概念 1. 自編碼器&#…

基于 Milvus Cloud + LlamaIndex 實現初級 RAG

初級 RAG 初級 RAG 的定義 初級 RAG 研究范式代表了最早的方法論,在 ChatGPT 廣泛采用后不久就取得了重要地位。初級 RAG 遵循傳統的流程,包括索引創建(Indexing)、檢索(Retrieval)和生成(Generation),常常被描繪成一個“檢索—讀取”框架,其工作流包括三個關鍵步…

AWS安全性身份和合規性之Key Management Service(KMS)

AWS Key Management Service&#xff08;KMS&#xff09;是一項用于創建和管理加密密鑰的托管服務&#xff0c;可幫助客戶保護其數據的安全性和機密性。 比如一家醫療保健公司需要在AWS上存儲敏感的病人健康數據&#xff0c;需要對數據進行加密以確保數據的機密性。他們使用AW…

課時134:awk實踐_邏輯控制_自定義函數

1.3.7 自定義函數 學習目標 這一節&#xff0c;我們從 基礎知識、簡單實踐、小結 三個方面來學習。 基礎知識 需求 雖然awk提供了內置的函數來實現相應的內置函數&#xff0c;但是有些功能場景&#xff0c;還是需要我們自己來設定&#xff0c;這就用到了awk的自定義函數功能…

WebSocket簡介

參考&#xff1a;Java NIO實現WebSocket服務器_nio websocket-CSDN博客 WebSocket API是HTML5中的一大特色&#xff0c;能夠使得建立連接的雙方在任意時刻相互推送消息&#xff0c;這意味著不同于HTTP&#xff0c;服務器服務器也可以主動向客戶端推送消息了。 WebSocket協議是…

使用TensorBoard記錄功能時,添加SummaryWriter到callbacks,某些版本可能不適用該如何修改

如果發現將SummaryWriter直接添加到callbacks不被支持&#xff0c;您可以采取另一種方式來集成TensorBoard記錄功能&#xff0c;即通過自定義回調函數來實現。Hugging Face Transformers庫允許用戶自定義訓練回調&#xff0c;這可以用來在訓練過程中向TensorBoard寫入日志。 下…

配置yum源

以下是在 Linux 系統中配置新的 yum 源的一般步驟和命令示例&#xff08;以 CentOS 系統為例&#xff09;&#xff1a; 備份原有 yum 源配置文件&#xff1a;mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak 創建新的 yum 源配置文件&#xff08…

【PB案例學習筆記】-08 控件拖動實現

寫在前面 這是PB案例學習筆記系列文章的第8篇&#xff0c;該系列文章適合具有一定PB基礎的讀者。 通過一個個由淺入深的編程實戰案例學習&#xff0c;提高編程技巧&#xff0c;以保證小伙伴們能應付公司的各種開發需求。 文章中設計到的源碼&#xff0c;小凡都上傳到了gitee…

反序列化漏洞的入門知識總結

1.概念定義 序列化與反序列化的目的是讓數據在傳輸和處理的時候更簡單&#xff0c;更快&#xff0c;反序列化出現在多種同面向對象語言所開發的網站和軟件上&#xff0c;比如java&#xff0c;php&#xff0c;python等等&#xff0c;如果有語言一個都沒學的&#xff0c;可以先去…

1941springboot VUE 服務機構評估管理系統開發mysql數據庫web結構java編程計算機網頁源碼maven項目

一、源碼特點 springboot VUE服務機構評估管理系統是一套完善的完整信息管理類型系統&#xff0c;結合springboot框架和VUE完成本系統&#xff0c;對理解JSP java編程開發語言有幫助系統采用springboot框架&#xff08;MVC模式開發&#xff09;&#xff0c;系統具有完整的源代…

【NOIP2014普及組復賽】題2:比例簡化

題2&#xff1a;比例簡化 【題目描述】 在社交媒體上&#xff0c;經常會看到針對某一個觀點同意與否的民意調查以及結果。例如&#xff0c;對某一觀點表示支持的有 1498 1498 1498 人&#xff0c;反對的有 902 902 902 人&#xff0c;那么贊同與反對的比例可以簡單的記為 …

計算機-編程相關

在 Linux 中、一切都是文件、硬件設備是文件、管道是文件、網絡套接字也是文件。 for https://juejin.cn/post/6844904103437582344 fork 進程的一些問題 fork 函數比較特殊、一次調用會返回兩次。在父進程和子進程都會返回。 每個進程在內核中都是一個 taskstruct 結構、for…

ECMAScript、BOM與DOM:網頁開發的三大基石

在深入Web開發的世界時&#xff0c;有三個核心概念構成了理解網頁如何工作以及如何與之交互的基礎&#xff1a;ECMAScript、BOM&#xff08;Browser Object Model&#xff09;&#xff0c;以及DOM&#xff08;Document Object Model&#xff09;。本文旨在簡要介紹這三個概念&a…

Thingsboard規則鏈:Entity Type Switch節點詳解

在物聯網&#xff08;IoT&#xff09;領域&#xff0c;隨著設備數量的爆炸式增長和數據復雜性的增加&#xff0c;高效、靈活的數據處理機制變得至關重要。作為一款先進的物聯網平臺&#xff0c;ThingsBoard提供了強大的規則鏈&#xff08;Rule Chains&#xff09;功能&#xff…

第四節 Starter 加載時機和源碼理解

tips&#xff1a;每個 springBoot 的版本不同&#xff0c;代碼的實現存會存在不同。 上一章&#xff0c;我們聊到 mybatis-spring-boot-starter&#xff1b; 簡單分析了它的結構。 這一章我們將著重分析 Starter 的加載機制&#xff0c;并結合源碼進行分析理解。 一、加載實際…