大唐湘华 發表於 2025-11-26 10:42:49

go如何使用cobra启动项目

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、基本使用</a></li><li><a href="#_label1">二、实现项目中开发使用</a></li></ul></div><p class="maodian"><a name="_label0"></a></p><h2>一、基本使用</h2>
<p>1、安装依赖包</p>
<div class="jb51code"><pre class="brush:bash;">go get -u github.com/spf13/cobra@latest</pre></div>
<p>2、简单的创建几个命令</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
        "github.com/spf13/cobra"
        "os"
)
var rootCmd = &amp;cobra.Command{
        Use:   "api",
        Short: "短的地址",
        Long:"长的地址",
}
// 命令一
var mockCmd = &amp;cobra.Command{
        Use:   "mock",
        Short: "mock短的",
        Long:"mock长的",
}
// 命令二
var exportCmd = &amp;cobra.Command{
        Use:   "export",
        Short: "export短的",
        Long:"export长的",
}
func main() {
        rootCmd.AddCommand(mockCmd)
        rootCmd.AddCommand(exportCmd)
        err := rootCmd.Execute()
        if err != nil {
                os.Exit(1)
        }
}</pre></div>
<p>3、运行上面的代码</p>
<div class="jb51code"><pre class="brush:go;">go run main.go mock ---&gt; 输出mock长的
go run main.go export --&gt; export长的</pre></div>
<p>4、常见的字段说明</p>
<ul><li><code>PersistentPreRunE</code>执行之前,且在任何子命令运行之前都会调用</li><li><code>PersistentPostRun</code>执行之后,且在所有子命令执行后都会调用</li><li><code>RunE</code>当命令的主要逻辑执行时触发,即命令的核心功能实现</li></ul>
<p>5、加载外面传递的参数</p>
<p>先定义接收的变量</p>
<div class="jb51code"><pre class="brush:bash;">var name string</pre></div>
<p>使用命名接收外面的数据</p>
<div class="jb51code"><pre class="brush:go;">func init() {
        rootCmd.PersistentFlags().StringVarP(&amp;name, "name", "n", "", "外部传递值进来")
}</pre></div>
<p>运行命令</p>
<div class="jb51code"><pre class="brush:bash;">go run main.go export -n=hello
</pre></div>
<p class="maodian"><a name="_label1"></a></p><h2>二、实现项目中开发使用</h2>
<p>1、比如我们日常<code>gin</code>项目开发</p>
<div class="jb51code"><pre class="brush:go;">├── api
│   └── service.go
├── cmd
│   ├── root.go
│   └── start.go
├── config
│   └── config.go
├── etc
│   ├── application.dev.yml
│   └── application.prod.yml
├── main.go</pre></div>
<p>2、<code>cmd/root.go</code>的文件</p>
<div class="jb51code"><pre class="brush:go;">package cmd
import (
        "fmt"
        "gin-admin-api/test251119/config"
        "github.com/spf13/cobra"
        "os"
)
var (
        cfgFile string
        cfg   *config.Config
)
var rootCmd = &amp;cobra.Command{
        Use:   "cmd",
        Short: "gin项目开发启动",
        Long:"gin项目开发启动",
        PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
                if cmd.Name() == "help" {
                        return nil
                }
                // 加载配置文件
                var err error
                cfg, err = config.Load(cfgFile)
                if err != nil {
                        return fmt.Errorf("加载配置文件失败: %w", err)
                }
                return nil
        },
        PersistentPostRun: func(cmd *cobra.Command, args []string) {
                // TODO 可以做数据库的关闭
        },
}
func init() {
        rootCmd.PersistentFlags().StringVarP(&amp;cfgFile, "etc", "c", "etc/application.dev.yml", "请输入启动的配置文件")
}
func Execute() {
        rootCmd.AddCommand(cmdStart)
        err := rootCmd.Execute()
        if err != nil {
                os.Exit(1)
        }
}</pre></div>
<p>3、<code>cmd/start.go</code>文件</p>
<div class="jb51code"><pre class="brush:go;">package cmd
import (
        "fmt"
        "gin-admin-api/test251119/api"
        "github.com/spf13/cobra"
        "os"
)
var cmdStart = &amp;cobra.Command{
        Use:   "start",
        Short: "启动项目",
        Long:"启动项目",
        Run: func(cmd *cobra.Command, args []string) {
                if err := startDaemon(); err != nil {
                        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
                        os.Exit(1)
                }
        },
}
func startDaemon() error {
        server := api.NewServer(cfg)
        err := server.ListenAndServe()
        return err
}</pre></div>
<p>4、<code>config/config.go</code>文件内容</p>
<div class="jb51code"><pre class="brush:go;">package config
import (
        "fmt"
        "github.com/spf13/viper"
        "os"
        "path/filepath"
)
type Config struct {
        Port int `mapstructure:"port"` // 启动端口
}
// Load loads configuration from file
func Load(cfgFile string) (*Config, error) {
        v := viper.New()
        if cfgFile != "" {
                v.SetConfigFile(cfgFile)
        } else {
                configDir := "./etc"
                if _, err := os.Stat(configDir); os.IsNotExist(err) {
                        if err := os.MkdirAll(configDir, 0755); err != nil {
                                return nil, fmt.Errorf("创建目录失败: %w", err)
                        }
                }
                v.AddConfigPath(configDir)
                v.SetConfigName("application.dev")
                v.SetConfigType("yml")
                configPath := filepath.Join(configDir, "application.dev.yml")
                if _, err := os.Stat(configPath); os.IsNotExist(err) {
                        fmt.Println("Config file not found, creating default config:", configPath)
                        // Copy example file if it exists
                        examplePath := filepath.Join(configDir, "application.dev.example")
                        if _, err := os.Stat(examplePath); err == nil {
                                if exampleData, err := os.ReadFile(examplePath); err == nil {
                                        if err := os.WriteFile(configPath, exampleData, 0644); err != nil {
                                                fmt.Printf("写入默认配置文件失败: %v\n", err)
                                        } else {
                                                fmt.Println("读取默认配置文件 成功")
                                        }
                                }
                        }
                }
        }
        // 设置默认值
        v.SetDefault("port", ":8080")
        if err := v.ReadInConfig(); err != nil {
                return nil, fmt.Errorf("reading config file: %w", err)
        }
        fmt.Println("Using config file:", v.ConfigFileUsed())
        var config Config
        if err := v.Unmarshal(&amp;config); err != nil {
                return nil, fmt.Errorf("unmarshaling config: %w", err)
        }
        return &amp;config, nil
}</pre></div>
<p>5、<code>api/service.go</code>文件内容</p>
<div class="jb51code"><pre class="brush:go;">package api
import (
        "fmt"
        "gin-admin-api/test251119/config"
        "github.com/gin-gonic/gin"
        "net/http"
)
type Server struct {
        server *http.Server
        router *gin.Engine
        config *config.Config
}
// NewServer 创建新的 Server 实例
func NewServer(cfg *config.Config) *Server {
        gin.SetMode(gin.DebugMode)
        router := gin.Default()
        router.Use(gin.Recovery())
        // 创建 HTTP 服务器
        srv := &amp;http.Server{
                Addr:    fmt.Sprintf(":%d", cfg.Port),
                Handler: router,
        }
        return &amp;Server{
                server: srv,
                router: router,
                config: cfg,
        }
}
// ListenAndServe 启动服务并监听端口
func (s *Server) ListenAndServe() error {
        fmt.Printf("服务启动:http://localhost:%d\n", s.config.Port)
        // 启动服务并修复端口格式
        return s.server.ListenAndServe()
}</pre></div>
<p>6、<code>application.dev.yml</code>文件</p>
<div class="jb51code"><pre class="brush:plain;">port: 9000
salt: abcdef</pre></div>
<p>7、启动文件<code>main.go</code></p>
<div class="jb51code"><pre class="brush:go;">package main
import "gin-admin-api/test251119/cmd"
func main() {
        cmd.Execute()
}</pre></div>
<p>8、启动</p>
<div class="jb51code"><pre class="brush:go;">go run main.go start默认使用dev文件
go run main.go start -c etc/application.prod.yml</pre></div>
頁: [1]
查看完整版本: go如何使用cobra启动项目