插件接口都在/interfaces文件目录下并有尽量详细的注释,你只需要查看interfaces目录下的文件接口就可以了解到linweb的功能。
linweb目前实现了请求上下文(context)、动态路由(router)、中间件(middleware)、依赖注入(Injector)、模型验证与模型映射(model --- validate、map)及应用内缓存(cache)等,其中部分实现参考了 极客兔兔的七天实现Web框架 。待开发功能及工作可在Roadmap中查看,欢迎建议、issue、pr和star~
在linweb中,将完全面向接口编程并将可扩展部分插件化。
linweb提供一套插件接口及默认实现,你也可以在新建linweb实例时添加自定义实现。
使用NewLinweb方法创建一个linweb,调用Run方法就可以运行一个没有任何api的web项目。
func main() {
l := linweb.NewLinweb()
l.Run(":9999")
}
linweb使用Options模式,可以在新建linweb实例时,传入自定义插件(插件必须实现相应的接口),未添加的插件将使用默认插件。相关插入选项位于plugins.go
中。
func main() {
l := linweb.NewLinweb(linweb.RouterPlugin(&CustomizeRouter{}))
l.Run(":9999")
}
linweb将面向Controller定义api接口。
①需要在controller方法的注释中添加注解,标识HTTP方法和路由路径。如果没有,将不作为一个http请求接口。
②方法的第一个参数必须为IContext,linweb将自动实例化,Context中保存request及response的信息。
③如果存在dto入参,linweb将自动解析request.body的json字符串,并将其转化为dto实例。
type LoginDto struct {
Name string `json:"Name"`
Password string `json:"Password"`
}
type UserController struct {
}
//[GET("/hello")]
func (user *UserController) Hello(c interfaces.IContext) {
c.Response().HTML(http.StatusOK, "<h1>Hello linweb</h1>")
}
//[POST("/login")]
func (user *UserController) Login(c interfaces.IContext, dto LoginDto) {
fmt.Println(dto)
c.Response().String(http.StatusOK, "Welcome %s!", dto.Name)
}
func main() {
l := linweb.NewLinweb()
l.AddControllers(&controllers.UserController{}, &controllers.BlogController{})
l.Run(":9999")
}
使用AddMiddlewares方法添加多个针对所有api接口的全局中间件。
func main() {
l := linweb.NewLinweb()
l.AddMiddlewares(PrintHelloMiddleware)
l.AddControllers(&controllers.UserController{}, &controllers.BlogController{})
l.Run(":9999")
}
func PrintHelloMiddleware(c interfaces.IContext) {
fmt.Println("hello linweb!")
c.Next()
fmt.Println("byebye linweb")
}
使用linweb的依赖注入插件可以实现在Controller内部自动将需要的实例注入,比如 当我们的Controller方法中需要操作数据库。
type UserController struct {
UserRepo *db.UserRepository
}
//[POST("/login")]
func (user *UserController) Login(c interfaces.IContext, dto LoginDto) {
dataUser := user.UserRepo.GetUserByName(dto.Name)
if dataUser != nil && dataUser.Password == dto.Password {
c.Response().String(http.StatusOK, "Welcome %s!", dto.Name)
return
}
c.Response().String(http.StatusBadRequest, "Password error!")
}
这样,每次请求来的时候,UserRepo将被自动实例化,并且可以调用。当然,我们需要在定义linweb时注册相应的依赖注入到容器中。
func main() {
l := linweb.NewLinweb()
l.AddSingleton(&db.UserRepository{})
l.AddControllers(&controllers.UserController{}, &controllers.BlogController{})
err := l.Run(":3002")
if err != nil {
log.Fatalln(err)
return
}
}
-
singleton模式的依赖注入,会在全局使用同一个实例注入。
-
transient模式的依赖注入,会在每一次请求到来的时候重新注入新的实例。
model用于对struct的模型验证与映射,采用链式调用的方式,可以通过NewModel方法传入需要操作的struct,通过调用Validate、MapToByFieldName等方法实现验证和Dto映射。目前使用validator、go-mapper实现验证与映射功能,使用规则详见链接。
type LoginDto struct {
Name string `json:"Name"`
Password string `json:"Password"`
}
type DatabaseModel struct {
Name string
Password string
}
type UserController struct {
}
//[POST("/login")]
func (user *UserController) Login(c interfaces.IContext, dto LoginDto) {
dataModel := &DatabaseModel{}
err := linweb.NewModel(dto).Validate().MapToByFieldName(dataModel).ModelError()
if err != nil {
c.Response().String(http.StatusInternalServerError, "Model error :%s!", err.Error())
}
c.Response().String(http.StatusOK, "Welcome %s!", dto.Name)
}
框架内置了缓存,可以自定义最大内存占用,达到上限采用LRU-K淘汰策略。缓存可以设置键有效时间,并使用 惰性删除 和 定期删除 策略,实现对过期键及时扫描删除。我们可以直接使用linweb提供的Cache单例。
type BlogController struct {
}
//[GET("/blog/:id")]
func (blog *BlogController) GetBlog(c interfaces.IContext) {
id, _ := strconv.Atoi(c.Request().Param("id"))
linweb.Cache.AddWithExpire("id", id, 10*time.Second)
c.Response().String(http.StatusOK, "id=%s", c.Request().Param("id"))
}