1. 简介
本文将介绍 Web3j —— 一个流行的 Web3 抽象库的 Java 实现。
Web3j 的核心作用是让 Java 应用通过 JSON-RPC 协议与以太坊节点通信,支持的传输方式包括 HTTP、WebSocket 和 IPC。
以太坊本身是个大话题,我们先快速回顾一下它的核心概念,为后续开发打好基础。
2. 以太坊概述
以太坊本质上是一个集以下四种角色于一体的平台:
- ✅ 加密货币(代币符号 ETH)
- ✅ 分布式超级计算机
- ✅ 区块链系统
- ✅ 智能合约网络(主要使用 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