1. 简介

本文将介绍 Web3j —— 一个流行的 Web3 抽象库的 Java 实现。

Web3j 的核心作用是让 Java 应用通过 JSON-RPC 协议与以太坊节点通信,支持的传输方式包括 HTTP、WebSocket 和 IPC。

以太坊本身是个大话题,我们先快速回顾一下它的核心概念,为后续开发打好基础。

2. 以太坊概述

以太坊本质上是一个集以下四种角色于一体的平台:

  1. 加密货币(代币符号 ETH)
  2. 分布式超级计算机
  3. 区块链系统
  4. 智能合约网络(主要使用 Solidity 编写)

简单来说,以太坊网络由大量相互连接的 节点(node)组成,这些节点通过类似网状拓扑的结构进行通信(技术上不完全准确,但有助于理解)。

Web3j(及其 JavaScript 版本 Web3)的作用是让 Web 应用连接到这些节点,从而提交交易(transaction)。这些交易本质上就是已部署到以太坊网络的 Solidity 智能合约函数调用。关于智能合约的创建与部署,可参考我们另一篇 Solidity 教程

每个节点都会将状态变更广播给其他节点,通过共识机制达成一致。✅ 这意味着每个节点都保存了完整的以太坊区块链历史记录,数据高度冗余、防篡改,并由全网节点共同验证。

如需深入了解以太坊,建议查阅 官方文档

3. 环境搭建

要使用 Web3j 的完整功能,需要做一些前置配置。Web3j 采用模块化设计,核心依赖如下:

<dependency>
    <groupId>org.web3j</groupId>
    <artifactId>core</artifactId>
    <version>3.3.1</version>
</dependency>

⚠️ 注意:Web3j 官方提供了集成配置的 Spring Boot Starter,适合快速上手。但本文聚焦核心功能,也会涵盖在 Spring MVC 中的集成方式,确保更广泛的兼容性。

所有模块可在 Maven Central 查看。

3.1. 编译合约:Truffle 或 Solc

编译和部署 Solidity 合约(.sol 文件)主要有两种方式:

  • 官方 Solidity 编译器(Solc)
  • Truffle(集成了测试、编译、部署的开发套件)

本文选择 Truffle,因为它能大幅简化开发流程,抽象了编译、迁移和部署的细节,同时底层仍调用 Solc,让我们能同时接触两者。

安装 Truffle:

$ npm install -g truffle
$ truffle version

四个核心命令:

$ truffle init     # 初始化项目
$ truffle compile  # 编译合约
$ truffle migrate  # 部署到链上
$ truffle test     # 运行测试

示例合约:

pragma solidity ^0.4.17;

contract Example {
  function Example() {
    // 构造函数
  }
}

编译后生成的 ABI(Application Binary Interface)如下:

{
  "contractName": "Example",
  "abi": [
    {
      "inputs": [],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "constructor"
    }
  ],
  "bytecode": "0x60606040523415600e57600080fd5b603580601b6...",
  "deployedBytecode": "0x6060604052600080fd00a165627a7a72305...",
  // ...
}

后续 Java 应用将通过 ABI 和字节码与部署的合约交互。

3.2. 测试环境:Ganache

最简单的本地测试网方案是使用 Ganache。它开箱即用,自带图形界面和 CLI,底层由 Ganache CLI 驱动。

默认连接地址:

  • http://localhost:8545
  • http://localhost:7545

其他方案如 MetaMask、Infura 或 Geth(Go 语言实现)也可行,但:

  • ✅ Ganache 配置最简单
  • ⚠️ Geth 搭建私链较复杂
  • ⚠️ MetaMask 在 Chrome 上的未来支持存在不确定性

Ganache 既可用于手动调试,也适用于自动化集成测试(需自行构建测试上下文)。

4. Web3 与 RPC 通信

Web3 提供了一层抽象,让客户端能方便地与以太坊节点交互。其底层基于 JSON-RPC 协议实现通信

Web3j 是 Web3.js 的官方 Java 移植版本。

初始化 Web3j 实例时需指定节点地址(provider):

