CLI 命令行实用程序开发实战 - Agenda

完整代码:http://139.9.57.167:20080/share/bmkj0qu76kvs669u1vn0?secret=false

一. 安装并简单使用cobra

1. 安装cobra

在vsc的gopath路径下使用命令安装cobra:

go get -v github.com/spf13/cobra/cobra

2. 生成可执行文件

使用命令生成cobra可执行文件:

go install github.com/spf13/cobra/cobra

此时可在bin文件夹下面发现生成了cobra.exe:
CLI 命令行实用程序开发实战 - Agenda_第1张图片

3. 简单使用cobra

1)首先用cobra init新建一个demo:

进入src文件夹,在控制台上使用命令创建demo:

cobra init demo --pkg-name=demo

2)使用cobra add register增加register命令:

进入上面过程中生成的demo文件夹,使用命令:

cobra add register


需要的文件就产生了:

3)修改 register.go:

init()添加中添加:

registerCmd.Flags().StringP("user", "u", "Anonymous", "Help message for username")

CLI 命令行实用程序开发实战 - Agenda_第2张图片
Run匿名回调函数中添加:

username, _ := cmd.Flags().GetString("user")
fmt.Println("register called by " + username)

CLI 命令行实用程序开发实战 - Agenda_第3张图片

4)测试命令:

使用命令测试:

go run main.go register --user=TestUser

出现结果:

二. agenda 开发项目

1. agenda项目目录

cmd :存放命令实现代码
entity :存放 User 对象读写与处理逻辑
data : 存储User信息和生成log
service:存放命令实现代码所需借用的功能函数
loghelper:存放实现log的相关代码
deepcopy:存放复制功能代码

2. 功能实现
a.用户注册

注册新用户时,用户需设置一个唯一的用户名和一个密码。另外,还需登记邮箱及电话信息。
如果注册时提供的用户名已由其他用户使用,应反馈一个适当的出错信息;成功注册后,亦应反馈一个成功注册的信息。

实现说明:

命令register用于创建新用户,需要唯一的用户名和相应的密码,以及个人邮箱和电话号码:

$register -u leaf -p 123456 -m 13.com -c 134
or
$register -u=leaf -p=123456 -m=13.com -c=134

其中-u表示用户名,后面添加用户名参数
-p表示用户名对应的密码
-m表示个人邮箱
-c表示电话号码

代码实现:

创建用户时必须完善用户名、密码、个人邮箱以及电话号码四项信息,所以这四个参数不能为空,同时还要限制用户名不能和已注册的用户名重复,具体代码如下:

package cmd

import (
	"demo/service"
	"fmt"
	"github.com/spf13/cobra"
)

// registerCmd represents the register command
var registerCmd = &cobra.Command{
	Use:   "register",
	Short: "register user",
	Run: func(cmd *cobra.Command, args []string) {
		tmp_u, _ := cmd.Flags().GetString("username")
		tmp_p, _ := cmd.Flags().GetString("password")
		tmp_m, _ := cmd.Flags().GetString("email")
		tmp_c, _ := cmd.Flags().GetString("cellphone")
		if tmp_u == "" || tmp_p == "" || tmp_m == "" || tmp_c == "" {
			fmt.Println("Please tell us your username[-u], password[-p], email[-m], cellphone[-c]")
			return
		}
		pass, err := service.UserRegister(tmp_u, tmp_p, tmp_m, tmp_c)
		if pass == false {
			fmt.Println("Username existed!")
			return
		} else {
			if err != nil {
				fmt.Println("Some unexpected error happened when try to record your info,Please read error.log for detail")
				return
			} else {
				fmt.Println("Successfully register!")
			}
		}
	},
}

func init() {
	rootCmd.AddCommand(registerCmd)
	registerCmd.Flags().StringP("username", "u", "", "username that haven't be registered")
	registerCmd.Flags().StringP("password", "p", "", "your password, must be longer than or equal to 6 characters")
	registerCmd.Flags().StringP("email", "m", "", "your email address")
	registerCmd.Flags().StringP("cellphone", "c", "", "your cellphone number")
}

具体创建时借助了service中的UserRegister函数,该函数首先查询已有用户列表中是否存在相同用户名,若存在则返回false,否则结合其他三项信息创建用户,并返回true:

