# 安装spring核心包
go get -u github.com/go-spring/spring-core@v1.1.0-rc2
# 安装web starter
# gin
go get -u github.com/go-spring/starter-gin@v1.1.0-rc2
# echo
go get -u github.com/go-spring/starter-echo@v1.1.0-rc2
main.go
package main
import (
"errors"
"github.com/go-spring/spring-core/gs"
"github.com/go-spring/spring-core/web"
// 引入spring web引擎
// gin
SpringGin "github.com/go-spring/spring-gin"
// echo
//SpringEcho "github.com/go-spring/spring-echo"
// 这里使用SpringGin方式创建一个web容器, 因此引入web starter而不是具体某个web引擎的starter
_ "github.com/go-spring/starter-web"
"log"
)
// 定义token过滤器
type TokenFilter struct {
}
/**
设置过滤器指定的path pattern范围, 这里设置为 /test2/* 即拦截 /test2/*类型的端点
若不定义该方法则默认为全局拦截器
*/
func (f *TokenFilter) URLPatterns() []string {
return []string{"/test2/*"}
}
// 实现 web.Filter 接口
func (t *TokenFilter) Invoke(ctx web.Context, chain web.FilterChain) {
token := ctx.QueryParam("token")
if token != "abcde" {
ctx.JSON(web.ERROR.Error(errors.New("invalid token")))
} else {
chain.Next(ctx)
}
}
func init() {
// 使用SpringGin创建web容器, 使用该方式可创建多http server
webContainer := SpringGin.NewContainer(web.ContainerConfig{
Port: 8080,
BasePath: "/",
})
// 为web容器添加token过滤器
webContainer.AddFilter(&TokenFilter{})
// 若直接使用默认容器则使用如下方法添加过滤器
// gs.Object(&TokenFilter{}).Export((*web.Filter)(nil))
// 注入容器并设置导出接口
gs.Object(webContainer).Export((*web.Container)(nil))
/*
访问 http://127.0.0.1:8080/test/t1 将不会经过token拦截器, 返回:
{
"code": 200,
"msg": "SUCCESS"
}
访问 http://127.0.0.1:8080/test2/t1 将被token过滤器拦截, 返回:
{
"code": -1,
"msg": "ERROR",
"err": "/path/main.go:32: invalid userId"
}
访问 http://127.0.0.1:8080/test2/t1?token=abcde 将被token过滤器放行, 返回:
{
"code": 200,
"msg": "SUCCESS"
}
*/
gs.Object(new(testController)).Init(func(c *testController) {
gs.GetMapping("/test/t1", c.echo)
gs.GetMapping("/test2/t1", c.echo)
})
}
// 定义测试控制器
type testController struct {
}
func (c *testController) echo(ctx web.Context) {
ctx.JSON(web.SUCCESS)
}
func main() {
log.Fatal(gs.Run())
}
在spring-gin v1.1.0-rc2版本中, 中间件不会直接拦截并返回结果, 而是将拦截器的结果与端点方法返回的结果组合返回, 这里修改源码文件github.com/go-spring/spring-gin/container.go的168行与174行即可解决(问题已反馈, 等到正式版应该不会有这种问题了)
// ...省略
func HandlerWrapper(fn web.Handler, wildCardName string, filters []web.Filter) []gin.HandlerFunc {
var handlers []gin.HandlerFunc
handlers = append(handlers, func(ginCtx *gin.Context) {
if WebContext(ginCtx) == nil {
NewContext(fn, wildCardName, ginCtx)
}
})
for _, filter := range filters {
f := filter
handlers = append(handlers, func(ginCtx *gin.Context) {
f.Invoke(WebContext(ginCtx), &ginFilterChain{ginCtx})
ginCtx.Abort() // 168行之后添加该代码
})
}
handlers = append(handlers, func(ginCtx *gin.Context) {
fn.Invoke(WebContext(ginCtx))
ginCtx.Abort() // 174行之后添加该代码
})
return handlers
}
// ...省略
Go-Spring启动的Web容器会带有默认的日志过滤器,当我们不需要使用默认日志而自定义日志时,可以在创建容器时重新设置日志过滤器, 如下所示:
main.go
package main
import (
"github.com/go-spring/spring-core/gs"
"github.com/go-spring/spring-core/web"
SpringGin "github.com/go-spring/spring-gin"
// 仅使用starter web
_ "github.com/go-spring/starter-web"
"log"
"time"
)
func init() {
// 方式一
// 创建gin容器, 并设置初始化方法
gs.Object(SpringGin.NewContainer(web.ContainerConfig{
Port: 8080,
BasePath: "/",
})).Init(func(container *SpringGin.Container) {
// 直接使用内置的web.FuncFilter方法构建过滤器
container.SetLoggerFilter(web.FuncFilter(func(ctx web.Context, chain web.FilterChain) {
// 自定义日志信息
startTime := time.Now()
chain.Next(ctx)
log.Printf("接口耗时:%v", time.Since(startTime))
}))
// 导出为web.Container类型(若不指定将无法检测到web容器)
}).Export((*web.Container)(nil))
// 方式二
// 使用gs.Provide + 函数方式创建 web 容器, 创建容器过程中配置容器日志过滤器及其他信息
//gs.Provide(func() web.Container {
// webContainer := SpringGin.NewContainer(web.ContainerConfig{
// Port: 8080,
// BasePath: "/",
// })
// webContainer.SetLoggerFilter(web.FuncFilter(func(ctx web.Context, chain web.FilterChain) {
// startTime := time.Now()
// chain.Next(ctx)
// log.Printf("接口耗时:%v", time.Since(startTime))
// }))
// return webContainer
//})
// 定义GET方法端点
gs.GetMapping("/", func(ctx web.Context) {
ctx.JSON(web.SUCCESS.Data("Hello Go-Spring!"))
})
}
func main() {
log.Fatal(gs.Run())
}