前端視角下的 Java

這是我們前端視角下的第二篇。接下來我還將從前端視角看 Go、C#、Rust 等不同的後端語言,可能會有錯誤的地方,歡迎指正,也歡迎關注我,後期還將有分析其他語言的文章,奧力給!

這篇文章不是一篇語法對比手冊,也不是「全端學習路線圖」。它是一個前端人站在自己的視角,用望遠鏡眺望 Java 這片大陸的觀察記錄。我們會發現,前端和後端看似說著完全不同的語言,實際上卻在用不同的語言講述同一套工程內容。

「當我們面對一面鏡子,不僅會看見自己的倒影,還能透過它,看見另一間屋子裡從未被點亮的角落。」

一、當我第一次打開 Java 專案

1.1 熟悉的陌生人:TS 與 Java 的語法基因

n 年前,第一次打開一個 Spring Boot 專案,我是在風中凌亂的。

java 體驗AI代碼助手 代碼解讀複製代碼@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;

    public Order getOrderById(Long id) {
        return orderRepository.findById(id)
            .orElseThrow(() -> new NotFoundException("Order not found"));
    }
}

我的大腦同時閃爍著兩種解讀:

  • Java 解讀:這是一個服務類,依賴注入倉庫,丟出例外。
  • TypeScript 解讀OrderService 看起來像一個類別元件,@Autowired 像是某種依賴注入的 Hook,orElseThrow 簡直就是 RxJS 的 throwError 的遠房親戚。

這種「既視感」背後有一個深刻的真相:TypeScript 和 Java 共享著 C 家族的型別語法遺產classinterfaceextendsimplements——這些關鍵字在兩種語言中幾乎是相同的。更微妙的是,TypeScript 的型別擦除(Type Erasure)設計理念和 Java 泛型的型別擦除有著驚人的相似之處:編譯時存在,執行時不留痕跡。

但語法相似性是最顯而易見的一層。真正讓我著迷的是兩種語言在工程約束上的差異。

1.2 編譯時 vs 執行時:兩種世界觀的分水嶺

Java 是編譯時的語言。它要求在編譯階段解決一切:型別一致性、可見性控制、例外路徑。這種嚴苛帶來了一種工業級的確定感——如果我們的 Java 程式碼通過了編譯,它大概率不會在執行時因為型別錯誤而崩潰。

JavaScript/TypeScript 則是執行時的語言。即使 TypeScript 的編譯器 (tsc) 報告了零個錯誤,我們依然要面對 undefined is not a function 的可能性,因為 any 的存在、型別斷言的存在,以及執行時型別擦除的本質。

這種差異塑造了兩套完全不同的除錯哲學:

  • Java 除錯:編譯器是我們的第一道防線,IDE 的紅線是絕對要遵守的。
  • 前端除錯:瀏覽器主控台是我們的主戰場,Source Map 是我們的時光機,Chrome DevTools 的 Performance 面板是我們理解執行時行為的顯微鏡。

在這裡我們會發現:Java 工程師傾向於在編譯時消滅不確定性,前端工程師則要學會與執行時的不確定性共存,並且透過建構工具鏈來管理它。這不是技術優劣之分,而是信任邊界的不同——Java 信任編譯器,前端信任 DevTools。

1.3 套件管理與建構工具:npm 與 Maven 的對比

維度 npm/yarn/pnpm Maven/Gradle
依賴宣告 package.json pom.xml / build.gradle
版本解析 語意化版本 + lockfile 嚴格版本 + 傳遞依賴解析
安裝速度 快(本地快取 + 平行) 慢(首次下載 + 本地倉庫)
腳本能力 極強(生命週期 hook) 較弱(外掛程式體系)
多套件管理 Monorepo(npm workspace / Turborepo / Nx) 多模組(multi-module)

前端套件管理器強調的是開發體驗的速度和靈活性。npm 的硬連結、Turborepo 的遠端快取,都是在解決「前端專案依賴爆炸但安裝必須快」的矛盾。

Java 建構工具強調的是可重現性和供應鏈安全。Maven 的中央倉庫、Gradle 的依賴鎖定,是在解決「企業級應用的生命週期用年來計算,今天的建構必須在三年後依然可重現」的問題。

