当前位置:   article > 正文

基于Hyperledger Fabric开发一个食品溯源项目(一)_hyperledger fabric 项目代码

hyperledger fabric 项目代码

最近接触了Hyperledger Fabric,官网给的app并没有界面,不过有一个单页版的项目,在此基础上做出了一个简易的食品溯源项目
github项目地址
功能:

  1. 发布食品
  2. 添加配料信息
  3. 中转食品
  4. 查询食品信息
  5. 查询配料信息
  6. 查询中转信息(只可以溯源整个食品信息,不能溯源配料信息)
前言
本篇文章只会对我认为比较重要地部分进行大致地讲解,不会讲解细节,如果有什么疑惑的地方请在评论区进行评论,会根据评论情况进行下一篇文章的编写

项目架构

前端使用AngularJs来进行页面渲染,后台使用Node.js返回Json数据,数据存储在Hyperledger Fabric提供的数据库

启动脚本详解

source-app/server.js
const middlewares = [
  express.static(path.join(__dirname, 'public')),//静态文件
  bodyParser.urlencoded({ extended: true }),//解析POST所传参数
  cookieParser(),//使用Cookie来进行Flash文字演示
  session({
    secret: 'super-secret-key',
    key: 'super-secret-cookie',
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 60000}
  }),
  flash()
]
app.use(middlewares)//激活中间件
app.use(express.static(path.join(__dirname, 'views')));//使用模板
app.set('view engine', 'ejs');//配置模板引擎
require('./routes.js')(app);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

URL分为三个部分

Part 1
获取HTML source-app/routes.js
app.get('/', function(req, res) {
		tuna.index(req, res);
});
...
  • 1
  • 2
  • 3
  • 4
Part 2
表单

表单提交流程

填写表单->POST到特定的URL->处理表单信息->重定向到首页

表单的HTML代码编写
source-app/views/form.ejs

<form method="post" action="/re_form" novalidate>
    <div class="section">食品信息</div>
    <div class="inner-wrap">
		<label>食品编号 <input type="text" name="field1" /></label>
        <label>食品名称 <input type="text" name="field1" /></label>
        <label>食品规格 <input type="text" name="field1" /></label>
		<label>食品生产日期 <input type="text" name="field1" /></label>
		<label>食品保质期 <input type="text" name="field1" /></label>
		<label>食品批次号 <input type="text" name="field1" /></label>
		<label>食品生产许可证编号<input type="text" name="field1" /></label>
		<label>食品生产商名称 <input type="text" name="field1" /></label>
		<label>食品生产价格<input type="text" name="field1" /></label>
		<label>食品生产所在地<input type="text" name="field1" /></label>
    </div>
    <div class="button-section">
     <input type="submit" name="提交" />
    </div>
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

POST到特定的URL
source-app/routes.js

app.post('/re_form', function(req, res) {
		var function_name = 'addProInfo'//调用chaincode中的函数
		tuna.re_form(req, res, function_name);
});
  • 1
  • 2
  • 3
  • 4

表单处理
source-app/controller.js

