beego框架编写食品溯源区块链后端
2024-01-09 20:21:26
区块链食品溯源项目
创建项目
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()
}
文章来源:https://blog.csdn.net/m0_58188818/article/details/135448302
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!