1

Beerus 上线啦,用 Go 开发的 web 解决方案

 2 years ago
source link: https://www.v2ex.com/t/821978
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Beerus 是一个用 Go 开发的 web 解决方案,包含一个 web 框架,一个数据库操作框架,一个正在规划中的 RPC 框架,目前( web 框架,数据库操作框架 已经发布了第一个版本)

Web 框架

因为他是牵头的框架,说到 web 大家想到的肯定是接口管理,所以他的名字就直接沿用了 Beerus ,也就是这一套项目的品牌名称,它是以 net/http 为基础,在此基础上扩展了路由的管理方式,并增加了拦截器,会话管理,用 struct 接收参数,参数验证等功能,还提供了 WebSocket 支持,可以将 http 协议升级到 WebSocket 并实现通信

数据库操作框架

名字叫 Beerus-DB ,用到了[go-sql-driver/mysql]来做数据库连接与基础操作,在此基础上做了很多扩展,比如:连接池管理,多数据源,事务管理,单表无 sql 操作,多表以及复杂操作可以自己写 sql ,sql 支持{}占位符,可以用 struct 作为参数来操作数据库等

HTTP 示例

创建一个函数管理路由

func CreateRoute() {
	// post route example
    route.POST("/example/post", func (req *commons.BeeRequest, res *commons.BeeResponse) {
        
        res.SendJson(`{"msg":"SUCCESS"}`)
    })

    // get route example
    route.GET("/example/get", func (req *commons.BeeRequest, res *commons.BeeResponse) {
    
        res.SendJson(`{"msg":"SUCCESS"}`)
    })
}
func main() {
    // Interceptors, routes, etc. Loading of data requires its own calls
    routes.CreateRoute()
    
    // Listen the service and listen to port 8080
    beerus.ListenHTTP(8080)
}

如果你想用实体接收参数,可以这么做

func CreateRoute() {
    // Example of parameter conversion to struct and parameter checksum
    route.POST("/example/post", func (req *commons.BeeRequest, res *commons.BeeResponse) {
        
        // 首先需要建一个实体的实例
        param := DemoParam{}
        
        // 调用这个函数,将请求的参数全部提取到实体中,支持任意请求方式
        params.ToStruct(req, &param, param)
        
        // 对参数进行验证,如果没通过就返回 提示信息
        var result = params.Validation(req, &param, param)
        if result != params.SUCCESS {
            res.SendErrorMsg(1128, result)
            return
        }
        
        // 如果你觉得上面的麻烦,那么也可以这样,直接采用一步到位的方式:参数提取 + 验证
        var result = params.ToStructAndValidation(req, &param, param)
        if result != params.SUCCESS {
            res.SendErrorMsg(1128, result)
            return
        }
        
        
        res.SendJson(`{"msg":"SUCCESS"}`)
    })
}

// DemoParam If you have a struct like this, and you want to put all the parameters from the request into this struct
type DemoParam struct {
    TestStringReception  string  `notnull:"true" msg:"TestStringReception Cannot be empty" routes:"/example/put"`
    TestIntReception     int     `max:"123" min:"32" msg:"TestIntReception The value range must be between 32 - 123" routes:"/example/post"`
    TestUintReception    uint    `max:"123" min:"32" msg:"TestUintReception The value range must be between 32 - 123"`
    TestFloatReception   float32 `max:"123" min:"32" msg:"TestFloatReception The value range must be between 32 - 123"`
    TestBoolReception    bool
    TestStringRegReception string `reg:"^[a-z]+$" msg:"TestStringRegReception Does not meet the regular"`
    TestBeeFileReception commons.BeeFile
    
    TestJsonReception []string
}

WebSocket 示例

创建一个函数来管理 WebSocket 路由

func CreateWebSocketRoute() {
	wroute.AddWebSocketRoute("/ws/test", onConnection, onMessage, onClose)
	wroute.AddWebSocketRoute("/ws/test2", onConnection, onMessage, onClose)
}

// In order to save time, only three functions are used below. In practice, you can configure a set of functions for each wroute

func onConnection(session *wparams.WebSocketSession, msg string) {
	session.SendString("connection success")
}

