文章目录
- 服务计算——goAgenda
- 1. 安装使用 cobra
- 2. goAgenda知识点汇总
- 3. 分析设计
- 3.1 子命令
- 3.2 agenda help
- 3.3 agenda user register
- 3.4 agenda user login
- 3.5 agenda user logout
- 3.6 agenda user lookup
- 3.7 agenda user delete
- 3.8 agenda meeting create
- 3.9 agenda meeting addUser
- 3.10 agenda meeting deleteUser
- 3.11 agenda meeting lookup
- 3.11 agenda meeting cancel
- 3.12 agenda meeting exit
- 3.13 agenda meeting clear
- 4. 数据结构定义
- 5. 程序测试
- 6. 项目组内成员与分工
- 7. 源代码
- 8. 参考资料
服务计算——goAgenda
1. 安装使用 cobra
根据老师的指令:
go get -v github.com/spf13/cobra/cobra
随后会遇到以下的情况(提示报错信息):
Fetching https://golang.org/x/sys/unix?go-get=1
https fetch failed: Get https://golang.org/x/sys/unix?go-get=1: dial tcp 216.239.37.1:443: i/o timeout
到这里我们有两个解决的办法:
- 进入
$GOPATH/src/golang.org/x
文件夹下,使用:
-
git clone https://github.com/golang/sys.git
-
git clone https://github.com/golang/text.git
这两条指令将远程库的文件克隆到本地的文件夹下
- 进入该链接,下载所需的文件,解压后复制到本地
随后使用
go install github.com/spf13/cobra/cobra
即可完成cobra
的安装
2. goAgenda知识点汇总
2.1 JSON读写学习
2.1.1 编码
结构体转JSON代码:
package main
import (
"encoding/json"
"fmt"
)
type DebugInfo struct {
Level string `json:"level,omitempty"` // Level解析为level,忽略空值
Msg string `json:"message"` // Msg解析为message
Author string `json:"-"` // 忽略Author,或者设为未导出字段
}
func main() {
dbgInfs := []DebugInfo{
DebugInfo{"debug", `File: "test.txt" Not Found`, "Cynhard"},
DebugInfo{"", "Logic error", "Gopher"},
}
if data, err := json.Marshal(dbgInfs); err == nil {
fmt.Printf("%s\n", data)
}
}
自定义结构对MarshalJSON()接口的实现
package main
import (
"encoding/json"
"fmt"
)
type Point struct{ X, Y int }
func (pt Point)MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"X":%d,"Y":%d}`, pt.X, pt.Y)), nil
}
func main() {
if data, err := json.Marshal(Point{50, 50}); err == nil {
fmt.Printf("%s\n", data)
}
}
2.1.2 解码
解码主要使用的是JSON包的函数func Unmarshal(data []byte,v interface{}) error
package main
import (
"encoding/json"
"fmt"
)
func main() {
data := `[{"Level":"debug","Msg":"File: \"test.txt\" Not Found"},` +
`{"Level":"","Msg":"Logic error"}]`
var dbgInfos []map[string]string
json.Unmarshal([]byte(data), &dbgInfos)
fmt.Println(dbgInfos)
}
2.1.3 JSON转结构体
与编码一样,JSON是通过反射机制来实现解码的,所以结构必须导出所转换的字段,不导出的字段不会被JSON包解析。另外解析的时候不区分大小写。
package main
import (
"encoding/json"
"fmt"
)
type DebugInfo struct {
Level string
Msg string
author string // 未导出字段不会被json解析
}
func (dbgInfo DebugInfo) String() string {
return fmt.Sprintf("{Level: %s, Msg: %s}", dbgInfo.Level, dbgInfo.Msg)
}
func main() {
data := `[{"level":"debug","msg":"File Not Found","author":"Cynhard"},` +
`{"level":"","msg":"Logic error","author":"Gopher"}]`
var dbgInfos []DebugInfo
json.Unmarshal([]byte(data), &dbgInfos)
fmt.Println(dbgInfos)
}
结构体也可以与编码的时候一样设置结构体字段标签
2.1.4 转换接口
和编码的时候类似,解码使用接口Unmarshaler,需要实现UnmarshalJSON([]byte) error
下面这个接口没有实现解码算法,只是将参数打印出来
package main
import (
"encoding/json"
"fmt"
)
type Point struct{ X, Y int }
func (Point) UnmarshalJSON(data []byte) error {
fmt.Println(string(data))
return nil
}
func main() {
data := `{"X":80,"Y":80}`
var pt Point
json.Unmarshal([]byte(data), &pt)
}
2.2 文件读写
使用ioutil的ReadFile和WriteFile,并使用stirng()等函数进行类型转换,例程:
package main
import(
"fmt"
"io/ioutil"
)
func main() {
//read
b, err := ioutil.ReadFile("test.log")
if err != nil {
fmt.Print(err)
}
fmt.Println(b)
str := string(b)
fmt.Println(str)
//write
d1 := []byte("hello\ngo\n")
err := ioutil.WriteFile("test.txt", d1, 0644)
check(err)
}
2.3 实例
使用user进行的测试(已经通过)
var myuser []entity.User
fmt.Println("JSON decode to structure test1")
jsonStr := `[{"username":"wtysos11""password":"123456","email":"wtysos11"}{"username":"wtysos11","password":"123456""email":"wtysos11"}]`
json.Unmarshal([]byte(jsonStr),&myuser)
fmt.Println(myuser)
if data,err:=json.Marshal(myuser);err==nil{
fmt.Printf("%s\n",data)
}
2.4 StringArray使用
使用cmd.Flags().StringArray()
可以声明一个flag
使用cmd.Flags().GetStringArray()
可以取得这个数组
对于数组而言只有重复使用标签才能够作为不同元素,比如-a="ss" -a="tt"
,而同一个标签内都算作是一个字符窜
2.5 异常
if 遇到错误
return errors.New("遇到xx错误")
3. 分析设计
3.1 子命令
- 大的方向上要实现
help、user、meeting
三个子命令 - 用户信息存储在
curUser.txt
中,User
和Meeting
实体要用json
进行存储 - 实现日志服务
3.2 agenda help
寻求帮助使用子命令agenda help
,列出命令说明。此外输入agenda help register可以
列出regsiter命令的描述
3.3 agenda user register
用户注册使用命令agenda user register
改指令可接受四个参数(必选):
- –username/-u,用户名
- –password/-p,密码
- –email/-e,邮箱
- –telphone/-t,电话
注:
- 此外用户名是唯一的,要查重。
- 邮箱、电话要检查有效性。
反馈:
- 如果登记成功,返回成功注册的信息
- 如果登记失败,反馈错误信息
3.4 agenda user login
用户登录使用子命令agenda user login
- –username/-u,用户名
- –password/-p,密码
注:
- 用户名与密码这两个参数为必须
反馈:
- 用户名与密码都正确的时候返回一个成功登录的信息
- 登录失败,返回登录失败的信息
3.5 agenda user logout
用户登出使用子命令agenda user logout
注:
用户登出后只能够使用用户注册和用户登录功能且这里命令不接受参数
反馈:
- 反馈登出信息
3.6 agenda user lookup
在创建的用户中查找某用户使用子命令agenda user lookup
注:
只有在已经登录的状态才可以使用
反馈:
- 如果找到用户,返回已注册的所有用户的用户名、邮箱以及电话信息(打表)
3.7 agenda user delete
删除用户使用子命令agenda user delete
注:
- 操作为删除自己的账号,自动注销
- 用户账号删除之后:
- 以该用户为发起者的会议将会被删除
- 以该用户为参与者的会议将会从参与者列表中移除该用户。如果此操作造成参与者数量为0,则会议也会被移除。
反馈:
- 返回成功注销的信息
- 失败要返回注销失败(有什么情况会导致注销失败吗?)
3.8 agenda meeting create
创建会议使用子命令agenda meeting create
参数:
- –start/-s,开始时间,格式为(YYYY-MM-DD/HH:mm:ss)
- –end/-e,结束时间
- –title/-t,会议主题
- –participant/-p,会议参与者
注:
- 用户无法分身参与多个会议,如果用户已有的会议安排与将要创建的会议在时间上有重叠,则会无法创建这个会议。
- 会议主题是唯一的。
反馈:
- 成功返回创建成功提示信息
- 失败返回创建失败相关信息
3.9 agenda meeting addUser
添加会议参与者使用子命令meeting addUser -p [Participator] -t [Title]
参数:
- –title/-t,会议主题
- –participants/-p,要添加的用户名(可以为多个)
反馈:
- 成功返回相关信息
- 失败也返回相关信息
3.10 agenda meeting deleteUser
删除会议参与者使用子命令meeting deleteUser -p [Participator] -t [Title]
参数:
- –title/-t,会议主题
- –participants/-p,要添加的用户名(可以为多个)
反馈:
- 成功返回相关信息
- 失败也返回相关信息
3.11 agenda meeting lookup
查找会议(仅登录可用)使用子命令meeting lookup -s [StartTime] -e [EndTime]
参数:
- –start/-s,开始时间
- –end/-e,结束时间
注:
- 已登录的用户可以查询自己的议程在某一时间段内的所有会议安排
3.11 agenda meeting cancel
取消会议(已经登录的用户可以取消自己发起的某一会议安排)使用子命令meeting cancel -t [title]
参数:
- –title/-t,会议主题
3.12 agenda meeting exit
退出会议(已经登录的用户可以退出自己参与的某一会议安排)使用子命令meeting exit -t [title]
参数:
- –title/-t,会议主题
注:
- 如果此操作造成会议参与者人数为0,则会议将会被删除
3.13 agenda meeting clear
清空会议(已经登录的用户可以清空自己发起的所有会议安排)使用子命令clear
4. 数据结构定义
4.1 用户(user)
位置:entity/useroper.go
中
作用:定义用户所需要的结构,以及相关的操作函数
type User struct{
Username string //用户名
Password string //密码
Email string // 电子邮箱
Telphone string // 电话
}
4.2 会议(conference)
位置:entity/conference.go
中
作用:定义会议所需要的结构,以及相关的操作函数
type Meeting struct{
StartTime string //开始时间
EndTime string //结束时间
Title string //会议标题
UserList []User //参与人数列表
}
5. 程序测试
为了可以在任意位置使用agenda命令,而不是进入工作目录后go run main.go
,采用先go build main.go
后重命名可执行程序为agenda,然后移动到gowork/bin
中,在每次运行命令时,golang会根据GOPATH的位置,在bin中找到相应的可执行程序,从而在任意位置使用agenda命令。
本次测试的shell为Z shell(zsh)。
根据cmd-design中的需求,对三个子命令分别进行测试,并将相应输出记录到日志中。
5.1 agenda根命令
5.2 help子命令
可以查看user子命令的帮助信息,用法如下:
agenda help user
agenda user —help
还可以查看用户命令下的其他子命令用法,如agenda help user register
等。
查看meeting子命令的帮助信息,用法:
agenda help meeting
agenda meeting --help
同样查看用户命令下的其他子命令用法,如agenda help meeting addUser
等。
5.3 user子命令
5.3.1 lookup
由于需要在运行agenda命令的目录下中保存user.txt和cache.txt,估进入goAgenda目录。
初始时在cache.txt保存着一个用户的登录信息,故可以直接使用lookup命令。
退出后cache.txt为logout状态,且只能使用register和login命令(见上图)。
5.3.2 login
5.3.3 register
5.3.4 delete
5.4 meeting子命令
5.4.1 lookup
5.4.2 addUser
5.4.3 deleteUser
5.3.4 cancel
5.3.5 create
5.3.6 exit
5.3.7 clear
6. 项目组内成员与分工
姓名 | 学号 | 工作 |
---|---|---|
王迎旭 | 16340226 | 实验报告与测试程序 |
吴天扬 | 16340240 | 整体框架的搭建、user与meeting功能的完善 |
王泽浩 | 16340232 | debug与优化提示信息 |
吴聪 | 16340237 | 完善日志功能、完善程序接口 |