在本節(jié)中,我們將介紹如何通過(guò)RESTful API將HyperledgeFabric網(wǎng)絡(luò)與Web應(yīng)用程序集成,并使用react.js作為前端。本教程中構(gòu)建的Web應(yīng)用程序僅是保單持有者應(yīng)用程序。
應(yīng)用執(zhí)行
在繼續(xù)下面操作步驟時(shí),請(qǐng)按照第一節(jié)內(nèi)容進(jìn)行搭建后,再繼續(xù)以下操作。
在insurance_application文件夾中,運(yùn)行以下命令以創(chuàng)建保單持有人Web應(yīng)用程序的框架:
npx create-react-app policyholder_app
cd policyholder_app
打開(kāi)src/app.js并刪除函數(shù)app返回中的代碼,只需添加hello world作為占位符,這樣app.js文件現(xiàn)在看起來(lái)如下
import React from ‘react’;
import ‘。/App.css’;
function App() {
return (
《p》Hello World《/p》
);
}
export default App;
用以下內(nèi)容替換src / App.css中的代碼:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.4;
background: #5B5B5B;
font-family: monospace;
font-size: 150%
}
a {
color: #333;
text-decoration: none;
font-family: monospace;
}
.container {
padding: 0 1rem;
}
.btn {
display: inline-block;
border: none;
background: #555;
color: #fff;
padding: 7px 20px;
cursor: pointer;
}
.btn:hover {
background: #666;
}
React應(yīng)用程序的默認(rèn)端口號(hào)是3000,因此需要更改它以使其不與REST API端口沖突。要執(zhí)行此操作,請(qǐng)將package.json的scripts部分更改為以下內(nèi)容以創(chuàng)建端口3001:
“scripts”: {
“start”: “PORT=3001 react-scripts start”,
“build”: “react-scripts build”,
“test”: “react-scripts test”,
“eject”: “react-scripts eject”
},
此外,我們需要在文件的底部添加一個(gè)代理,該代理將連接到Hyperledger Composer Network,因此只需在結(jié)束大括號(hào)之前添加以下行:
“proxy”: “http://localhost:3000/”
在此文件夾中創(chuàng)建以下新文件夾src/components和以下新文件header.js。這將為我們的應(yīng)用程序創(chuàng)建一個(gè)簡(jiǎn)單的標(biāo)題,其中包含指向主頁(yè)的鏈接:
import React, { Component } from ‘react’
import { Link } from ‘react-router-dom’;
class Header extends Component {
render() {
return (
《header style={headerStyle}》
《h1 style={titleStyle}》Policyholder Blockchain Insurance《/h1》
《Link style={linkStyle} to=“/”》Home《/Link》
《/header》
)
}
}
const headerStyle = {
background: ‘#333’,
color: ‘#fff’,
textAlign: ‘right’,
padding: ‘10px’
}
const linkStyle = {
color: ‘#fff’,
textDecoration: ‘none’
}
const titleStyle = {
textAlign: ‘left’
}
export default Header;
現(xiàn)在修改app.js,以便導(dǎo)入:
import { BrowserRouter as Router, Route } from ‘react-router-dom’;
import Header from ‘。/components/Header’
它實(shí)現(xiàn)了組件Header.js,如下所示:
《Router》
《Header/》
《/Router》
App.js現(xiàn)在看起來(lái)應(yīng)該是這樣的:
import React from ‘react’;
import { BrowserRouter as Router, Route } from ‘react-router-dom’;
import ‘。/App.css’;
import Header from ‘。/components/Header’
function App() {
return (
《Router》
《Header/》
《/Router》
);
}
export default App;
您可能需要安裝react-router-dom:
npm install --save react-router-dom
此外,您可能還需要安裝react-responsive-modal:
npm install react-responsive-modal --save
現(xiàn)在運(yùn)行應(yīng)用程序以通過(guò)從policyholder_app文件夾運(yùn)行以下命令來(lái)測(cè)試所有工作正常
npm start
如果一切正常,應(yīng)用程序應(yīng)如下所示:
創(chuàng)建一個(gè)與Blockchain RESTful API連接的函數(shù)。使用以下代碼創(chuàng)建src / Connection.js:
function search(query, cb) {
return new Promise( (resolve,reject) =》 {
return fetch(`api/${query}`, {
accept: “application/json”
})
.then(parseJSON)
.then(data =》 resolve(data));
})
}
function create(type, data){
return new Promise((resolve, reject) =》 {
return fetch(`api/${type}`, {
headers: {
‘Accept’: ‘a(chǎn)pplication/json’,
‘Content-Type’: ‘a(chǎn)pplication/json’
},
method: ‘post’,
body: JSON.stringify(data)
})
.then(parseJSON)
.then(() =》 resolve())
})
}
function parseJSON(response) {
return response.json();
}
const Connection = { search, create };
export default Connection;
在components文件夾中創(chuàng)建一個(gè)類(lèi)組件Homepage.js. 這將顯示主頁(yè)上的所有組件:
import React, { Component } from ‘react’
class Homepage extends Component {
render() {
return (
《div》
《/div》);
}
}
//PropTypes
Homepage.propTypes = {
}
export default Homepage
要導(dǎo)入用戶資產(chǎn)并在主頁(yè)上顯示它們,需要另一個(gè)類(lèi)組件。創(chuàng)建一個(gè)類(lèi)組件usersassets.js并包含以下代碼:
import React, { Component } from ‘react’
import PropTypes from ‘prop-types’;
import UserAssetsItems from ‘。/UserAssetsItems’
class UserAssets extends Component {
render() {
return (
《div》
{this.props.assets.map((asset) =》 (
《UserAssetsItems key={asset.id} asset={asset}/》
))}
《/div》
)}
}
//PropTypes
UserAssets.propTypes = {
assets: PropTypes.array.isRequired
}
export default UserAssets
這將需要以props數(shù)組的形式傳遞資產(chǎn)。要顯示資源,請(qǐng)使用map循環(huán)遍歷數(shù)組,并將項(xiàng)目傳遞給名為UserAssetsItems.js的類(lèi)組件。
創(chuàng)建單獨(dú)處理資產(chǎn)的類(lèi)組件UserAssetsItems.js。這只是創(chuàng)建一張具有資產(chǎn)類(lèi)型和價(jià)值的卡片。請(qǐng)注意,我已經(jīng)在這里完成了內(nèi)聯(lián)樣式,但如果您更喜歡使用CSS,則可以使用CSS執(zhí)行此操作。
import React, { Component } from ‘react’
import PropTypes from ‘prop-types’;
class UserAssetsItems extends Component {
render() {
let assetStyle = {
card: {
display: ‘inline-block’,
background: ‘#333’,
width: ‘350px’,
height: ‘160px’,
textAlign: ‘left’,
padding: ‘20px’,
margin: ‘20px’,
border: ‘5px solid #333’,
color: ‘white’
}
}
return (
《div style = { assetStyle.card }》
《p》Description: {this.props.asset.assetType}《/p》
《p》 Value: {this.props.asset.value}《/p》
《/div》
)
}
}
//PropTypes
UserAssetsItems.propTypes = {
asset: PropTypes.object.isRequired
}
export default UserAssetsItems
通過(guò)在文件頂部添加以下行,將userassetsitems導(dǎo)入到userassets
import UserAssetsItems from ‘。/UserAssetsItems’
將UserAssets導(dǎo)入主頁(yè)并更新主頁(yè)代碼,如下所示。這只是顯示用戶資產(chǎn)并為其設(shè)置樣式。現(xiàn)在主頁(yè)還要求將資產(chǎn)數(shù)組作為prop傳遞,以便將其傳遞給UserAssets.js
import React, { Component } from ‘react’
import UserAssets from ‘。/UserAssets’
import PropTypes from ‘prop-types’;
class Homepage extends Component {
render() {
let style = {
UserAssetsStyle: {
position: ‘relative’,
top: ‘10px’,
width: ‘58%’,
borderRight: ‘1px solid black’,
}
}
return (
《div》
《div style = { style.UserAssetsStyle }》
《UserAssets assets = { this.props.assets } /》
《/div》
《/div》);
}
}
//PropTypes
Homepage.propTypes = {
assets: PropTypes.array.isRequired
}
export default Homepage
回到app.js中,添加一個(gè)狀態(tài),以便包括用戶的名稱和一個(gè)空的資產(chǎn)數(shù)組,如下所示:
state = {
name: “joe”,
assets: []
}
該名稱將用作硬編碼值,因?yàn)樵摼W(wǎng)站尚未登錄。
通過(guò)在文件頂部添加以下行,將connection.js導(dǎo)入app.js。
import Connection from ‘。/Connection’
為了能夠獲取用戶資產(chǎn),需要在執(zhí)行此操作的區(qū)塊鏈網(wǎng)絡(luò)中創(chuàng)建查詢。因此,在文件夾risk-analysis-tutorial中,將以下行添加到將返回用戶資產(chǎn)的queries.qry:
query selectAssetByPolicyholder {
description: “Select an asset based on the owner”
statement:
SELECT org.acme.riskanalysis.PrivateAsset
WHERE (policyholder == _$policyholder)
}
現(xiàn)在將package.json更新到版本4并重新部署您的網(wǎng)絡(luò):
composer archive create --sourceType dir --sourceName 。 -a risk-analysis-tutorial@0.0.4.bna
composer network install --card PeerAdmin@hlfv1 --archiveFile risk-analysis-tutorial@0.0.4.bna
composer network upgrade -c PeerAdmin@hlfv1 -n risk-analysis-tutorial -V 0.0.4
運(yùn)行composer rest服務(wù)器
composer-rest-server -c admin@risk-analysis-tutorial -n never -u true -w true
向App.js添加一個(gè)函數(shù)以從區(qū)塊鏈網(wǎng)絡(luò)中檢索用戶資產(chǎn),如下所示:
getAssets = () =》 {
// Search for the users assets
Connection.search(‘queries/selectAssetByPolicyholder?policyholder=resource%3Aorg.acme.riskanalysis.Policyholder%23’ + this.state.name)
.then(data =》 {
//store the assets in the assets array
this.setState({
assets: data
})
// Retrieve the user object from the state
let user = this.state.user
// Add the number of assets to the object
user.numAssets = this.state.assets.length
// Update the state
this.setState({
user
})
let assets = this.state.assets
for (let i = 0; i 《 assets.length; i++) {
// Set insurance status
if (assets[i].insuranceCompany == null) {
assets[i].insured = false
}
else {
assets[i].insured = true
}
}
// Update the state
this.setState({
assets: assets
})
})
}
通過(guò)將以下行添加到文件頂部,將主頁(yè)導(dǎo)入App.js
import Homepage from ‘。/components/Homepage’
既然我們有了這些資產(chǎn),就可以將它們傳遞到我們的主頁(yè),所以在app.js中的路由器中添加以下行,將這些資產(chǎn)作為props傳遞。
《Route exact path={“/”} render={props =》 (
《React.Fragment》
《h1》My Assets《/h1》
《Homepage assets={this.state.assets} /》
《/React.Fragment》
)}
/》
您的完整app.js文件現(xiàn)在應(yīng)該如下所示:componentwillmount():
import React, { Component } from ‘react’;
import { BrowserRouter as Router, Route } from ‘react-router-dom’;
import ‘。/App.css’;
import Header from ‘。/components/Header’
import Connection from ‘。/Connection’
import Homepage from ‘。/components/Homepage’
class App extends Component {
state = {
name: “joe”,
assets: []
}
componentWillMount() {
this.getAssets()
}
getAssets = () =》 {
// Search for the users assets
Connection.search(‘queries/selectAssetByPolicyholder?policyholder=resource%3Aorg.acme.riskanalysis.Policyholder%23’ + this.state.name)
.then(data =》 {
//store the assets in the assets array
this.setState({
assets: data
})
// Retrieve the user object from the state
let user = this.state.user
// Add the number of assets to the object
user.numAssets = this.state.assets.length
// Update the state
this.setState({
user
})
let assets = this.state.assets
for (let i = 0; i 《 assets.length; i++) {
// Set insurance status
if (assets[i].insuranceCompany == null) {
assets[i].insured = false
}
else {
assets[i].insured = true
}
}
// Update the state
this.setState({
assets: assets
})
})
}
render() {
return (
《Router》
《Header /》
《Route exact path={“/”} render={props =》 (
《React.Fragment》
《h1》My Assets《/h1》
《Homepage assets={this.state.assets} /》
《/React.Fragment》
)}
/》
《/Router》
);
}
}
export default App;
如果一切正常,您應(yīng)該在Web應(yīng)用程序中看到以下內(nèi)容。 注意此處顯示的資產(chǎn)是本教程第1部分中創(chuàng)建的資產(chǎn)。
為了可以添加新資產(chǎn),我們需要App.js中的一個(gè)函數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn),所以在App.js中創(chuàng)建AddAsset函數(shù):
addAsset = (assetType, value, durationInMonths) =》 {
// Create the data object
const data = {
“$class”: “org.acme.riskanalysis.CreateNewAsset”,
“policyholder”: “org.acme.riskanalysis.Policyholder#” + this.state.name,
“assetType”: assetType,
“value”: Number(value),
“durationInMonths”: Number(durationInMonths)
}
// Send this data to the Hyperledger Network
Connection.create(‘CreateNewAsset’, data)
.then((err) =》 {
if (err) {
console.log(err)
}
// Get the new asset
this.getAssets()
})
}
評(píng)論