至此与服务有关的东西已经写完了,接下需要一个与用户交互的前端,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、拒签票据
待签收票据->详情->拒签
如果是拒签票据,票据规返回给发起背书人,在背书人列表可查
不论是签收或是拒签都应只能对一个票据操作一次,这里为了掩饰,未做这一处理