Java连接以太坊节点,实践指南与代码示例
以太坊作为全球领先的智能合约平台,吸引了大量开发者的关注,在实际应用开发中,我们经常需要使用Java等编程语言与以太坊节点进行交互,例如查询账户余额、发送交易、调用智能合约等,本文将详细介绍如何使用Java连接到以太坊节点,并实现基本的交互功能。
准备工作
在开始之前,你需要确保以下准备工作已完成:
-
以太坊节点:
- 本地节点:你可以运行自己的以太坊节点客户端,如Geth(Go语言实现)或Parity(Rust语言实现),启动节点时,需要确保启用了HTTP-RPC接口,默认端口为8545,Geth启动命令可能包含
--http --http.addr "0.0.0.0" --http.port "8545" --http.api "eth,net,web3,personal"等参数。 - 远程节点:你也可以使用远程的以太坊节点服务,如Infura、Alchemy等,这些服务通常提供一个HTTP或WebSocket的URL。
- 本地节点:你可以运行自己的以太坊节点客户端,如Geth(Go语言实现)或Parity(Rust语言实现),启动节点时,需要确保启用了HTTP-RPC接口,默认端口为8545,Geth启动命令可能包含
-
Java开发环境:确保你已经安装了JDK(建议版本8或以上)和Maven(或Gradle)构建工具。
-
以太坊Java库:我们将使用目前较为流行和维护良好的 Web3j 库,它是一个轻量级的、异步的Java库,用于与以太坊节点交互。
引入Web3j依赖
如果你使用Maven,在pom.xml文件中添加以下依赖:
<dependencies>
<!-- Web3j Core -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.9.8</version> <!-- 请查阅Web3j官网获取最新版本 -->
</dependency>
<!-- Web3j Console (可选,提供命令行工具) -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>console</artifactId>
<version>4.9.8</version>
</dependency>
<!-- Web3j Utils (可选,提供一些实用工具) -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>utils</artifactId>
<version>4.9.8</version>
</dependency>
</dependencies>
如果你使用Gradle,在build.gradle文件中添加:
implementation 'org.web3j:core:4.9.8' // 请查阅Web3j官网获取最新版本 implementation 'org.web3j:console:4.9.8' implementation 'org.web3j:utils:4.9.8'
连接以太坊节点
Web3j提供了多种方式连接到以太坊节点,最常用的是通过HTTP/HTTPS。
连接到本地节点
假设你的本地以太坊节点运行在 http://localhost:8545。
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import java.io.IOException;
public class EthereumConnector {
private static final String NODE_URL = "http://localhost:8545";
private Web3j web3j;
public void connect() {
// 创建Web3j实例,连接到指定的节点URL
web3j = Web3j.build(new HttpService(NODE_URL));
System.out.println("Connecting to Ethereum node at: " + NODE_URL);
try {
// 测试连接,获取客户端版本
String clientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
System.out.println("Connected successfully! Client version: " + clientVersion);
} catch (IOException e) {
System.err.println("Failed to connect to Ethereum node: " + e.getMessage());
e.printStackTrace();
}
}
public Web3j getWeb3j() {
return web3j;
}
public static void main(String[] args) {
EthereumConnector connector = new EthereumConnector();
connector.connect();
}
}
连接到远程节点(如Infura)
以In

Infura的Rinkeby测试网URL格式为:https://rinkeby.infura.io/v3/YOUR_PROJECT_ID
public class RemoteEthereumConnector {
private static final String INFURA_URL = "https://rinkeby.infura.io/v3/YOUR_PROJECT_ID"; // 替换为你的Infura项目ID
private Web3j web3j;
public void connect() {
web3j = Web3j.build(new HttpService(INFURA_URL));
System.out.println("Connecting to remote Ethereum node at: " + INFURA_URL);
try {
String clientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
System.out.println("Connected successfully! Client version: " + clientVersion);
} catch (IOException e) {
System.err.println("Failed to connect to remote Ethereum node: " + e.getMessage());
e.printStackTrace();
}
}
// 其他方法与上面类似...
}
基本交互示例
成功连接到节点后,我们可以进行一些基本的操作。
获取最新区块号
try {
BigInteger latestBlockNumber = web3j.ethBlockNumber().send().getBlockNumber();
System.out.println("Latest block number: " + latestBlockNumber);
} catch (IOException e) {
e.printStackTrace();
}
获取账户余额
假设我们有一个以太坊地址 0x...,我们需要知道它的余额(单位:Wei)。
String address = "0xYourEthereumAddressHere"; // 替换为实际的以太坊地址
try {
EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
BigInteger balanceInWei = balance.getBalance();
System.out.println("Balance of " + address + ": " + balanceInWei.toString() + " Wei");
// 将Wei转换为Ether (1 Ether = 10^18 Wei)
BigDecimal balanceInEther = new BigDecimal(balanceInWei).divide(new BigDecimal(BigInteger.TEN.pow(18)));
System.out.println("Balance in Ether: " + balanceInEther);
} catch (IOException e) {
e.printStackTrace();
}
发送交易(转账)
发送交易是一个相对复杂的过程,需要以下步骤:
- 解锁账户(如果是本地节点且账户有密码):
personalUnlockAccount - 构造交易:
EthSendTransaction - 等待交易确认:
ethGetTransactionReceipt
注意:实际发送交易需要账户的私钥,切勿在代码中硬编码私钥,应该使用安全的方式(如环境变量、密钥库文件+密码)来管理私钥,以下仅为演示如何调用发送交易的方法,不包含私钥处理。
// !!! 警告:以下代码仅为演示,实际使用时切勿硬编码私钥 !!!
String fromAddress = "0xSenderAddress";
String toAddress = "0xReceiverAddress";
String privateKey = "YOUR_PRIVATE_KEY_HERE"; // 危险!不要这样做!
// 1. 解锁账户 (本地节点可能需要)
// try {
// personalUnlockAccount = web3j.personalUnlockAccount(fromAddress, privateKeyPassword).send();
// if (!personalUnlockAccount.accountUnlocked()) {
// System.out.println("Failed to unlock account");
// return;
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
// 2. 构造交易
BigInteger value = new BigInteger("1000000000000000000"); // 1 Ether in Wei
BigInteger gasLimit = BigInteger.valueOf(21000); // 转账通常21000 gas
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); // 获取当前建议gas价格
Transaction transaction = Transaction.createEtherTransaction(
fromAddress,
nonce, // 需要获取nonce
gasPrice,
gasLimit,
toAddress,
value
);
// 3. 发送交易
try {
EthSendTransaction ethSendTransaction = web3j.ethSendTransaction(transaction).send();
if (ethSendTransaction.getTransactionHash() != null) {
System.out.println("Transaction sent! Hash: " + ethSendTransaction.getTransactionHash());
// 4. 等待交易确认 (可选)
// TransactionReceipt receipt = web3j.ethGetTransactionReceipt(ethSendTransaction.getTransactionHash()).send();
// while (receipt.getTransactionReceipt() == null) {
// Thread.sleep(1000);
// receipt = web3j.ethGetTransactionReceipt(ethSendTransaction.getTransactionHash()).send();
// }
// System.out.println("Transaction confirmed! Status: " + receipt.getTransactionReceipt().getStatus());
} else {
System.out.println("Failed to send transaction: " + eth