哈哈哈,這個時候發現有個尷尬的點:當我第一次用 Gradle 建構一個微服務專案花了 8 分鐘時,我都要氣死了。前端要是建構花費了 8 分鐘,是絕對要挨罵的,要被鞭屍的。但當我跟後端了解到這個建構產物會被部署到 2000 個容器執行個體上、執行五年之久時,我突然又被啪啪打臉,好像沒有哪個前端應用能做到這樣,就理解了這種「慢」背後的工程理性。


二、執行時的超能力——V8 與 JVM 的兩種實作

2.1 兩個 VM,兩種自由觀

前端程式碼執行在瀏覽器裡,瀏覽器執行在作業系統之上,作業系統執行在硬體之上。這是一個層層嵌套的沙盒。

Java 程式碼執行在 JVM 裡,JVM 執行在作業系統之上。這同樣也是一個沙盒,但 Java 的沙盒有牆也有門——我們可以透過 JNI 呼叫本地程式碼,可以透過 sun.misc.Unsafe 做一些危險的事。

前端沙盒的特點是嚴格且不可逾越。我們不能直接存取檔案系統(除非透過 Electron 或 File System Access API),我們不能直接操作記憶體,我們不能在瀏覽器裡起一個真正的 TCP 伺服器(因為 WebSocket 和 WebTransport 都是受控的)。

這種限制在前端早期是一種詛咒,像是帶著鐐銬跳舞,但在現在也有好處。正是因為瀏覽器給前端戴上了鐐銬,前端才發明了史上最精巧的非同步程式設計模型

2.2 Event Loop vs Thread Pool:並行的兩種語法

這是我最想了解的部分。

javascript 体验AI代碼助手 代碼解讀複製代碼// 前端:協作式多工
setTimeout(() => console.log('A'), 0);
Promise.resolve().then(() => console.log('B'));
console.log('C');
// 輸出: C, B, A
java 体验AI代碼助手 代碼解讀複製代碼// Java:搶佔式多執行緒
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("A"));
executor.submit(() -> System.out.println("B"));
System.out.println("C");
// 輸出: C(幾乎肯定先輸出),然後 A 和 B 的順序不確定

前端只有一個執行緒(主執行緒),但它透過 Event Loop 實現了宏觀上的並行。所有的非同步操作——網路請求、計時器、使用者輸入——都被塞進一個佇列,由 Event Loop 依序排程。這種模式的前提是:每個任務都必須快速完成,否則就會阻塞 UI

Java 有真正的多執行緒。一個 Spring Boot 應用可以同時處理數百個請求,每個請求在一個獨立的執行緒中執行。執行緒可以阻塞(比如等待資料庫回應),其他執行緒不受影響。這種自由帶來了一種命令式的從容:我們不需要把程式碼切成碎片來避免阻塞,我們可以寫線性、由上而下的邏輯。

但是,現代 Java 正在向我們前端學習:Project Loom(虛擬執行緒)的本質,就是把 Java 的執行緒模型變得像 JavaScript 的 async/await 一樣輕量。WebFlux 和 Netty 的回應式程式設計,乾脆就是在 JVM 上實作了一個 Event Loop。而前端,透過 Web Workers 和 Service Workers,也在偷偷地獲得真正的多執行緒能力。

兩種執行時正在走向彼此。這也是我們今天的目的,我們去了解 Java 並不是一定要取代對方,而是走向彼此,保持同頻。JVM 上實作 Event Loop 不是巧合,而是因為現代硬體和分散式系統的本質要求:既要能處理海量並發連線(Event Loop 擅長),又要能利用多核心 CPU(多執行緒擅長)。

2.3 GC 的兩種面孔

V8 的垃圾回收器是分代式 + 增量式 + 並行式的,它最大的敵人是「停頓」(Stop-the-World),因為任何超過 16ms 的停頓都會表現為掉幀(Jank)。所以 V8 的 GC 工程師像走鋼索一樣,在記憶體回收和渲染幀率之間尋找平衡。