// 使用默认本地节点(localhost:8545)
Web3j web3a = Web3j.build(new HttpService());

// 指定自定义节点
Web3j web3b = Web3j.build(new HttpService("http://localhost:8545"));

// 使用第三方服务(如 MyEtherWallet)
Web3j myEtherWallet = Web3j.build(
  new HttpService("https://api.myetherapi.com/eth"));

不传参数时,默认连接 http://localhost:8545

5. 核心 Web3j 方法

了解了如何连接节点后,来看几个常用操作。⚠️ 建议用 CompletableFuture 包装异步调用,避免阻塞。

5.1. 获取当前区块高度

public EthBlockNumber getBlockNumber() {
    return this.web3j.ethBlockNumber()
        .sendAsync()
        .get();
}

5.2. 获取账户列表

public EthAccounts getEthAccounts() {
    return this.web3j.ethAccounts()
        .sendAsync()
        .get();
}

5.3. 查询账户交易次数

public EthGetTransactionCount getTransactionCount() {
    return this.web3j.ethGetTransactionCount(
        "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
        DefaultBlockParameter.valueOf("latest")
    ).sendAsync().get();
}

5.4. 查询账户余额

public EthGetBalance getEthBalance() {
    return this.web3j.ethGetBalance(
        "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
        DefaultBlockParameter.valueOf("latest")
    ).sendAsync().get();
}

6. 在 Web3j 中操作智能合约

使用 Truffle 编译合约后,可通过 Web3j 的命令行工具生成 Java 封装类(Smart Contract Wrapper),让调用更像普通 Java 对象。

工具下载地址:GitHub Releases

6.1. 生成合约封装类

使用 CLI 自动生成 Java 类:

web3j truffle generate [--javaTypes|--solidityTypes] \
  /path/to/<truffle-output>.json \
  -o /path/to/src/main/java \
  -p com.your.package

示例:

web3j truffle generate dev_truffle/build/contracts/Example.json \
  -o src/main/java/com/baeldung/web3/contract \
  -p com.baeldung

生成的 Example.java 类:

public class Example extends Contract {
    private static final String BINARY = "0x60606040523415600e576...";
    // ...
}

6.2. 钱包与凭证管理

可编程生成钱包文件:

WalletUtils.generateNewWalletFile("myPassword123", new File("/wallets"), true);

加载凭证用于后续签名:

Credentials credentials = WalletUtils.loadCredentials("myPassword123", "/wallets/UTC--...");

6.3. 部署合约

通过封装类一键部署:

Example contract = Example.deploy(
    web3j,
    credentials,
    ManagedTransaction.GAS_PRICE,
    Contract.GAS_LIMIT
).send();

String contractAddress = contract.getContractAddress();

6.4. 调用合约方法(发送交易)

手动构造交易(适用于复杂或动态场景):

List<Type> inputParams = new ArrayList<>();
List<TypeReference<?>> outputParams = new ArrayList<>();
Function function = new Function("setValue", inputParams, outputParams);
String encodedFunction = FunctionEncoder.encode(function);

Transaction transaction = Transaction.createFunctionCallTransaction(
    "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
    BigInteger.valueOf(100), // nonce
    BigInteger.valueOf(20_000_000_000L), // gas price
    BigInteger.valueOf(6_700_000), // gas limit
    "0x8eeb85d32cf465507dd71d507100c1407d73d8a4", // 合约地址
    encodedFunction
);

EthSendTransaction response = web3j.ethSendTransaction(transaction)
    .sendAsync()
    .get();

String transactionHash = response.getTransactionHash();

✅ 推荐优先使用自动生成的封装类调用方法,更安全、简洁。手动构造适用于需要精细控制 nonce、gas 等参数的场景。

完整功能参考 Web3j 官方文档

7. 总结

搞定!我们已经成功搭建了基于 Web3j 的 Java 以太坊客户端,可以开始玩转区块链了。

所有示例代码已上传至 GitHub:https://github.com/eugenp/tutorials/tree/master/ethereum


原始标题:Lightweight Ethereum clients Using Web3j | Baeldung