{"id":427822,"date":"2021-04-17T14:30:49","date_gmt":"2021-04-17T06:30:49","guid":{"rendered":"http:\/\/4563.org\/?p=427822"},"modified":"2021-04-17T14:30:49","modified_gmt":"2021-04-17T06:30:49","slug":"mixgo-v1-1-%e5%8f%91%e5%b8%83-go-%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e8%84%9a%e6%89%8b%e6%9e%b6%e5%b7%a5%e5%85%b7","status":"publish","type":"post","link":"http:\/\/4563.org\/?p=427822","title":{"rendered":"MixGo v1.1 \u53d1\u5e03, Go \u5feb\u901f\u5f00\u53d1\u811a\u624b\u67b6\u5de5\u5177"},"content":{"rendered":"<div>\n<div>\n<div>\n<h1>                  MixGo v1.1 \u53d1\u5e03, Go \u5feb\u901f\u5f00\u53d1\u811a\u624b\u67b6\u5de5\u5177               <\/h1>\n<p> <\/p>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : onanying <\/span>  <span><i><\/i> 3<\/span> <\/div>\n<div> <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div isfirst=\"1\"> <\/p>\n<p>Mix Go \u662f\u4e00\u4e2a\u57fa\u4e8e Go \u8fdb\u884c\u5feb\u901f\u5f00\u53d1\u7684\u5b8c\u6574\u7cfb\u7edf\uff0c\u7c7b\u4f3c\u524d\u7aef\u7684 <code>Vue CLI<\/code>\uff0c\u63d0\u4f9b\uff1a<\/p>\n<ul>\n<li> \u901a\u8fc7 <code>mix-go\/mixcli<\/code> \u5b9e\u73b0\u7684\u4ea4\u4e92\u5f0f\u9879\u76ee\u811a\u624b\u67b6\uff1a\n<ul>\n<li>\u53ef\u4ee5\u751f\u6210 <code>cli<\/code>, <code>api<\/code>, <code>web<\/code>, <code>grpc<\/code> \u591a\u79cd\u9879\u76ee\u4ee3\u7801<\/li>\n<li>\u751f\u6210\u7684\u4ee3\u7801\u5f00\u7bb1\u5373\u7528<\/li>\n<li>\u53ef\u9009\u62e9\u662f\u5426\u9700\u8981 <code>.env<\/code> \u73af\u5883\u914d\u7f6e<\/li>\n<li>\u53ef\u9009\u62e9\u662f\u5426\u9700\u8981 <code>.yml<\/code>, <code>.json<\/code>, <code>.toml<\/code> \u7b49\u72ec\u7acb\u914d\u7f6e<\/li>\n<li>\u53ef\u9009\u62e9\u4f7f\u7528 <code>gorm<\/code>, <code>xorm<\/code> \u7684\u6570\u636e\u5e93<\/li>\n<li>\u53ef\u9009\u62e9\u4f7f\u7528 <code>logrus<\/code>, <code>zap<\/code> \u7684\u65e5\u5fd7\u5e93<\/li>\n<\/ul>\n<\/li>\n<li>\u901a\u8fc7 <code>mix-go\/xcli<\/code> \u5b9e\u73b0\u7684\u547d\u4ee4\u884c\u539f\u578b\u5f00\u53d1\u3002<\/li>\n<li>\u57fa\u4e8e <code>mix-go\/xdi<\/code> \u7684 DI, IoC \u5bb9\u5668\u3002<\/li>\n<\/ul>\n<h2>Github | Gitee<\/h2>\n<ul>\n<li>https:\/\/github.com\/mix-go\/mix<\/li>\n<li>https:\/\/gitee.com\/mix-go\/mix<\/li>\n<\/ul>\n<h2>\u5feb\u901f\u5f00\u59cb<\/h2>\n<p>\u5b89\u88c5<\/p>\n<pre><code>go get github.com\/mix-go\/mixcli <\/code><\/pre>\n<p>\u521b\u5efa\u9879\u76ee<\/p>\n<pre><code>$ mixcli new hello Use the arrow keys to navigate: \u2193 \u2191 \u2192 \u2190  ? Select project type:   \u25b8 CLI     API     Web (contains the websocket)     gRPC <\/code><\/pre>\n<h2>\u6280\u672f\u4ea4\u6d41<\/h2>\n<p>\u77e5\u4e4e\uff1a https:\/\/www.zhihu.com\/people\/onanying<br \/> \u5fae\u535a\uff1a http:\/\/weibo.com\/onanying<br \/> \u5b98\u65b9 QQ \u7fa4\uff1a284806582, 825122875\uff0c\u6572\u95e8\u6697\u53f7\uff1agoer<\/p>\n<h2>\u7f16\u5199\u4e00\u4e2a CLI \u7a0b\u5e8f<\/h2>\n<p>\u9996\u5148\u6211\u4eec\u4f7f\u7528 <code>mixcli<\/code> \u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u9879\u76ee\u9aa8\u67b6\uff1a<\/p>\n<pre><code>$ mixcli new hello Use the arrow keys to navigate: \u2193 \u2191 \u2192 \u2190  ? Select project type:   \u25b8 CLI     API     Web (contains the websocket)     gRPC <\/code><\/pre>\n<p>\u751f\u6210\u9aa8\u67b6\u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\uff1a<\/p>\n<pre><code>. \u251c\u2500\u2500 README.md \u251c\u2500\u2500 bin \u251c\u2500\u2500 commands \u251c\u2500\u2500 conf \u251c\u2500\u2500 configor \u251c\u2500\u2500 di \u251c\u2500\u2500 dotenv \u251c\u2500\u2500 go.mod \u251c\u2500\u2500 go.sum \u251c\u2500\u2500 logs \u2514\u2500\u2500 main.go <\/code><\/pre>\n<p><code>mian.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<ul>\n<li><code>xcli.AddCommand<\/code> \u65b9\u6cd5\u4f20\u5165\u7684 <code>commands.Commands<\/code> \u5b9a\u4e49\u4e86\u5168\u90e8\u7684\u547d\u4ee4<\/li>\n<\/ul>\n<pre><code>package main  import (   \"github.com\/mix-go\/cli-skeleton\/commands\"   _ \"github.com\/mix-go\/cli-skeleton\/configor\"   _ \"github.com\/mix-go\/cli-skeleton\/di\"   _ \"github.com\/mix-go\/cli-skeleton\/dotenv\"   \"github.com\/mix-go\/dotenv\"   \"github.com\/mix-go\/xcli\" )  func main() {   xcli.SetName(\"app\").     SetVersion(\"0.0.0-alpha\").     SetDebug(dotenv.Getenv(\"APP_DEBUG\").Bool(false))   xcli.AddCommand(commands.Commands...).Run() } <\/code><\/pre>\n<p><code>commands\/main.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u6211\u4eec\u53ef\u4ee5\u5728\u8fd9\u91cc\u81ea\u5b9a\u4e49\u547d\u4ee4\uff0c\u67e5\u770b\u66f4\u591a<\/p>\n<ul>\n<li><code>RunI<\/code> \u5b9a\u4e49\u4e86 <code>hello<\/code> \u547d\u4ee4\u6267\u884c\u7684\u63a5\u53e3\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528 <code>Run<\/code> \u8bbe\u5b9a\u4e00\u4e2a\u533f\u540d\u51fd\u6570<\/li>\n<\/ul>\n<pre><code>package commands  import (   \"github.com\/mix-go\/xcli\" )  var Commands = []*xcli.Command{   {     Name:  \"hello\",     Short: \"tEcho demo\",     Options: []*xcli.Option{       {         Names: []string{\"n\", \"name\"},         Usage: \"Your name\",       },       {         Names: []string{\"say\"},         Usage: \"tSay ...\",       },     },     RunI: &amp;HelloCommand{},   }, } <\/code><\/pre>\n<p><code>commands\/hello.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u4e1a\u52a1\u4ee3\u7801\u5199\u5728 <code>HelloCommand<\/code> \u7ed3\u6784\u4f53\u7684 <code>main<\/code> \u65b9\u6cd5\u4e2d<\/p>\n<ul>\n<li>\u4ee3\u7801\u4e2d\u53ef\u4ee5\u4f7f\u7528 <code>flag<\/code> \u83b7\u53d6\u547d\u4ee4\u884c\u53c2\u6570\uff0c\u67e5\u770b\u66f4\u591a<\/li>\n<\/ul>\n<pre><code>package commands  import (   \"fmt\"   \"github.com\/mix-go\/xcli\/flag\" )  type HelloCommand struct { }  func (t *HelloCommand) Main() {   name := flag.Match(\"n\", \"name\").String(\"OpenMix\")   say := flag.Match(\"say\").String(\"Hello, World!\")   fmt.Printf(\"%s: %sn\", name, say) } <\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\u6211\u4eec\u7f16\u8bd1\u4e0a\u9762\u7684\u7a0b\u5e8f\uff1a<\/p>\n<ul>\n<li>linux &amp; macOS<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go main.go <\/code><\/pre>\n<ul>\n<li>win<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go.exe main.go <\/code><\/pre>\n<p>\u67e5\u770b\u5168\u90e8\u547d\u4ee4\u7684\u5e2e\u52a9\u4fe1\u606f\uff1a<\/p>\n<pre><code>$ cd bin $ .\/go_build_main_go  Usage: .\/go_build_main_go [OPTIONS] COMMAND [opt...]  Global Options:   -h, --help    Print usage   -v, --version Print version information  Commands:   hello         Echo demo  Run '.\/go_build_main_go COMMAND --help' for more information on a command.  Developed with Mix Go framework. (openmix.org\/mix-go) <\/code><\/pre>\n<p>\u67e5\u770b\u4e0a\u9762\u7f16\u5199\u7684 hello \u547d\u4ee4\u7684\u5e2e\u52a9\u4fe1\u606f\uff1a<\/p>\n<pre><code>$ .\/go_build_main_go hello --help Usage: .\/go_build_main_go hello [opt...]  Command Options:   -n, --name    Your name   --say         Say ...  Developed with Mix Go framework. (openmix.org\/mix-go) <\/code><\/pre>\n<p>\u6267\u884c <code>hello<\/code> \u547d\u4ee4\uff0c\u5e76\u4f20\u5165\u4e24\u4e2a\u53c2\u6570\uff1a<\/p>\n<pre><code>$ .\/go_build_main_go hello --name=liujian --say=hello liujian: hello <\/code><\/pre>\n<h3>\u7f16\u5199\u4e00\u4e2a Worker Pool \u961f\u5217\u6d88\u8d39<\/h3>\n<p>\u961f\u5217\u6d88\u8d39\u662f\u9ad8\u5e76\u53d1\u7cfb\u7edf\u4e2d\u6700\u5e38\u7528\u7684\u5f02\u6b65\u5904\u7406\u6a21\u578b\uff0c\u901a\u5e38\u6211\u4eec\u662f\u7f16\u5199\u4e00\u4e2a CLI \u547d\u4ee4\u884c\u7a0b\u5e8f\u5728\u540e\u53f0\u6267\u884c Redis \u3001RabbitMQ \u7b49 MQ \u7684\u961f\u5217\u6d88\u8d39\uff0c\u5e76\u5c06\u5904\u7406\u7ed3\u679c\u843d\u5730\u5230 mysql \u7b49\u6570\u636e\u5e93\u4e2d\uff0c\u7531\u4e8e\u8fd9\u7c7b\u9700\u6c42\u7684\u6807\u51c6\u5316\u6bd4\u8f83\u5bb9\u6613\uff0c\u56e0\u6b64\u6211\u4eec\u5f00\u53d1\u4e86 mix-go\/xwp \u5e93\u6765\u5904\u7406\u8fd9\u7c7b\u9700\u6c42\uff0c\u57fa\u672c\u4e0a\u5927\u90e8\u5206\u5f02\u6b65\u5904\u7406\u7c7b\u9700\u6c42\u90fd\u53ef\u4f7f\u7528\u3002<\/p>\n<p>\u65b0\u5efa <code>commands\/workerpool.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<ul>\n<li><code>workerpool.NewDispatcher(jobQueue, 15, NewWorker)<\/code> \u521b\u5efa\u4e86\u4e00\u4e2a\u8c03\u5ea6\u5668<\/li>\n<li><code>NewWorker<\/code> \u8d1f\u8d23\u521d\u59cb\u5316\u6267\u884c\u4efb\u52a1\u7684\u5de5\u4f5c\u534f\u7a0b<\/li>\n<li>\u4efb\u52a1\u6570\u636e\u4f1a\u5728 <code>worker.Do<\/code> \u65b9\u6cd5\u4e2d\u89e6\u53d1\uff0c\u6211\u4eec\u53ea\u9700\u8981\u5c06\u6211\u4eec\u7684\u4e1a\u52a1\u903b\u8f91\u5199\u5230\u8be5\u65b9\u6cd5\u4e2d\u5373\u53ef<\/li>\n<li>\u5f53\u7a0b\u5e8f\u63a5\u6536\u5230\u8fdb\u7a0b\u9000\u51fa\u4fe1\u53f7\u65f6\uff0c\u8c03\u5ea6\u5668\u80fd\u5e73\u6ed1\u63a7\u5236\u6240\u6709\u7684 Worker \u5728\u6267\u884c\u5b8c\u961f\u5217\u91cc\u5168\u90e8\u7684\u4efb\u52a1\u540e\u518d\u9000\u51fa\u8c03\u5ea6\uff0c\u4fdd\u8bc1\u6570\u636e\u7684\u5b8c\u6574\u6027<\/li>\n<\/ul>\n<pre><code>package commands  import (     \"context\"     \"fmt\"     \"github.com\/mix-go\/cli-skeleton\/di\"     \"github.com\/mix-go\/xwp\"     \"os\"     \"os\/signal\"     \"strings\"     \"syscall\"     \"time\" )  type worker struct {     xwp.WorkerTrait }  func (t *worker) Do(data interface{}) {     defer func() {         if err := recover(); err != nil {             logger := di.Logrus()             logger.Error(err)         }     }()      \/\/ \u6267\u884c\u4e1a\u52a1\u5904\u7406     \/\/ ...          \/\/ \u5c06\u5904\u7406\u7ed3\u679c\u843d\u5730\u5230\u6570\u636e\u5e93     \/\/ ... }  func NewWorker() xwp.Worker {     return &amp;worker{} }  type WorkerPoolDaemonCommand struct { }  func (t *WorkerPoolDaemonCommand) Main() {     redis := globals.Redis()     jobQueue := make(chan interface{}, 50)     d := xwp.NewDispatcher(jobQueue, 15, NewWorker)      ch := make(chan os.Signal)     signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)     go func() {         &lt;-ch         d.Stop()     }()      go func() {         for {             res, err := redis.BRPop(context.Background(), 3*time.Second, \"foo\").Result()             if err != nil {                 if strings.Contains(err.Error(), \"redis: nil\") {                     continue                 }                 fmt.Println(fmt.Sprintf(\"Redis Error: %s\", err))                 d.Stop();                 return             }             \/\/ brPop \u547d\u4ee4\u6700\u540e\u4e00\u4e2a\u952e\u624d\u662f\u503c             jobQueue &lt;- res[1]         }     }()      d.Run() \/\/ \u963b\u585e\u4ee3\u7801\uff0c\u76f4\u5230\u4efb\u52a1\u5168\u90e8\u6267\u884c\u5b8c\u6210\u5e76\u4e14\u5168\u90e8 Worker \u505c\u6b62 } <\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\u53ea\u9700\u8981\u628a\u8fd9\u4e2a\u547d\u4ee4\u901a\u8fc7 <code>xcli.AddCommand<\/code> \u6ce8\u518c\u5230 CLI \u4e2d\u5373\u53ef\u3002<\/p>\n<h2>\u7f16\u5199\u4e00\u4e2a API \u670d\u52a1<\/h2>\n<p>\u9996\u5148\u6211\u4eec\u4f7f\u7528 <code>mixcli<\/code> \u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u9879\u76ee\u9aa8\u67b6\uff1a<\/p>\n<pre><code>$ mixcli new hello Use the arrow keys to navigate: \u2193 \u2191 \u2192 \u2190  ? Select project type:     CLI   \u25b8 API     Web (contains the websocket)     gRPC <\/code><\/pre>\n<p>\u751f\u6210\u9aa8\u67b6\u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\uff1a<\/p>\n<pre><code>. \u251c\u2500\u2500 README.md \u251c\u2500\u2500 bin \u251c\u2500\u2500 commands \u251c\u2500\u2500 conf \u251c\u2500\u2500 configor \u251c\u2500\u2500 controllers \u251c\u2500\u2500 di \u251c\u2500\u2500 dotenv \u251c\u2500\u2500 go.mod \u251c\u2500\u2500 go.sum \u251c\u2500\u2500 main.go \u251c\u2500\u2500 middleware \u251c\u2500\u2500 routes \u2514\u2500\u2500 runtime <\/code><\/pre>\n<p><code>mian.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<ul>\n<li><code>xcli.AddCommand<\/code> \u65b9\u6cd5\u4f20\u5165\u7684 <code>commands.Commands<\/code> \u5b9a\u4e49\u4e86\u5168\u90e8\u7684\u547d\u4ee4<\/li>\n<\/ul>\n<pre><code>package main  import (   \"github.com\/mix-go\/api-skeleton\/commands\"   _ \"github.com\/mix-go\/api-skeleton\/configor\"   _ \"github.com\/mix-go\/api-skeleton\/di\"   _ \"github.com\/mix-go\/api-skeleton\/dotenv\"   \"github.com\/mix-go\/dotenv\"   \"github.com\/mix-go\/xcli\" )  func main() {   xcli.SetName(\"app\").     SetVersion(\"0.0.0-alpha\").     SetDebug(dotenv.Getenv(\"APP_DEBUG\").Bool(false))   xcli.AddCommand(commands.Commands...).Run() } <\/code><\/pre>\n<p><code>commands\/main.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u6211\u4eec\u53ef\u4ee5\u5728\u8fd9\u91cc\u81ea\u5b9a\u4e49\u547d\u4ee4\uff0c\u67e5\u770b\u66f4\u591a<\/p>\n<ul>\n<li><code>RunI<\/code> \u6307\u5b9a\u4e86\u547d\u4ee4\u6267\u884c\u7684\u63a5\u53e3\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528 <code>Run<\/code> \u8bbe\u5b9a\u4e00\u4e2a\u533f\u540d\u51fd\u6570<\/li>\n<\/ul>\n<pre><code>package commands  import (   \"github.com\/mix-go\/xcli\" )  var Commands = []*xcli.Command{   {     Name:  \"api\",     Short: \"tStart the api server\",     Options: []*xcli.Option{       {         Names: []string{\"a\", \"addr\"},         Usage: \"tListen to the specified address\",       },       {         Names: []string{\"d\", \"daemon\"},         Usage: \"tRun in the background\",       },     },     RunI: &amp;APICommand{},   }, } <\/code><\/pre>\n<p><code>commands\/api.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u4e1a\u52a1\u4ee3\u7801\u5199\u5728 <code>APICommand<\/code> \u7ed3\u6784\u4f53\u7684 <code>main<\/code> \u65b9\u6cd5\u4e2d\uff0c\u751f\u6210\u7684\u4ee3\u7801\u4e2d\u5df2\u7ecf\u5305\u542b\u4e86\uff1a<\/p>\n<ul>\n<li>\u76d1\u542c\u4fe1\u53f7\u505c\u6b62\u670d\u52a1<\/li>\n<li>\u6839\u636e\u6a21\u5f0f\u6253\u5370\u65e5\u5fd7<\/li>\n<li>\u53ef\u9009\u7684\u540e\u53f0\u5b88\u62a4\u6267\u884c<\/li>\n<\/ul>\n<p>\u57fa\u672c\u4e0a\u65e0\u9700\u4fee\u6539\u5373\u53ef\u4e0a\u7ebf\u4f7f\u7528<\/p>\n<pre><code>package commands  import (   \"context\"   \"fmt\"   \"github.com\/gin-gonic\/gin\"   \"github.com\/mix-go\/api-skeleton\/di\"   \"github.com\/mix-go\/api-skeleton\/routes\"   \"github.com\/mix-go\/dotenv\"   \"github.com\/mix-go\/xcli\/flag\"   \"github.com\/mix-go\/xcli\/process\"   \"os\"   \"os\/signal\"   \"strings\"   \"syscall\"   \"time\" )  type APICommand struct { }  func (t *APICommand) Main() {   if flag.Match(\"d\", \"daemon\").Bool() {     process.Daemon()   }    logger := di.Logrus()   server := di.Server()   addr := dotenv.Getenv(\"GIN_ADDR\").String(\":8080\")   mode := dotenv.Getenv(\"GIN_MODE\").String(gin.ReleaseMode)    \/\/ server   gin.SetMode(mode)   router := gin.New()   routes.SetRoutes(router)   server.Addr = flag.Match(\"a\", \"addr\").String(addr)   server.Handler = router    \/\/ signal   ch := make(chan os.Signal)   signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)   go func() {     &lt;-ch     logger.Info(\"Server shutdown\")     ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)     if err := server.Shutdown(ctx); err != nil {       logger.Errorf(\"Server shutdown error: %s\", err)     }   }()    \/\/ logger   if mode != gin.ReleaseMode {     handlerFunc := gin.LoggerWithConfig(gin.LoggerConfig{       Formatter: func(params gin.LogFormatterParams) string {         return fmt.Sprintf(\"%s|%s|%d|%s\",           params.Method,           params.Path,           params.StatusCode,           params.ClientIP,         )       },       Output: logger.Out,     })     router.Use(handlerFunc)   }    \/\/ run   welcome()   logger.Infof(\"Server start at %s\", server.Addr)   if err := server.ListenAndServe(); err != nil &amp;&amp; !strings.Contains(err.Error(), \"http: Server closed\") {     panic(err)   } } <\/code><\/pre>\n<p>\u5728 <code>routes\/main.go<\/code> \u6587\u4ef6\u4e2d\u914d\u7f6e\u8def\u7531\uff1a<\/p>\n<p>\u5df2\u7ecf\u5305\u542b\u4e00\u4e9b\u5e38\u7528\u5b9e\u4f8b\uff0c\u53ea\u9700\u8981\u5728\u8fd9\u91cc\u65b0\u589e\u8def\u7531\u5373\u53ef\u5f00\u59cb\u5f00\u53d1<\/p>\n<pre><code>package routes  import (   \"github.com\/gin-gonic\/gin\"   \"github.com\/mix-go\/api-skeleton\/controllers\"   \"github.com\/mix-go\/api-skeleton\/middleware\" )  func SetRoutes(router *gin.Engine) {   router.Use(gin.Recovery()) \/\/ error handle    router.GET(\"hello\",     middleware.CorsMiddleware(),     func(ctx *gin.Context) {       hello := controllers.HelloController{}       hello.Index(ctx)     },   )    router.POST(\"users\/add\",     middleware.AuthMiddleware(),     func(ctx *gin.Context) {       hello := controllers.UserController{}       hello.Add(ctx)     },   )    router.POST(\"auth\", func(ctx *gin.Context) {     auth := controllers.AuthController{}     auth.Index(ctx)   }) } <\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\u6211\u4eec\u7f16\u8bd1\u4e0a\u9762\u7684\u7a0b\u5e8f\uff1a<\/p>\n<ul>\n<li>linux &amp; macOS<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go main.go <\/code><\/pre>\n<ul>\n<li>win<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go.exe main.go <\/code><\/pre>\n<p>\u542f\u52a8\u670d\u52a1\u5668<\/p>\n<pre><code>$ bin\/go_build_main_go api              ___           ______ ___  _ \/__ ___ _____ ______    \/ __ `__ \/ \/ \/ \/__  __ `\/  __   \/ \/ \/ \/ \/ \/ \/ \/ \/ _  \/_\/ \/\/ \/_\/ \/ \/_\/ \/_\/ \/_\/_\/ \/_\/_  __, \/ ____\/                       \/____\/   Server      Name:      mix-api Listen      Addr:      :8080 System      Name:      darwin Go          Version:   1.13.4 Framework   Version:   1.0.9 time=2020-09-16 20:24:41.515 level=info msg=Server start file=api.go:58 <\/code><\/pre>\n<h2>\u7f16\u5199\u4e00\u4e2a Web \u670d\u52a1<\/h2>\n<p>\u5185\u5bb9\u653e\u4e0d\u4e0b\uff0c\u7701\u7565&#8230;<\/p>\n<h2>\u7f16\u5199\u4e00\u4e2a gRPC \u670d\u52a1\u3001\u5ba2\u6237\u7aef<\/h2>\n<p>\u9996\u5148\u6211\u4eec\u4f7f\u7528 <code>mixcli<\/code> \u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u9879\u76ee\u9aa8\u67b6\uff1a<\/p>\n<pre><code>$ mixcli new hello Use the arrow keys to navigate: \u2193 \u2191 \u2192 \u2190  ? Select project type:     CLI     API     Web (contains the websocket)   \u25b8 gRPC <\/code><\/pre>\n<p>\u751f\u6210\u9aa8\u67b6\u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\uff1a<\/p>\n<pre><code>. \u251c\u2500\u2500 README.md \u251c\u2500\u2500 bin \u251c\u2500\u2500 commands \u251c\u2500\u2500 conf \u251c\u2500\u2500 configor \u251c\u2500\u2500 di \u251c\u2500\u2500 dotenv \u251c\u2500\u2500 go.mod \u251c\u2500\u2500 go.sum \u251c\u2500\u2500 main.go \u251c\u2500\u2500 protos \u251c\u2500\u2500 runtime \u2514\u2500\u2500 services <\/code><\/pre>\n<p><code>mian.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<ul>\n<li><code>xcli.AddCommand<\/code> \u65b9\u6cd5\u4f20\u5165\u7684 <code>commands.Commands<\/code> \u5b9a\u4e49\u4e86\u5168\u90e8\u7684\u547d\u4ee4<\/li>\n<\/ul>\n<pre><code>package main  import (   \"github.com\/mix-go\/dotenv\"   \"github.com\/mix-go\/grpc-skeleton\/commands\"   _ \"github.com\/mix-go\/grpc-skeleton\/configor\"   _ \"github.com\/mix-go\/grpc-skeleton\/di\"   _ \"github.com\/mix-go\/grpc-skeleton\/dotenv\"   \"github.com\/mix-go\/xcli\" )  func main() {   xcli.SetName(\"app\").     SetVersion(\"0.0.0-alpha\").     SetDebug(dotenv.Getenv(\"APP_DEBUG\").Bool(false))   xcli.AddCommand(commands.Commands...).Run() } <\/code><\/pre>\n<p><code>commands\/main.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u6211\u4eec\u53ef\u4ee5\u5728\u8fd9\u91cc\u81ea\u5b9a\u4e49\u547d\u4ee4\uff0c\u67e5\u770b\u66f4\u591a<\/p>\n<ul>\n<li>\u5b9a\u4e49\u4e86 <code>grpc:server<\/code>\u3001<code>grpc:client<\/code> \u4e24\u4e2a\u5b50\u547d\u4ee4<\/li>\n<li><code>RunI<\/code> \u6307\u5b9a\u4e86\u547d\u4ee4\u6267\u884c\u7684\u63a5\u53e3\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528 <code>Run<\/code> \u8bbe\u5b9a\u4e00\u4e2a\u533f\u540d\u51fd\u6570<\/li>\n<\/ul>\n<pre><code>package commands  import (   \"github.com\/mix-go\/xcli\" )  var Commands = []*xcli.Command{   {     Name:  \"grpc:server\",     Short: \"gRPC server demo\",     Options: []*xcli.Option{       {         Names: []string{\"d\", \"daemon\"},         Usage: \"Run in the background\",       },     },     RunI: &amp;GrpcServerCommand{},   },   {     Name:  \"grpc:client\",     Short: \"gRPC client demo\",     RunI:  &amp;GrpcClientCommand{},   }, } <\/code><\/pre>\n<p><code>protos\/user.proto<\/code> \u6570\u636e\u7ed3\u6784\u6587\u4ef6\uff1a<\/p>\n<p>\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u7aef\u4ee3\u7801\u4e2d\u90fd\u9700\u8981\u4f7f\u7528 <code>.proto<\/code> \u751f\u6210\u7684 go \u4ee3\u7801\uff0c\u56e0\u4e3a\u53cc\u65b9\u9700\u8981\u4f7f\u7528\u8be5\u6570\u636e\u7ed3\u6784\u901a\u8baf<\/p>\n<ul>\n<li><code>.proto<\/code> \u662f gRPC \u901a\u4fe1\u7684\u6570\u636e\u7ed3\u6784\u6587\u4ef6\uff0c\u91c7\u7528 protobuf \u534f\u8bae<\/li>\n<\/ul>\n<pre><code>syntax = \"proto3\";  package go.micro.grpc.user; option go_package = \".;protos\";  service User {     rpc Add(AddRequest) returns (AddResponse) {} }  message AddRequest {     string Name = 1; }  message AddResponse {     int32 error_code = 1;     string error_message = 2;     int64 user_id = 3; } <\/code><\/pre>\n<p>\u7136\u540e\u6211\u4eec\u9700\u8981\u5b89\u88c5 gRPC \u76f8\u5173\u7684\u7f16\u8bd1\u7a0b\u5e8f\uff1a<\/p>\n<ul>\n<li>https:\/\/www.cnblogs.com\/oolo\/p\/11840305.html#%E5%AE%89%E8%A3%85-grpc<\/li>\n<\/ul>\n<p>\u63a5\u4e0b\u6765\u6211\u4eec\u5f00\u59cb\u7f16\u8bd1 <code>.proto<\/code> \u6587\u4ef6\uff1a<\/p>\n<ul>\n<li>\u7f16\u8bd1\u6210\u529f\u540e\u4f1a\u5728\u5f53\u524d\u76ee\u5f55\u751f\u6210 <code>protos\/user.pb.go<\/code> \u6587\u4ef6<\/li>\n<\/ul>\n<pre><code>cd protos protoc --go_out=plugins=grpc:. user.proto <\/code><\/pre>\n<p><code>commands\/server.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u670d\u52a1\u7aef\u4ee3\u7801\u5199\u5728 <code>GrpcServerCommand<\/code> \u7ed3\u6784\u4f53\u7684 <code>main<\/code> \u65b9\u6cd5\u4e2d\uff0c\u751f\u6210\u7684\u4ee3\u7801\u4e2d\u5df2\u7ecf\u5305\u542b\u4e86\uff1a<\/p>\n<ul>\n<li>\u76d1\u542c\u4fe1\u53f7\u505c\u6b62\u670d\u52a1<\/li>\n<li>\u53ef\u9009\u7684\u540e\u53f0\u5b88\u62a4\u6267\u884c<\/li>\n<li><code>pb.RegisterUserServer<\/code> \u6ce8\u518c\u4e86\u4e00\u4e2a\u9ed8\u8ba4\u670d\u52a1\uff0c\u7528\u6237\u53ea\u9700\u8981\u6269\u5c55\u81ea\u5df1\u7684\u670d\u52a1\u5373\u53ef<\/li>\n<\/ul>\n<pre><code>package commands  import (   \"github.com\/mix-go\/dotenv\"   \"github.com\/mix-go\/grpc-skeleton\/di\"   pb \"github.com\/mix-go\/grpc-skeleton\/protos\"   \"github.com\/mix-go\/grpc-skeleton\/services\"   \"github.com\/mix-go\/xcli\/flag\"   \"github.com\/mix-go\/xcli\/process\"   \"google.golang.org\/grpc\"   \"net\"   \"os\"   \"os\/signal\"   \"strings\"   \"syscall\" )  var listener net.Listener  type GrpcServerCommand struct { }  func (t *GrpcServerCommand) Main() {   if flag.Match(\"d\", \"daemon\").Bool() {     process.Daemon()   }    addr := dotenv.Getenv(\"GIN_ADDR\").String(\":8080\")   logger := di.Logrus()    \/\/ listen   listener, err := net.Listen(\"tcp\", addr)   if err != nil {     panic(err)   }   listener = listener    \/\/ signal   ch := make(chan os.Signal)   signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)   go func() {     &lt;-ch     logger.Info(\"Server shutdown\")     if err := listener.Close(); err != nil {       panic(err)     }   }()    \/\/ server   s := grpc.NewServer()   pb.RegisterUserServer(s, &amp;services.UserService{})    \/\/ run   welcome()   logger.Infof(\"Server run %s\", addr)   if err := s.Serve(listener); err != nil &amp;&amp; !strings.Contains(err.Error(), \"use of closed network connection\") {     panic(err)   } } <\/code><\/pre>\n<p><code>services\/user.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u670d\u52a1\u7aef\u4ee3\u7801\u4e2d\u6ce8\u518c\u7684 <code>services.UserService{}<\/code> \u670d\u52a1\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<p>\u53ea\u9700\u8981\u586b\u5145\u4e1a\u52a1\u903b\u8f91\u5373\u53ef<\/p>\n<pre><code>package services  import (   \"context\"   pb \"github.com\/mix-go\/grpc-skeleton\/protos\" )  type UserService struct { }  func (t *UserService) Add(ctx context.Context, in *pb.AddRequest) (*pb.AddResponse, error) {   \/\/ \u6267\u884c\u6570\u636e\u5e93\u64cd\u4f5c   \/\/ ...    resp := pb.AddResponse{     ErrorCode:    0,     ErrorMessage: \"\",     UserId:       10001,   }   return &amp;resp, nil } <\/code><\/pre>\n<p><code>commands\/client.go<\/code> \u6587\u4ef6\uff1a<\/p>\n<p>\u5ba2\u6237\u7aef\u4ee3\u7801\u5199\u5728 <code>GrpcClientCommand<\/code> \u7ed3\u6784\u4f53\u7684 <code>main<\/code> \u65b9\u6cd5\u4e2d\uff0c\u751f\u6210\u7684\u4ee3\u7801\u4e2d\u5df2\u7ecf\u5305\u542b\u4e86\uff1a<\/p>\n<ul>\n<li>\u901a\u8fc7\u73af\u5883\u914d\u7f6e\u83b7\u53d6\u670d\u52a1\u7aef\u8fde\u63a5\u5730\u5740<\/li>\n<li>\u8bbe\u5b9a\u4e86 <code>5s<\/code> \u7684\u6267\u884c\u8d85\u65f6\u65f6\u95f4<\/li>\n<\/ul>\n<pre><code>package commands  import (     \"context\"     \"fmt\"   \"github.com\/mix-go\/dotenv\"   pb \"github.com\/mix-go\/grpc-skeleton\/protos\"     \"google.golang.org\/grpc\"     \"time\" )  type GrpcClientCommand struct { }  func (t *GrpcClientCommand) Main() {   addr := dotenv.Getenv(\"GIN_ADDR\").String(\":8080\")     ctx, _ := context.WithTimeout(context.Background(), time.Duration(5)*time.Second)     conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithBlock())     if err != nil {         panic(err)     }     defer func() {         _ = conn.Close()     }()     cli := pb.NewUserClient(conn)     req := pb.AddRequest{         Name: \"xiaoliu\",     }     resp, err := cli.Add(ctx, &amp;req)     if err != nil {         panic(err)     }     fmt.Println(fmt.Sprintf(\"Add User: %d\", resp.UserId)) } <\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\u6211\u4eec\u7f16\u8bd1\u4e0a\u9762\u7684\u7a0b\u5e8f\uff1a<\/p>\n<ul>\n<li>linux &amp; macOS<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go main.go <\/code><\/pre>\n<ul>\n<li>win<\/li>\n<\/ul>\n<pre><code>go build -o bin\/go_build_main_go.exe main.go <\/code><\/pre>\n<p>\u9996\u5148\u5728\u547d\u4ee4\u884c\u542f\u52a8 <code>grpc:server<\/code> \u670d\u52a1\u5668\uff1a<\/p>\n<pre><code>$ bin\/go_build_main_go grpc:server              ___           ______ ___  _ \/__ ___ _____ ______    \/ __ `__ \/ \/ \/ \/__  __ `\/  __   \/ \/ \/ \/ \/ \/ \/ \/ \/ _  \/_\/ \/\/ \/_\/ \/ \/_\/ \/_\/ \/_\/_\/ \/_\/_  __, \/ ____\/                       \/____\/   Server      Name:      mix-grpc Listen      Addr:      :8080 System      Name:      darwin Go          Version:   1.13.4 Framework   Version:   1.0.20 time=2020-11-09 15:08:17.544 level=info msg=Server run :8080 file=server.go:46 <\/code><\/pre>\n<p>\u7136\u540e\u5f00\u542f\u4e00\u4e2a\u65b0\u7684\u7ec8\u7aef\uff0c\u6267\u884c\u4e0b\u9762\u7684\u5ba2\u6237\u7aef\u547d\u4ee4\u4e0e\u4e0a\u9762\u7684\u670d\u52a1\u5668\u901a\u4fe1<\/p>\n<pre><code>$ bin\/go_build_main_go grpc:client Add User: 10001 <\/code><\/pre>\n<h2>\u5982\u4f55\u4f7f\u7528 DI \u5bb9\u5668\u4e2d\u7684 Logger \u3001Database \u3001Redis \u7b49\u7ec4\u4ef6<\/h2>\n<p>\u9879\u76ee\u4e2d\u8981\u4f7f\u7528\u7684\u516c\u5171\u7ec4\u4ef6\uff0c\u90fd\u5b9a\u4e49\u5728 <code>di<\/code> \u76ee\u5f55\uff0c\u6846\u67b6\u9ed8\u8ba4\u751f\u6210\u4e86\u4e00\u4e9b\u5e38\u7528\u7684\u7ec4\u4ef6\uff0c\u7528\u6237\u4e5f\u53ef\u4ee5\u5b9a\u4e49\u81ea\u5df1\u7684\u7ec4\u4ef6\uff0c\u67e5\u770b\u66f4\u591a<\/p>\n<ul>\n<li>\u53ef\u4ee5\u5728\u54ea\u91cc\u4f7f\u7528<\/li>\n<\/ul>\n<p>\u53ef\u4ee5\u5728\u4ee3\u7801\u7684\u4efb\u610f\u4f4d\u7f6e\u4f7f\u7528\uff0c\u4f46\u662f\u4e3a\u4e86\u53ef\u4ee5\u4f7f\u7528\u5230\u73af\u5883\u53d8\u91cf\u548c\u81ea\u5b9a\u4e49\u914d\u7f6e\uff0c\u901a\u5e38\u6211\u4eec\u5728 <code>xcli.Command<\/code> \u7ed3\u6784\u4f53\u5b9a\u4e49\u7684 <code>Run<\/code>\u3001<code>RunI<\/code> \u4e2d\u4f7f\u7528\u3002<\/p>\n<ul>\n<li>\u4f7f\u7528\u65e5\u5fd7\uff0c\u6bd4\u5982\uff1a<code>logrus<\/code>\u3001<code>zap<\/code><\/li>\n<\/ul>\n<pre><code>logger := di.Logrus() logger.Info(\"test\") <\/code><\/pre>\n<ul>\n<li>\u4f7f\u7528\u6570\u636e\u5e93\uff0c\u6bd4\u5982\uff1a<code>gorm<\/code>\u3001<code>xorm<\/code><\/li>\n<\/ul>\n<pre><code>db := di.Gorm() user := User{Name: \"Jinzhu\", Age: 18, Birthday: time.Now()} result := db.Create(&amp;user) fmt.Println(result) <\/code><\/pre>\n<ul>\n<li>\u4f7f\u7528 Redis\uff0c\u6bd4\u5982\uff1a<code>go-redis<\/code><\/li>\n<\/ul>\n<pre><code>rdb := di.GoRedis() val, err := rdb.Get(context.Background(), \"key\").Result() if err != nil {     panic(err) } fmt.Println(\"key\", val) <\/code><\/pre>\n<h2>\u4f9d\u8d56<\/h2>\n<p>\u5b98\u65b9\u5e93<\/p>\n<ul>\n<li>https:\/\/github.com\/mix-go\/mixcli<\/li>\n<li>https:\/\/github.com\/mix-go\/xcli<\/li>\n<li>https:\/\/github.com\/mix-go\/xdi<\/li>\n<li>https:\/\/github.com\/mix-go\/xwp<\/li>\n<li>https:\/\/github.com\/mix-go\/xfmt<\/li>\n<li>https:\/\/github.com\/mix-go\/dotenv<\/li>\n<\/ul>\n<p>\u7b2c\u4e09\u65b9\u5e93<\/p>\n<ul>\n<li>https:\/\/github.com\/gin-gonic\/gin<\/li>\n<li>https:\/\/gorm.io<\/li>\n<li>https:\/\/github.com\/go-redis\/redis<\/li>\n<li>https:\/\/github.com\/jinzhu\/configor<\/li>\n<li>https:\/\/github.com\/uber-go\/zap<\/li>\n<li>https:\/\/github.com\/sirupsen\/logrus<\/li>\n<li>https:\/\/github.com\/natefinch\/lumberjack<\/li>\n<li>https:\/\/github.com\/lestrrat-go\/file-rotatelogs<\/li>\n<li>https:\/\/github.com\/go-session\/session<\/li>\n<li>https:\/\/github.com\/go-session\/redis<\/li>\n<li>https:\/\/github.com\/dgrijalva\/jwt-go<\/li>\n<li>https:\/\/github.com\/gorilla\/websocket<\/li>\n<li>https:\/\/github.com\/golang\/grpc<\/li>\n<li>https:\/\/github.com\/golang\/protobuf<\/li>\n<\/ul>\n<h2>License<\/h2>\n<p>Apache License Version 2.0, http:\/\/www.apache.org\/licenses\/<\/p>\n<\/p><\/div>\n<div> <b>\u5927\u4f6c\u6709\u8a71\u8aaa<\/b> (<span>12<\/span>)        <\/div>\n<div> <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<ul>\n<li data-pid=\"5736625\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : cexll <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u5c31\u8fd9\uff1f                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736626\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : RyanTaro <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u8fd9\u6846\u67b6\u4e5f\u597d\u610f\u601d\u53d1\u51fa\u6765\u5f00\u6e90?                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736627\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : CEBBCAT <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             @cexll <br \/>@RyanTaro <\/p>\n<p>\u4e0d\u592a\u660e\u767d\uff0c\u662f\u53d1\u751f\u4e86\u4ec0\u4e48\u5417\uff1f                                                            <\/p><\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736628\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : SWYou <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u5367\u69fd\uff0c\u8fd9\u4e0a\u4e0d\u61c2\u5f97\u7ed9\u70b9\u9f13\u52b1\u5417\uff1f                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736629\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : linvon <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             @CEBBCAT #3 <br \/>@SWYou #4 <br \/>\u770b\u4e00\u8fd8\u662f\u9879\u76ee\u7684 contributer\uff0c\u4f30\u8ba1\u662f\u81ea\u5df1\u4eba\u5427                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736630\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : TangMonk <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u633a\u597d\u7684\uff0c\u8d5e\u4e00\u4e2a                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736631\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : keer <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u4e3b\u7684 MixPHP \u4e5f\u5f88\u725b\u903c\u5440\u3002                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736632\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : airplayxcom <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u90fd\u7528 gin \u3001gorm \u4e86\uff0c \u4e3a\u5565\u8fd8\u8981\u505a\u80f6\u6c34\u3002                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736633\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : zh5e <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u633a\u597d\u7684\uff0c\u8d5e\u4e00\u4e2a                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736634\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : CheatEngine <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u751f\u6210\u51fa\u6765\u7684\u6405\u5c4e\u68cd\u4ee3\u7801,\u771f\u7684,\u6709\u8fd9\u4e2a\u65f6\u95f4\u4e0d\u5982\u62ff go \u9020\u4e2a\u8f6e\u5b50,\u800c\u4e0d\u662f\u9020\u6beb\u65e0\u6280\u672f\u542b\u91cf\u7684\u4ee3\u7801\u751f\u6210\u5668.<br \/>\u8fd9\u79cd\u4ee3\u7801\u54ea\u6709\u7b80\u6d01\u6027\u53ef\u8a00? &#8220;\u4efb\u4f55\u4ee5\u4ee3\u7801\u751f\u6210\u5668\u751f\u6210\u7684\u4fb5\u5165\u4e1a\u52a1\u7684\u5916\u90e8\u4ee3\u7801\u90fd\u662f\u5783\u573e&#8221;.\u5982\u679c\u4e0d\u660e\u767d\u6211\u8fd9\u53e5\u8bdd,\u53ef\u4ee5\u770b\u770b\u9694\u58c1\u7684 beego \u7684\u6ce8\u89e3\u8def\u7531.\u6ce8\u89e3\u53ea\u662f\u5f00\u53d1,\u8fd0\u884c\u7684\u65f6\u5019\u4f7f\u7528\u81ea\u52a8\u751f\u6210\u7684\u4ee3\u7801.\u4e0d\u5165\u4fb5\u4e1a\u52a1,\u56e0\u4e3a controller \u91cc\u53ea\u6709\u4e00\u4e2a\u6ce8\u89e3.                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736635\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u4e3b<\/span> <span>\u8cc7\u6df1\u5927\u4f6c : onanying <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             @CheatEngine \u4f60\u4f1a\u7528\u4e00\u4e2a\u522b\u4eba\u9020\u7684\u8f6e\u5b50\uff0c\u7136\u540e\u4f60\u54ea\u91cc\u6765\u7684\u4f18\u8d8a\u611f\uff1f\u8c01\u7ed9\u4f60\u7684\u52c7\u6c14\uff1f                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li data-pid=\"5736636\" data-uid=\"2\">\n<div>\n<div>\n<div> <span>\u4e3b<\/span> <span>\u8cc7\u6df1\u5927\u4f6c : onanying <\/span>  <\/div>\n<div> <i title=\"\u5f15\u7528\"><\/i>  <span>          <\/span> <\/div>\n<\/p><\/div>\n<div>                                                             \u751f\u6210\u7684\u4ee3\u7801\u91cc\u4f7f\u7528\u4e86\u8fd9\u4e9b\u8f6e\u5b50\uff0c\u53cd\u6b63\u4f60\u4e5f\u662f\u770b\u4e0d\u5230\u7684\uff0c\u53ea\u770b\u5230\u4e86\u4ee3\u7801\u751f\u6210\u5668\u3002<\/p>\n<p>https:\/\/github.com\/mix-go\/xcli<br \/>https:\/\/github.com\/mix-go\/xdi<br \/>https:\/\/github.com\/mix-go\/xwp<br \/>https:\/\/github.com\/mix-go\/xfmt                                                            <\/div>\n<\/p><\/div>\n<\/li>\n<li>\n","protected":false},"excerpt":{"rendered":"<p>MixGo v1.1 \u53d1\u5e03, Go&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[],"tags":[],"_links":{"self":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts\/427822"}],"collection":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=427822"}],"version-history":[{"count":0,"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts\/427822\/revisions"}],"wp:attachment":[{"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=427822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=427822"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=427822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}