# Java与智能合约交互-Read函数

By [MrLiuBai](https://paragraph.com/@mrliubai) · 2022-05-07

---

之所以选择利用java与智能合约进行交互，完全是因为本人只会Java，并且Java是世界上最好的语言。

**_能干什么_**

*   监控合约状态，读取合约的关键参数，可作为后台数据源。
    
*   转账、授权等基础交互。
    
*   实现例如抢购、提挖买等复杂交互。
    

**_代码分享_**

1.引入依赖

        <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>core</artifactId>
            <version>5.0.0</version>
        </dependency>
    

2.新建**Web3j**对象

    Web3j web3 = Web3j.build(new HttpService(rpcUrl));
    

*   rpcUrl变量是区块链网络节点的url链接，这些节点会提供很多标准的api方法通过该url进行调用，web3j模块就是在此api上进行封装。
    
*   不同网络的rpcUrl可以在对应的区块链浏览器api文档上找到，百度关键字也很容易获取。
    

3.调用智能合约的只读函数

        /**
         * 读取合约状态
         *
         * @param contractAddress 合约地址
         * @param functionName    合约函数名称
         * @param input           输入参数
         * @param output          返回变量类型
         * @return 合约函数返回值
         * @throws Exception 与节点交互失败
         */
        public List<Type> readContract(String contractAddress, String functionName, List<Type> input, List<TypeReference<?>> output) throws Exception {
            // 生成需要调用函数的data
            Function function = new Function(functionName, input, output);
            String data = FunctionEncoder.encode(function);
            // 组建请求的参数
            EthCall response = web3.ethCall(
                    Transaction.createEthCallTransaction(ownerAddress, contractAddress, data),
                    DefaultBlockParameterName.LATEST)
                    .send();
            // 解析返回结果
            return FunctionReturnDecoder.decode(
                    response.getValue(), function.getOutputParameters());
        }
    

*   contractAddress参数代表智能合约的地址，如"0x123456789..."
    
*   functionName参数代表需要调用合约中写函数的函数名，比如查询代币余额，该参数传"balanceOf"
    
*   input参数表示合约函数需要传入的参数，参数类型需要与solidity函数参数类型保持一致
    
    *   例子：Arrays.asList(new Address("0x6dF655480F465DC36347a5616E875D155804F0c5"), new Uint256(10000000));
        
    *   solidity的各类变量类型在web3j库中均有封装
        
*   output参数表示合约函数返回的参数类型，参数类型需要与solidity函数返回类型保持一致
    
    *   例子：Arrays.asList(new TypeReference(){});
        
        *   solidity函数可能会返回多个不同类型的返回值
            
*   4.查询代币余额的代码示例
    
            /**
             * 获取某个代币的余额
             *
             * @param contractAddress 代币合约地址
             * @param address         查询用户地址
             * @return 余额：单位ether
             * @throws Exception 与节点交互失败
             */
            public String balanceOf(String contractAddress, String address) throws Exception {
                List input = Arrays.asList(new Address(address));
                List output = Arrays.asList(new TypeReference<Uint256>() {
                });
                List<Type> result = readContract(contractAddress, "balanceOf", input, output);
                Uint256 balance = (Uint256) result.get(0);
                return Convert.fromWei(balance.getValue().toString(), Convert.Unit.ETHER).toString();
            }
        
    
    *   output数组传入的长度决定readContract方法返回值数组的长度
        
    *   1 ether = 1^18 wei，由于链上大部分的代币精度都是18位小数，这里直接做通用处理
        
    
    掌握这些知识点最好的方法是自己将代码跑起来，去链上获取你想获取的信息 !

---

*Originally published on [MrLiuBai](https://paragraph.com/@mrliubai/java-read)*
