Java基于Web3j调用智能智能合约案例

下面将提供一个完整的Java调用智能合约的示例,包括环境配置、合约部署和调用方法。

1. 环境准备

添加依赖

复制代码
<!-- Maven 依赖 -->
<dependencies>
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.9.7</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>

2. 智能合约示例

Solidity合约代码

复制代码
// SimpleStorage.sol
pragma solidity ^0.8.0;

contract SimpleStorage {
    uint256 private value;
    string private text;
    
    event ValueChanged(uint256 newValue);
    event TextChanged(string newText);
    
    function setValue(uint256 _value) public {
        value = _value;
        emit ValueChanged(_value);
    }
    
    function getValue() public view returns (uint256) {
        return value;
    }
    
    function setText(string memory _text) public {
        text = _text;
        emit TextChanged(_text);
    }
    
    function getText() public view returns (string memory) {
        return text;
    }
}

3. Java调用代码

主要工具类

复制代码
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.gas.DefaultGasProvider;
import java.math.BigInteger;

public class ContractCaller {
    
    private Web3j web3j;
    private Credentials credentials;
    private String contractAddress;
    
    public ContractCaller(String nodeUrl, String privateKey) {
        this.web3j = Web3j.build(new HttpService(nodeUrl));
        this.credentials = Credentials.create(privateKey);
    }
    
    /**
     * 部署合约
     */
    public String deployContract() throws Exception {
        SimpleStorage contract = SimpleStorage.deploy(
            web3j, 
            credentials, 
            new DefaultGasProvider()
        ).send();
        
        this.contractAddress = contract.getContractAddress();
        System.out.println("合约部署成功,地址: " + contractAddress);
        return contractAddress;
    }
    
    /**
     * 加载已部署的合约
     */
    public SimpleStorage loadContract(String contractAddress) {
        return SimpleStorage.load(
            contractAddress, 
            web3j, 
            credentials, 
            new DefaultGasProvider()
        );
    }
    
    /**
     * 调用合约的写方法
     */
    public void setValue(String contractAddress, BigInteger value) throws Exception {
        SimpleStorage contract = loadContract(contractAddress);
        TransactionReceipt receipt = contract.setValue(value).send();
        System.out.println("设置值成功,交易哈希: " + receipt.getTransactionHash());
    }
    
    /**
     * 调用合约的读方法
     */
    public BigInteger getValue(String contractAddress) throws Exception {
        SimpleStorage contract = loadContract(contractAddress);
        BigInteger value = contract.getValue().send();
        System.out.println("获取的值: " + value);
        return value;
    }
    
    /**
     * 设置文本
     */
    public void setText(String contractAddress, String text) throws Exception {
        SimpleStorage contract = loadContract(contractAddress);
        TransactionReceipt receipt = contract.setText(text).send();
        System.out.println("设置文本成功,交易哈希: " + receipt.getTransactionHash());
    }
    
    /**
     * 获取文本
     */
    public String getText(String contractAddress) throws Exception {
        SimpleStorage contract = loadContract(contractAddress);
        String text = contract.getText().send();
        System.out.println("获取的文本: " + text);
        return text;
    }
}

测试类

复制代码
import java.math.BigInteger;

public class ContractCallerTest {
    