func onMessage(session *wparams.WebSocketSession, msg string) {
	session.SendString("I got the message.")
}

func onClose(session *wparams.WebSocketSession, msg string) {
    println(msg + "-------------------------------")
}
func main() {
    // Interceptors, routes, etc. Loading of data requires its own calls
    routes.CreateRoute()
    routes.CreateWebSocketRoute()
    
    // Listen the service and listen to port 8080
    beerus.ListenHTTP(8080)
}

根据条件查询单表数据

conditions := make([]*entity.Condition,0)
conditions = append(conditions, &entity.Condition{Key:"id > ?", Val: 10})
conditions = append(conditions, &entity.Condition{Key:"and user_name = ?", Val: "bee"})
conditions = append(conditions, &entity.Condition{Key: "order by create_time desc", Val: entity.NotWhere})

resultMap, err := operation.GetDBTemplate("Data source name").Select("table name", conditions)

根据条件修改单表数据

// 条件设定
conditions := make([]*entity.Condition,0)
conditions = append(conditions, &entity.Condition{Key:"id = ?", Val: 1})

// 要修改的数据设定
data := ResultStruct{UserName: "TestNoSqlUpdate"}

// 执行修改操作
result, err := operation.GetDBTemplate("Data source name").Update("table name", dbutil.StructToMapIgnore(&data, data, true),conditions)

根据条件删除单表数据

// 设定删除条件
conditions := make([]*entity.Condition,0)
conditions = append(conditions, &entity.Condition{Key:"id = ?", Val: 2})

// 执行删除操作
_, err := operation.GetDBTemplate("Data source name").Delete("table name", conditions)

插入一条数据

data := ResultStruct{
    UserName: "TestNoSqlInsert",
    UserEmail: "[email protected]",
    UpdateTime: "2021-12-09 13:50:00",
}

result, err := operation.GetDBTemplate("Data source name").Insert("table name", dbutil.StructToMapIgnore(&data, data, true))

自定义 sql

// struct 参数
res := ResultStruct{Id: 1}

// 查多条, 注:这里需要用到占位符
resultMap, err := operation.GetDBTemplate("Data source name").SelectListByMap("select * from xt_message_board where id < {id}", dbutil.StructToMap(&res, res))

// 查一条, 注:这里需要用到占位符
resultMap, err := operation.GetDBTemplate("Data source name").SelectOneByMap("select * from xt_message_board where id < {id}", dbutil.StructToMap(&res, res))
res := ResultStruct{Id: 1, UserName: "TestUpdateByMap"}

// 无论是增删改,都是调用 ExecByMap 函数,将 sql 和参数传入即可,注:这里需要用到占位符
operation.GetDBTemplate("Data source name").ExecByMap("update xt_message_board set user_name = {user_name} where id = {id}", dbutil.StructToMap(&res, res))
data := ResultStruct{
    UserName: "TestNoSqlInsert",
    UserEmail: "[email protected]",
}

// 创建分页参数
param := entity.PageParam{
    CurrentPage: 1,  // 第几页
    PageSize: 20,  // 每页多少条
    Params: dbutil.StructToMap(&data, data), // 查询参数
}

// 执行查询操作
result, err := operation.GetDBTemplate("Data source name").SelectPage("select * from xt_message_board where user_name = {user_name} and user_email = {user_email}", param)
// 开启事务
id, err := db.Transaction()
if err != nil {
    t.Error("TestUpdateTx: " + err.Error())
    return
}

res := ResultStruct{Id: 1, UserName: "TestUpdateTx"}

// 注:这里使用的不是 GetDBTemplate ,ExecByMap ,而是 GetDBTemplateTx 和 ExecByTxMap
// 使用事务和不使用事务,在调用的函数上,区别就是多了个 Tx
ss, err := operation.GetDBTemplateTx(id, "dbPoolTest").ExecByTxMap("update xt_message_board set user_name = {user_name} where id = {id}", dbutil.StructToMap(&res, res))

if err != nil {
    // 如果有问题就回滚事务
    db.Rollback(id)
    t.Error("TestUpdateTx: " + err.Error())
    return
}

// 提交事务
db.Commit(id)

想了解更多的话,可以查阅我们的文档哦

https://beeruscc.com


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK