环境 : ubuntu20
fisco : 2.8.0
java:1.8
solidity: 0.6.10
这篇将讲解如何使用http的相关包,发送网络请求直接调用合约
请提前启动fisco节点和webase-front
我们准备一个简单的合约HelloWorld.sol
pragma solidity>=0.4.24 <0.6.11;
contract HelloWorld {
string name;
constructor() public {
name = "Hello, World!";
}
function get() public view returns (string memory) {
return name;
}
function set(string memory n) public {
name = n;
}
}
我们启动一个空的项目,并且只导入web包,fastjson包,hutool包依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.76version>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.8.11version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
然后我们还需要导两个包,作为我们发送http请求的依赖包,我们使用okhttps,当然还有其他开源的http请求的依赖包
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.12.0version>
dependency>
一个简单的http请求发送代码如下
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data.toJSONString()); // 进行json传值,post 请求【第一个是提交方式和编写形式,第二个参数是数据】
Request request = new Request.Builder()
.url(transUrl) //发送请求到哪个地址
.post(requestBody) //post请求
.build();
final Call call = client.newCall(request);
Response response = call.execute(); //发送请求,获得返回体数据
但是我们每次调用合约交易都要重新执行一遍http请求代码,太过于重复了,所以我们需要编写一个工具类HttpUtils
import java.io.IOException;
import java.util.List;
@Component
public class HttpUtils {
private static String contractAddress;
private static String contractName;
private static String contractAbi;
private static String transUrl;
@Value("${contract.address}")
private void setContractAddress(String _address){
contractAddress = _address;
}
@Value("${contract.name}")
private void setContractName(String _name){
contractName = _name;
}
@Value("${contract.abi}")
private void setContractAbi(String _abi){
contractAbi = _abi;
}
@Value("${transurl}")
private void setTransUrl(String _url){
transUrl = _url;
}
private static OkHttpClient client = new OkHttpClient();
static private String commonReq(String userAddress, String funcName, List funcParam) {
JSONArray abiJSON = JSON.parseArray(contractAbi);
JSONObject data = new JSONObject();
data.put("groupId", "1"); //群组
data.put("user", userAddress); // 发送交易的用户地址
data.put("contractName", contractName); //合约名
data.put("version", "");
data.put("funcName", funcName); // 方法名
data.put("funcParam", funcParam);//方法数据
data.put("contractAddress", contractAddress);//合约地址
data.put("contractAbi", abiJSON); //合约的abi
data.put("useAes", false);
data.put("useCns", false);
data.put("cnsName", "");//cns版本管理,没有用cns部署就不需要
try {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data.toJSONString());
Request request = new Request.Builder()
.url(transUrl) //webasefront url
.post(requestBody) //post请求
.build();
final Call call = client.newCall(request);
Response response = call.execute();
return response.body().string();
}catch (IOException exception){
System.out.println(exception.getMessage());
}
return null;
}
//执行写操作
public static JSONObject writeContract(String userAddress,String funcName,List funcParam) {
String result = HttpUtils.commonReq(userAddress,funcName, funcParam);
JSONObject _obj = JSON.parseObject(result);
if (_obj.getIntValue("code") > 0 || !_obj.get("status").equals("0x0")) {
System.out.println(_obj);
return null;
}
return _obj;
}
//执行读操作
public static JSONArray readContract(String contractAddress,String funcName,List funcParam){
String result = HttpUtils.commonReq(contractAddress,funcName, funcParam);
JSONArray _obj = JSON.parseArray(result);
return _obj;
}
}
applicaiton.properties
contract.address=0xbdfb70e866a5531205ac2505c18e6a54acd7849e # 合约部署地址
contract.name=HelloWorld # 合约名
contract.abi=[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"get","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"n","type":"string"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}] # helloworld代码的abi
transurl=http://192.168.19.133:5002/WeBASE-Front/trans/handle # webase-front的ip地址和发送交易的路径
server.port=8086
解释一下这种发送除了携带合约地址,合约的方法参数和参数外,还需要各种节点相关信息,
具体可以查看webase-front发送交易的官方文档。
然后我们写一个TestController来调用helloworld合约的set和get方法
package com.yijiuyiyi.helloworld2.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yijiuyiyi.helloworld2.entity.HelloWorldSet;
import com.yijiuyiyi.helloworld2.util.HttpUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class TestController {
private String userAddress = "0x49176c03339b314451e543a764db3f4b6fe8e0e2"; //交易需要有个发起人调用,我就随机用一个用户地址来调用
@PostMapping("/set")
public JSONObject set(@RequestBody HelloWorldSet dto) throws Exception {
List list = new ArrayList<>();
list.add(dto.getN());
JSONObject jsonObject = HttpUtils.writeContract(userAddress, "set", list);
return jsonObject;
}
@GetMapping("/get")
public JSONArray get() throws Exception {
JSONArray array = HttpUtils.readContract("get", new ArrayList());
return array;
}
}
然后我们启动项目,进行测试
{
"blockHash": "0x9bcf1618ab5e24b6206b1e6cb372de6d1d5cf9900e0a162b31b95756f8a2ab1d",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"contractAddress": "0x0000000000000000000000000000000000000000",
"transactionIndex": "0x0",
"message": "Success",
"receiptProof": null,
"transactionHash": "0x868fc0f2b86874ba65562785790db2baf17a487414a3a50340dd59ff5d4c3c8b",
"output": "0x",
"input": "0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c68656c6c6f313233333434340000000000000000000000000000000000000000",
"gasUsed": "29493",
"statusMsg": "None",
"txProof": null,
"root": "0x6f022173c185f30dbf45c32fc9bf66d7b19d427975e676ba012cd1dc0a263e9d",
"blockNumber": "1897",
"statusOK": true,
"from": "0x49176c03339b314451e543a764db3f4b6fe8e0e2",
"to": "0xbdfb70e866a5531205ac2505c18e6a54acd7849e",
"logs": [],
"status": "0x0"
}
测试完成
这种调用方式,会比较轻量化,因为只需要发送http接口请求就可以了,但是如果接口多起来,会编写的工作量会比较大,而且返回的是字符串,还需要进行处理成所需要的对象。但是如果使用上篇文章的第一种调用方法,多接口的项目就会比较方便,因为各种请求体和返回体对象,都已经帮我们生成了