链码开发基础(Node.js)

链码Node.js工程介绍

在Chaincode代码中主要包括package.json、index.js、lib目录以及test目录

链码Node.js工程package.json

  • 1. 主要依赖:fabric-contract-api、fabric-shim
  • 2. 测试主要依赖:mochai、chai、sinon
  • 3. 测试方法:npm run test
  • 4. 运行方法:npm run start

chaincode开发指南

1. 核心功能fabric-contract-api、fabric-shim

2. 代码测试不需要连接区块链 测试过程使用sinon.js模拟

Chaincode对应文件创建

在lib目录创建assetTransfer.js

初始化配置:

定义Contract类

定义AssetTransfer类

使用module.exports将AssetTransfer设置成对外访问模块

定义InitLedger功能

功能:初始化链码中数据,使用async将方法定义为异步执行。首先定义assets变量,再通过for循环加 载至区块链中

1.定义assets变量在其中加入模拟资产数据

2.使用for循环加载进区块链

  • (1)使用ctx.stub.putState(使用await获取异步执行结果) 添加至区块链,主键为ID
  • (2)加载进区块链时数据需要转化为Buffer类型
  • (3)使用'json-stringify-deterministic' 和'sort-keys
定义CreateAsset功能

功能:创建新数据到区块链,使用async将方法定义为异步执行。首先判断数据ID是否在链中存在,接下 来添加数据,最后通过json返回数据

  • 1. 使用ctx.stub.putState(使用await获取异步执行结果)添加至区块链,主键为ID
  • 2. 加载进区块链时数据需要转化为Buffer类型
  • 3. 使用'json-stringify-deterministic' 和'sort-keys-recursive'两个功能保证数据顺序
定义ReadAsset功能

功能:通过Asset的ID查询资产数据,以JSON格式返回

1. 通过ctx.stub.getState获取数据,查询参数为Asset的ID

2. 数据通过JSON返回

定义AssetExists功能

功能:通过Asset的ID判断资产是否存在

1. 通过ctx.stub.getState获取数据,查询参数为Asset的ID 2. 数据通过JSON返回

定义DeleteAsset功能

功能:通过Asset的ID删除数据。删除前需要判断资产是否存在

1. 通过ctx.stub.getState获取数据,查询参数为Asset的ID 2. 数据通过JSON返回

创建index.js并添加代码