JVM 的 G1 / ZGC / Shenandoah 也在追求低延遲,但 Java 應用的容忍度高得多。一次 10ms 的 GC 停頓對於一個 API 伺服器來說完全可以接受——它只意味著某個請求的延遲增加了 10ms,使用者感知很小。

這裡我們發現:前端 GC 優化的目標是「不打擾使用者」,Java GC 優化的目標是「不影響吞吐」。這兩種優化方向反映了一個根本差異:前端直接面對感官體驗,後端直接面對資源效率


三、狀態管理——從 Redux 到 Spring Bean

3.1 前端狀態管理的演進:從混沌到秩序

我在 16 年剛入前端坑時,第一次用 Redux,被它的嚴格流程震撼:

javascript 体验AI代碼助手 代碼解讀複製代碼// Action → Dispatcher → Reducer → Store → View
store.dispatch({ type: 'INCREMENT' });
// reducer 是純函數,回傳新狀態
// 元件透過 connect / useSelector 訂閱狀態

現在,我在 Java 裡居然看到了對稱:

java 体验AI代碼助手 代碼解讀複製代碼// Controller → Service → Repository → Database
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderDTO dto) {
    return orderService.create(dto); // Service 是業務邏輯的「reducer」
}

這不是硬要類比。Redux 的三原則——單一資料來源、狀態唯讀、使用純函數修改——在 Spring 的架構中有精確的對應:

Redux 概念 Java/Spring 對應 本質
Store ApplicationContext / BeanFactory 全域狀態容器
Action Service Method Call / DTO 意圖的序列化表達
Reducer Service / Business Logic 純的狀態轉換邏輯
Selector Repository Query / DTO Mapper 狀態查詢與投影
Middleware Interceptor / AOP / Filter 橫切關注點
Dispatch Transactional Method Invocation 原子性狀態提交

3.2 React Hooks vs 依賴注入:組合邏輯的兩種路徑

React Hooks 是前端過去十年最偉大的發明之一。它的核心是:在函式元件中,透過閉包和依賴陣列,實現邏輯的組合與重用

javascript 体验AI代碼助手 代碼解讀複製代碼function useUser(userId) {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]);
  return user;
}
// 使用:const user = useUser(123);

Java 的依賴注入(Dependency Injection)解決的是同一個更高層次的問題:如何在元件之間共享和重用邏輯,同時保持可測試性和可組合性

java 体验AI代碼助手 代碼解讀複製代碼@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User getUser(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}
// 使用:@Autowired private UserService userService;

兩者的差異在於組合的時機

  • Hooks 是編譯前/執行時的動態組合。我們可以條件性地呼叫 Hook(雖然 React 有限制),可以在執行時決定使用哪個 Hook。
  • DI 是啟動時的靜態組合。Spring 在應用啟動時解析所有依賴關係,建構一個不可變的依賴圖。

這裡有個有趣的發現:Hooks 的組合是縱向的(在一個元件函式內,多個 Hook 層層疊加),DI 的組合是橫向的(一個 Service 依賴多個 Repository,像組裝樂高積木)。前端元件是一棵不斷生長的樹,Hook 沿著樹的枝幹流淌;Java 應用是一張預先編織好的網,Bean 之間的關係在啟動時就已確定。

3.3 Context vs ThreadLocal:狀態作用域的兩種方式

React 的 Context API 讓狀態可以跨越元件層級傳遞,而不需要層層 props drilling。

Java 的 ThreadLocal 讓狀態可以綁定到目前執行執行緒,在整個呼叫鏈中隱式可用。

兩者都是隱式上下文傳遞機制,都解決了「深層呼叫中如何存取全域/半全域狀態」的問題。但 Context 是顯式宣告的(Provider/Consumer),ThreadLocal 是隱式掛載的。這再次體現了前端「顯式優於隱式」的顯性設計文化與 Java「慣例優於設定」的隱性工程文化之間的張力。


四、型別系統——前端型別體操與 Java 泛型

4.1 TypeScript:結構性型別的自由主義

TypeScript 的型別系統是結構化的(structural typing)。一個物件只要「長得像」某個介面,它就是這個介面的實例:

