一、说明
在上一篇文章中 [《Hyperledger Fabric 2.x 自定义智能合约》] 分享了智能合约的安装并使用 cli
客户端进行合约的调用;本文将使用 Java
代码基于 fabric-gateway-java
进行区块链网络的访问与交易,并集成 SpringBoot
框架。
Fabric Gateway SDK
实现Fabric的编程模型,提供了一系列简单的API给应用程序与Fabric区块链网络进行交互;
网络拓扑图:
应用程序将各自的网络交互委托给其网关,每个网关都了解网络信道拓扑,包括组织的多个Peer节点和排序节点,使应用程序专注于业务逻辑;Peer节点可以使用gossip协议在组织内部和组织之间相互通信。
二、Mavn依赖
添加网关sdk的依赖:
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.2.3</version>
</dependency>
三、准备配置文件
工程的目录结构如下图所示:
3.1. 准备网络证书
创建目录 crypto-config
把 orderer
和 peer
节点的证书文件复制进来。
证书文件从 fabric-samples
的 test-network
目录中复制 ordererOrganizations
与 peerOrganizations
文件夹:
3.2. 创建网络配置
创建文件 connection.json
内容如下:
{
\"name\": \"basic-network\",
\"version\": \"1.0.0\",
\"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.28.134: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.28.134: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.28.134: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.28.134: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.28.134: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\"
}
]
}
}
}
需按实际情况修改url中的地址,内容中分别包含了
channels
、organizations
、orderers
、peers
、ca
的配置
3.3. SpringBoot配置
在 application.yml
中添加以下内容,用于访问网关的相关配置:
fabric:
# wallet文件夹路径(自动创建)
walletDirectory: wallet
# 网络配置文件路径
networkConfigPath: connection.json
# 用户证书路径
certificatePath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
# 用户私钥路径
privateKeyPath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk
# 访问的组织名
mspid: Org1MSP
# 用户名
username: user1
# 通道名字
channelName: mychannel
# 链码名字
contractName: mycc
四、连接合约
分别构建网关、通道和合约的Bean对象,代码如下:
/**
* 连接网关
*/
@Bean
public Gateway connectGateway() throws IOException, InvalidKeyException, CertificateException {
//使用org1中的user1初始化一个网关wallet账户用于连接网络
Wallet wallet = Wallets.newFileSystemWallet(Paths.get(this.walletDirectory));
X509Certificate certificate = readX509Certificate(Paths.get(this.certificatePath));
PrivateKey privateKey = getPrivateKey(Paths.get(this.privateKeyPath));
wallet.put(username, Identities.newX509Identity(this.mspid, certificate, privateKey));
//根据connection.json 获取Fabric网络连接对象
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, username)
.networkConfig(Paths.get(this.networkConfigPath));
//连接网关
return builder.connect();
}
/**
* 获取通道
*/
@Bean
public Network network(Gateway gateway) {
return gateway.getNetwork(this.channelName);
}
/**
* 获取合约
*/
@Bean
public Contract contract(Network network) {
return network.getContract(this.contractName);
}
五、合约调用
创建controller类,注入Contract对象调用合约方法:
@Resource
private Contract contract;
@Resource
private Network network;
@GetMapping(\"/getUser\")
public String getUser(String userId) throws ContractException {
byte[] queryAResultBefore = contract.evaluateTransaction(\"getUser\",userId);
return new String(queryAResultBefore, StandardCharsets.UTF_8);
}
@GetMapping(\"/addUser\")
public String addUser(String userId, String userName, String money) throws ContractException, InterruptedException, TimeoutException {
byte[] invokeResult = contract.createTransaction(\"addUser\")
.setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
.submit(userId, userName, money);
String txId = new String(invokeResult, StandardCharsets.UTF_8);
return txId;
}
六、测试接口
调用接口 getUser
:
http://127.0.0.1:9001/getUser?userId=1
返回:
{
\"money\": 300,
\"name\": \"zlt\",
\"userId\": \"1\"
}
调用接口 addUser
:
http://127.0.0.1:9001/addUser?userId=6&userName=test6&money=600
返回:
2ae291bb6a366b5ba01ad49e4237da8def9e9828cc2c982e8c49d4b763af0157
七、代码下载
gitee:https://gitee.com/zlt2000/my-fabric-application-java
github:https://github.com/zlt2000/my-fabric-application-java
来源:https://www.cnblogs.com/xyou/p/15976296.html
本站部分图文来源于网络,如有侵权请联系删除。