CLI 命令行实用程序开发实战 - Agenda
课程网站下环境配置
在课程网站http://139.9.57.167:20080/ 配置cobra需要先通过su获得管理员权限,然后使用chmod 777 /home
获取/home
路径下所有文件的读写权限。
在$GOPATH/src/golang.org/x
目录下用 git clone 下载 sys 和 text 项目
git clone https://github.com/golang/text
git clone https://github.com/golang/sys
然后安装cobra并设置$GOBIN路径。
go install github.com/spf13/cobra/cobra
export PATH=$PATH:${GOPATH//://bin:}/bin
Agenda 实现
本次作业我一共完成了三条指令:注册、登录、退出。文件目录如下所示:
用户注册
要求
- 注册新用户时,用户需设置一个唯一的用户名和一个密码。另外,还需登记邮箱及电话信息。
- 如果注册时提供的用户名已由其他用户使用,应反馈一个适当的出错信息;成功注册后,亦应反馈一个成功注册的信息。
注册的命令为(将[...]
替换为相应的内容)
go run main.go register --user=[username] --password=[userpassword] --email=[useremail] --telephone=[usertelephone]
如
go run main.go register --user=TestUser5 --password=123 --email=123 --telephone=123
使用cobra add register
命令进行文件的管理。然后再cmd/register.go
下的init
函数中进行修改。
func init() {
rootCmd.AddCommand(registerCmd)
registerCmd.Flags().StringP("user", "u", "", "Help message for username")
registerCmd.Flags().StringP("password", "p", "", "Password")
registerCmd.Flags().StringP("email", "e", "", "Email")
registerCmd.Flags().StringP("telephone", "t", "", "Telephone")
}
将所需的四条信息在回调函数中保存到一个结构体中。
type User struct {
Username, Password, Email, Telephone string
}
var registerCmd = &cobra.Command{
Use: "register",
Short: "register",
Long: `register a user`,
Run: func(cmd *cobra.Command, args []string) {
register.Username, _ = cmd.Flags().GetString("user")
register.Password, _ = cmd.Flags().GetString("password")
register.Email, _ = cmd.Flags().GetString("email")
register.Telephone, _ = cmd.Flags().GetString("telephone")
...
}
}
用户注册需要保证用户名的唯一性,且需要数据的持久化。所以需要把每次的注册信息保存到一个json
文件User.json
中。每次用户注册时,读取该文件并遍历是否用重名用户,如果出现重名就显示错误信息并返回。
readFile()
for _, value := range persons {
if value.Username == register.Username {
fmt.Println("Wrong: This Username is used!")
return
}
}
如果不重名就将该新用户写入到User.json
文件中,并将登陆成功的用户写入临时文件CurrentUser.json
临时保存(保存登录状态),并提示注册成功的信息。
writeFile(register)
writeCurrent(register)
fmt.Println("Register successfully", register.Username)
读写json
文件的函数如下所示:
func readFile() {
filePtr, err := os.Open("entity/User.json")
if err != nil {
fmt.Println("Open file failed [Err:%s]", err.Error())
return
}
defer filePtr.Close()
// 创建json解码器
decoder := json.NewDecoder(filePtr)
err = decoder.Decode(&persons)
if err != nil {
fmt.Println("Decoder failed", err.Error())
}
}
func writeFile(newUser User) {
// 打开文件
filePtr, err := os.OpenFile("entity/User.json", os.O_APPEND|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
fmt.Println("Open file failed", err.Error())
return
}
defer filePtr.Close()
// 创建Json编码器
encoder := json.NewEncoder(filePtr)
persons = append(persons, newUser)
err = encoder.Encode(persons)
if err != nil {
fmt.Println("Encoder failed", err.Error())
}
}
测试
我们先使用go run main.go register --user=TestUser6 --password=123 --email=123 --telephone=123
来测试注册:
然后再次注册会提示用户名已经被使用的错误提示。
用户登录
要求
- 用户使用用户名和密码登录 Agenda 系统。
- 用户名和密码同时正确则登录成功并反馈一个成功登录的信息。否则,登录失败并反馈一个失败登录的信息。
**注意:**在这里我又增加了新的设定,用户登录后必须退出才能重新登录,但是用户登录后(注册后)可以不退出进行注册,而此时的当前用户是新注册的用户。
思路跟register
是一致的,只不过少了几个参数,故再次不做赘述,直接上代码。
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var loginUser User
// loginCmd represents the login command
var loginCmd = &cobra.Command{
Use: "login",
Short: "login",
Long: `login`,
Run: func(cmd *cobra.Command, args []string) {
loginUser.Username, _ = cmd.Flags().GetString("user")
loginUser.Password, _ = cmd.Flags().GetString("password")
readCurrent()
for _,value:=range current{
if value.Username!=""{
fmt.Println("You didn't Log out!")
return
}
}
readFile()
for _,value:=range persons{
if value.Username==loginUser.Username && value.Password==loginUser.Password{
fmt.Println("Login successfully!")
writeCurrent(loginUser)
return
}
}
fmt.Println("Wrong: Username or password is wrong!")
},
}
func init() {
rootCmd.AddCommand(loginCmd)
loginCmd.Flags().StringP("user", "u", "", "Help message for username")
loginCmd.Flags().StringP("password","p","","Password")
}
测试
使用刚刚注册的用户名和密码进行登录测试。
先退出刚才注册后自动登录的账号:
go run main.go logout
然后再用刚才注册的账号进行登录。
go run main.go login --user=TestUser6 --password=123
显示登陆成功。
用户登出
要求:
已登录的用户登出系统后,只能使用用户注册和用户登录功能。
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// logoutCmd represents the logout command
var logoutCmd = &cobra.Command{
Use: "logout",
Short: "A brief description of your command",
Long: `logout`,
Run: func(cmd *cobra.Command, args []string) {
readFile()
readCurrent()
for _,value:=range current{
if value.Username!=""{
fmt.Println("Log out successfully")
var u User
writeCurrent(u)
return
}
}
fmt.Println("Log out called")
},
}
func init() {
rootCmd.AddCommand(logoutCmd)
}