区块链食品溯源项目
创建项目
bee new trace
安装go-sdk
go get github.com/FISCO-BCOS/go-sdk
-
将webase的sdk证书文件复制到自己的项目
-
修改config.toml使sdk是本项目下
修改配置文件app.conf
appname = trace httpport = 8080 runmode = dev autorender = false copyrequestbody = true EnableDocs = true contractAddress=0xc5a3d4384897acb9ce3e9096644c35aa903d1687 distributorAddress=0x1cb30f505b9e338bb48f9cec3ceadd1d2d4da565 distributorPK=5eff4114710e69a7677a39145b71ab4b763c126aa118defd2f0316a604e9495cad29c3854604e3b7721588b4778d047e2deb9911a48ae04125e22fdce8eda292 producerAddress=0x1cb30f505b9e338bb48f9cec3ceadd1d2d4da565 producerPK=e885dc09e398461121608831780410fb2e6c782d2afc95e324057dec60e07f34d8bde9f6cdc63dd79591988165b63b9ebb96e0ddbc823fe80c6570bcee5c97fd retailerAddress=0x746afad125d42011b289ef421e8703e0dd867b60 retailerPK=47f39c99583acea98ab31b5b38f13bd0c05726e9304cf5e803bc4cf82910c1ddb80b7941bb9bad4db450e2d761045161ea67b8cb74a66f738004d5927c3a1f70
地址私钥根据自己的webase修改
新建conf.go获取配置文件信息
package conf import ( "fmt" "github.com/astaxie/beego" ) var ( ContractAddress string DistributorAddress string DistributorPK string ProducerAddress string ProducerPK string RetailerAddress string RetailerPK string ) func init() { err := beego.LoadAppConfig("ini","conf/app.conf") if err != nil{ fmt.Println(err) return } ContractAddress, _ =beego.AppConfig.String("contractAddress") DistributorAddress,_ = beego.AppConfig.String("distributorAddress") DistributorPK,_ = beego.AppConfig.String("distributorPK") ProducerAddress,_ = beego.AppConfig.String("producerAddress") ProducerPK,_ = beego.AppConfig.String("producerPK") RetailerAddress,_ = beego.AppConfig.String("retailerAddress") RetailerPK,_ = beego.AppConfig.String("retailerPK") }
将go-sdk下config.go和config_pem.go复制到项目目录conf目录下
编写Service层
将合约编译成go文件
abigen -abi abi/FoodInfo.abi -bin bin/FoodInfo.bin -pkg main -type FoodInfo -out FoodInfo.go abigen -abi abi/Role.abi -bin bin/Role.bin -pkg main -type Role -out Role.go abigen -abi abi/RoleController.abi -bin bin/RoleController.bin -pkg main -type RoleController -out RoleController.go abigen -abi abi/Trace.abi -bin bin/Trace.bin -pkg main -type Trace -out Trace.go
编写TraceService
与合约进行交互
package service import ( "log" "github.com/FISCO-BCOS/go-sdk/abi/bind" "github.com/FISCO-BCOS/go-sdk/client" conf2 "github.com/FISCO-BCOS/go-sdk/conf" "github.com/ethereum/go-ethereum/common" //"github.com/FISCO-BCOS/go-sdk/client" "trace/conf" ) var Tracecli TraceSession func init() { configs, err := conf.ParseConfigFile("config.toml") if err != nil { log.Fatal(err) } client, err := client.Dial((*conf2.Config)(&configs[0])) if(err != nil) { log.Fatal(err) } address := conf.ContractAddress ContractAddress := common.HexToAddress(address) instance, err := NewTrace(ContractAddress,client) if err != nil{ log.Fatal(err) } Tracecli = TraceSession{Contract: instance, CallOpts: *client.GetCallOpts(),TransactOpts: *client.GetTransactOpts()} } func LoadUser(user string) { fromAddress := "" privateKey := "" switch user { case "producer": fromAddress = conf.ProducerAddress privateKey = conf.ProducerPK case "distributor": fromAddress = conf.DistributorAddress privateKey = conf.DistributorPK case "retailer": fromAddress = conf.RetailerAddress privateKey = conf.RetailerPK default: return } ket,_ := crpto.HexToECDSA(privateKey) auth := bind.NewKeyedTransactor(key) auth.From = common.HexToAddress(fromAddress) files, _ := conf.ParseConfigFile("config.toml") client,_ := client.Dial((*conf2.Config)(&files[0])) instance,_ := TraceSession{Contract: instance,CallOpts: *client.GetCallOpts(), TransactOpts: *auth} }
编写foodInfoService
package service import ( "fmt" "strconv" ) type FoodInfoService struct{} func (fs *FoodInfoService) Trace(traceNumber string) interface{} { trace := get_trace(traceNumber) return trace } func (fs *FoodInfoService) Get_food(traceNumber string) map[string]interface{} { response := make(map[string]interface{}) name, current, quality, _, err := Tracecli.GetTraceinfoByTraceNumber(traceNumber) byTraceNumber, i, i2, _, err := Tracecli.GetTraceDetailByTraceNumber(traceNumber) if err != nil { fmt.Println(err) } response["timestamp"] = byTraceNumber[len(byTraceNumber)-1] response["produce"] = i[0] response["name"] = name response["current"] = current response["address"] = i2[0] response["quality"] = quality return response } func (fs *FoodInfoService) GetFoodList() []int { food, _ := Tracecli.GetAllFood() intSlice := make([]int, len(food)) for i, v := range food { intSlice[i] = int(v.Int64()) } return intSlice } func get_trace(traceNumber string) []interface{} { _, s, _, _, err := Tracecli.GetTraceinfoByTraceNumber(traceNumber) var responses []interface{} byTraceNumber, i, i2, i3, err := Tracecli.GetTraceDetailByTraceNumber(traceNumber) if err != nil { fmt.Println(err) } for index := 0; index < len(byTraceNumber); index++ { if index == 0 { response := make(map[string]interface{}) response["traceNumber"] = traceNumber response["name"] = s response["produce_time"] = byTraceNumber[0] response["timestamp"] = byTraceNumber[index] response["from"] = i[index] response["quality"] = i3[index] response["from_address"] = i2[index] i4 := append(responses, response) responses = i4 } else { response := make(map[string]interface{}) response["traceNumber"] = traceNumber response["name"] = s response["produce_time"] = byTraceNumber[0] response["timestamp"] = byTraceNumber[index] response["from"] = i[index-1] response["to"] = i[index] response["quality"] = i3[index] response["from_address"] = i2[index-1] i4 := append(responses, response) responses = i4 } } return responses } func (fs *FoodInfoService) GetTrace(traceNumber string) []interface{} { _, s, _, _, err := Tracecli.GetTraceinfoByTraceNumber(traceNumber) var responses []interface{} byTraceNumber, i, i2, i3, err := Tracecli.GetTraceDetailByTraceNumber(traceNumber) if err != nil { fmt.Println(err) } for index := 0; index < len(byTraceNumber); index++ { if index == 0 { response := make(map[string]interface{}) response["traceNumber"] = traceNumber response["name"] = s response["produce_time"] = byTraceNumber[0] response["timestamp"] = byTraceNumber[index] response["from"] = i[index] response["quality"] = i3[index] response["from_address"] = i2[index] i4 := append(responses, response) responses = i4 } else { response := make(map[string]interface{}) response["traceNumber"] = traceNumber response["name"] = s response["produce_time"] = byTraceNumber[0] response["timestamp"] = byTraceNumber[index] response["from"] = i[index-1] response["quality"] = i3[index] response["from_address"] = i2[index-1] i4 := append(responses, response) responses = i4 } } return responses } func (f FoodInfoService) Producing() []interface{} { var resList []interface{} numList := f.GetFoodList() for index := 0; index < len(numList); index++ { trace := f.GetTrace(strconv.Itoa(numList[index])) if len(trace) == 1 { i := append(resList, trace[0]) resList = i } } fmt.Println("Producing: ", resList) return resList } func (f FoodInfoService) Distributing() []interface{} { numList := f.GetFoodList() var resList []interface{} for index := 0; index < len(numList); index++ { trace := f.GetTrace(strconv.Itoa(numList[index])) if len(trace) == 2 { i := append(resList, trace[1]) resList = i } } return resList } func (f FoodInfoService) Retailing() []interface{} { numList := f.GetFoodList() var resList []interface{} for index := 0; index < len(numList); index++ { trace := f.GetTrace(strconv.Itoa(numList[index])) if len(trace) == 3 { i := append(resList, trace[2]) resList = i } } return resList }
编写食物数据模型Food
food.go
package models import "math/big" // Food 表示食物的数据模型 type Food struct { Name string `json:"name"` // 食物名称 TraceNumber *big.Int `json:"TraceNumber"` // 追溯编号,使用 *big.Int 类型以支持大整数 TraceName string `json:"TraceName"` // 追溯名称 Quality uint8 `json:"Quality"` // 食物质量,使用 uint8 表示无符号 8 位整数 }
在utils下统一请求数据格式
response.go
package utils import ( "encoding/json" "fmt" ) // returnDataStruct 定义了用于返回 JSON 数据的结构体 type returnDataStruct struct { Ret int `json:"ret"` // 返回状态码 Msg string `json:"msg"` // 返回消息 Data interface{} `json:"data"` // 返回数据,使用空接口表示可以包含任何类型的数据 } // Send_json 用于构建并返回标准的 JSON 响应 func Send_json(ret int, msg string, data interface{}) []byte { // 构建 returnDataStruct 结构体实例 retu, err := json.Marshal(returnDataStruct{ Ret: ret, Msg: msg, Data: data, }) if err != nil { fmt.Println("error:", err) } return retu } // Send_custom_json 用于构建并返回标准的 json响应 func Send_custom_json(ret int, data_key string, data interface{}) []byte { response := make(map[string]interface{}) response["ret"] = ret response[data_key] = data retu, err := json.Marshal(response) if err != nil { fmt.Println(err) } return retu }
编写给用户返回的数据格式
User.go
package controllers import ( "trace/conf" "trace/utils" "github.com/beego/beego/v2/server/web" ) type User struct { web.Controller } func (u User) Userinfof() { userName := u.GetString("userName") var jsons []byte switch userName { case "produce": jsons = utils.Send_custom_json(200, "address", conf.ProducerAddress) case "distributor": jsons = utils.Send_custom_json(200, "address", conf.DistributorAddress) case "retailer": jsons = utils.Send_custom_json(200, "address", conf.RetailerAddress) default: jsons = utils.Send_custom_json(200, "error", "user not found") } u.Ctx.ResponseWriter.Write(jsons) }
注册路由
web.Router("/userinfo", &controllers.User{}, "*:Userinfof")
编写处理与食物追溯相关请求
Trace.go
package controllers import "github.com/beego/beego/v2/server/web" type Trace struct { web.Controller }
newfood处理创建新食物的请求
func (t Trace) newFood() { t.newFood() }
处理创建新食物的具体逻辑
func (t *Trace) newfood() { // 初始化 Food 结构体 var food models.Food // 获取请求体数据 data := t.Ctx.Input.RequestBody // 调用 paramjson 函数解析 JSON 数据 success, parsedFood := paramjson(data, &food) if !success { // 如果解析失败,返回错误响应 t.Ctx.ResponseWriter.Write(utils.Send_json(0, "传入参数不正确", parsedFood)) return } // 调用 LoadUser 函数加载用户 service.LoadUser("producer") // 调用 Tracecli.NewFood 函数创建新食物 _, receipt, err := service.Tracecli.NewFood(parsedFood.Name, parsedFood.TraceNumber, parsedFood.TraceName, strconv.Itoa(int(parsedFood.Quality))) if err != nil { // 如果创建失败,返回错误响应 t.Ctx.ResponseWriter.Write(utils.Send_json(0, "trace already exist", err)) return } // 返回成功响应 t.Ctx.ResponseWriter.Write(utils.Send_json(1, "ok", receipt)) }
编写解析json数据具体逻辑
func paramjson(data []byte, food *models.Food) (bool, models.Food) { // 如果输入数据为 nil,则返回解析失败的结果 if data == nil { return false, models.Food{} } // 尝试解析 JSON 数据并填充到 models.Food 结构体中 if err := json.Unmarshal(data, &food); err != nil { // 解析失败,则返回解析失败的结果 return false, models.Food{} } else { // 解析成功,则返回解析后的 models.Food 结构体 return true, *food } }
配置路由
web.Router("/produce", &controllers.Trace{}, "POST:NewFood")
Adddistribution 处理食物分销的请求
func (t Trace) Adddistribution() { t.adddistribution() }
adddistribution 处理食物分销的具体逻辑
func (t Trace) adddistribution() { var food models.Food data := t.Ctx.Input.RequestBody paramjson(data, &food) b, i := paramjson(data, &food) if !b { t.Ctx.ResponseWriter.Write(utils.Send_json(0, "传入参数不正确", i)) } service.LoadUser("distributor") _, receipt, err := service.Tracecli.AddTraceInfoByDistributor(food.TraceNumber, food.TraceName, new(big.Int).SetUint64(uint64(food.Quality))) if err != nil { t.Ctx.ResponseWriter.Write(utils.Send_json(0, "error", err)) } t.Ctx.ResponseWriter.Write(utils.Send_json(1, "ok", receipt)) }
配置路由
web.Router("/distributor", &controllers.Trace{}, "POST:Adddistribution")
Addretail 处理食物零售的请求
func (t Trace) Addretail() { t.Addretail() }
addretail 处理食物零售的具体逻辑
func (t Trace) addretail() { var food models.Food data := t.Ctx.Input.RequestBody paramjson(data, &food) b, i := paramjson(data, &food) if !b { t.Ctx.ResponseWriter.Write(utils.Send_json(0, "传入参数不正确", i)) } service.LoadUser("retailer") _, receipt, err := service.Tracecli.AddTraceInfoByRetailer(food.TraceNumber, food.TraceName, new(big.Int).SetUint64(uint64(food.Quality))) if err != nil { t.Ctx.ResponseWriter.Write(utils.Send_json(0, "error", err)) } t.Ctx.ResponseWriter.Write(utils.Send_json(1, "ok", receipt)) }
配置路由
web.Router("/addretail", &controllers.Trace{}, "POST:Addretail")
编写GetfoodInfo 控制器
处理食品信息的请求
type GetfoodInfo struct { web.Controller }
Trace 获取某个食品的溯源信息
func (g GetfoodInfo) Trace() { // 检索追溯号和 FoodInfoService 实例 tn, fs := g.getTraceNumberAndService() // 在 FoodInfoService 上调用 Get_food 方法,并以 JSON 格式响应结果 g.Ctx.Output.JSON(fs.Get_food(tn), false, false) }
getTraceNumberAndService 是一个辅助方法,用于检索追溯号和 FoodInfoService
编写getTraceNumberAndService方法
func (g GetfoodInfo) getTraceNumberAndService() (string, *service.FoodInfoService) { // 从请求参数中检索追溯号 tn := g.GetString("traceNumber") // 将追溯号转换为整数 atoi, _ := strconv.Atoi(tn) // 检查追溯号是否小于 0 或为空;如果是,则以错误响应 if atoi < 0 || tn == "" { g.Ctx.ResponseWriter.Write(utils.Send_custom_json(0, "error", "invalid parameter")) } // 创建 FoodInfoService 的新实例 fs := &service.FoodInfoService{} // 返回追溯号和 FoodInfoService 实例 return tn, fs }
配置路由
web.Router("/trace", &controllers.GetfoodInfo{}, "*:Trace")
获取某个食品当前信息
func (g GetfoodInfo) GetFood() { tn, fs := g.getTraceNumberAndService() g.Ctx.Output.JSON(fs.Get_food(tn), false, false) }
配置路由
web.Router("/food", &controllers.GetfoodInfo{}, "*:GetFood")
获取某个生产商的食物信息
func (g GetfoodInfo) Producing() { fs := g.getFoodInfoService() g.Ctx.Output.JSON(fs.Producing(), false, false) }
getFoodInfoService 是用于获取 FoodInfoService 实例的方法文章来源:https://www.toymoban.com/news/detail-778285.html
func (g GetfoodInfo) getFoodInfoService() *service.FoodInfoService { // 创建并返回 FoodInfoService 的新实例 fs := &service.FoodInfoService{} return fs }
配置路由
web.Router("/producing", &controllers.GetfoodInfo{}, "GET:Producing")
获取位于中间商的食物信息
func (g GetfoodInfo) Distributing() { fs := g.getFoodInfoService() g.Ctx.Output.JSON(fs.Distributing(), false, false) }
配置路由
web.Router("/distributing", &controllers.GetfoodInfo{}, "GET:Distributing")
获取超市的食物信息
func (g GetfoodInfo) Retailing() { fs := g.getFoodInfoService() g.Ctx.Output.JSON(fs.Retailing(), false, false) }
配置路由
web.Router("/retailing", &controllers.GetfoodInfo{}, "GET:Retailing")
INITROLE 函数用于初始化角色设置
INITROLE
// INITROLE 函数用于初始化角色设置 func INITROLE() { // 从配置中获取分发者的地址和私钥 fromAddress := conf.DistributorAddress privateKey := conf.DistributorPK // 将私钥解析为 ECDSA 密钥 key, err := crypto.HexToECDSA(privateKey) if err != nil { fmt.Println("error private:", err) return } // 创建一个新的 KeyedTransactor,将密钥和地址设置为授权信息 auth := bind.NewKeyedTransactor(key) auth.From = common.HexToAddress(fromAddress) // 从配置文件中解析 FISCO-BCOS 客户端的配置 files, _ := conf.ParseConfigFile("config.toml") client, _ := client.Dial((*conf2.Config)(&files[0])) // 部署 Service 合约并获取合约实例 _, _, instance, _ := service.DeployService(client.GetTransactOpts(), client) session := service.ServiceSession{Contract: instance, CallOpts: *client.GetCallOpts(), TransactOpts: *client.GetTransactOpts()} // 将分发者地址转换为 common.Address 类型 address := common.HexToAddress(conf.DistributorAddress) // 设置 Distributor 角色 _, _, err = session.SetDRRole(address.String()) if err != nil { fmt.Println(err) } // 将生产者地址转换为 common.Address 类型 address1 := common.HexToAddress(conf.ProducerAddress) // 设置 Producer 角色 _, _, err = session.ResetPRRole(address1.String()) if err != nil { fmt.Println(err) } // 将零售商地址转换为 common.Address 类型 address2 := common.HexToAddress(conf.RetailerAddress) // 设置 Retailer 角色 _, _, err = session.ResetRRRole(address2.String()) if err != nil { fmt.Println(err) } // 部署 Role 合约并获取合约实例 _, _, instance1, err := Role.DeployService(client.GetTransactOpts(), client) if err != nil { fmt.Println(err) } session1 := Role.ServiceSession{Contract: instance1, CallOpts: *client.GetCallOpts(), TransactOpts: *client.GetTransactOpts()} // 判断所有角色是否设置成功 err1 := session1.OnlyDRRole(address) err2 := session1.OnlyPRRole(address1) err3 := session1.OnlyPRRole(address2) if err1 != nil || err2 != nil || err3 != nil { fmt.Println(err1) fmt.Println(err2) fmt.Println(err3) } }
main函数初始化文章来源地址https://www.toymoban.com/news/detail-778285.html
func main() { // 初始化角色 INITROLE() // 设置 Beego 路由不区分大小写 beego.BConfig.RouterCaseSensitive = false // 运行 Beego 应用 beego.Run() }
到了这里,关于beego框架编写食品溯源区块链后端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!