typescript 体验AI代碼助手 代碼解讀複製代碼interface Point { x: number; y: number; }
const p = { x: 1, y: 2, z: 3 }; // 有額外的 z,但仍然是 Point
function print(p: Point) { console.log(p.x, p.y); }
print(p); // ✅ 完全合法

這種「鴨子型別」的哲學源於 JavaScript 的動態本質。TypeScript 不能改變執行時行為,所以它選擇在編譯時提供一種「建議性」的約束。

4.2 Java:名義性型別的保守主義

Java 的型別系統是名義化的(nominal typing)。一個類別必須顯式宣告它實作了某個介面:

java 体验AI代碼助手 代碼解讀複製代碼interface Drawable { void draw(); }
class Circle implements Drawable {
    public void draw() { /* ... */ }
}

如果 Circledraw() 方法但沒有寫 implements Drawable,它在 Java 的型別世界裡就不是 Drawable

這種嚴格性在大規模團隊協作中是一種保護。當我們面對一個百萬行程式碼的遺留系統時,名義型別系統像是一道道上了鎖的門——我們不可能「不小心」把一個不相關的物件傳進某個方法,編譯器會擋在我們面前。

4.3 泛型:型別體操的兩種難度

TypeScript 的泛型是圖靈完備的。我見過以前的團隊寫出過這樣的程式碼:

typescript 体验AI代碼助手 代碼解讀複製代碼type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

這是遞迴的條件型別,是在型別層面執行的程式。TypeScript 的型別系統可以模擬條件、迴圈、遞迴——因為它是一門函式式語言。

Java 的泛型則保守得多。型別擦除意味著 List<String>List<Integer> 在執行時是同一個類別。Java 16 的 record、Java 17 的 sealed class,以及即將到來的 Valhalla 專案(值型別),都是在逐步釋放型別系統的表達能力,但始終保持著對 JVM 相容性的敬畏。

注意點:TypeScript 的型別體操讓我們在前端就體驗到了「元編程」的快感,但這種快感有時是危險的。當我們花三天寫出一個完美的遞迴型別,卻只為了讓一個邊緣案例通過編譯時,我們可能已經陷入了過度工程的陷阱。Java 泛型的保守,在大規模工程中是一種謙遜。突然發現這個差別很有意思,有些設計和妥協,不一定是我們程式設計師的問題,是語言的問題。


五:元件即服務,服務即元件——前端元件化與 Java 微服務的架構同構

5.1 元件的邊界與服務的邊界

前端元件化思想的巔峰是 React 的「一切都是元件」:我們的頁面是元件,我們的按鈕是元件,我們的資料取得邏輯(Hook)也是元件。

Java 微服務架構的巔峰是「一切都是服務」:使用者服務、訂單服務、庫存服務、通知服務。

這兩種拆分背後的驅動力很神奇地達到了一致:

驅動力 前端元件 Java 微服務
職責單一 一個元件只做一件事 一個服務只負責一個聚合根
獨立部署 程式碼分割 + 懶加載 容器化 + CI/CD 獨立流水線
介面契約 Props / Callbacks API REST / gRPC / DTO
狀態隔離 元件內部 state / Lifting State Up 服務私有資料庫 / 避免共享庫
組合重用 元件嵌套 / Render Props / HOC 服務編排 / Saga 模式 / BFF

5.2 BFF 模式:前後端架構的交會點

BFF(Backend for Frontend)是我認為前後端協作最優雅的結合點,也是在 18 年開始講述大前端時必備的,沒想到時間已經過去了 8 年了。

scss 体验AI代碼助手 代碼解讀複製代碼┌─────────────┐     ┌─────────────┐     ┌─────────────────┐
│   Mobile    │────→│  Mobile BFF │────→│                 │
│   Client    │     │  (Node/Java)│     │                 │
├─────────────┤     ├─────────────┤     │   Microservices │
│   Web SPA   │────→│   Web BFF   │────→│     Cluster     │
├─────────────┤     ├─────────────┤     │                 │
│   Admin SPA │────→│ Admin BFF   │────→│                 │
│             │     │  (Node/Java)│     │                 │
└─────────────┘     └─────────────┘     └─────────────────┘

BFF 層用 Node.js 寫,前端可以用自己最熟悉的語言來組裝後端服務。它本質上是把前端元件的組合邏輯,延伸到了伺服器端