func UserRegister(username string, password string, email string, phone string) (bool, error) {
	user := entity.QueryUser(func(u *entity.User) bool {
		return u.Name == username
	})
	if len(user) == 1 {
		errLog.Println("User Register: the username has already existed")
		return false, nil
	}
	entity.CreateUser(&entity.User{username, password, email, phone})
	if err := entity.Sync(); err != nil {
		return true, err
	}
	return true, nil
}
b.用户登录

用户使用用户名和密码登录 Agenda 系统。
用户名和密码同时正确则登录成功并反馈一个成功登录的信息。否则,登录失败并反馈一个失败登录的信息。

实现说明:

用命令login -u -p来实现用户登录功能,示例如下:

$ login -u leaf -p 123456
or
$ login -u=leaf -p=123456

其中-u表示用户名,后面添加用户名参数
-p表示用户名对应的密码

代码实现:

login需要用正确的用户名以及对应密码进行登录,所以要限制用户名和密码不能为空,当已经登录了一个用户时,需要先退出当前登录,再登录新的用户。具体代码如下:

package cmd

import (
	"fmt"
	"demo/service"
	"github.com/spf13/cobra"
)



// loginCmd represents the login command
var loginCmd = &cobra.Command{
	Use:   "login",
	Short: "for guest to login",
	Long:  `for guests to enter correct username and password to login `,
	Run: func(cmd *cobra.Command, args []string) {
		username, _ := cmd.Flags().GetString("username")
		if username == "" {
			fmt.Println("username required.")
			return 
		}
		password, _ := cmd.Flags().GetString("password")
		if password == "" {
			fmt.Println("password required.")
			return 
		}
		if _, flag := service.GetCurUser(); flag == true {
			fmt.Println("Please logout the current account")
			return
		}
		if tf := service.UserLogin(username, password); tf == true {
			fmt.Println("Login Successfully. Current User: ", username)
		}  else {
			fmt.Println("Failed to log in! Please input the correct username and password!")
		}
		return 
	},
}

func init() {
	rootCmd.AddCommand(loginCmd)
	loginCmd.Flags().StringP("username", "u", "", "the name of user to log in")
	loginCmd.Flags().StringP("password", "p", "", "the password of user to log in")
}

对应的service里面的函数功能是,GetCurUser()先通过entity中函数查询当前是否有用户正在登录,如果有,则返回true,否则返回false;

func GetCurUser() (entity.User, bool) {
	if cu, err := entity.GetCurUser(); err != nil {
		return cu, false
	} else {
		return cu, true
	}
}

UserLogin(username string, password string)函数通过entity中函数查询输入用户名和密码是否匹配,匹配则返回true,否则返回false;同时登录成功时会将该用户名存储为当前用户名:

func UserLogin(username string, password string) bool {
	user := entity.QueryUser(func(u *entity.User) bool {
		if u.Name == username && u.Password == password {
			return true
		}
		return false
	})
	if len(user) == 0 {
		errLog.Println("Login: User not Exist")
		return false
	}
	entity.SetCurUser(&user[0])
	if err := entity.Sync(); err != nil {
		errLog.Println("Login: error occurred when set curuser")
		return false
	}
	return true
}
c.用户登出

已登录的用户登出系统后,只能使用用户注册和用户登录功能。

实现说明:

用户登出后会切换到默认用户,命令形式为:

$ logout
代码实现:

登出失败时会记录错误信息。具体代码如下:

package cmd

import (
	"fmt"
	"demo/service"
	"github.com/spf13/cobra"
)

// logoutCmd represents the logout command
var logoutCmd = &cobra.Command{
	Use:   "logout",
	Short: "logout",
	Long:  `log out as a guest`,
	// Args:  cobra.MaximumNArgs(0),
	Run: func(cmd *cobra.Command, args []string) {
		if err := service.UserLogout(); err != true {
			fmt.Println("Error! Details for error.log!")
		} else {
			fmt.Println("Logout Successfully!")
		}
	},
}

func init() {
	rootCmd.AddCommand(logoutCmd)
}

对应的service里面的函数功能是,UserLogout()通过entity中函数实现用户登出。entity中相关函数会将当前用户名设为空:

func Logout() error {
	curUserName = nil
	return Sync()
}
func Sync() error {
	if err := writeToFile(); err != nil {
		errLog.Println("writeToFile fail:", err)
		return err
	}
	return nil
}
3.功能测试
创建用户:

创建新用户:

当用户名和已有用户名重复时报错:

用户登录:

密码和用户不匹配时会报错:

相匹配时登录成功:

当前用户未退出,想再次登录时会报错:

用户登出:

你可能感兴趣的:(学习)