Fabric 票据系统(六) goWeb

至此与服务有关的东西已经写完了,接下需要一个与用户交互的前端,Go语言本身提供了一个Web服务器来处理HTTP请求,并为HTML提供模板。

新建web目录,包含三个子目录

  • web/tpl:包含所有的HTML页面(模板)
  • web/static:包含所有CSS,Javascript,图片…
  • web/controllers :包含将呈现模板的所有函数

使用MVC(模型 - 视图 - 控制器)模式使其更具可读性。模型将是区块链部分,视图是模板和控制器由controllers目录中的功能提供

  • web/tpl/login.html
  • web/tpl/issue.html
  • web/tpl/bills.html
  • web/tpl/billInfo.html
  • web/tpl/waitAccept.html
  • web/tpl/waitAcceptInfo.html
  • web/controller/controllerHandler.go
  • web/controller/controllerResponse.go
  • web/controllers/userInfo.go
  • web/app.go
  • web/static

web 中添加 controller 目录

controller 目录中新建 controllerHandler 用于处理各种请求

controller 目录中新建 controllerResponse 用于响应请求

用户登录: userInfo.go

系统指定用户: admin, alice, bob, jack

一、开启服务,设置路由

编辑app.go

package Web

import (
	"zhq/bill/Web/Controllers"
	"fmt"
	"net/http"
)

func WebStart(app *Controllers.Application)error  {
	// 指定文件服务器
	//如果不指定文件服务器,css和js将不起作用
	fs := http.FileServer(http.Dir("Web/Static"))
	http.Handle("/Static/", http.StripPrefix("/Static/", fs))

	fmt.Println("启动应用程序,监听端口号:8888")
	http.HandleFunc("/",app.LoginView)
	http.HandleFunc("/login.html",app.LoginView)
	//登录按钮响应
	http.HandleFunc("/login",app.Login)
	//发布票据页
	http.HandleFunc("/issue.html",app.Issue)
	//发布票据
	http.HandleFunc("/issue",app.SaveBill)
	//查询我的票据列表
	http.HandleFunc("/bills.html",app.QueryMyBills)
	//发起背书
	http.HandleFunc("/endorse",app.Endorse)
	//查看票据详情
	http.HandleFunc("/billinfo",app.QueryBillInfo)
	//查看所有待签收票据
	http.HandleFunc("/waitAccept.html",app.WaitAccepts)
	//查看代签收票据详情
	http.HandleFunc("/waitAcceptInfo.html",app.WaitAcceptInfo)
	//退出登录
	http.HandleFunc("/loginout",app.LoginOut)
	//签收票据
	http.HandleFunc("/accept",app.Accetp)
	//拒签票据
	http.HandleFunc("/reject",app.Reject)
	err := http.ListenAndServe(":8888",nil)
	if err != nil {
		return fmt.Errorf("启动web服务失败:%s",err.Error())
	}
	return nil
}

二、封装处理请求响应

编辑controllerHandler.go

发布票据SaveBill()

1、获取页面提交的Bill表单数据

bill := Service.Bill{
		BillInfoID:       r.FormValue("BillInfoID"),
		BillInfoAmt:      r.FormValue("BillInfoAmt"),
		BillInfoType:     r.FormValue("BillInfoType"),
		BillInfoIsseDate: r.FormValue("BillInfoIsseDate"),
		BillInfoDueDate:  r.FormValue("BillInfoDueDate"),
		DrwrCmID:         r.FormValue("DrwrCmID"),
		DrwrAcct:         r.FormValue("DrwrAcct"),
		AccptrCmID:       r.FormValue("AccptrCmID"),
		AccptrAcct:       r.FormValue("AccptrAcct"),
		PyeeCmID:         r.FormValue("PyeeCmID"),
		PyeeAcct:         r.FormValue("PyeeAcct"),
		HoldrCmID:        r.FormValue("HoldrCmID"),
		HoldrAcct:        r.FormValue("HoldrAcct"),
	}
	

对应issue.html中的表单


<!--
 <form action="/issue" method="post">
                    <!-- 发布票据 -->
                    <div class="publish">
                        <div class="">
                            <div class="pub1">
                                <p>票据号码</p>
                                <input type="text" name="BillInfoID" value="" placeholder=""/>
                                <p>票据金额</p>
                                <input type="text" name="BillInfoAmt" value="" placeholder=""/>
                                <p>票据类型</p>
                                <input type="text" name="BillInfoType" value="" placeholder=""/>
                            </div>
                            <div class="pub2">
                                <p>票据出票日期</p>
                                <input type="text" name="BillInfoIsseDate" value="" placeholder=""/>
                                <p>票据到期日期</p>
                                <input type="text" name="BillInfoDueDate" value="" placeholder=""/>
                            </div>
                            <div class="pub3">
                                <p>出票人名称</p>
                                <input type="text" name="DrwrAcct" value="" placeholder=""/>
                                <p>出票人证件号码</p>
                                <input type="text" name="DrwrCmID" value="" placeholder=""/>
                                <p>承兑人名称</p>
                                <input type="text" name="AccptrAcct" value="" placeholder=""/>
                                <p>承兑人证件号码</p>
                                <input type="text" name="AccptrCmID" value="" placeholder=""/>
                            </div>
                            <div class="pub4">
                                <p>收款人名称</p>
                                <input type="text" name="PyeeAcct" value="" placeholder=""/>
                                <p>收款人证件号码</p>
                                <input type="text" name="PyeeCmID" value="" placeholder=""/>
                                <p>持票人名称</p>
                                <input type="text" name="HoldrAcct" value="" />
                                <p>持票人证件号码</p>
                                <input type="text" name="HoldrCmID" value="" />
                            </div>
                            <p>
                                <span><input type="submit" class="issueBtn" value="提交"/></span>
                            </p>
-->

2、调用链码

上一篇已经实现了Service的封装,通过Service来调用链码

transactionID, err := app.Fabric.IssueBill(bill)

3、返回响应结果

	var msg string
	if err != nil {
		msg = "票据发布失败:" + err.Error()
	} else {
		msg = "票据发布成功:" + transactionID
	}
	data := &struct {
		Msg  string
		Flag bool
		Cuser User

	}{
		Msg:  msg,
		Flag: true,
		Cuser: cuser,

	}
	ShowView(w, r, "issue.html", data)

发布票据的功能就完成了,因为前面做了一些分装,所以实现起来很方便,其他的都差不多,就不多说了,以下为完整代码

package Controllers

import (
	"zhq/bill/Service"
	"net/http"
	"fmt"
	"encoding/json"
)

