以太坊作为全球最大的去中心化应用平台,其主网络承载着无数的价值转移、智能合约执行和去中心化金融(DeFi)活动,对于Java开发者而言,若想在以太坊生态中构建应用,Web3j无疑是一把利器,本文将详细介绍如何使用Web3j库来连接以太坊主网络,并进行基本的交互操作。

什么是Web3j

Web3j是一个轻量级、模块化且响应式的Java库,用于与以太坊节点进行交互,它提供了丰富的API,允许开发者:

  • 连接到以太坊节点(本地或远程)
  • 创建和管理以太坊账户(钱包)
  • 发送以太币(ETH)和交易
  • 部署和调用智能合约
  • 监听区块链事件
  • 查询区块链状态(如区块信息、交易收据、账户余额等)

相较于传统的JSON-RPC手动调用,Web3j封装了复杂的底层细节,使得Java开发者能够更便捷、更安全地与以太坊网络进行交互。

准备工作:环境与依赖

在开始之前,请确保你已经准备好以下环境:

  1. Java开发环境:JDK 8或更高版本。
  2. Maven或Gradle:用于项目管理和依赖下载,本文以Maven为例。
  3. 以太坊节点访问方式:这是调用以太坊主网络的关键,你有以下几种选择:
    • 运行本地节点:下载并运行以太坊客户端(如Geth或Parity),优点是完全自主可控,数据最全;缺点是对硬件配置要求较高,同步主网数据需要较长时间和大量存储空间。
    • 使用第三方Infura服务:Infura提供了可靠的以太坊节点访问服务,无需自己运行节点,你只需要在Infura官网注册并创建一个项目,即可获得一个节点URL(以https://mainnet.infura.io/v3/YOUR_PROJECT_ID格式),这是大多数开发者的首选,尤其是对于不需要全节点同步的应用。
    • 使用Alchemy或其他类似服务:与Infura类似,Alchemy也是提供高质量以太坊节点访问服务的平台,同样提供免费的套餐。

项目配置:引入Web3j依赖

在你的Maven项目的pom.xml文件中添加Web3j依赖:

<dependencies>
    <!-- Web3j 核心库 -->
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.9.8</version> <!-- 请使用最新版本 -->
    </dependency>
    <!-- 如果你需要使用Solidity智能合约编译后的Java包装类,还需要添加以下依赖 -->
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>solidity</artifactId>
        <version>4.9.8</version> <!-- 与core版本保持一致 -->
    </dependency>
</dependencies>

连接以太坊主网络

连接以太坊主网络的核心是创建Web3j实例,并指定主网络的节点URL。

以太坊主网络的Chain ID为1,Web3j在构建时通常会自动根据URL识别网络,但明确指定也是一种好习惯。

import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
public class EthereumMainnetConnector {
    public static void main(String[] args) {
        // 替换为你的Infura或Alchemy节点URL
        String mainnetUrl = "https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID";
        // 创建Web3j实例,连接到以太坊主网络
        Web3j web3j = Web3j.build(new HttpService(mainnetUrl));
        try {
            // 测试连接是否成功
            String clientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
            System.out.println("成功连接到以太坊主网络!");
            System.out.println("客户端版本: " + clientVersion);
            // 订阅连接状态监听(可选)
            web3j.addReconnectHandler(() -> {
                System.out.println("与
随机配图
以太坊节点断开连接,尝试重新连接..."); }); } catch (Exception e) { System.err.println("连接以太坊主网络失败: " + e.getMessage()); e.printStackTrace(); } finally { // 关闭Web3j连接,释放资源 if (web3j != null) { web3j.shutdown(); } } } }

代码说明

  • HttpService(mainnetUrl):创建一个基于HTTP的服务,用于与远程节点通信。
  • Web3j.build():构建Web3j实例。
  • web3j.web3ClientVersion().send().getWeb3ClientVersion():调用web3_clientVersion RPC方法获取客户端版本,这是测试连接是否最简单直接的方式。
  • web3j.shutdown():关闭连接,特别是在长时间运行的应用中,记得在不需要时关闭以释放资源。

常见交互操作示例

连接成功后,你就可以使用Web3j进行各种区块链操作了。

查询账户余额

import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.utils.Convert;
import org.web3j.utils.Convert.Unit;
// 假设web3j实例已创建
String address = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"; // 替换为你要查询的以太坊地址
try {
    EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
    BigInteger weiValue = balance.getBalance();
    // 将Wei转换为ETH
    String ethValue = Convert.fromWei(weiValue.toString(), Unit.ETH).toPlainString();
    System.out.println("地址 " + address + " 的余额为: " + ethValue + " ETH");
} catch (Exception e) {
    e.printStackTrace();
}

发送ETH交易

发送交易需要账户的私钥,请务必注意私钥的安全性,不要硬编码在代码中或提交到版本控制系统,推荐使用从密钥库文件(如UTC/JSON)加载私钥。

import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.utils.Numeric;
import java.math.BigInteger;
// 假设web3j实例已创建
String senderPrivateKey = "YOUR_SENDER_PRIVATE_KEY"; // 发送方私钥(实际应用中安全获取)
String receiverAddress = "0xReceiverAddressHere"; // 接收方地址
BigInteger gasLimit = BigInteger.valueOf(21000); // 转账ETH的典型gas限制
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); // 获取当前建议的gas价格
BigInteger value = Convert.toWei("0.1", Unit.ETH).toBigInteger(); // 转账0.1 ETH
try {
    Credentials credentials = Credentials.create(senderPrivateKey);
    RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
            credentials.getAddress(), // 发送方地址(可选,web3j会从私钥推导)
            nonce, // nonce,必须比该地址上一笔交易的nonce大1
            gasPrice,
            gasLimit,
            receiverAddress,
            value
    );
    // 计算交易签名
    byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
    String hexValue = Numeric.toHexString(signedMessage);
    // 发送交易
    EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).send();
    if (ethSendTransaction.getTransactionHash() != null) {
        System.out.println("交易发送成功!交易哈希: " + ethSendTransaction.getTransactionHash());
    } else {
        System.out.println("交易发送失败: " + ethSendTransaction.getError().getMessage());
    }
} catch (Exception e) {
    e.printStackTrace();
}

注意nonce的获取非常重要,web3j.ethGetTransactionCount(senderAddress, DefaultBlockParameterName.PENDING).send().getTransactionCount()可以获取下一个可用的nonce。

智能合约交互简介

如果需要与部署在以太坊主网上的智能合约交互,你需要:

  1. 获取合约ABI(Application Binary Interface):通常是JSON格式。
  2. 获取合约地址:部署后获得的合约地址。
  3. 使用Web3j的load方法加载合约
// 假设有合约ABI和地址
String contractAddress = "0xYourContractAddressHere";
String contractABI = "[...]"; // 合约的ABI JSON字符串
// 加载合约
Contract contract = Contract.load(contractAddress, web