/*
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';
const assetTransfer = require('./lib/assetTransfer')

module.exports.AssetTransfer = assetTransfer;
module.exports.contracts = [assetTransfer];

安装fabric依赖

npm设置国内源:npm config set registry https://registry.npmmirror.com

运行以下代码

npm install fabric-contract-api@2.4.2 fabric-shim@2.4.2

验证fabric依赖安装情况

查看package.json,将有如下变化:

安装测试框架依赖

npm install -D eslint mocha sinon chai sinon-chai

添加测试文件assetTransfer.test.js

'use strict';
 
const sinon = require('sinon');
const chai = require('chai');
const sinonChai = require('sinon-chai');
const  expect  = chai.expect;
const { Context } = require('fabric-contract-api');
const { ChaincodeStub } = require('fabric-shim');

const AssetTransfer = require('../lib/assetTransfer.js'); 
let assert = sinon.assert;
chai.use(sinonChai);  

describe('Asset Transfer Basic Tests', () => {
    let transactionContext, chaincodeStub, asset;

    beforeEach(() => {
        transactionContext = new Context();
        chaincodeStub = sinon.createStubInstance(ChaincodeStub);
        transactionContext.setChaincodeStub(chaincodeStub);

        chaincodeStub.putState.callsFake((key, value) => {
            if (!chaincodeStub.states) {
                chaincodeStub.states = {};
            }
            chaincodeStub.states[key] = value;
        });

        chaincodeStub.getState.callsFake(async (key) => {
            let ret;
            if (chaincodeStub.states) {
                ret = chaincodeStub.states[key];
            }
            return Promise.resolve(ret);
        });

        chaincodeStub.deleteState.callsFake(async (key) => {
            if (chaincodeStub.states) {
                delete chaincodeStub.states[key];
            }
            return Promise.resolve(key);
        });

        chaincodeStub.getStateByRange.callsFake(async () => {
            function* internalGetStateByRange() {
                if (chaincodeStub.states) {
                    const copied = Object.assign({}, chaincodeStub.states);
                    for (let key in copied) {
                        yield { value: copied[key] };
                    }
                }
            }

            return Promise.resolve(internalGetStateByRange());
            });
            asset = {
                ID: "asset1",
                Color: "blue",
                Size: 5,
                Owner: "Tomoko",
                ApprasisedValue: 300, 
        };
    });
    describe('Test InitLedger', () => {
        it('should return success on InitLedger', async () => {
            let assetTransfer = new AssetTransfer();
            await assetTransfer.InitLedger(transactionContext);  

            let ret = JSON.parse((await chaincodeStub.getState('asset1')).toString()); 
            expect(ret).to.eql(Object.assign({ docType: 'asset' }, asset));
        });
    });
});

运行npm命令获取测试结果 

征信积分链码开发(一) (Nodejs版)

背景介绍

在市场行为中存在企业吸引融资,银行贷款等金融行为。政府部门包括法院、税务局、市场监督管 理局等机构为了保证市场良好运行,需要对企业、银行等机构进行监督。故而在可以构建法院、税 务局、市场监督管理局为基础的信用积分规则,用于准确评定企业机构信用情况。为了能够对信用 情况进行标准化,采用积分的形式,对企业的信用进行打分。分数越高表示信用情况越好。反之, 信用分数越低则代表信用越差。他们制定的信用积分规则如下。

构建区块链目标

构建联盟链分别包括法院、税务局、市场监督管理局等机构,通过积分上链形式用于评估对应机构 的信用情况

开发链码征信数据 管理功能

在windows环境中创建credit_chaincode目录,使用VSCode打开credit_chaincode并初始化

npm init -y

准备package.json

添加.eslintrc.js

'use strict';

module.exports = {
    env: {
        node: true,
        mocha: true,
        es6: true
    },
    "extends": "eslint:recommended",
    "overrides": [
        {
            "env": {
                "node": true
            },
            "files": [
                ".eslintrc.{js,cjs}"
            ],
            "parserOptions": {
                "sourceType": "script"
            }
        }
    ],
    "parserOptions": {
        "ecmaVersion": "latest"
    },
    "rules": {
    }
}

编写项目入口index.js

'use strict';
const creditContract = require('./lib/creditChaincode');

module.exports.CreditContract = creditContract;
module.exports.contracts = [creditContract];

征信数据上链和查询功能

在VSCode对应项目中创建lib目录,并在其中加入creditChaincode.js文件,在文件中加入以下代码用于 实现数据的上传与查询

'use strict';
const { Contract } = require('fabric-contract-api');
class CreditContract extends Contract {
    //新建征信主体
    async createCreditSubject(ctx, key, name, type) {
        console.info('=== START : 创建征信主体 ===');
        const subject = {
            key: key, name: name,
            type: type, score: 0
        };
        await ctx.stub.putState(key, Buffer.from(JSON.stringify(subject)));
        console.info('=== END : 创建征信主体 ===');
        return subject;
    }
    // 查询征信主体
    async queryCreditSubject(ctx, subjectKey) {
        console.info('=== START : 查询征信主体 ===');
        const bytes = await ctx.stub.getState(subjectKey);
        if (!bytes || bytes.length === 0) {
            const msg = `${subjectKey} 征信主体不存在`;
            console.warn(msg);
            throw new Error(msg);
        }
        const subject = JSON.parse(bytes.toString());
        console.info('=== END : 查询征信主体 ===');
        return subject;
    }
    // 创建组合键
    async _createCompositeKey(ctx, indexName, key) {
        if (!key || key === "") {
            throw new Error(`Key 不能为空`);
        }
        if (indexName === "") {
            return key;
        }
        return ctx.stub.createCompositeKey(indexName, [key]);
    }
    // 创建征信主体
    async createCreditSubjectEx(ctx, key, name, type) {
        console.info('============= START : 创建征信主体=========== ');
        const subject = {
            key: key,
            name: name,
            type: type,
            score: 0
        };
        let indexName = 'name~type';
        let compositeKey = this._createCompositeKey(ctx, indexName, [name, type]);
        await ctx.stub.putState(compositeKey, Buffer.from(JSON.stringify(subject)));
        console.info('============= END : 创建征信主体=========== ');
        return subject;
    }
    // 按照name+type查询征信主体
    async queryCreditByNameType(ctx, name, type) {
        console.info('============= START : 查询征信主体===========');
        const CompositeKey = this._createCompositeKey(ctx, 'name~type', [
            name,
            type,
        ]);
        const bytes = await ctx.stub.getState(CompositeKey);
        if (!bytes || bytes.length === 0) {
            const msg = `${name} ${type} 征信主体不存在`;
            console.warn(msg);
            throw new Error(msg);
        }
        const subject = JSON.parse(bytes.toString());
        console.info('============= END : 查询征信主体===========');
        return subject;
    }
    //将状态的iterator转换成JSON
    async _Iterator2Json(iterator) {
        let allResults = [];
        let res = await iterator.next();
        while (!res.done) {
            if (res.value && res.value.value.toString()) {
                let jsonRes = {};
                console.log(res.value.value.toString('utf8'));
                jsonRes.Key = res.value.key;
                try {
                    jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
                } catch (err) {
                    console.log(err);
                    jsonRes.Record = res.value.value.toString('utf8');
                }
                allResults.push(jsonRes);
            }
            res = await iterator.next();
        }
        iterator.close();
        return allResults;
    }
    // 查询征信主体
    async queryCreditByRange(ctx, startKey, endKey) {
        let resultsIterator = await ctx.stub.getStateByRange(startKey, endKey);
        let results = await this._Iterator2Json(resultsIterator, false);
        return JSON.stringify(results);
    }
}
module.exports = CreditContract;

安装单元测试包

使用如下具体命令安装:

npm install -D eslint mocha sinon chai sinon-chai

安装fabric依赖的npm包

使用如下具体命令安装:

npm install fabric-contract-api@2.4.2 fabric-shim@2.4.2

编写测试用例

'use strict';
const sinon = require('sinon');
const chai = require('chai');
const sinonChai = require('sinon-chai');
const expect = chai.expect;
chai.use(sinonChai);
let assert = sinon.assert;
const { Context } = require('fabric-contract-api');
const { ChaincodeStub, ClientIdentity } = require('fabric-shim');
const CreditContract = require('../lib/creditChaincode.js');
describe('Credit Chaincode Test', () => {
    let stub, ctx, ClientId;

    beforeEach(() => {
        ctx = new Context();
        stub = sinon.createStubInstance(ChaincodeStub);
        stub.getMspID.returns('Org1');
        ctx.setChaincodeStub(stub);

        ClientId = sinon.createStubInstance(ClientIdentity);

        stub.putState.callsFake((key, value) => {
            if (!stub.states) {
                stub.states = {};
            }
            stub.states[key] = value;
        });
        stub.getState.callsFake(async (key) => {
            let ret;
            if (stub.states) {
                ret = stub.states[key];
            }
            return Promise.resolve(ret);
        });
        stub.deleteState.callsFake(async (key) => {
            if (stub.states) {
                delete stub.states[key];
            }
        });
    });
    describe('Test CreditSubject function', () => {
        it('should return success on createCreditSubject', async () => {
            let creditContract = new CreditContract();
            let creditSubject = await creditContract.createCreditSubject(ctx, "A001", "My Company", "Company");
            let scroe = creditSubject.score;
            expect(scroe).to.equals(0);
        });
        it('should return success on queryCreditSubject', async () => {
            let creditContract = new CreditContract();
            await creditContract.createCreditSubject(ctx, "A001", "My Company", "Company");
            let creditSubject = await creditContract.queryCreditSubject(ctx, "A001");
            let name = creditSubject.name;
            expect(name).to.equals("My Company");
        });
        it('should return success on createCreditSubjectEx', async () => {
            let creditContract = new CreditContract();
            let creditSubject = await creditContract.createCreditSubjectEx(ctx, "A001", "My Company", "Company");
            let scroe = creditSubject.score;
            expect(scroe).to.equals(0);
        });
        it('should return success on queryCreditByNameType', async () => {
            let creditContract = new CreditContract();
            await creditContract.createCreditSubjectEx(ctx, "A001", "My Company", "Company");
            let creditSubject = await creditContract.queryCreditByNameType(ctx, "My Company", "Company");
            let name = creditSubject.name;
            expect(name).to.equals("My Company");
        })
    });
})

执行测试

执行以下命令,进行测试:

npm run test

部署管理征信链码

链码操作准备

拷贝credit_chaincode到chaincode目录下,前提需要把项目中的配置文件删掉

打包链码

启动容器

docker-compose -f fabric-compose.yaml start

 查看

 进入上级test目录运行以下命令打包:

export FABRIC_CFG_PATH=${PWD}/config

peer lifecycle chaincode package ./chaincode/credit_chaincode.tar.gz --path ./chaincode/credit_chaincode --lang node --label credit_chaincode_1.1

检查打包结果

安装链码

运行以下进入fabric-cli容器:

docker exec -it fabric-cli bash

1. 在org1中安装 运行以下链码安装:

. scripts/set-env.sh 1 0 7051
peer lifecycle chaincode install chaincode/credit_chaincode.tar.gz

2. 在org2中安装 运行以下链码安装:

. scripts/set-env.sh 2 0 9051
peer lifecycle chaincode install chaincode/credit_chaincode.tar.gz

3. 查看安装情况

peer lifecycle chaincode queryinstalled

批准链码

org1批准链码

1. 设置链码环境变量(ID为上面安装的链码)

export CC_PACKAGE_ID=credit_chaincode_1.1:2c3741f2faf6862eecd3f3c0f7296bbba1d93cf4302cca64e79a7689fba47a23

 2. 设置Org1环境变量

. scripts/set-env.sh 1 0 7051

3.批准链码

peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com --channelID $CHANNEL_NAME --name credit_chaincode --version 1.1 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

org2批准链码

1. 设置Org2环境变量
 

. scripts/set-env.sh 2 0 9051

2.批准链码

peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com --channelID $CHANNEL_NAME --name credit_chaincode --version 1.1 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

检查提交准备

peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name credit_chaincode --version 1.1 --sequence 1 --tls --cafile $ORDERER_CA --output json

提交链码

提交链码是特殊交易,需要背书节点背书,因此需要指定2个背书节点。具体操作如下:

peer lifecycle chaincode commit -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com --channelID $CHANNEL_NAME --name credit_chaincode --version 1.1 --sequence 1 --tls --cafile $ORDERER_CA --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA

查询提交的链码

peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name credit_chaincode --tls --cafile $ORDERER_CA

使用docker查看链码安装情况

docker ps

查看运行镜像形成容器情况

docker logs -f b1ddd21303a5

测试验证

调用createCreditSubject功能

peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name credit_chaincode --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"function":"createCreditSubject", "Args":["A001","My Company","Company"]}'

 调用queryCreditSubject功能

peer chaincode query -C $CHANNEL_NAME --name credit_chaincode -c '{"function":"queryCreditSubject","Args":["A001"]}'

观察正在运行的链码容器运行情况

区块链征信后端开发链码调用

项目架构

项目配置

使用vscode打开项目

编写后端代码

启动go-gateway项目

通过以下方式持久化运行

 nohup bee run &

通过tail命令可以查看nohup.out对应日志

tail -f nohup.out

在项目中添加/createCreditSubject接口

修改具体配置路径,改成虚拟机的IP地址

重启后端项目

使用postman验证/createCreditSubject接口

在项目中添加/queryCreditSubject接口

使用postman验证/queryCreditSubject接口

区块链征信后端开发---用户管理功能开发

架构设计

  • 1. 服务端使用MySQL以及Redis实现用户注册与登录功能
  • 2. Mysql用户数据保存
  • 3. Redis在用户持久化登录使用

登录流程示例

使用容器启动mysql(对外挂载3307端口)

docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3306 -d mysql:5.7

Mysql配置

创建credit数据库并创建user表

user表结构如下,其中id设为主键并自增

Redis安装

以容器方式运行,对外映射6379端口

docker run -itd -p 6379:6379 redis

使用requirements.txt安装依赖

在项目添加config.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cors import *
import redis
from urllib.parse import quote_plus as urlquote

app=Flask(__name__)
userName = 'root'
password = '123456'
dbHost = '192.168.200.112'
dbPort = 3307
dbName="credit"
app.config['SQLALCHEMY_DATABASE_URI'] =f'mysql://{userName}:{urlquote(password)}@{dbHost}:{dbPort}/{dbName}?charset=utf8'
db=SQLAlchemy(app)
CORS(app,resources=r'/*')

redis_service=redis.StrictRedis(host="192.168.200.112",port=6379,db=0)

添加user.py

使用user.py配置user表连接,具体代码如下:

from config import db
class User (db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String)
    password = db.Column(db.String)

    def __init__(self,username,password):
        self.username=username
        self.password=password

修改app.py

修改文件中加载app模块的方式,改为从config加载 添加其他依赖加载

添加token生成方式

• 在app.py中添加,具体代码如下

添加注册业务

• 在app.py中添加/register路由,具体代码如下:

添加登录业务

在app.py中添加/login路由,具体代码如下:

添加过滤器@app.before_request

在app.py中添加如下代码:

app.py

from flask import Flask, request, jsonify
import requests
import json
import hashlib
import random
from config import app, db, redis_service
from user import User

invokeURL = "http://192.168.200.112:8080/invoke"
evaluateURL = "http://192.168.200.112:8080/evaluate"

def get_token():
    """
    随机生成token
    """
    src = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz!@#$%^&*()',20))
    m2 = hashlib.md5()
    m2.update(src.encode("utf8"))
    return m2.hexdigest()

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.before_request
def before():
    url = request.path
    if url == '/login' or url == '/register':
        pass
    else:
        token = request.headers.get('token')
        if token is None:
            return jsonify({'code':500,'data':'用户未登录'})
        username = redis_service.get(token)
        if username:
            pass
        else:
            return jsonify({'code':500,'data':'用户未登录'})

@app.route('/register',methods=['POST'])
def register():
    get_json = request.json
    username = get_json['username']
    password = get_json['password']
    get_user = User.query.filter_by(username=username).first()
    if get_user is not None:
        return jsonify({'code':500, 'msg':'User exists!'})
    save_user = User(username, password)
    db.session.add(save_user)
    db.session.commit()
    return jsonify({'code': 200, 'msg': "Register Success!"})

@app.route('/login',methods=['POST'])
def login():
    get_json = request.json
    username = get_json['username']
    password = get_json['password']
    get_user = User.query.filter_by(username=username).first()
    if get_user is None:
        return jsonify({'code': 404, 'msg': "User not exist"})
    if get_user.password == password:
        token = get_token()
        redis_service.set(token, username)
        data = {'token': token, 'username': username}
        return jsonify({'code': 200, 'msg': data})
    else:
        return jsonify({'code': 500, 'msg': 'Password error!'})

@app.route('/createCreditSubject', methods=['POST'])
def create_credit():
    json_data = request.json
    payload = json.dumps({
        "channelName": "applicationchannel",
        "chaincodeName": "credit_chaincode",
        "funcName": "createCreditSubject",
        "paramArray": json_data.get("paramArray")
    })
    headers = {'Content-Type': 'application/json'}
    response = requests.request("POST", invokeURL, headers=headers, data=payload)

    print(response.text)
    return jsonify({'code': 200, "msg": "create success"})

@app.route('/queryCreditSubject', methods=['POST'])
def credit_query():
    json_data = request.json
    payload = json.dumps({
        "channelName": "applicationchannel",
        "chaincodeName": "credit_chaincode",
        "funcName": "queryCreditSubject",
        "paramArray": json_data.get("paramArray")
    })
    headers = {'Content-Type': 'application/json'}
    response = requests.request("POST", evaluateURL, headers=headers, data=payload)

    print(response.text)
    return jsonify({'code': 200, "msg": "query success", "data": response.text})

if __name__ == '__main__':
    app.run()

使用postman验证注册

在验证实现过滤器功能,当请求路由为/login或者/register可以正常访问接口,当接口为其他接口需要再headers中加入token时,需要启动虚拟机

前端项目架构

使用VSCode打开项目

安装依赖

运行以下命令:

npm cache clean --force 
npm install

启动项目

运行以下命令: 

npm run serve

运行成功将有如下显示:

开发用户注册与 登录功能 

开发注册功能

在views目录添加Register.vue,添加<template>标签对应内容

<template>
    <div class="index_background">
        <el-row style="height: 100%;">
            <el-col :span="8" :offset="8" style="border-style: solid;border-color: #e6e6e6;margin-top: 5%;">
            <el-row>
                <el-col :span="16" :offset="4">
                <el-form label-width="80px">
                    <h3>登录界面</h3>
                    <el-form-item label="用户名">
                        <el-input type="primary" v-model="username"></el-input>
                    </el-form-item>
                    <el-form-item label="密码">
                        <el-input type="primary" v-model="password" show-password></el-input>
                    </el-form-item>
                    <el-form-item label="确认密码">
                        <el-input type="primary" v-model="validPassword" show-password></el-input>
                    </el-form-item>
                </el-form>
                </el-col>
            </el-row>
            <el-row style="margin-bottom: 20px;">
                <el-button type="primary" @click="register">注册</el-button>
                <el-button type="primary" @click="goback">返回</el-button>
            </el-row>
            </el-col>
        </el-row>
    </div>
</template>

开发注册功能

在Register.vue,添加<script>标签对应内容

<script>
    export default {
        name:"Register",
        data(){
            return {
              username:'',
              password:'',
              validPassword:'',  
            }
        },
        methods: {
            register(){
                if(this.password != this.validPassword){
                    alert("密码输入不匹配!")
                }else{
                    let postData = {
                        username:this.username,
                        password:this.password,
                    }
                    this.axios.post('register',postData).then((response) => {
                        if(response.data.code==200){
                            alert('注册成功')
                            this.$router.push('/login')
                        }else{
                            alert(`注册失败,${response.data.data}`)
                        }
                    }).catch(error => {
                        console.error(error);
                        alert('网络错误,请稍后再试')
                    })
                }
            },
            goback:function(){
                this.username=''
                this.password=''
                this.$router.push('/index')
            }
        }
    }
</script>

开发注册功能

在Register.vue,添加<style>标签对应内容

<style>
.index_background{
    background: url('../assets/images/bg.jpg');
    width: 100%;
    height: 100%;
}
</style>

开发登录功能

在views目录添加Login.vue,添加标签对应内容

<template>
    <div class="index_background">
        <el-row style="height: 100%;">
            <el-col :span="8" :offset="8" style="border-style: solid;border-color: #e6e6e6;margin-top: 5%;">
                <el-row>
                    <el-col :span="16" :offset="4">
                        <el-form label-width="80px">
                            <h3>登录界面</h3>
                            <el-form-item label="用户名">
                                <el-input type="primary" v-model="username"></el-input>
                            </el-form-item>
                            <el-form-item label="密码">
                                <el-input type="primary" v-model="password" show-password></el-input>
                            </el-form-item>
                        </el-form>
                    </el-col>
                </el-row>
                <el-row style="margin-bottom: 20px;">
                    <el-button type="primary" @click="login">登录</el-button>
                    <el-button type="primary" @click="register">注册</el-button>
                </el-row>
            </el-col>
        </el-row>
    </div>
</template>

开发登录功能

在Login.vue,添加<script>标签对应内容

<script>
export default {
    name: "Login",
    data() {
        return {
            username: '',
            password: ''
        }
    },
    methods: {
        login() {
            let postData = {
                username: this.username,
                password: this.password,
            }
            this.axios.post('login', postData).then((response) => {
                if (response.data.code == 200) {
                    let respData = response.data.msg
                    this.$cookies.set('token',respData.token)
                    this.$cookies.set('username',respData.username)
                    alert('登录成功')
                    this.$router.push('/home')
                } else {
                    alert(`登录失败,${response.data.msg}`)
                }
            })
            
        },
        register: function () {
            this.$router.push('/register')
        }
    }
}
</script>

开发登录功能

在Login.vue,添加<style>标签对应内容

<style>
.index_background {
    background: url('../assets/images/bg.jpg');
    width: 100%;
    height: 100%;
}
</style>

 

修改router.js添加登录与注册路由

import Home from '@/views/Home';
import Register from './views/Register.vue';
import Login from './views/Login.vue';


export default [
    {
        path: '/',
        redirect: '/home'
    },
    {
        path:'/home',
        component: Home
    },
    {
        path:'/login',
        component:Login
    },
    {
        path:'/register',
        component:Register
    }
]

验证注册页面

访问注册页面有如下显示说明注册成功:

验证登录页面

访问登录页面有如下显示说明登录成功:

开发征信主体管理功能

发征信主体功能

在views目录添加Credit.vue,添加标签对应内容

<template>
    <el-row style="height: 100%;">
        <el-row style="height: 10%; border-bottom-style: solid;border-bottom-color: #e6e6e6;">
            <el-col :span="4" style="height: 100%;">
                <h2>示例应用程序</h2>
            </el-col>
            <el-col :span="4" style="position: absolute; right: 10%; bottom: 0px;">
                你好!{{ $cookies.get("username") }}
                <el-button type="text" size="medium" style="font-size: 20px" @click="logout">登出</el-button>
            </el-col>
        </el-row>
        <el-row style="height: 90%;">
            <el-col :span="4" style="height: 100%;">
                <navigator></navigator>
            </el-col>
            <el-col :span="20" style="height: 100%;">
                <h1>征信主体操作页面</h1>
                <el-divider></el-divider>
                <el-row>
                    <el-col :span="8" :offset="0">
                        <el-button type="primary" @click="Visible">创建征信主体</el-button>
                    </el-col>
                </el-row>
                <el-row>
                    <el-form>
                        <el-row>
                            <el-col :span="16">
                                <el-form-item label="Key:" label-width="120px">
                                    <el-input type="primary" placeholder="请输入查询ID" v-model="Keyid"></el-input>
                                </el-form-item>
                            </el-col>
                            <el-col :span="4">
                                <el-button type="primary" @click="queryCreditSubject">查询</el-button>
                            </el-col>
                        </el-row>
                    </el-form>
                </el-row>
                <el-divider></el-divider>
                <el-row v-if="dataVisible">
                    <el-col :span="22" :offset="1">
                        <el-row>
                            <el-col :span="4">
                                <h1>查询结果</h1>
                            </el-col>
                        </el-row>
                        <el-row>
                            <el-form label-width="100px">
                                <el-form-item label="查询结果:">
                                    {{ result }}
                                </el-form-item>
                            </el-form>
                        </el-row>
                    </el-col>
                </el-row>
                <el-dialog :visible.sync="addVisible" title="征信主体">
                    <el-form :model="form" status-icon ref="form" label-width="100px">
                        <el-form-item label="key" prop="description">
                            <el-input type="primary" v-model="form.key"></el-input>
                        </el-form-item>
                        <el-form-item label="name" prop="description">
                            <el-input type="primary" v-model="form.name"></el-input>
                        </el-form-item>
                        <el-form-item label="type" prop="description">
                            <el-input type="primary" v-model="form.type"></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-button type="primary" @click="createCreditSubject">修改</el-button>
                        </el-form-item>
                    </el-form>
                </el-dialog>
            </el-col>
        </el-row>
    </el-row>
</template>

开发征信主体功能

在views目录添加Credit.vue,添加<script>对应的标签

<script>
import Navigator from "@/components/Navigator";

export default {
    name: "Home",
    components: {
        Navigator
    },
    data() {
        return {
            addVisible: false,
            dataVisible: false,
            result: [],
            Keyid: "",
            form: {
                key: "",
                name: "",
                type: ""
            }
        };
    },
    methods: {
        validLogin() {
            if (this.$cookies.get("username") === undefined) {
                this.$router.push('/login');
            }
        },
        logout() {
            this.$cookies.remove('token');
            this.$cookies.remove('username');
            this.$router.push('/login');
        },
        Visible() {
            this.addVisible = true;
        },
        createCreditSubject() {
            let postData = {
                paramArray: [this.form.key, this.form.name, this.form.type]
            };
            this.axios.post('/createCreditSubject', postData, {
                headers: {
                    'token': this.$cookies.get("token")
                }
            }).then((response) => {
                if (response.data.code === 200) {
                    alert('新增成功');
                    setTimeout(() => {
                        this.addVisible = false;
                    }, 1000);
                } else {
                    alert(`新增失败,${response.data.data}`);
                }
            }).catch(error => {
                console.error(error);
                alert("网络错误,请稍后再试");
            });
        },
        queryCreditSubject() {
            let postData = {
                paramArray: [this.Keyid]
            };
            this.axios.post('/queryCreditSubject', postData, {
                headers: {
                    'token': this.$cookies.get("token")
                }
            }).then((response) => {
                if (response.data.code === 200) {
                    this.result = response.data.data;
                    console.log(this.result);
                    this.dataVisible = true;
                }
            })
        },
    },
    created() {
        this.validLogin();
    }
};
</script>

开发登录功能

在Credit.vue,添加<style>标签对应的内容

<style scoped></style>

修改router.js

添加/credit路由配置

import Home from '@/views/Home';
import Register from './views/Register.vue';
import Login from './views/Login.vue';
import Credit from './views/Credit.vue'


export default [
    {
        path: '/',
        redirect: '/home'
    },
    {
        path:'/home',
        component: Home
    },
    {
        path: '/credit',
        component: Credit
    },
    {
        path:'/login',
        component:Login
    },
    {
        path:'/register',
        component:Register
    }
]

修改Navigator.vue

添加credit选项

<template>
  <el-row class="tac" style="height: 100%;">
    <el-menu class="el-menu-vertical-demo" style="height: 100%" @select="handleSelect">
      <el-menu-item index="1">主页</el-menu-item>
      <el-menu-item index="2">征信主体</el-menu-item>
    </el-menu>
  </el-row>
</template>

<script>
export default {
  name: "Navigator",
  methods: {
    handleSelect(key, keyPath) {
      console.log(key, keyPath)
      if (key === '1') {
        this.$router.push('/home');
      }
      if (key === '2') {
        this.$router.push('/credit');
      }
    },
    logout() {
      this.$cookies.remove('token');
      this.$router.push('/login');
    }
  }
}
</script>

<style scoped>

</style>

验证创建征信主体

启动项目,在导航内,点击“征信主体”,点击“创建征信主体”,输入指定内容,有如下显示说明创建成功:

验证查询征信主体

点击“征信主体”,在中key输入对应内容,点击查询,有如下显示说明创建成功:

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Hyperledger Fabric中,部署链码需要以下步骤: 1. 编写链码并打包成tar.gz格式的文件。 2. 将tar.gz文件安装到peer节点上。 3. 实例化链码并指定其初始参数。 具体步骤如下: 1. 编写链码并打包成tar.gz格式的文件。 在编写链码时,需要遵循Fabric提供的链码规范。链码可以使用Go、Java、Node.js等语言编写。编写完成后,需要将链码打包成tar.gz格式的文件。 2. 将tar.gz文件安装到peer节点上。 使用peer节点上的命令行工具(peer cli)将链码安装到peer节点上。安装命令如下: ``` peer chaincode install -n <chaincode_name> -v <chaincode_version> -p <chaincode_path> ``` 其中,`<chaincode_name>`为链码名称,`<chaincode_version>`为链码版本号,`<chaincode_path>`为链码所在路径。 3. 实例化链码并指定其初始参数。 使用peer节点上的命令行工具(peer cli)实例化链码并指定其初始参数。实例化命令如下: ``` peer chaincode instantiate -o <orderer_address> -C <channel_name> -n <chaincode_name> -v <chaincode_version> -c '{"Args":["init","arg1","arg2","arg3"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')" ``` 其中,`<orderer_address>`为orderer节点的地址,`<channel_name>`为通道名称,`<chaincode_name>`为链码名称,`<chaincode_version>`为链码版本号,`'{"Args":["init","arg1","arg2","arg3"]}'`为链码的初始参数,`-P "OR ('Org1MSP.peer','Org2MSP.peer')"`为链码的背书策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值