    public static void main(String[] args) {
        try {
            // 配置参数
            String nodeUrl = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"; // 以太坊节点
            String privateKey = "YOUR_PRIVATE_KEY"; // 私钥
            
            ContractCaller caller = new ContractCaller(nodeUrl, privateKey);
            
            // 1. 部署合约
            String contractAddress = caller.deployContract();
            
            // 2. 设置数值
            caller.setValue(contractAddress, BigInteger.valueOf(12345));
            
            // 3. 读取数值
            BigInteger value = caller.getValue(contractAddress);
            
            // 4. 设置文本
            caller.setText(contractAddress, "Hello Web3j!");
            
            // 5. 读取文本
            String text = caller.getText(contractAddress);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4. 使用Web3j命令行工具生成Java包装类

生成Java包装类步骤:

复制代码
# 1. 安装web3j命令行工具
curl -L get.web3j.io | sh

# 2. 编译Solidity合约
solc SimpleStorage.sol --bin --abi --optimize -o build/

# 3. 生成Java包装类
web3j generate solidity -b build/SimpleStorage.bin -a build/SimpleStorage.abi -o src/main/java -p com.yourpackage.contracts

生成的Java包装类(部分):

复制代码
// 这是web3j自动生成的合约包装类
public class SimpleStorage extends Contract {
    
    public static final String BINARY = "0x606060..."; // 合约字节码
    
    public SimpleStorage(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
    }
    
    // 合约方法...
}

5. 高级功能示例

事件监听

复制代码
public class EventListener {
    
    public void listenToEvents(String contractAddress, Web3j web3j, Credentials credentials) throws Exception {
        SimpleStorage contract = SimpleStorage.load(
            contractAddress, 
            web3j, 
            credentials, 
            new DefaultGasProvider()
        );
        
        // 监听ValueChanged事件
        contract.valueChangedEventFlowable(DefaultBlockParameterName.EARLIEST, 
            DefaultBlockParameterName.LATEST).subscribe(event -> {
            System.out.println("值改变事件: " + event.newValue);
        });
        
        // 监听TextChanged事件
        contract.textChangedEventFlowable(DefaultBlockParameterName.EARLIEST, 
            DefaultBlockParameterName.LATEST).subscribe(event -> {
            System.out.println("文本改变事件: " + event.newText);
        });
    }
}

错误处理

复制代码
public class ContractCallerWithErrorHandling {
    
    public void safeContractCall(String contractAddress, BigInteger value) {
        try {
            ContractCaller caller = new ContractCaller("YOUR_NODE_URL", "YOUR_PRIVATE_KEY");
            caller.setValue(contractAddress, value);
        } catch (Exception e) {
            if (e.getMessage().contains("insufficient funds")) {
                System.out.println("余额不足");
            } else if (e.getMessage().contains("gas required exceeds allowance")) {
                System.out.println("Gas不足");
            } else {
                System.out.println("调用失败: " + e.getMessage());
            }
        }
    }
}

6. 配置说明

重要配置参数

复制代码
public class Web3jConfig {
    
    // 不同的网络配置
    public static final String MAINNET = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID";
    public static final String ROPSTEN = "https://ropsten.infura.io/v3/YOUR_PROJECT_ID";
    public static final String GANACHE = "http://localhost:7545";
    
    // Gas配置
    public static class CustomGasProvider extends DefaultGasProvider {
        @Override
        public BigInteger getGasPrice() {
            return BigInteger.valueOf(20_000_000_000L); // 20 Gwei
        }
        
        @Override
        public BigInteger getGasLimit() {
            return BigInteger.valueOf(300_000L);
        }
    }
}

注意事项

  1. 私钥安全: 永远不要在代码中硬编码私钥,使用环境变量或安全配置
  2. Gas费用: 合理设置Gas价格和限制
  3. 错误处理: 完善的异常处理机制
  4. 网络选择: 根据需求选择合适的网络(主网、测试网、本地网络)
相关推荐
自由的疯17 小时前
Java Jenkins、Dockers和Kubernetes有什么区别
java·后端·架构
哲此一生98418 小时前
SpringBoot3集成Mybatis(开启第一个集成Mybatis的后端接口)
java·spring boot·mybatis
浮游本尊18 小时前
Java学习第26天 - 微服务监控与运维实践
java
高山上有一只小老虎18 小时前
idea2025社区版设置打开的多个文件展示在工具栏下方
java·ide·intellij-idea
凸头18 小时前
责任链模式
java·开发语言·责任链模式
qq_4798754318 小时前
TimerFd & Epoll
java·服务器·数据库
Flobby52918 小时前
「JMM+Java锁+AQS」 知识图谱
java·后端
Deschen18 小时前
设计模式-组合模式
java·设计模式·组合模式
焰火199918 小时前
[Java]Redisson的分布式锁及看门狗机制
java·后端