├── README.md ├── static ├── imgs │ ├── books │ │ ├── xsw.jpg │ │ ├── caoda.jpg │ │ ├── goweb.jpg │ │ ├── xuhen.jpg │ │ ├── huangjh.jpg │ │ ├── go-in-action.jpg │ │ ├── go-programming-blueprints.png │ │ ├── mastering-go-web-services.jpg │ │ ├── go-programming-language-book.png │ │ ├── building-microservices-with-go.jpg │ │ ├── building-restful-web-services-with-go.jpg │ │ ├── powerful-command-line-applications-in-go.jpg │ │ └── hands-on-software-architecture-with-golang.jpg │ ├── wx_qrcode.jpg │ ├── logos │ │ ├── etcd.png │ │ ├── jrtt.png │ │ ├── tidb.png │ │ ├── caddy.jpeg │ │ ├── prometheus.png │ │ ├── netflix.svg │ │ ├── cloudflare-icon.svg │ │ ├── the-new-york-times-icon.svg │ │ ├── mongodb.svg │ │ ├── uber-app-icon.svg │ │ ├── dropbox.svg │ │ ├── github.svg │ │ ├── uber.svg │ │ ├── kubernetes.svg │ │ ├── twitch.svg │ │ ├── capital-one.svg │ │ ├── stripe.svg │ │ ├── google-cloud.svg │ │ ├── didi.svg │ │ ├── comcast.svg │ │ └── mercadoLibre.svg │ ├── studygolang-white.png │ ├── solutions │ │ ├── americanexpress-logo.png │ │ ├── twitter-logo.svg │ │ ├── netflix-logo.svg │ │ ├── CLI-green.svg │ │ ├── webdev-green.svg │ │ ├── target-logo.svg │ │ ├── uber-logo.svg │ │ ├── dropbox-logo.svg │ │ ├── twitch-logo.svg │ │ ├── capital-one-logo.svg │ │ ├── ops-green.svg │ │ ├── cloud-green.svg │ │ └── mercadolibre-logo.svg │ ├── menu-24px.svg │ ├── menu-24px-white.svg │ ├── close-24px.svg │ ├── star-24px.svg │ ├── quote.svg │ ├── go-logo-blue.svg │ ├── go-logo-white.svg │ ├── pink.svg │ ├── gophers │ │ ├── peach.svg │ │ └── happy.svg │ └── pilot-bust.svg └── js │ └── base.js ├── template ├── gopher.html ├── about.html ├── common │ └── layout.html ├── solutions │ └── webdev.html └── solution.html ├── go.mod ├── .github └── CODEOWNERS ├── .gitignore ├── config └── config.toml ├── Makefile ├── http ├── controller │ ├── routes.go │ ├── repo.go │ └── index.go ├── http.go └── funcs.go ├── main.go ├── util └── file.go ├── LICENSE ├── global ├── init.go └── app.go └── .air.conf /README.md: -------------------------------------------------------------------------------- 1 | # golangclub 2 | Go语言俱乐部 3 | -------------------------------------------------------------------------------- /static/imgs/books/xsw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/xsw.jpg -------------------------------------------------------------------------------- /static/imgs/wx_qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/wx_qrcode.jpg -------------------------------------------------------------------------------- /static/imgs/books/caoda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/caoda.jpg -------------------------------------------------------------------------------- /static/imgs/books/goweb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/goweb.jpg -------------------------------------------------------------------------------- /static/imgs/books/xuhen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/xuhen.jpg -------------------------------------------------------------------------------- /static/imgs/logos/etcd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/logos/etcd.png -------------------------------------------------------------------------------- /static/imgs/logos/jrtt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/logos/jrtt.png -------------------------------------------------------------------------------- /static/imgs/logos/tidb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/logos/tidb.png -------------------------------------------------------------------------------- /static/imgs/books/huangjh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/huangjh.jpg -------------------------------------------------------------------------------- /static/imgs/logos/caddy.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/logos/caddy.jpeg -------------------------------------------------------------------------------- /static/imgs/logos/prometheus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/logos/prometheus.png -------------------------------------------------------------------------------- /static/imgs/books/go-in-action.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/go-in-action.jpg -------------------------------------------------------------------------------- /static/imgs/studygolang-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/studygolang-white.png -------------------------------------------------------------------------------- /static/imgs/books/go-programming-blueprints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/go-programming-blueprints.png -------------------------------------------------------------------------------- /static/imgs/books/mastering-go-web-services.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/mastering-go-web-services.jpg -------------------------------------------------------------------------------- /static/imgs/solutions/americanexpress-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/solutions/americanexpress-logo.png -------------------------------------------------------------------------------- /template/gopher.html: -------------------------------------------------------------------------------- 1 | {{define "title"}}Gopher名人 — Go语言俱乐部{{end}} 2 | {{define "content"}} 3 |
4 | Gopher 名人列表。。。 5 |
6 | {{end}} -------------------------------------------------------------------------------- /static/imgs/books/go-programming-language-book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/go-programming-language-book.png -------------------------------------------------------------------------------- /static/imgs/books/building-microservices-with-go.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/building-microservices-with-go.jpg -------------------------------------------------------------------------------- /static/imgs/books/building-restful-web-services-with-go.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/building-restful-web-services-with-go.jpg -------------------------------------------------------------------------------- /static/imgs/books/powerful-command-line-applications-in-go.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/powerful-command-line-applications-in-go.jpg -------------------------------------------------------------------------------- /static/imgs/books/hands-on-software-architecture-with-golang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris1119/golangclub/HEAD/static/imgs/books/hands-on-software-architecture-with-golang.jpg -------------------------------------------------------------------------------- /static/imgs/menu-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/polaris1119/golangclub 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/labstack/echo/v4 v4.9.0 7 | github.com/labstack/gommon v0.3.1 8 | github.com/spf13/viper v1.5.0 9 | ) 10 | -------------------------------------------------------------------------------- /static/imgs/menu-24px-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/close-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/star-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | # https://help.github.com/articles/about-codeowners/ 4 | # 5 | # Order is important; the last matching pattern takes the most 6 | # precedence. 7 | 8 | * @polaris1119 @unknwon 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | .idea 15 | 16 | tmp 17 | 18 | golangclub 19 | 20 | vendor 21 | .vscode 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /config/config.toml: -------------------------------------------------------------------------------- 1 | 2 | # 域名 3 | domain = "https://golangclub.com/" 4 | name = "Go语言俱乐部" 5 | 6 | # 定义 HTTP 监听端口 7 | [http] 8 | host = "" 9 | port = 2019 10 | 11 | # 存储配置 12 | [storage] 13 | driver = "mysql" 14 | user = "root" 15 | password = "" 16 | host = "localhost" 17 | port = 3306 18 | dbname = "golangclub" 19 | charset = "utf8mb4" 20 | 21 | [seo] 22 | keywords = "go.dev golangclub" 23 | description = "索引" -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GitCommitLog=`git log --pretty=oneline -n 1` 2 | GitRelease=`git describe --dirty --all` 3 | BuildTime=`date '+%Y-%m-%d %H:%M:%S'` 4 | LdFlags="-X 'main.gitCommitLog=${GitCommitLog}' -X 'main.gitRelease=${GitRelease}' -X 'main.buildTime=${BuildTime}'" 5 | 6 | build: fmt 7 | @echo "building project..." 8 | go build -ldflags ${LdFlags} github.com/polaris1119/golangclub 9 | @echo "build finished!" 10 | 11 | fmt: 12 | gofmt -w . -------------------------------------------------------------------------------- /http/controller/routes.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package controller 10 | 11 | import "github.com/labstack/echo/v4" 12 | 13 | func RegisterRoutes(e *echo.Echo) { 14 | new(IndexController).RegisterRoutes(e) 15 | new(RepoController).RegisterRoutes(e) 16 | } 17 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/labstack/echo/v4" 5 | "github.com/labstack/echo/v4/middleware" 6 | 7 | "github.com/polaris1119/golangclub/http/controller" 8 | ) 9 | 10 | func main() { 11 | e := echo.New() 12 | 13 | e.Use(middleware.Recover()) 14 | e.Use(middleware.Logger()) 15 | 16 | // 去除尾部斜杠 17 | e.Pre(middleware.RemoveTrailingSlash()) 18 | 19 | // 服务静态文件 20 | e.Static("/static", "static") 21 | 22 | controller.RegisterRoutes(e) 23 | 24 | e.Logger.Fatal(e.Start(":2019")) 25 | } 26 | -------------------------------------------------------------------------------- /util/file.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package util 10 | 11 | import "os" 12 | 13 | // Exist 检查文件或目录是否存在 14 | // 如果由 filename 指定的文件或目录存在则返回 true,否则返回 false 15 | func Exist(filename string) bool { 16 | _, err := os.Stat(filename) 17 | return err == nil || os.IsExist(err) 18 | } 19 | -------------------------------------------------------------------------------- /http/controller/repo.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "bytes" 5 | "os/exec" 6 | 7 | "github.com/labstack/echo/v4" 8 | "github.com/labstack/gommon/log" 9 | 10 | "github.com/polaris1119/golangclub/global" 11 | ) 12 | 13 | type RepoController struct{} 14 | 15 | func (r RepoController) RegisterRoutes(e *echo.Echo) { 16 | e.POST("/repo/pull", r.pull) 17 | } 18 | 19 | // pull 自动拉去仓库最新代码 20 | func (r RepoController) pull(ctx echo.Context) error { 21 | secret := "L072uFhwQ6" 22 | _ = secret 23 | 24 | strCmd := "cd " + global.App.RootDir + "; git pull" 25 | cmd := exec.Command("sh", "-c", strCmd) 26 | var out bytes.Buffer 27 | cmd.Stdout = &out 28 | err := cmd.Run() 29 | 30 | ctx.Logger().Infoj(log.JSON{"pull_result": out.String()}) 31 | 32 | return err 33 | } 34 | -------------------------------------------------------------------------------- /static/imgs/solutions/twitter-logo.svg: -------------------------------------------------------------------------------- 1 | Twitter_Logo_Blue -------------------------------------------------------------------------------- /static/imgs/quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /static/imgs/logos/netflix.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/solutions/netflix-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 徐新华 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /global/init.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package global 10 | 11 | import ( 12 | "flag" 13 | "fmt" 14 | "math/rand" 15 | "sync" 16 | "time" 17 | 18 | "github.com/spf13/viper" 19 | ) 20 | 21 | var once = new(sync.Once) 22 | 23 | var ( 24 | config = flag.String("config", "config", "配置文件名称,默认 config") 25 | ) 26 | 27 | func Init() { 28 | once.Do(func() { 29 | if !flag.Parsed() { 30 | flag.Parse() 31 | } 32 | 33 | // 随机数种子 34 | rand.Seed(time.Now().UnixNano()) 35 | 36 | // 配置文件名称 37 | viper.SetConfigName(*config) 38 | // 配置文件查找路径 39 | viper.AddConfigPath("/etc/golangclub/") 40 | viper.AddConfigPath("$HOME/.golangclub") 41 | viper.AddConfigPath(App.RootDir + "/config") 42 | // 读取配置文件 43 | err := viper.ReadInConfig() 44 | if err != nil { 45 | panic(fmt.Errorf("Fatal error config file: %s \n", err)) 46 | } 47 | 48 | // 填充 global.App 需要的数据 49 | App.fillOtherField() 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /.air.conf: -------------------------------------------------------------------------------- 1 | # Config file for [Air](https://github.com/cosmtrek/air) in TOML format 2 | 3 | # Working directory 4 | # . or absolute path, please note that the directories following must be under root 5 | root = "." 6 | # Optional! If `watch_dir` is empty, use `root`. 7 | watch_dir = "" 8 | tmp_dir = "tmp" 9 | 10 | [build] 11 | # Just plain old shell command. You could use `make` as well. 12 | cmd = "gofmt -w . && go build github.com/polaris1119/golangclub" 13 | # Binary file yields from `cmd`. 14 | bin = "golangclub" 15 | # Customize binary. 16 | # full_bin = "APP_ENV=dev APP_USER=air ./tmp/studygolang" 17 | # This log file places in your tmp_dir. 18 | log = "air_errors.log" 19 | # Watch these filename extensions. 20 | include_ext = ["go"] 21 | # Ignore these filename extensions or directories. 22 | exclude_dir = ["assets", "tmp", "vendor", "template", "static", "docs", "node_modules"] 23 | # There's no necessary to trigger build each time file changes if it's too frequency. 24 | delay = 1000 # ms 25 | 26 | [log] 27 | # Show log time 28 | time = false 29 | 30 | [color] 31 | # Customize each part's color. If no color found, use the raw app log. 32 | main = "magenta" 33 | watcher = "cyan" 34 | build = "yellow" 35 | runner = "green" 36 | 37 | [misc] 38 | # Delete tmp directory on exit 39 | clean_on_exit = true 40 | -------------------------------------------------------------------------------- /static/imgs/logos/cloudflare-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/go-logo-blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/go-logo-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/logos/the-new-york-times-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/logos/mongodb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/logos/uber-app-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | uber_rides_api_icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/imgs/solutions/CLI-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /static/imgs/solutions/webdev-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /http/controller/index.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package controller 10 | 11 | import ( 12 | "github.com/labstack/echo/v4" 13 | 14 | . "github.com/polaris1119/golangclub/http" 15 | ) 16 | 17 | type IndexController struct{} 18 | 19 | // RegisterRoutes 注册路由 20 | func (i IndexController) RegisterRoutes(e *echo.Echo) { 21 | e.GET("/", i.index) 22 | e.GET("/solutions", i.solution) 23 | e.GET("/learn", i.learn) 24 | e.GET("/gopher", i.gopher) 25 | e.GET("/about", i.about) 26 | e.GET("/solutions/:typ", i.solutionProxy) 27 | } 28 | 29 | // index 首页 30 | func (i IndexController) index(ctx echo.Context) error { 31 | return Render(ctx, "index.html", nil) 32 | } 33 | 34 | // solution 解决方案 35 | func (i IndexController) solution(ctx echo.Context) error { 36 | return Render(ctx, "solution.html", map[string]interface{}{"solution_active": "Header-menuItem--active"}) 37 | } 38 | 39 | // learn 学习资源 40 | func (i IndexController) learn(ctx echo.Context) error { 41 | return Render(ctx, "learn.html", map[string]interface{}{"learn_active": "Header-menuItem--active"}) 42 | } 43 | 44 | // gopher 名人 45 | func (i IndexController) gopher(ctx echo.Context) error { 46 | return Render(ctx, "gopher.html", map[string]interface{}{"gopher_active": "Header-menuItem--active"}) 47 | } 48 | 49 | // about 关于 50 | func (i IndexController) about(ctx echo.Context) error { 51 | return Render(ctx, "about.html", map[string]interface{}{"about_active": "Header-menuItem--active"}) 52 | } 53 | 54 | // solutionProxy 代理所有 solutions 子路由 55 | func (i IndexController) solutionProxy(ctx echo.Context) error { 56 | typ := ctx.Param("typ") 57 | return Render(ctx, "solutions/"+typ+".html", map[string]interface{}{"solution_active": "Header-menuItem--active"}) 58 | } 59 | -------------------------------------------------------------------------------- /static/js/base.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /** 6 | * A bit of navigation related code for handling dismissible elements. 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | function registerHeaderListeners() { 12 | const header = document.querySelector('.js-header'); 13 | const menuButtons = document.querySelectorAll('.js-headerMenuButton'); 14 | menuButtons.forEach(button => { 15 | button.addEventListener('click', e => { 16 | e.preventDefault(); 17 | header.classList.toggle('is-active'); 18 | button.setAttribute( 19 | 'aria-expanded', 20 | header.classList.contains('is-active') 21 | ); 22 | }); 23 | }); 24 | 25 | const scrim = document.querySelector('.js-scrim'); 26 | scrim.addEventListener('click', e => { 27 | e.preventDefault(); 28 | header.classList.remove('is-active'); 29 | menuButtons.forEach(button => { 30 | button.setAttribute( 31 | 'aria-expanded', 32 | header.classList.contains('is-active') 33 | ); 34 | }); 35 | }); 36 | } 37 | 38 | window.addEventListener('DOMContentLoaded', () => { 39 | registerHeaderListeners(); 40 | }); 41 | 42 | // Register feedback listeners. 43 | window.addEventListener('load', () => { 44 | const buttons = document.querySelectorAll('.js-feedbackButton'); 45 | buttons.forEach(button => { 46 | button.addEventListener('click', sendFeedback); 47 | }); 48 | }); 49 | 50 | // Launches the feedback interface. 51 | function sendFeedback() { 52 | userfeedback.api.startFeedback({ productId: '5131929', bucket: 'Default' }); 53 | } 54 | 55 | window.dataLayer = window.dataLayer || []; 56 | function gtag() { 57 | dataLayer.push(arguments); 58 | } 59 | gtag('js', new Date()); 60 | gtag('config', 'UA-141356704-1'); 61 | })(); 62 | -------------------------------------------------------------------------------- /http/http.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package http 10 | 11 | import ( 12 | "bytes" 13 | "html/template" 14 | "net/http" 15 | "strings" 16 | 17 | "github.com/labstack/echo/v4" 18 | 19 | "github.com/polaris1119/golangclub/global" 20 | ) 21 | 22 | const ( 23 | LayoutTpl = "common/layout.html" 24 | ) 25 | 26 | // Render html 输出 27 | func Render(ctx echo.Context, contentTpl string, data map[string]interface{}) error { 28 | if data == nil { 29 | data = map[string]interface{}{} 30 | } 31 | 32 | contentTpl = LayoutTpl + "," + contentTpl 33 | htmlFiles := strings.Split(contentTpl, ",") 34 | for i, contentTpl := range htmlFiles { 35 | htmlFiles[i] = global.App.TemplateDir + contentTpl 36 | } 37 | tpl, err := template.New("layout.html").Funcs(funcMap). 38 | Funcs(template.FuncMap{"include": tplInclude}).ParseFiles(htmlFiles...) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | data["path"] = ctx.Path() 44 | 45 | return executeTpl(ctx, tpl, data) 46 | } 47 | 48 | func executeTpl(ctx echo.Context, tpl *template.Template, data map[string]interface{}) error { 49 | // css 和 js 可以每个页面保留一些自己特有的 50 | 51 | // 如果没有定义 css 和 js 模板,则定义之 52 | if jsTpl := tpl.Lookup("js"); jsTpl == nil { 53 | tpl.Parse(`{{define "js"}}{{end}}`) 54 | } 55 | if cssTpl := tpl.Lookup("css"); cssTpl == nil { 56 | tpl.Parse(`{{define "css"}}{{end}}`) 57 | } 58 | 59 | // 如果没有 seo 模板,则定义之 60 | if seoTpl := tpl.Lookup("seo"); seoTpl == nil { 61 | tpl.Parse(`{{define "seo"}} 62 | 63 | 64 | {{end}}`) 65 | } 66 | 67 | global.App.SetUptime() 68 | // global.App.SetCopyright() 69 | 70 | data["app"] = global.App 71 | 72 | // 记录处理时间 73 | // data["resp_time"] = time.Since(ctx.Get("req_start_time").(time.Time)) 74 | 75 | buf := new(bytes.Buffer) 76 | err := tpl.Execute(buf, data) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | return ctx.HTML(http.StatusOK, buf.String()) 82 | } 83 | -------------------------------------------------------------------------------- /static/imgs/logos/dropbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/solutions/target-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 12 | 14 | 16 | 18 | 22 | 26 | 29 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /global/app.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package global 10 | 11 | import ( 12 | "fmt" 13 | "os" 14 | "path/filepath" 15 | "runtime" 16 | "strings" 17 | "sync" 18 | "time" 19 | 20 | "github.com/labstack/echo/v4" 21 | "github.com/spf13/viper" 22 | 23 | "github.com/polaris1119/golangclub/util" 24 | ) 25 | 26 | func init() { 27 | App.Version = "V1.0" 28 | App.LaunchTime = time.Now() 29 | 30 | App.RootDir = "." 31 | 32 | if !viper.InConfig("http.port") { 33 | App.RootDir = inferRootDir() 34 | } 35 | App.TemplateDir = App.RootDir + "/template/" 36 | 37 | fileInfo, err := os.Stat(os.Args[0]) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | App.Date = fileInfo.ModTime() 43 | 44 | App.Build.GoVersion = runtime.Version() 45 | App.Build.EchoVersion = echo.Version 46 | } 47 | 48 | // inferRootDir 递归推导项目根目录 49 | func inferRootDir() string { 50 | cwd, err := os.Getwd() 51 | if err != nil { 52 | panic(err) 53 | } 54 | 55 | var infer func(d string) string 56 | infer = func(d string) string { 57 | if d == "/" { 58 | panic("请确保在项目根目录或子目录下运行程序,当前在:" + cwd) 59 | } 60 | 61 | if util.Exist(d + "/config") { 62 | return d 63 | } 64 | 65 | return infer(filepath.Dir(d)) 66 | } 67 | 68 | return infer(cwd) 69 | } 70 | 71 | var App = &app{} 72 | 73 | type app struct { 74 | Name string 75 | Version string 76 | Date time.Time 77 | 78 | // 项目根目录 79 | RootDir string 80 | // 模板根目录 81 | TemplateDir string 82 | 83 | // 启动时间 84 | LaunchTime time.Time 85 | Uptime time.Duration 86 | 87 | Domain string 88 | SEO map[string]string 89 | 90 | Build struct { 91 | GitCommitLog string 92 | BuildTime string 93 | GitRelease string 94 | GoVersion string 95 | EchoVersion string 96 | } 97 | 98 | locker sync.Mutex 99 | } 100 | 101 | func (a *app) SetUptime() { 102 | a.locker.Lock() 103 | defer a.locker.Unlock() 104 | a.Uptime = time.Now().Sub(a.LaunchTime) 105 | } 106 | 107 | func (a *app) FillBuildInfo(gitCommitLog, buildTime, gitRelease string) { 108 | a.Build.GitCommitLog = gitCommitLog 109 | a.Build.BuildTime = buildTime 110 | 111 | pos := strings.Index(gitRelease, "/") 112 | if pos >= -1 { 113 | a.Build.GitRelease = gitRelease[pos+1:] 114 | } 115 | 116 | fmt.Println(a) 117 | } 118 | 119 | func (a *app) fillOtherField() { 120 | a.Name = viper.GetString("name") 121 | a.Domain = viper.GetString("domain") 122 | a.SEO = viper.GetStringMapString("seo") 123 | } 124 | 125 | func (a *app) String() string { 126 | return "Build Info:" + 127 | "\nGit Commit Log: " + a.Build.GitCommitLog + 128 | "\nGit Release Info: " + a.Build.GitRelease + 129 | "\nBuild Time: " + a.Build.BuildTime + 130 | "\nGo Version: " + a.Build.GoVersion 131 | } 132 | -------------------------------------------------------------------------------- /http/funcs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. The StudyGolang Authors. All rights reserved. 3 | * Use of this source code is governed by a MIT-style 4 | * license that can be found in the LICENSE file. 5 | * https://golangclub.com 6 | * Author:polaris polaris@studygolang.com 7 | */ 8 | 9 | package http 10 | 11 | import ( 12 | "bytes" 13 | "encoding/json" 14 | "html/template" 15 | "math" 16 | "math/rand" 17 | "path/filepath" 18 | "strings" 19 | "time" 20 | 21 | "github.com/polaris1119/golangclub/global" 22 | ) 23 | 24 | // funcMap 自定义模板函数 25 | var funcMap = template.FuncMap{ 26 | // 转为前端显示需要的时间格式 27 | "formatTime": func(i interface{}) string { 28 | ctime, ok := i.(string) 29 | if !ok { 30 | return "" 31 | } 32 | t, _ := time.Parse("2006-01-02 15:04:05", ctime) 33 | return t.Format(time.RFC3339) + "+08:00" 34 | }, 35 | "format": func(i interface{}, format string) string { 36 | switch i.(type) { 37 | case time.Time: 38 | return (i.(time.Time)).Format(format) 39 | case int64: 40 | val := i.(int64) 41 | return time.Unix(val, 0).Format(format) 42 | } 43 | 44 | return "" 45 | }, 46 | "hasPrefix": func(s, prefix string) bool { 47 | if strings.HasPrefix(s, prefix) { 48 | return true 49 | } 50 | return false 51 | }, 52 | "add": func(nums ...interface{}) int { 53 | total := 0 54 | for _, num := range nums { 55 | if n, ok := num.(int); ok { 56 | total += n 57 | } 58 | } 59 | return total 60 | }, 61 | "mod": func(num1, num2 int) int { 62 | if num1 == 0 { 63 | num1 = rand.Intn(500) 64 | } 65 | 66 | return num1 % num2 67 | }, 68 | "divide": func(num1, num2 int) int { 69 | return int(math.Ceil(float64(num1) / float64(num2))) 70 | }, 71 | "explode": func(s, sep string) []string { 72 | return strings.Split(s, sep) 73 | }, 74 | "noescape": func(s string) template.HTML { 75 | return template.HTML(s) 76 | }, 77 | "timestamp": func(ts ...time.Time) int64 { 78 | if len(ts) > 0 { 79 | return ts[0].Unix() 80 | } 81 | return time.Now().Unix() 82 | }, 83 | "parseJSON": func(str string) map[string]interface{} { 84 | result := make(map[string]interface{}) 85 | json.Unmarshal([]byte(str), &result) 86 | return result 87 | }, 88 | "genList": func(n int, steps ...int) []int { 89 | step := 1 90 | if len(steps) > 0 { 91 | step = steps[0] 92 | } 93 | num := int(math.Ceil(float64(n) / float64(step))) 94 | nums := make([]int, num) 95 | for i := 0; i < num; i++ { 96 | nums[i] = i + 1 97 | } 98 | 99 | return nums 100 | }, 101 | } 102 | 103 | // tplInclude 支持 include 模板 104 | func tplInclude(file string, dot map[string]interface{}) template.HTML { 105 | var buffer = &bytes.Buffer{} 106 | tpl, err := template.New(filepath.Base(file)).Funcs(funcMap).ParseFiles(global.App.TemplateDir + file) 107 | if err != nil { 108 | return "" 109 | } 110 | 111 | err = tpl.Execute(buffer, dot) 112 | if err != nil { 113 | return "" 114 | } 115 | 116 | return template.HTML(buffer.String()) 117 | } 118 | -------------------------------------------------------------------------------- /template/about.html: -------------------------------------------------------------------------------- 1 | {{define "title"}}关于 — Go语言俱乐部{{end}} 2 | {{define "content"}} 3 |
4 |