type Application struct {
	Fabric *Service.FabricSetupService

}
var cuser User
func (app *Application)LoginView(w http.ResponseWriter,r *http.Request)  {
	ShowView(w,r,"login.html",nil)
}
func (app *Application)Login(w http.ResponseWriter,r *http.Request){
	userName := r.FormValue("userName")
	password := r.FormValue("password")

	data := &struct {
		CurrentUser User
		Flag    bool
	}{
		Flag:false,
	}

	var flag bool
	for _, user := range Users {
		if user.UserName == userName && user.Password == password {
			cuser = user
			flag = true
			break
		}
	}

	if flag {
		// 登录成功, 根据当前用户查询票据列表
		fmt.Println("当前登录用户信息:", cuser)
		//向表单中插入数据
		//r.Form.Set("holdeCmId", cuser.CmId)
		app.QueryMyBills(w, r)
	} else {
		data.Flag = true
		data.CurrentUser.UserName = userName
		ShowView(w, r, "login.html", data)
	}
}
// 查询我的票据列表
func (app *Application) QueryMyBills(w http.ResponseWriter, r *http.Request)  {
	holdeCmId := cuser.CmId
	result, err := app.Fabric.QueryBill(holdeCmId)
	if err != nil{
		fmt.Println("查询当前用户的票据列表失败: ", err.Error())
	}

	var bills = []Service.Bill{}
	fmt.Println("当前用户Id:", holdeCmId,"bills:",bills)

	json.Unmarshal(result, &bills)
	data := &struct {
		Bills   []Service.Bill
		Cuser   User
	}{
		Bills: bills,
		Cuser: cuser,
	}
	ShowView(w, r, "bills.html", data)
}
//发布票据页
func (app *Application) Issue(w http.ResponseWriter, r *http.Request)  {
	data := &struct {
		Msg   string
		Flag  bool
		Cuser User
	}{
		Msg:   "",
		Flag:  false,
		Cuser: cuser,
	}
	ShowView(w, r, "issue.html", data)
}
//发布票据
func (app *Application) SaveBill(w http.ResponseWriter, r *http.Request)  {
	bill := Service.Bill{
		BillInfoID:       r.FormValue("BillInfoID"),
		BillInfoAmt:      r.FormValue("BillInfoAmt"),
		BillInfoType:     r.FormValue("BillInfoType"),
		BillInfoIsseDate: r.FormValue("BillInfoIsseDate"),
		BillInfoDueDate:  r.FormValue("BillInfoDueDate"),
		DrwrCmID:         r.FormValue("DrwrCmID"),
		DrwrAcct:         r.FormValue("DrwrAcct"),
		AccptrCmID:       r.FormValue("AccptrCmID"),
		AccptrAcct:       r.FormValue("AccptrAcct"),
		PyeeCmID:         r.FormValue("PyeeCmID"),
		PyeeAcct:         r.FormValue("PyeeAcct"),
		HoldrCmID:        r.FormValue("HoldrCmID"),
		HoldrAcct:        r.FormValue("HoldrAcct"),
	}



	transactionID, err := app.Fabric.IssueBill(bill)
	var msg string
	if err != nil {
		msg = "票据发布失败:" + err.Error()
	} else {
		msg = "票据发布成功:" + transactionID
	}
	data := &struct {
		Msg  string
		Flag bool
		Cuser User

	}{
		Msg:  msg,
		Flag: true,
		Cuser: cuser,

	}
	ShowView(w, r, "issue.html", data)
}
//发起背书
func (app *Application) Endorse(w http.ResponseWriter, r *http.Request)  {
	waitEndorseAcct := r.FormValue("waitEndorseAcct")
	waitEndorseCmId := r.FormValue("waitEndorseCmId")
	billNo := r.FormValue("billNo")
	result,err := app.Fabric.Endorse(billNo,waitEndorseCmId,waitEndorseAcct)
	if err != nil{
		fmt.Println(err.Error())
	}

	r.Form.Set("billInfoNo",billNo)
	r.Form.Set("flag","t")
	r.Form.Set("Msg",result)
	app.QueryBillInfo(w,r)
}
//签收票据
func (app *Application) Accetp(w http.ResponseWriter, r *http.Request)  {
	billNo := r.FormValue("billNo")
	cmid := cuser.CmId
	acct := cuser.Acct
	result,err :=app.Fabric.Accept(billNo,cmid,acct)
	if err != nil {
		fmt.Println(err.Error())
	}
	r.Form.Set("billNo",billNo)
	r.Form.Set("flag","t")
	r.Form.Set("Msg",result)
	app.WaitAcceptInfo(w,r)
}
//拒签票据
func (app *Application) Reject(w http.ResponseWriter, r *http.Request)  {
	billNo := r.FormValue("billNo")
	cmid := cuser.CmId
	acct := cuser.Acct
	result,err :=app.Fabric.Reject(billNo,cmid,acct)
	if err != nil {
		fmt.Println(err.Error())
	}
	r.Form.Set("billNo",billNo)
	r.Form.Set("flag","t")
	r.Form.Set("Msg",result)
	app.WaitAcceptInfo(w,r)
}
//查询票据详情
func (app *Application) QueryBillInfo(w http.ResponseWriter, r *http.Request)  {

	billInfoNo := r.FormValue("billNo")
	result, err := app.Fabric.QueryBillByNo(billInfoNo)
	if err != nil {
		fmt.Println(err.Error())
	}
	var bill Service.Bill

	json.Unmarshal(result, &bill)
	data := &struct {
		Cuser User
		Bill  Service.Bill
		Flag bool
		Msg string

	}{
		Bill:  bill,
		Cuser: cuser,
		Flag:false,
		Msg:"",

	}
	flag := r.FormValue("flag")
	if flag=="t" {
		data.Flag = true
		data.Msg = r.FormValue("Msg")
	}
	ShowView(w, r, "billInfo.html", data)
}
//待签收票据列表
func (app *Application) WaitAccepts(w http.ResponseWriter, r *http.Request)  {
	waitEndorseCmId := cuser.CmId
	result,err := app.Fabric.QueryMyWaitBills(waitEndorseCmId)
	if err != nil {
		fmt.Println(err.Error())
	}
	var bills []Service.Bill
	json.Unmarshal(result,&bills)
	data := &struct {
		Bills []Service.Bill
		Cuser User
	}{
		Bills:bills,
		Cuser:cuser,
	}
	ShowView(w,r,"waitAccept.html",data)
}
//待签收票据详情
func (app *Application) WaitAcceptInfo(w http.ResponseWriter, r *http.Request)  {
	billNo := r.FormValue("billNo")
	result,err := app.Fabric.QueryBillByNo(billNo)
	if err != nil {
		fmt.Println(err.Error())
	}
	var bill Service.Bill
	json.Unmarshal(result,&bill)
	data := &struct {
		Bill Service.Bill
		Cuser User
		Flag bool
		Msg string
	}{
		bill,
		cuser,
		false,
		"",
	}
	flag := r.FormValue("flag")
	if flag == "t" {
		data.Flag = true
		data.Msg = r.FormValue("Msg")
	}
	ShowView(w,r,"waitAcceptInfo.html",data)
}
//退出登录
func (app *Application) LoginOut(w http.ResponseWriter, r *http.Request)  {
	cuser = User{}
	app.LoginView(w,r)
}

三、封装响应

编辑 controllerResponse.go

func ShowView(w http.ResponseWriter, r *http.Request, templateName string, data interface{}) {
	page := filepath.Join("Web","TPL",templateName)
	//创建模板实例
	resultTemplate,err := template.ParseFiles(page)
	if err != nil {
		fmt.Println("创建模板实例错误:",err)
		return
	}
	//融合数据
	err = resultTemplate.Execute(w,data)
	if err != nil {
		fmt.Println("融合模板数据时发生错误",err)
	}
}

templateName 跳转页面名 data 页面间传递的数据

创建登录用户结构体

编辑userInfo.go

package Controllers
type User struct {
	UserName	string	`json:"UserName"`
	Name		string	`json:"Name"`
	Password	string	`json:"Password"`
	CmId		string	`json:"CmId"`
	Acct		string	`json:"Acct"`
}

初始化一些账户,用于测试,为了方便直接用数组保存,实际用户当然是用数据库保存

var Users []User

//创建4个用户,模拟数据库存储
func init()  {
	admin := User{UserName: "admin", Name: "管理员", Password: "123456", CmId: "HODR01", Acct: "管理员"}
	alice := User{UserName: "alice", Name: "A公司", Password: "123456", CmId: "ACMID", Acct: "A公司"}
	bob := User{UserName: "bob", Name: "B公司", Password: "123456", CmId: "BCMID", Acct: "B公司"}
	jack := User{UserName: "jack", Name: "C公司", Password: "123456", CmId: "CCMID", Acct: "C公司"}

	Users = append(Users, admin)
	Users = append(Users, alice)
	Users = append(Users, bob)
	Users = append(Users, jack)
}

运行测试

cd $GOPATH/src/zhq/bill go build make

1、登录

使用初始化的4个用户任一一个登录

登录

2、发布一个票据

填写票据内容,然后提交

发布票据

3、查看我的票据

刚刚发布的票据已经可以查看到了

我的票据

4、票据详情

票据详情

5、发起背书

填写背书人名称,背书人证件号码

发起背书

6、退出当前用户,登录发起背书时,指定的账户

登录成功,可以看到刚才需要背书的票据

我的票据

7、签收票据

待签收票据->详情->签收票据

签收票据

如果是签收票据,票据规自己所有,在我的票据列表可查

8、拒签票据

待签收票据->详情->拒签

签收票据

如果是拒签票据,票据规返回给发起背书人,在背书人列表可查

不论是签收或是拒签都应只能对一个票据操作一次,这里为了掩饰,未做这一处理

哦了,票据项目至此就完成了

源码下载

感谢韩晓东(老韩)指导

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