fabric-gateway-java 调用虚拟机上的fabric链码,以fabcar为例
作为学习的记录。我是在虚拟机上搭建了fabric网络和通道,并部署了官方示例fabcar链码,现在想在windows上通过fabric-gateway-java 实现对fabric上链码的调用。fabric的版本是2.4.0,编译器是IDEA,代码基于springboot框架。fanric环境的搭建、test-network及通道的创建、链码的部署这里不再赘述。首先导入如下依赖:<depen
作为学习的记录。我是在虚拟机上搭建了fabric网络和通道,并部署了官方示例fabcar链码,现在想在windows上通过fabric-gateway-java 实现对fabric上链码的调用。
fabric的版本是2.4.0,编译器是IDEA,代码基于springboot框架。
fanric环境的搭建、test-network及通道的创建、链码的部署这里不再赘述。
首先导入如下依赖:
<dependency>
<groupId>org.hyperledger.fabric-sdk-java</groupId>
<artifactId>fabric-sdk-java</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.2.0</version>
</dependency>
代码的结构,我的结构是这样的:
首先,我们需要将test-network建立好之后,文件夹test-neteork/organizations下的orderorganizations和peerorganizations文件从虚拟机中复制到代码中,我是放在了resources/crypto-config目录下。
随后写的是链接建立文件,connection.json。
{
"name": "basic-network",
"version": "1.0.0",
"dependencies": {
},
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300"
},
"orderer": "300"
}
}
},
"channels": {
"mychannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true
},
"peer0.org2.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true
}
}
}
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
],
"certificateAuthorities": [
"ca-org1"
],
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}
},
"Org2": {
"mspid": "Org2MSP",
"peers": [
"peer0.org2.example.com"
],
"certificateAuthorities": [
"ca-org2"
],
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem"
}
}
},
"orderers": {
"orderer.example.com": {
"url": "grpcs://192.168.16.129:7050",
"mspid": "OrdererMSP",
"grpcOptions": {
"ssl-target-name-override": "orderer.example.com",
"hostnameOverride": "orderer.example.com"
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
},
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/signcerts/Admin@example.com-cert.pem"
}
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://192.168.16.129:7051",
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com",
"request-timeout": 120001
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
}
},
"peer0.org2.example.com": {
"url": "grpcs://192.168.16.129:9051",
"grpcOptions": {
"ssl-target-name-override": "peer0.org2.example.com",
"hostnameOverride": "peer0.org2.example.com",
"request-timeout": 120001
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
}
}
},
"certificateAuthorities": {
"ca-org1": {
"url": "https://192.168.16.129:7054",
"grpcOptions": {
"verify": true
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"
},
"registrar": [
{
"enrollId": "admin",
"enrollSecret": "adminpw"
}
]
},
"ca-org2": {
"url": "https://192.168.16.129:8054",
"grpcOptions": {
"verify": true
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem"
},
"registrar": [
{
"enrollId": "admin",
"enrollSecret": "adminpw"
}
]
}
}
}
其中的ip换成自己虚拟机的ip,文件路径根据自己存放的orderorganizations和peerorganizations的目录进行调整。
之后配置properties文件:
fabric.networkConnectionConfigPath = src/main/resources/connection.json
fabric.certificatePath = src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
fabric.privateKeyPath = src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk
指定了,connection,json文件的位置,和后续链接用到的私钥和证书目录。
之后就可以开始写代码了hh。
首先是配置类的代码,主要功能是从properties文件中读取需要的参数值
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "fabric")
@Data
public class HyperLedgerFabricProperties {
String networkConnectionConfigPath;
String certificatePath;
String privateKeyPath;
}
之后还是一个配置类,用来获取gateway.
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Identities;
import org.hyperledger.fabric.gateway.Wallet;
import org.hyperledger.fabric.gateway.Wallets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
@Configuration
@AllArgsConstructor
@Slf4j
public class HyperLedgerConfig {
final HyperLedgerFabricProperties hyperLedgerFabricProperties;
@Bean
public Gateway gateway() throws Exception {
BufferedReader certificateReader = Files.newBufferedReader(Paths.get(hyperLedgerFabricProperties.getCertificatePath()), StandardCharsets.UTF_8);
X509Certificate certificate = Identities.readX509Certificate(certificateReader);
BufferedReader privateKeyReader = Files.newBufferedReader(Paths.get(hyperLedgerFabricProperties.getPrivateKeyPath()), StandardCharsets.UTF_8);
PrivateKey privateKey = Identities.readPrivateKey(privateKeyReader);
Wallet wallet = Wallets.newInMemoryWallet();
wallet.put("user1" , Identities.newX509Identity("Org1MSP", certificate , privateKey));
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet , "user1")
.networkConfig(Paths.get("src/main/resources/connection.json"));
Gateway gateway = builder.connect();
log.info("=========================================== connected fabric gateway {} " , gateway);
return gateway;
}
}
没有问题以后,就是controller的代码,这里就以queryAllCars命令为例。
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.StringUtils;
import org.hyperledger.fabric.gateway.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeoutException;
@RestController
@RequestMapping("/car")
@Slf4j
@AllArgsConstructor
public class Fabriccontroller {
final Gateway gateway;
@GetMapping("/queryall")
public Map<String, Object> queryall() throws ContractException {
Map<String, Object> result = Maps.newConcurrentMap();
Contract contract = getContract();
byte[] car = contract.evaluateTransaction("queryAllCars");
result.put("result", StringUtils.newStringUtf8(car));
return result;
}
private Network getNetwork(){
return gateway.getNetwork("mychannel");
}
private Contract getContract(){
return getNetwork().getContract("fabcar");
}
}
最后getnetwork()和getcontract()的参数分别是通道的名称和链码的名称,根据自己的情况做调整。
最后,运行主启动类。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties
public class FabricJdkApplication {
public static void main(String[] args) {
SpringApplication.run(FabricJdkApplication.class, args);
}
}
注意:一定要在linux中先运行起来测试网络并安装好链码后才能够连接成功。
浏览器测试一下,返回查询数据
还有一点注意的是,当我们这一次工作结束,关闭了区块链网络。下一次在重启网络,要更新代码中的 orderorganizations和peerorganizations,替换成新网络的属性文件,否则自然是链接不上的。
学习中参考了B站“老哥没有饿意”的视频。作为初学者,如有问题和错误,欢迎大家的讨论和指正。
更多推荐
所有评论(0)