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. 网络选择: 根据需求选择合适的网络(主网、测试网、本地网络)
相关推荐
Hello.Reader2 小时前
Data Sink定义、参数与可落地示例
java·前端·网络
2401_837088503 小时前
stringRedisTemplate.opsForHash().entries
java·redis
lkbhua莱克瓦244 小时前
Java基础——集合进阶3
java·开发语言·笔记
蓝-萧5 小时前
使用Docker构建Node.js应用的详细指南
java·后端
多喝开水少熬夜5 小时前
Trie树相关算法题java实现
java·开发语言·算法
lkbhua莱克瓦245 小时前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
音符犹如代码6 小时前
Java并发List实战:CopyOnWriteArrayList原理与ArrayList常见面试题
java·开发语言·面试·list
代码or搬砖6 小时前
Docker 部署 Java 项目实践
java·docker·容器
又是忙碌的一天7 小时前
抽象类和接口
java·开发语言
August_._7 小时前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle