forked from gourouting/singo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Chengka
committed
Sep 13, 2018
0 parents
commit bfd645a
Showing
21 changed files
with
711 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
MYSQL_DSN="db_user@/db_name?charset=utf8&parseTime=True&loc=Local" | ||
REDIS_ADDR="127.0.0.1:6379" | ||
REDIS_PW="" | ||
REDIS_DB="" | ||
SESSION_SECRE="" | ||
GIN_MODE="debug" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.vscode/ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Golang API范例项目 | ||
|
||
## 目的 | ||
|
||
本项目采用了一系列Golang中比较流行的组件,可以以本项目为基础快速搭建Restful Web API | ||
|
||
## 特色 | ||
|
||
本项目已经整合了许多开发API所必要的组件: | ||
|
||
1. Gin: 轻量级Web框架,自称路由速度是golang最快的 | ||
2. GORM: ORM工具。本项目需要配合Mysql使用 | ||
3. Gin-Session: Gin框架提供的Session操作工具 | ||
4. Go-Redis: Golang Redis客户端 | ||
5. godotenv: 开发环境下的环境变量工具,方便使用环境变量 | ||
6. Gin-Cors: Gin框架提供的跨域中间件 | ||
7. 自行实现了国际化i18n的一些基本功能 | ||
|
||
本项目已经预先实现了一些常用的代码方便参考和复用: | ||
|
||
1. 创建了用户模型 | ||
2. 实现了```/api/v1/user/register```用户注册接口 | ||
3. 实现了```/api/v1/user/login```用户登录接口 | ||
4. 实现了```/api/v1/user/me```用户资料接口(需要登录后获取session) | ||
5. 实现了```/api/v1/user/logout```用户登出接口(需要登录后获取session) | ||
|
||
本项目已经预先创建了一系列文件夹划分出下列模块: | ||
|
||
1. api文件夹就是MVC框架的controller,负责协调各部件完成任务 | ||
2. model文件夹负责存储数据库模型和数据库操作相关的代码 | ||
3. service负责处理比较复杂的业务,把业务代码模型化可以有效提高业务代码的质量(比如用户注册,充值,下单等) | ||
4. serializer储存通用的json模型,把model得到的数据库模型转换成api需要的json对象 | ||
5. cache负责redis缓存相关的代码 | ||
6. auth权限控制文件夹 | ||
7. util一些通用的小工具 | ||
8. conf放一些静态存放的配置文件,其中locales内放置翻译相关的配置文件 | ||
|
||
## Godotenv | ||
|
||
项目在启动的时候依赖以下环境变量,但是在也可以在项目根目录创建.env文件设置环境变量便于使用(建议开发环境使用) | ||
|
||
```shell | ||
MYSQL_DSN="db_user:db_password@/db_name?charset=utf8&parseTime=True&loc=Local" # Mysql连接地址 | ||
REDIS_ADDR="127.0.0.1:6379" # Redis端口和地址 | ||
REDIS_PW="" # Redis连接密码 | ||
REDIS_DB="" # Redis库从0到10 | ||
SESSION_SECRE="" # Seesion密钥,必须设置而且不要泄露 | ||
GIN_MODE="debug" | ||
``` | ||
|
||
## Go 依赖 | ||
|
||
```shell | ||
go get -u github.com/gin-gonic/gin | ||
go get -u github.com/jinzhu/gorm | ||
go get -u github.com/gin-contrib/cors | ||
go get -u github.com/gin-contrib/sessions | ||
go get -u github.com/joho/godotenv | ||
go get -u github.com/go-redis/redis | ||
``` | ||
|
||
## 运行 | ||
|
||
```shell | ||
go run main.go | ||
``` | ||
|
||
项目运行后启动在3000端口(可以修改,参考gin文档) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package api | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"gin_example/model" | ||
"gin_example/serializer" | ||
"gin_example/util" | ||
|
||
"github.com/gin-gonic/gin" | ||
validator "gopkg.in/go-playground/validator.v8" | ||
) | ||
|
||
// Ping 状态检查页面 | ||
func Ping(c *gin.Context) { | ||
c.JSON(200, serializer.Response{ | ||
Status: 0, | ||
Msg: "Pong", | ||
}) | ||
} | ||
|
||
// CurrentUser 获取当前用户 | ||
func CurrentUser(c *gin.Context) *model.User { | ||
if user, _ := c.Get("user"); user != nil { | ||
if u, ok := user.(*model.User); ok { | ||
return u | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// ErrorResponse 返回错误消息 | ||
func ErrorResponse(err error) serializer.Response { | ||
if ve, ok := err.(validator.ValidationErrors); ok { | ||
for _, e := range ve { | ||
field := util.T(fmt.Sprintf("Field.%s", e.Field)) | ||
tag := util.T(fmt.Sprintf("Tag.Valid.%s", e.Tag)) | ||
return serializer.Response{ | ||
Status: 40001, | ||
Msg: fmt.Sprintf("%s%s", field, tag), | ||
Error: fmt.Sprint(err), | ||
} | ||
} | ||
} | ||
if _, ok := err.(*json.UnmarshalTypeError); ok { | ||
return serializer.Response{ | ||
Status: 40001, | ||
Msg: "JSON类型不匹配", | ||
Error: fmt.Sprint(err), | ||
} | ||
} | ||
|
||
return serializer.Response{ | ||
Status: 40001, | ||
Msg: "参数错误", | ||
Error: fmt.Sprint(err), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package api | ||
|
||
import ( | ||
"gin_example/serializer" | ||
"gin_example/service" | ||
|
||
"github.com/gin-contrib/sessions" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// UserRegister 用户注册接口 | ||
func UserRegister(c *gin.Context) { | ||
var service service.UserRegisterService | ||
if err := c.ShouldBind(&service); err == nil { | ||
if user, err := service.Register(); err != nil { | ||
c.JSON(200, err) | ||
} else { | ||
res := serializer.BuildUserResponse(user) | ||
c.JSON(200, res) | ||
} | ||
} else { | ||
c.JSON(200, ErrorResponse(err)) | ||
} | ||
} | ||
|
||
// UserLogin 用户登录接口 | ||
func UserLogin(c *gin.Context) { | ||
var service service.UserLoginService | ||
if err := c.ShouldBind(&service); err == nil { | ||
if user, err := service.Login(); err != nil { | ||
c.JSON(200, err) | ||
} else { | ||
// 设置Session | ||
s := sessions.Default(c) | ||
s.Clear() | ||
s.Set("user_id", user.ID) | ||
s.Save() | ||
|
||
res := serializer.BuildUserResponse(user) | ||
c.JSON(200, res) | ||
} | ||
} else { | ||
c.JSON(200, ErrorResponse(err)) | ||
} | ||
} | ||
|
||
// UserMe 用户详情 | ||
func UserMe(c *gin.Context) { | ||
user := CurrentUser(c) | ||
res := serializer.BuildUserResponse(*user) | ||
c.JSON(200, res) | ||
} | ||
|
||
// UserLogout 用户登出 | ||
func UserLogout(c *gin.Context) { | ||
s := sessions.Default(c) | ||
s.Clear() | ||
s.Save() | ||
c.JSON(200, serializer.Response{ | ||
Status: 0, | ||
Msg: "登出成功", | ||
}) | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package cache | ||
|
||
import ( | ||
"os" | ||
"strconv" | ||
|
||
"github.com/gin-gonic/gin" | ||
"github.com/go-redis/redis" | ||
) | ||
|
||
// RedisClient Redis缓存客户端单例 | ||
var RedisClient *redis.Client | ||
|
||
// Redis 在中间件中初始化redis链接 | ||
func Redis() gin.HandlerFunc { | ||
db, _ := strconv.ParseUint(os.Getenv("REDIS_DB"), 10, 64) | ||
client := redis.NewClient(&redis.Options{ | ||
Addr: os.Getenv("REDIS_ADDR"), | ||
Password: os.Getenv("REDIS_PW"), | ||
DB: int(db), | ||
}) | ||
|
||
_, err := client.Ping().Result() | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
RedisClient = client | ||
|
||
return func(c *gin.Context) { | ||
c.Set("RedisClient", client) | ||
c.Next() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Tag: | ||
required: "必须存在,而且不能为空" | ||
min: "不够长" | ||
max: "太长" | ||
Field: | ||
Name: "名称" | ||
Nickname: "用户昵称" | ||
UserName: "用户名" | ||
Password: "密码" | ||
PasswordConfirm: "密码校验" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package main | ||
|
||
import ( | ||
"gin_example/api" | ||
"gin_example/cache" | ||
"gin_example/middleware" | ||
"gin_example/model" | ||
"gin_example/util" | ||
"os" | ||
|
||
"github.com/gin-gonic/gin" | ||
"github.com/joho/godotenv" | ||
) | ||
|
||
func main() { | ||
godotenv.Load() | ||
|
||
// 从配置文件读取配置 | ||
if err := util.LoadLocales("conf/locales/zh-cn.yaml"); err != nil { | ||
panic(err) | ||
} | ||
|
||
r := gin.Default() | ||
|
||
// 中间件, 顺序不能改 | ||
r.Use(model.Database(os.Getenv("MYSQL_DSN"))) | ||
r.Use(cache.Redis()) | ||
r.Use(middleware.Session(os.Getenv("SESSION_SECRET"))) | ||
r.Use(middleware.Cors()) | ||
r.Use(middleware.CurrentUser()) | ||
|
||
// 路由 | ||
v1 := r.Group("/api/v1") | ||
{ | ||
v1.POST("ping", api.Ping) | ||
|
||
// 用户登录 | ||
v1.POST("user/register", api.UserRegister) | ||
|
||
// 用户登录 | ||
v1.POST("user/login", api.UserLogin) | ||
|
||
// 需要登录保护的 | ||
v1.Use(middleware.AuthRequired()) | ||
{ | ||
// User Routing | ||
v1.GET("user/me", api.UserMe) | ||
v1.DELETE("user/logout", api.UserLogout) | ||
} | ||
} | ||
|
||
// 监听 | ||
r.Run(":3000") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package middleware | ||
|
||
import ( | ||
"gin_example/model" | ||
"gin_example/serializer" | ||
|
||
"github.com/gin-contrib/sessions" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// CurrentUser 获取登录用户 | ||
func CurrentUser() gin.HandlerFunc { | ||
return func(c *gin.Context) { | ||
session := sessions.Default(c) | ||
uid := session.Get("user_id") | ||
if uid != nil { | ||
user, err := model.GetUser(uid) | ||
if err == nil { | ||
c.Set("user", &user) | ||
} | ||
} | ||
c.Next() | ||
} | ||
} | ||
|
||
// AuthRequired 需要登录 | ||
func AuthRequired() gin.HandlerFunc { | ||
return func(c *gin.Context) { | ||
if user, _ := c.Get("user"); user != nil { | ||
if _, ok := user.(*model.User); ok { | ||
c.Next() | ||
return | ||
} | ||
} | ||
|
||
c.JSON(200, serializer.Response{ | ||
Status: 401, | ||
Msg: "需要登录", | ||
}) | ||
c.Abort() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package middleware | ||
|
||
import ( | ||
"github.com/gin-contrib/cors" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// Cors 跨域配置 | ||
func Cors() gin.HandlerFunc { | ||
config := cors.DefaultConfig() | ||
config.AllowMethods = []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"} | ||
config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Cookie"} | ||
config.AllowOrigins = []string{"http://www.example.com"} | ||
config.AllowCredentials = true | ||
return cors.New(config) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package middleware | ||
|
||
import ( | ||
"github.com/gin-contrib/sessions" | ||
"github.com/gin-contrib/sessions/cookie" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// Session 初始化session | ||
func Session(secret string) gin.HandlerFunc { | ||
store := cookie.NewStore([]byte(secret)) | ||
//Also set Secure: true if using SSL, you should though | ||
store.Options(sessions.Options{HttpOnly: true, MaxAge: 7 * 86400, Path: "/"}) | ||
return sessions.Sessions("gin-session", store) | ||
} |
Oops, something went wrong.