上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

beego框架编写食品溯源区块链后端

guduadmin341月前

区块链食品溯源项目

创建项目

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 实例的方法

    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函数初始化

    func main() {
        // 初始化角色
        INITROLE()
    ​
        // 设置 Beego 路由不区分大小写
        beego.BConfig.RouterCaseSensitive = false
    ​
        // 运行 Beego 应用
        beego.Run()
    }

网友评论

搜索
最新文章
热门文章
热门标签
 
 梦见女人是什么意思  已婚女人梦见两条蛇  梦见钱财被盗是什么预兆