关于

5 | 6 | 7 |

Go 语言俱乐部Go.dev 的中国本土化站点,由 Go 语言中文网 发起。 Go 语言中文网是 Go 语言爱好者分享 Go 语言知识,交流使用经验的学习家园,而 Go 语言俱乐部是 Go 语言爱好者的中心,提供来自整个 Go 生态系统的集中和策划的资源。

8 | 9 |

Go gopher 10 | Go 语言俱乐部提供:

11 | 12 |
    13 |
  1. 集中展示发布在 index.golang.org 的 Go 包和模块信息
  2. 14 |
  3. 基本学习资源
  4. 15 |
  5. 关键用例和案例研究
  6. 16 |
17 | 18 |

Go 语言俱乐部目前处于 MVP 状态。 我们为我们所建立的东西感到骄傲,并且很高兴与社区分享它。我们希望你能在使用 Go 语言俱乐部中找到价值和乐趣。开发版只有一小部分功能,我们正在积极的寻求反馈。如果您有任何想法、建议或问题,请联系我们。

19 | 20 |

Sharing feedback / Reporting an issue

21 | 22 |

On the footer of every page there are two links, “Share Feedback” and “Report an issue”. These links will enable you to capture a screenshot of the page you are on, annotate that screenshot, and then send this directly to the go.dev team.

