Fabric 2.x鏈碼之綜合應用

在上一小節對Fabric 2.x鏈碼有了基本瞭解之後,本節以學生信息上鍊爲例,說明Fabric 2.x鏈碼的綜合應用。代碼如下,內容包括:學生信息上鍊、查詢學生信息(依據key)、查詢key區間的學生信息、修改學生信息、獲取歷史信息等內容。

package main

import (
        "encoding/json"
        "fmt"
        "github.com/hyperledger/fabric-contract-api-go/contractapi"
        "strconv"
        "time"
)

// 定義一個對象,繼承合約對象
type Student struct {
        contractapi.Contract
}

// 上鍊信息(對象)
type StudentInfo struct {
        Number  string `json:"number"`
        Name    string `json:"name"`
        Age     string `json:"age"`
        Address string `json:"address"`
}

// QueryResult structure used for handling result of query
type QueryResult struct {
        Key    string `json:"Key"`
        Record *StudentInfo
}
type QueryHistoryResult struct {
        TxId string `json:"tx_id"`
        Value string `json:"value"`
        IsDel string `json:"is_del"`
        OnChainTime string `json:"on_chain_time"`
}
// 初始化賬本
func (s *Student) InitLedger(ctx contractapi.TransactionContextInterface) error {
        StudentInfos := []StudentInfo{
                {Number: "2020001", Name: "張三", Age: "23", Address: "北京"},
                {Number: "2020002", Name: "李四", Age: "24", Address: "上海"},
                {Number: "2020003", Name: "王五", Age: "25", Address: "廣州"},
                {Number: "2020004", Name: "趙六", Age: "26", Address: "深圳"},
                {Number: "2020005", Name: "田七", Age: "27", Address: "天津"},
                {Number: "2020006", Name: "阿香", Age: "28", Address: "重慶"},
                {Number: "2020007", Name: "阿凱", Age: "29", Address: "杭州"},
                {Number: "2020008", Name: "阿蘭", Age: "30", Address: "南京"},
                {Number: "2020009", Name: "旺財", Age: "31", Address: "成都"},
                {Number: "2020010", Name: "小明", Age: "32", Address: "西安"},
        }
        for _, StudentInfo := range StudentInfos {
                StudentInfoAsBytes, _ := json.Marshal(StudentInfo)
                err := ctx.GetStub().PutState(StudentInfo.Number, StudentInfoAsBytes)
                if err != nil {
                        return fmt.Errorf("Failed to put to world state. %s", err.Error())
                }
        }
        return nil
}

// 上鍊學生信息
func (s *Student) CreateStudentInfo(ctx contractapi.TransactionContextInterface, number string, name string, age string, address string) error {
        StudentInfo := StudentInfo{
                Number:  number,
                Name:    name,
                Age:     age,
                Address: address,
        }
        StudentInfoAsBytes, _ := json.Marshal(StudentInfo)
        return ctx.GetStub().PutState(StudentInfo.Number, StudentInfoAsBytes)
}

//查詢學生信息
func (s *Student) QueryStudentInfo(ctx contractapi.TransactionContextInterface, StudentInfoNumber string) (*StudentInfo, error) {
        StudentInfoAsBytes, err := ctx.GetStub().GetState(StudentInfoNumber)
        if err != nil {
                return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
        }
        if StudentInfoAsBytes == nil {
                return nil, fmt.Errorf("%s does not exist", StudentInfoNumber)
        }
        stuInfo := new(StudentInfo)
        //注意: Unmarshal(data []byte, v interface{})的第二個參數爲指針類型(結構體地址)
        err = json.Unmarshal(StudentInfoAsBytes, stuInfo) //stuInfo := new(StudentInfo),stuInfo本身就是指針
        if err != nil {
                return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
        }
        return stuInfo, nil
}

// 查詢學生信息(查詢的key末尾是數字,有對應的區間)
func (s *Student) QueryAllStudentInfos(ctx contractapi.TransactionContextInterface, startNum, endNum string) ([]QueryResult, error) {
        resultsIterator, err := ctx.GetStub().GetStateByRange(startNum, endNum)
        if err != nil {
                return nil, err
        }
        defer resultsIterator.Close()
        results := []QueryResult{}
        for resultsIterator.HasNext() {
                queryResponse, err := resultsIterator.Next()

                if err != nil {
                        return nil, err
                }
                StudentInfo := new(StudentInfo)
                _ = json.Unmarshal(queryResponse.Value, StudentInfo)

                queryResult := QueryResult{Key: queryResponse.Key, Record: StudentInfo}
                results = append(results, queryResult)
        }
        return results, nil
}

// 修改學生信息
func (s *Student) ChangeStudentInfo(ctx contractapi.TransactionContextInterface, number string, name string, age string, address string) error {
        stuInfo, err := s.QueryStudentInfo(ctx, number)
        if err != nil {
                return err
        }
        stuInfo.Number = number
        stuInfo.Name = name
        stuInfo.Age = age
        stuInfo.Address = address
        StudentInfoAsBytes, _ := json.Marshal(stuInfo)
        return ctx.GetStub().PutState(number, StudentInfoAsBytes)
}

//獲取歷史信息
func (s *Student) GetHistory(ctx contractapi.TransactionContextInterface, number string) ([]QueryHistoryResult, error) {
        resultsIterator, err := ctx.GetStub().GetHistoryForKey(number)
        if err != nil {
                return nil, err
        }
        defer resultsIterator.Close()
        //results := []QueryResult{}
        //results := make([]QueryResult, 0)
        results := make([]QueryHistoryResult, 0)
        for resultsIterator.HasNext() {
                if queryResponse, err := resultsIterator.Next();err==nil{
                        res := QueryHistoryResult{}
                        res.TxId=queryResponse.TxId
                        res.Value=string(queryResponse.Value)
                        res.IsDel=strconv.FormatBool(queryResponse.IsDelete)
                        res.OnChainTime=time.Unix(queryResponse.Timestamp.Seconds,0).Format("2006-01-02 15:04:05")
                        results= append(results, res)
                }
                if err!=nil {
                        return nil,err
                }
        }
        return results, nil
}

func main() {
        chaincode, err := contractapi.NewChaincode(new(Student))
        if err != nil {
                fmt.Printf("Error create fabStudentInfo chaincode: %s", err.Error())
                return
        }
        if err := chaincode.Start(); err != nil {
                fmt.Printf("Error starting fabStudentInfo chaincode: %s", err.Error())
        }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章