但如果這個 BFF 用 Java 寫呢?我們會發現,一個 Java BFF 的 Controller 方法和一個 React 的 useQuery Hook 在做著極其相似的事:

  • 聚合多個下游請求
  • 轉換資料格式以適配特定客戶端
  • 處理快取和降級邏輯
  • 管理錯誤邊界

所以:BFF 是前端元件化思想在後端的上溢(外溢也可以),也是後端服務編排思想在前端的下滲(下鑽也可以)。


六:思維模型——事件迴圈與執行緒池背後的分歧

6.1 前端思維:回應式與連續性

前端的應用不是「執行一次然後退出」的腳本。它是一個長時間執行的、事件驅動的、持續回應變化的過程。

前端的思維模型可以用一句話概括:「狀態變了,世界應該怎樣更新?」

這種思維是:

  • 拉取式的(Pull-based):元件在渲染時讀取目前狀態,而不是等待狀態被推過來。
  • 宣告式的(Declarative):我們描述 UI 應該長什麼樣,框架負責計算如何從目前狀態到達目標狀態。
  • 時間感知的(Time-aware):前端天然地考慮「這個動畫在 300ms 後應該是什麼狀態」、「這個 debounce 在 500ms 內有沒有新輸入」。

6.2 後端思維:交易性與邊界性

後端 API 不是長時間執行的對話(WebSocket 除外)。它是一個有明確起止點的、原子性的、邊界封閉的計算過程。

起止點:從接到 HTTP 請求開始,到回傳回應結束; 原子性:一個介面在接到明確的入參時,只做一件事情; 邊界封閉:有明確的資料邊界;

Java 工程師的思維模型也可以用一句話概括:「這個請求進來,正確的結果應該怎樣產生?」

這種思維是:

  • 推送式的(Push-based):請求帶著資料進來,系統處理它,把結果推回去。
  • 命令式的(Imperative):我們寫下一行行指令,明確告訴電腦先做什麼、後做什麼。
  • 空間感知的(Space-aware):後端工程師天然地考慮「這個查詢會掃描多少行資料」、「這個鎖會阻塞多少並發執行緒」、「這個物件在 heap 上佔多少記憶體」。

6.3 兩種思維的融合:現代全端的第三條路

優秀的前端在學習後端思維。他們開始用資料庫的視角思考客戶端狀態(ORM 化的狀態管理,如 Prisma / TanStack Query),開始關心「前端資料一致性」和「樂觀更新的回滾策略」。

優秀的後端也在學習前端思維。他們開始用回應式程式設計(Reactor / RxJava)處理串流資料,開始用 CQRS 和 Event Sourcing 模擬前端的事件驅動模型,開始關心「使用者體驗的延遲」而不僅僅是「系統吞吐的 QPS」。

最終我們會發現:前端和後端的思維不是對立的兩極,而是一個光譜的兩端。真正的高手可以在光譜上自由滑動,根據問題選擇最合適的思維模型。


七:業務視角下,語言只是介面,理解才是實作

圖 3:業務視角下,產品、前端、後端構成價值交付的三角——語言只是工具,理解才是基礎設施。

7.1 業務不關心我們用什麼語言

產品提需求說:「使用者點擊下單按鈕後,應該在 2 秒內看到訂單確認。」

這句話同時給前端和後端下了需求:

  • 前端:按鈕需要有 loading 狀態,需要有骨架畫面或樂觀更新,需要在 2 秒內給出視覺回饋。
  • 後端:下單 API 的 P99 延遲必須小於 800ms,交易必須在 500ms 內提交,訊息必須在 200ms 內進入 MQ。

產品不關心前端用 React 還是 Vue,不關心後端用 Java 還是 Go。業務只關心價值是否被正確地、快速地、可靠地交付到使用者手中

7.2 團隊政治和語言偏見

在技術團隊裡,語言選擇有時會成為一種身份政治,已經 2026 年了,有些公司有些團隊這種現象還是存在的。

「我們 Java 團隊不寫 Node.js」 ——這句話的背後可能是合理的(JVM 生態的監控、維運、中介軟體已經成熟),也可能是不合理的(對新技術的恐懼、對技能組投資的沉沒成本執念)。

