mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-01-23 17:20:24 +08:00
add quick example
This commit is contained in:
parent
38806e7237
commit
77e23ad65d
BIN
doc/images/shorturl-arch.png
Normal file
BIN
doc/images/shorturl-arch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
182
doc/shorturl.md
Normal file
182
doc/shorturl.md
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
# 使用go-zero从0到1快速构建高并发的短链服务
|
||||||
|
|
||||||
|
## 0. 什么是短链服务?
|
||||||
|
|
||||||
|
短链服务就是将长的URL网址,通过程序计算等方式,转换为简短的网址字符串。
|
||||||
|
|
||||||
|
写此短链服务是为了从整体上演示go-zero构建完整微服务的过程,算法和实现细节尽可能简化了,所以这不是一个高阶的短链服务。
|
||||||
|
|
||||||
|
## 1. 短链微服务架构图
|
||||||
|
|
||||||
|
![架构图](images/shorturl-arch.png)
|
||||||
|
|
||||||
|
## 2. 创建工作目录并初始化go.mod
|
||||||
|
|
||||||
|
* 创建工作目录`shorturl`
|
||||||
|
* 在`shorturl`目录下执行`go mod init shorturl`初始化`go.mod`
|
||||||
|
|
||||||
|
## 3. 编写API Gateway代码
|
||||||
|
|
||||||
|
* 通过goctl生成`shorturl.api`并编辑,为了简洁,去除了文件开头的`info`,代码如下:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type (
|
||||||
|
shortenReq struct {
|
||||||
|
url string `form:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
shortenResp struct {
|
||||||
|
shortUrl string `json:"shortUrl"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
expandReq struct {
|
||||||
|
key string `form:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
expandResp struct {
|
||||||
|
url string `json:"url"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
service shorturl-api {
|
||||||
|
@server(
|
||||||
|
handler: ShortenHandler
|
||||||
|
)
|
||||||
|
get /shorten(shortenReq) returns(shortenResp)
|
||||||
|
|
||||||
|
@server(
|
||||||
|
handler: ExpandHandler
|
||||||
|
)
|
||||||
|
get /expand(expandReq) returns(expandResp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
type用法和go一致,service用来定义get/post/head/delete等api请求,解释如下:
|
||||||
|
|
||||||
|
* `service shorturl-api {`这一行定义了service名字
|
||||||
|
* `@server`部分用来定义server端用到的属性
|
||||||
|
* `handler`定义了服务端handler名字
|
||||||
|
* `get /shorten(shortenReq) returns(shortenResp)`定义了get方法的路由、请求参数、返回参数等
|
||||||
|
|
||||||
|
* 使用goctl生成API Gateway代码
|
||||||
|
|
||||||
|
```shell
|
||||||
|
goctl api go -api shorturl.api -dir api
|
||||||
|
```
|
||||||
|
|
||||||
|
生成的文件结构如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── api
|
||||||
|
│ ├── etc
|
||||||
|
│ │ └── shorturl-api.yaml // 配置文件
|
||||||
|
│ ├── internal
|
||||||
|
│ │ ├── config
|
||||||
|
│ │ │ └── config.go // 定义配置
|
||||||
|
│ │ ├── handler
|
||||||
|
│ │ │ ├── expandhandler.go // 实现expandHandler
|
||||||
|
│ │ │ ├── routes.go // 定义路由处理
|
||||||
|
│ │ │ └── shortenhandler.go // 实现shortenHandler
|
||||||
|
│ │ ├── logic
|
||||||
|
│ │ │ ├── expandlogic.go // 实现ExpandLogic
|
||||||
|
│ │ │ └── shortenlogic.go // 实现ShortenLogic
|
||||||
|
│ │ ├── svc
|
||||||
|
│ │ │ └── servicecontext.go // 定义ServiceContext
|
||||||
|
│ │ └── types
|
||||||
|
│ │ └── types.go // 定义请求、返回结构体
|
||||||
|
│ └── shorturl.go // main入口定义
|
||||||
|
├── go.mod
|
||||||
|
├── go.sum
|
||||||
|
└── shorturl.api
|
||||||
|
```
|
||||||
|
|
||||||
|
* 启动API Gateway服务,默认侦听在8888端口
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go run api/shorturl.go -f api/etc/shorturl-api.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
* 测试API Gateway服务
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -i "http://localhost:8888/shorten?url=a"
|
||||||
|
```
|
||||||
|
|
||||||
|
返回如下:
|
||||||
|
|
||||||
|
```http
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
Date: Thu, 27 Aug 2020 14:31:39 GMT
|
||||||
|
Content-Length: 15
|
||||||
|
|
||||||
|
{"shortUrl":""}
|
||||||
|
```
|
||||||
|
|
||||||
|
* 可以修改`internal/svc/servicecontext.go`来传递服务依赖(如果需要)
|
||||||
|
* 实现逻辑可以修改`internal/logic`下的对应文件
|
||||||
|
|
||||||
|
## 4. 编写shorten/expand rpc服务(未完)
|
||||||
|
|
||||||
|
## 5. 定义数据库表结构
|
||||||
|
|
||||||
|
* shorturl下创建rpc/model目录:`mkdir -p rpc/model`
|
||||||
|
* 在roc/model目录下编写创建shorturl表的sql文件`shorturl.sql`,如下:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `shorturl`
|
||||||
|
(
|
||||||
|
`id` bigint(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`key` varchar(255) NOT NULL DEFAULT '' COMMENT 'shorten key',
|
||||||
|
`url` varchar(255) DEFAULT '' COMMENT 'original url',
|
||||||
|
PRIMARY KEY(`id`),
|
||||||
|
UNIQUE KEY `key_index`(`key`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 自动生成CRUD+cache代码
|
||||||
|
|
||||||
|
* 在`rpc/model`目录下执行如下命令生成CRUD+cache代码,`-c`表示使用`redis cache`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
goctl model mysql ddl -c -src shorturl.sql -dir .
|
||||||
|
```
|
||||||
|
|
||||||
|
生成后的文件结构如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── api
|
||||||
|
│ ├── etc
|
||||||
|
│ │ └── shorturl-api.yaml
|
||||||
|
│ ├── internal
|
||||||
|
│ │ ├── config
|
||||||
|
│ │ │ └── config.go
|
||||||
|
│ │ ├── handler
|
||||||
|
│ │ │ ├── expandhandler.go
|
||||||
|
│ │ │ ├── routes.go
|
||||||
|
│ │ │ └── shortenhandler.go
|
||||||
|
│ │ ├── logic
|
||||||
|
│ │ │ ├── expandlogic.go
|
||||||
|
│ │ │ └── shortenlogic.go
|
||||||
|
│ │ ├── svc
|
||||||
|
│ │ │ └── servicecontext.go
|
||||||
|
│ │ └── types
|
||||||
|
│ │ └── types.go
|
||||||
|
│ └── shorturl.go
|
||||||
|
├── go.mod
|
||||||
|
├── go.sum
|
||||||
|
├── rpc
|
||||||
|
│ └── model
|
||||||
|
│ ├── shorturl.sql
|
||||||
|
│ ├── shorturlmodel.go // CRUD+cache代码
|
||||||
|
│ └── vars.go // 定义常量和变量
|
||||||
|
├── shorturl.api
|
||||||
|
└── shorturl.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 未完待续
|
||||||
|
|
@ -185,6 +185,7 @@ go get -u github.com/tal-tech/go-zero
|
|||||||
|
|
||||||
## 8. 文档 (逐步完善中)
|
## 8. 文档 (逐步完善中)
|
||||||
|
|
||||||
|
* [从0到1快速构建一个高并发的微服务系统](doc/shorturl.md)
|
||||||
* [goctl使用帮助](doc/goctl.md)
|
* [goctl使用帮助](doc/goctl.md)
|
||||||
* [关键字替换和敏感词过滤工具](doc/keywords.md)
|
* [关键字替换和敏感词过滤工具](doc/keywords.md)
|
||||||
|
|
||||||
|
@ -194,11 +194,11 @@ var (
|
|||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "mysql",
|
Name: "mysql",
|
||||||
Usage: `generate mysql model"`,
|
Usage: `generate mysql model`,
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "ddl",
|
Name: "ddl",
|
||||||
Usage: `generate mysql model from ddl"`,
|
Usage: `generate mysql model from ddl`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "src, s",
|
Name: "src, s",
|
||||||
@ -221,15 +221,15 @@ var (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "datasource",
|
Name: "datasource",
|
||||||
Usage: `generate model from datasource"`,
|
Usage: `generate model from datasource`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "url",
|
Name: "url",
|
||||||
Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`,
|
Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database`,
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "table, t",
|
Name: "table, t",
|
||||||
Usage: `source table,tables separated by commas,like "user,course"`,
|
Usage: `source table,tables separated by commas,like "user,course`,
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "cache, c",
|
Name: "cache, c",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# generate model with cache from ddl
|
# generate model with cache from ddl
|
||||||
goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c=true
|
goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c
|
||||||
|
|
||||||
# generate model with cache from data source
|
# generate model with cache from data source
|
||||||
goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model"
|
goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model"
|
@ -2,6 +2,4 @@ package gen
|
|||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var ErrCircleQuery = errors.New("circle query with other fields")
|
||||||
ErrCircleQuery = errors.New("circle query with other fields")
|
|
||||||
)
|
|
||||||
|
@ -82,7 +82,7 @@ func (g *defaultGenerator) Start(withCache bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// generate error file
|
// generate error file
|
||||||
filename := filepath.Join(dirAbs, "error.go")
|
filename := filepath.Join(dirAbs, "vars.go")
|
||||||
if !util.FileExists(filename) {
|
if !util.FileExists(filename) {
|
||||||
err = ioutil.WriteFile(filename, []byte(template.Error), os.ModePerm)
|
err = ioutil.WriteFile(filename, []byte(template.Error), os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -6,6 +6,7 @@ func (m *{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimaryKey}}
|
|||||||
if err!=nil{
|
if err!=nil{
|
||||||
return err
|
return err
|
||||||
}{{end}}
|
}{{end}}
|
||||||
|
|
||||||
{{.keys}}
|
{{.keys}}
|
||||||
_, err {{if .containsIndexCache}}={{else}}:={{end}} m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
_, err {{if .containsIndexCache}}={{else}}:={{end}} m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := ` + "`" + `delete from ` + "` +" + ` m.table + ` + " `" + ` where {{.originalPrimaryKey}} = ?` + "`" + `
|
query := ` + "`" + `delete from ` + "` +" + ` m.table + ` + " `" + ` where {{.originalPrimaryKey}} = ?` + "`" + `
|
||||||
|
@ -4,8 +4,5 @@ var Error = `package model
|
|||||||
|
|
||||||
import "github.com/tal-tech/go-zero/core/stores/sqlx"
|
import "github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||||
|
|
||||||
var (
|
var ErrNotFound = sqlx.ErrNotFound
|
||||||
ErrNotFound = sqlx.ErrNotFound
|
|
||||||
)
|
|
||||||
|
|
||||||
`
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user