我将转到Python/Django。在Django中,我非常喜欢它的模块化应用程序项目结构设计,每个应用程序都有不同的商务模型、路线和视图。然后,所有的应用程序都会在中央/项目的主路由系统内进行通信,等等。
Django项目结构,例如:
- myproject
- myproject
- urls.py
- views.py
...
- planner
- urls.py
- views.py
- models.py
...我正试图在Go项目中实现类似的项目设计:
- myproject
- cmd
- api
- main.go
- routes.go
- handlers.go
- planner
- routes.go
- handlers.go
- models.go摘自cmd/api/main.go:
package main
...
db, err := sql.Open("pgx", cfg.db.dsn)
...
srv := &http.Server{
Addr: fmt.Sprintf("localhost:%d", app.config.port),
Handler: app.routes()
}
...摘自cmd/api/ from .cmd:
package main
func (app *application) routes() *httprouter.Router {
router := httprouter.New()
planner.Routes(router)
return router
}节选自cmd/planner/常规。开始:
package planner
...
func Routes(router *httprouter.Router) {
router.HandlerFunc(http.MethodPost, "/v1/planner/todos", CreateTodoHandler)
}摘自cmd/planner/models.go.开始:
package planner
type PlannerModel struct {
DB *sql.DB
}
func (p PlannerModel) InsertTodo(todo *Todo) error {
query := `INSERT INTO todos (title, user_id)
VALUES ($1, $2)
RETURNING id, created_at`
return p.DB.QueryRow(query, todo.Title, todo.UserID).Scan(&todo.ID, &todo.CreatedAt)
}现在的问题是,我需要使用cmd/api/main.go文件中从package main初始化的DB连接到cmd/planner/handlers.go。由于变量来自主包,所以我无法将它导入应用程序的(计划程序)处理程序函数中。
package planner
func CreateTodoHandler(w http.ResponseWriter, r *http.Request) {
var input struct {
Title string `json:"title"`
UserID int64 `json:"user_id"`
}
err := helpers.ReadJSON(w, r, &input)
...
todo := &Todo{
Title: input.Title,
UserID: input.UserID,
}
...
// How to use/inject DB connection dependency into the PlannerModel?
pm := PlannerModel{
DB: // ????
}
err = pm.InsertTodo(todo)
...
}我认为有一个全局DB变量可以解决这个问题,或者我找到的一个合理的answer是在一个单独的包中声明这个变量,并在main.go中初始化它。另一种方法是让Planner/handlers.go属于package main,并在主包中创建一个application结构,以保存项目的所有模型并在处理程序中使用它,但我想这将挫败解耦的体系结构设计。
我想知道什么是首选的方法,或者是否有更好的方法来实现类似的解耦项目结构(如Django ),并且仍然将main.go中的变量初始化到其他包中并进行测试?
发布于 2022-07-26 10:22:26
当我从Python/Django转到Go时,我也有过类似的经历。
在每个应用程序中访问db连接的解决方案是在每个具有db连接字段的应用程序中定义结构,然后主要创建db连接和所有应用程序结构。
// planner.go
func (t *Todo) Routes(router *httprouter.Router) {
router.HandlerFunc(http.MethodPost, "/v1/planner/todos", t.CreateTodoHandler)
}// handlers.go
struct Todo {
DB: *sql.DB
}
func (t *Todo) CreateTodo(w http.ResponseWriter, r *http.Request) {
var input struct {
Title string `json:"title"`
UserID int64 `json:"user_id"`
}
err := helpers.ReadJSON(w, r, &input)
...
todo := &Todo{
Title: input.Title,
UserID: input.UserID,
}
...
pm := PlannerModel{
DB: t.DB
}
err = pm.InsertTodo(todo)
...
}这将解决您当前的问题,但如果您没有更好的应用程序设计,则会出现其他问题。
建议阅读这两篇博文,以便更好地理解Go中的应用程序设计和代码结构。
发布于 2022-07-26 17:41:52
我的方法是在DI中使用干净的架构。
使用db连接声明存储库的示例:https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L58-L63
在服务声明中使用存储库的示例:https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L65-L70
这与其他DI类似,例如wire。
优点是:
https://stackoverflow.com/questions/73076117
复制相似问题