const request = {
    chaincodeId: 'source-app',
    fcn: function_name,//调用chaincode中的函数
    args: req.body.field1,//获取表单所填信息(函数所需参数)
    chainId: 'mychannel',
    txId: tx_id
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

调用Chaincode

chaincode/source-app/source-app.go

func (a *FoodChainCode) addProInfo(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    var err error 
    var FoodInfos FoodInfo

    if len(args)!=10{
        return shim.Error("Incorrect number of arguments.")
    }
    FoodInfos.FoodID = args[0]
    if FoodInfos.FoodID == ""{
        return shim.Error("FoodID can not be empty.")
    }
    
    
    FoodInfos.FoodProInfo.FoodName = args[1]
    FoodInfos.FoodProInfo.FoodSpec = args[2]
    FoodInfos.FoodProInfo.FoodMFGDate = args[3]
    FoodInfos.FoodProInfo.FoodEXPDate = args[4]
    FoodInfos.FoodProInfo.FoodLOT = args[5]
    FoodInfos.FoodProInfo.FoodQSID = args[6]
    FoodInfos.FoodProInfo.FoodMFRSName = args[7]
    FoodInfos.FoodProInfo.FoodProPrice = args[8]
    FoodInfos.FoodProInfo.FoodProPlace = args[9]
    ProInfosJSONasBytes,err := json.Marshal(FoodInfos)
    if err != nil{
        return shim.Error(err.Error())
    }

    err = stub.PutState(FoodInfos.FoodID,ProInfosJSONasBytes)
    if err != nil{
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
Part 3

返回Json
source-app/routes.js

app.get('/source/:id', function(req, res) {
    var function_name = 'getProInfo'//调用chaincode函数
    tuna.get_tuna(req, res, function_name);
});
  • 1
  • 2
  • 3
  • 4

source-app/controller.js

const request = {
    chaincodeId: 'source-app',
    txId: tx_id,
    fcn: function_name,//调用chaincode函数
    args: [key]//函数所需参数
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

调用Chaincode
chaincode/source-app/source-app.go

func(a *FoodChainCode) getProInfo (stub shim.ChaincodeStubInterface,args []string) pb.Response{
    
    if len(args) != 1{
        return shim.Error("Incorrect number of arguments.")
    }
    FoodID := args[0]
    resultsIterator,err := stub.GetHistoryForKey(FoodID)
    if err != nil {
        return shim.Error(err.Error())
    }
    defer resultsIterator.Close()
    
    var foodProInfo ProInfo

    for resultsIterator.HasNext(){
        var FoodInfos FoodInfo
        response,err :=resultsIterator.Next()
        if err != nil {
            return shim.Error(err.Error())
        }
        json.Unmarshal(response.Value,&FoodInfos)
        if FoodInfos.FoodProInfo.FoodName != ""{
            foodProInfo = FoodInfos.FoodProInfo
            continue
        }
    }
    jsonsAsBytes,err := json.Marshal(foodProInfo)//转为Json格式
    if err != nil {
        return shim.Error(err.Error())
    }
    return shim.Success(jsonsAsBytes)
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

例子
访问http://120.27.18.178:3389/source/1001,可以得到以下数据

{"FoodName":"苹果","FoodSpec":"123456","FoodMFGDate":"2018-8-27","FoodEXPDate":"一月","FoodLOT":"123","FoodQSID":"456","FoodMFRSName":"啦啦啦","FoodProPrice":"2","FoodProPlace":"郑州"}
  • 1

AngularJs与单页页面

如果我们没有进行查询,我们希望页面呈现为这样 ![这里写图片描述](https://img-blog.csdn.net/201808281721147?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V5ZV93YXRlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 当我们查询之后,我们希望页面呈现为这样 ![这里写图片描述](https://img-blog.csdn.net/20180828172158650?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V5ZV93YXRlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) HTML代码编写

source-app/views/search.ejs

<body ng-app="application" ng-controller="appController">
		<div class="form-wrapper">
			<input type="text" id="search" placeholder="食品编号..." ng-model="query_id" required>
			<input type="submit" value="搜索" id="submit" ng-click="querySource()">
		</div>
		<table cellspacing="0" id="query_source">
			<tr>
				<th>食品名称</th>
				<th>食品规格</th>
				<th>食品生产日期</th>
				<th>食品保质期</th>
				<th>食品批次号</th>
				<th>食品生产许可证编号</th>
				<th>食品生产商名称</th>
				<th>食品生产价格</th>
				<th>食品生产所在地</th>
			</tr>
			<tr>
          			<td>{{query_source.FoodName}}</td>
          			<td>{{query_source.FoodSpec}}</td>
          			<td>{{query_source.FoodMFGDate}}</td>
          			<td>{{query_source.FoodEXPDate}}</td>
		  		<td>{{query_source.FoodLOT}}</td>
		  		<td>{{query_source.FoodQSID}}</td>
		  		<td>{{query_source.FoodMFRSName}}</td>
		  		<td>{{query_source.FoodProPrice}}</td>
		  		<td>{{query_source.FoodProPlace}}</td>
        		</tr>
		</table>
	</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

AngularJs脚本编写

source-app/public/js/app.js

var app = angular.module('application', []);

// Angular Controller
app.controller('appController', function($scope, appFactory){

	$("#success_holder").hide();
	$("#success_create").hide();
	$("#error_holder").hide();
	$("#error_query").hide();
	$scope.querySource = function(){
		var id = $scope.query_id;
		appFactory.querySource(id, function(data){
			$scope.query_source = data;
			if ($scope.query_tuna == "Could not locate tuna"){
				console.log()
				$("#error_query").show();
			} else{
				$("#error_query").hide();
			}
		});
	}
});

app.factory('appFactory', function($http){
	var factory = {};
	factory.querySource = function(id, callback){
    	$http.get('/source/'+id).success(function(output){
			callback(output)
		});
	}
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

可以不用搞懂basic-network文件夹(我自己也不懂,不过并不影响写项目,如果读者懂,欢迎指导)

如果有什么不懂的地方或想搞懂更细节的地方,请在评论区留言

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/646389
推荐阅读
相关标签
  

闽ICP备14008679号