使用go搭建个人博客(四):cmd工具上传文件

  上一篇文章介绍结合数据库书写了处理上传文件的接口,将md文件接收并解析存放到了数据库,那么这一篇就来介绍怎么书写cmd命令行工具,上传文件。

创建命令行工具

  之前的文章有介绍过,创建命令行工具就直接使用github.com/urfave/cli这个库了,它能比较方便的设置命令参数和说明,配置文档

首先在cmd目录下创建main.go
cmd/main.go

1
2
3
4
5
6
7
package main

import (
...

"github.com/urfave/cli"
)

创建main函数,使用cli初始化命令行工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 创建App实例
app := cli.NewApp()
// 这个应用的名称
app.Name = "bpost"
// 使用介绍
app.Usage = "Managing blog posts"
// 版本
app.Version = "0.0.1"

var filePath string
var fileName string
var host string

// 设置命令行可以识别的参数 例如 bpost --upload ...
app.Flags = []cli.Flag{
cli.StringFlag{
// 名称, --upload 或者 --up
Name: "upload,up",
// 使用说明
Usage: "Upload an article by that `file path`",
// 获取的值得存放位置, bpost --upload abc.txt 这里的 abc.txt 就会存放到filePath变量中
Destination: &filePath,
},
cli.StringFlag{
Name: "remove,rm",
Usage: "Remove the article by that `file name`",
Destination: &fileName,
},
cli.StringFlag{
Name: "config,cf",
Usage: "Config http request `host`",
Destination: &host,
},
}

简单的初始化程序后,我们运行看看,这个工具长什么样子。在项目cmd目录下,执行go run main.go --help,当然你也是可以go build main.go或者go install main.go去打包成二进制文件,直接执行的,这里为了方便开发调试,就直接run了。可以看到命令行输出的信息为:

--help

可以看到一个简单的命令行工具已经成形,之后就是书写处理逻辑了,上传文件等。

上传文件

  上传文件会需要去请求接口,处理上传文件的接口上一篇文章已经写好了,我们这里就不多说了,有兴趣的可以看一下上一篇文章介绍的实现。

接着在mian.go中处理命令行工具的响应处理方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
func main() {
...
...
// 默认请求设置为本地的8888端口
var url = "http://localhost:8888"
// 查看是否存在配置文件,这里的配置文件很简单,里面只是存了一个请求地址的域,没有使用很麻烦的配置,这里推荐可以使用yaml的格式文件存储,并使用读取配置文件的库"github.com/spf13/viper",来进行读取。
isexists := exists("./url.config")
if isexists {
file, rdRrr := ioutil.ReadFile("./url.config")
if rdRrr != nil {
log.Fatalln("[ERROR] ", rdRrr)
}
// 有配置文件的话,就修改url的值
url = string(file)
}

// 命令行App执行后的响应方法
app.Action = func(c *cli.Context) error {
if filePath != "" {
upload(filePath, url)
}
if fileName != "" {
remove(fileName, url)
}
if host != "" {
config(host)
}
return nil
}
err := app.Run(os.Args)
checkErr(err)

}

func upload(filePath, url string) {
...
}
func remove(fileName, url string) {
...
}
func config(host string) {
...
}

上面已经把命令参数对应的响应方法已经处理完毕了,接下来只需要将upload函数完善,那么这个命令行工具就可以上传文件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
func upload(filePath, url string) {
_, err := os.Stat(filePath) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) == false {
log.Fatalf("%s 路径不存在", filePath)
}
}
// 创建表单文件
// CreateFormFile 用来创建表单,第一个参数是字段名,第二个参数是文件名
buf := new(bytes.Buffer)
writer := multipart.NewWriter(buf)
fileName := filepath.Base(filePath)
formFile, err := writer.CreateFormFile("upload", fileName)
if err != nil {
log.Fatalf("Create form file failed: %s\n", err)
}

// 从文件读取数据,写入表单
srcFile, err := os.Open(filePath)
if err != nil {
log.Fatalf("Open source file failed: %s\n", err)
}
defer srcFile.Close()
_, err = io.Copy(formFile, srcFile)
if err != nil {
log.Fatalf("Write to form file falied: %s\n", err)
}

// 发送表单
contentType := writer.FormDataContentType()
writer.Close() // 发送之前必须调用Close()以写入结尾行
var res *http.Response
res, err = http.Post(url+"/upload", contentType, buf)
if err != nil {
log.Fatalf("Post failed: %s\n", err)
}
defer res.Body.Close()
// 判断接口返回参数,查看是否上传成功
body, _ := ioutil.ReadAll(res.Body)
var dataMap map[string]interface{}
json.Unmarshal(body, &dataMap)
if dataMap["status"] != 0 {
log.Fatalf("Post failed: %s\n", dataMap["msg"])
}
log.Println("[SUCCESS] Upload file is successfully. ", filePath)
}

上面代码主要逻辑就是,创建表单文件,然后将准备上传文件的内容读取出来写入到表单文件,然后通过http发送表单文件。

写到这里,我们就可以上传一下这个命令行工具,看是否能正常上传文件。

首先第一步: 启动服务器: 在项目根目录下,运行go run main.go
第二部: 使用cmd工具上传文件,在cmd目录下运行go run main.go --up test1.md。test1.md里面的内容需要符合上一篇介绍的md格式,不然会上传失败等。如果大家使用我的源码进行测试,那可能需要新建自己的md文件,因为我源码上的数据库里面已经测试了几个,所以再test.md上传的话,会报已经存在的反馈。

运行结果

由图片可以看出,当我们上传文件的时候,服务正在执行sql进行数据库操作,当然这些信息是xorm在开发模式下才会出现的,是可以进行调整的。

最后

  cmd工具肯定不只有上传文件的功,大家还可以增加需要的功能,当然,服务器上就需要想要的处理接口。我的源码中cmd工具实现了上传文件、删除文件、配置上传地址等功能,如果里面有些代码看不完全的,可以去我的github上,查看完整的源码,直接运行下。欢迎留言或者使用邮箱(zz__0123@163.com)联系我讨论,初学实践分享,有很多不足,请多多指教。