23 | 24 |

Or you can send your bugs, ideas, feature requests and questions to go-discovery-feedback@google.com.

25 | 26 |

Adding a package

27 | 28 |

To add a package or module, simply fetch it from proxy.golang.org. Documentation is generated based on Go source code downloaded from the proxy.golang.org/<module>@<version>.zip. New module versions are fetched from index.golang.org and added to the go.dev site every few minutes.

29 | 30 |

The guidelines for writing documentation for the godoc tool apply to go.dev.

31 | 32 |

It’s important to write a good summary of the package in the first sentence of the package comment. The go.dev site indexes the first sentence and displays it in search results.

33 | 34 |

Removing a package

35 | 36 |

If you would like a package removed, please send an email to go-discovery-feedback@google.com, with the import path or module path that you want to remove.

37 | 38 |

License policy

39 | 40 |

Information for a given package or module may be limited if we are not able to detect a suitable license. See our license policy for more information.

41 | 42 |
43 | {{end}} -------------------------------------------------------------------------------- /static/imgs/logos/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /static/imgs/logos/uber.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 14 | 25 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /static/imgs/solutions/uber-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 14 | 25 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /static/imgs/logos/kubernetes.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/solutions/dropbox-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 13 | 27 | 28 | 29 | 30 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /static/imgs/logos/twitch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 70 | 71 | 75 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /static/imgs/solutions/twitch-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 70 | 71 | 75 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /static/imgs/logos/capital-one.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/logos/stripe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 64 | 70 | 71 | 77 | 78 | 83 | 84 | 92 | 93 | 99 | 100 | 106 | 107 | 113 | 114 | 115 | 116 | 121 | 122 | -------------------------------------------------------------------------------- /static/imgs/logos/google-cloud.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/solutions/capital-one-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | -------------------------------------------------------------------------------- /static/imgs/logos/didi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 新logo 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /static/imgs/logos/comcast.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 16 | 19 | 22 | 25 | 27 | 29 | 31 | 35 | 42 | 47 | 52 | 58 | 62 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /static/imgs/solutions/ops-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/imgs/pink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/gophers/peach.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/imgs/solutions/cloud-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /static/imgs/gophers/happy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/common/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{template "title" .}} 5 | 6 | {{template "seo" .}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 57 | 88 | 90 | 91 |
92 | {{template "content" .}} 93 |
94 | 95 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /static/imgs/logos/mercadoLibre.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 14 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 38 | 44 | 49 | 52 | 57 | 60 | 61 | 62 | 63 | 65 | 67 | 68 | 71 | 82 | 87 | 88 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /static/imgs/solutions/mercadolibre-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 14 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 38 | 44 | 49 | 52 | 57 | 60 | 61 | 62 | 63 | 65 | 67 | 68 | 71 | 82 | 87 | 88 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /static/imgs/pilot-bust.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/solutions/webdev.html: -------------------------------------------------------------------------------- 1 | {{define "title"}}Go Web 开发 - golangclub.com{{end}} 2 | {{define "content"}} 3 |
4 |
5 |

Go Web 开发

6 |

Go 为 Web 应用程序提供了高性能,安全, 7 | 以及对开发人员友好的工具集

8 | 9 |

Go 旨在使开发人员能够快速开发可扩展的、安全的 Web 应用程序。Go 标准库看自带易用的、安全的、高性能的、稳健的 Web 服务器,以及 Web 模板库。Go 完美支持了所有的新技术, 比如:HTTP/2,各种流行的数据库,包括MySQL、 12 | MongoDB、 13 | ElasticSearch,最新的加密技术,如 TLS 1.3 等等。由于 Go 具有极好的可移植性,所以 Go Web 应用程序可以运行在任何的环境、云平台和操作系统上

16 | 17 |

Go gopher 18 | 对于企业来说,Go 是快速跨平台部署的首选。凭借其 Goroutine、本地编译以及基于 URI 的 Package 命名空间,使 Go 代码能够快速编译为单个的、非常小的二进制文件(具有零依赖性)

19 | 20 |

来自 QArea 市场经理 Andrew 22 | Smith 写道:“如果你正在为网络编程,移动开发,微服务,ERP 系统寻找强力的工具,根据很多真实的案例证明,进行相同类型的任务开发,使用 Go 进行 Web 开发比 Python 要快很多”

23 | 24 |
25 |
26 | Quotation mark. 27 |
28 |

29 | Go 语言是我见过的和使用过的最简单的语言,对我来说,Go 比 JavaScript 更易于学习 30 |

31 | 34 |
35 | 36 |

Bayburtsyan 总结了他的公司改用 Go 的五个关键原因:

37 |
    38 |
  1. 39 |

    编译成单个二进制文件 — “根据操作系统类型和体系结构的不同,Go 会使用静态链接将所有依赖项库和模块组合到一个二进制文件中”

    40 |
  2. 41 | 42 |
  3. 43 |

    静态类型 — “对大规模应用来说,类型系统真的很重要” 44 |

    45 |
  4. 46 | 47 |
  5. 48 |

    性能 — “Go 性能这么好的原因是由于其并发模型以及CPU可扩展性。当我们需要处理很多内部请求时,相比于 Python 的线程,Goroutines 在资源使用上会少 10 倍以上”

    49 |
  6. 50 | 51 |
  7. 52 |

    不再需要 Web 框架 — “实际上在大多数情况下,我们不再需要任何第三方库”

    53 |
  8. 54 | 55 |
  9. 56 |

    强大的 IDE 支持和调试 — “在我们的项目用 Go 重写后,我们的代码量比以前减少了 64% ”

    57 |
  10. 58 |
59 | 60 | 61 | 62 | 126 | 127 |

核心解决方案

128 | 129 |

Go web 开发书单

130 | 131 | 200 | 201 | 205 | 206 | 224 | 225 | 229 | 230 | 241 | 242 | 246 | 247 | 252 | 253 | 257 | 258 | 273 | 274 | 278 | 279 | 288 | 289 |

课程

290 | 291 | 295 | 296 |

项目

297 | 298 | 305 | 306 |
307 |
308 | 309 | {{end}} -------------------------------------------------------------------------------- /template/solution.html: -------------------------------------------------------------------------------- 1 | {{define "title"}}解决方案 — Go语言俱乐部{{end}} 2 | {{define "content"}} 3 |
4 |
5 |

解决方案

6 |
7 |
8 |
9 |
10 |

11 | 利用 Go 来改进你的开发过程 12 |

13 |
14 |
15 |
16 |
17 |
18 |

专为今天的需求而设计

19 |
20 | 91 |
92 |
93 |
94 |
95 |
96 |

使用 Go 的公司

97 |
98 | 271 |
272 |
273 | {{end}} 274 | --------------------------------------------------------------------------------