「後端只會寫 CRUD」 ——這句話的背後可能是傲慢(忽視了分散式交易、高並發、資料一致性的複雜性),也可能是失望(確實有些後端工程師停留在簡單的增刪改查層面,沒有深入業務)。

一個前端應有的成熟:不貶低自己不擅長的領域。當我們說「Java 太囉嗦」時,我們是否理解這種「囉嗦」在穩定和合規場景下的價值?當我們說「前端只是做介面」時,我們是否了解現代前端在邊緣運算(Edge Computing)、SSR 水合、串流傳輸中的複雜度?

7.3 API 契約:前後端的「結婚證書」

前後端之間最重要的技術文件不是架構設計書,不是資料庫 ER 圖,而是 API 的契約

OpenAPI(Swagger)、GraphQL Schema、gRPC Proto——這些都是契約的形式。契約的本質是雙方對「什麼是真實」達成共識

前端根據契約渲染介面,後端根據契約提供資料。當契約被打破,雙方的世界觀就產生了分歧。

最有生產力的團隊,是那些把契約當作共同資產來維護的團隊。前端工程師理解為什麼某個欄位在 Java 裡是 Optional<Long> 而不是 Long(因為資料庫外鍵可能為空),後端工程師理解為什麼前端需要巢狀資源的批次查詢介面(為了減少 N+1 次網路往返)。

7.4 語言即邊界,邊界即組織

康威定律說:「設計系統的組織,其產生的設計等同於組織間的溝通結構。」

在業務團隊裡,語言選擇往往強化了組織邊界:

  • Java 後端團隊擁有「資料主權」和「業務規則解釋權」
  • 前端團隊擁有「使用者體驗解釋權」和「互動設計主權」

這種分工有其效率邏輯,但也有其隱性成本。當一個業務需求需要修改同時涉及 Java 領域模型和前端狀態結構時,組織邊界就變成了阻力

技術組織也應該打破這種剛性邊界:

  • BFF 層 讓前端團隊擁有部分後端編排能力
  • 全端框架(如 Next.js / Nuxt / Spring Boot + Thymeleaf)模糊前後端分工
  • 共享型別定義(如 OpenAPI Generator 自動產生 TS 型別)降低溝通摩擦
  • Feature Team 取代 Component Team,讓同一個團隊擁有端到端交付能力

結語:鏡子的兩面,山的兩面

寫了這麼多,我想回到開篇的比喻:鏡子。

Java 之於前端,不是一座需要征服的山,而是一面需要理解的鏡子。當我們站在 TypeScript 去看 Java 時,我們看到的不是陌生的異域,而是我們已熟知概念的另一種表達:

  • 我們熟悉的 React Context,在 Java 裡叫 Dependency Injection Container
  • 我們熟悉的 Redux Action,在 Java 裡叫 Service Method Invocation
  • 我們熟悉的 useEffect cleanup,在 Java 裡叫 try-with-resources / @PreDestroy
  • 我們熟悉的 Vite Hot Module Replacement,在 Java 裡叫 JRebel / Spring Boot DevTools
  • 我們熟悉的 TypeScript Interface,在 Java 裡叫 POJO / DTO / Record
  • 我們熟悉的 npm audit,在 Java 裡叫 OWASP Dependency-Check

最後: 前端和後端的不同,本質上是 使用者距離 的不一樣。前端離使用者的眼睛和手近,所以它關心像素、幀率、互動回饋;後端離使用者的資料和交易近,所以它關心一致性、持久性、並發安全。

Java 不是前端的對立面,它是前端在伺服器端的倒影。當我們真正理解了這一點,我們不只是會成為一個更好的前端工程師——我們還會成為一個 理解完整價值鏈條 的技術人。

而那個境界,或許才是我們真正應該追求的 「全端」:不是會寫兩種程式碼,而是能在兩種思維之間自由穿梭,始終看見問題的全貌。


原文出處:https://juejin.cn/post/7632567246008385590


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝3   💬10   ❤️1
233
🥈
我愛JS
💬2  
8
🥉
Gigi
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登