diff --git a/README.md b/README.md index f987f4f..d074a77 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Freedom DDD Framework + [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/8treenet/freedom/blob/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/8treenet/freedom)](https://goreportcard.com/report/github.com/8treenet/freedom)[![GoDoc](https://godoc.org/github.com/8treenet/freedom?status.svg)](https://godoc.org/github.com/8treenet/freedom) [![GitHub release](https://img.shields.io/github/v/release/8treenet/freedom.svg)](https://github.com/8treenet/freedom/releases) -###### Freedom是一个基于六边形架构的框架,可以支撑充血的领域模型范式。 + +###### Freedom 是一个基于六边形架构的框架,可以支撑充血的领域模型范式。 ## Overview + - 集成 Iris - HTTP/H2C Server & Client - 集成普罗米修斯 @@ -18,20 +21,25 @@ - 一级缓存 & 二级缓存 & 防击穿 ## 安装 + ```sh $ go install github.com/8treenet/freedom/freedom@latest $ freedom version ``` ## 脚手架创建项目 + ```sh $ freedom new-project [project-name] $ cd [project-name] +$ go mod tidy $ go run server/main.go ``` ## 脚手架生成增删查改和持久化对象 + #### + ```sh # freedom new-po -h 查看更多 $ cd [project-name] @@ -46,8 +54,9 @@ $ freedom new-po --json ./domain/po/schema.json ## Example #### [基础教程](https://github.com/8treenet/freedom/blob/master/example/base) -#### [http2监听和依赖倒置](https://github.com/8treenet/freedom/blob/master/example/http2) -#### [事务组件&自定义组件&Kafka&领域事件组件](https://github.com/8treenet/freedom/blob/master/example/infra-example) -#### [一个完整的电商demo,包含CQS、聚合、实体、领域事件、资源库、基础设施](https://github.com/8treenet/freedom/blob/master/example/fshop) +#### [http2 监听和依赖倒置](https://github.com/8treenet/freedom/blob/master/example/http2) + +#### [事务组件&自定义组件&Kafka&领域事件组件](https://github.com/8treenet/freedom/blob/master/example/infra-example) +#### [一个完整的电商 demo,包含 CQS、聚合、实体、领域事件、资源库、基础设施](https://github.com/8treenet/freedom/blob/master/example/fshop) diff --git a/README_EN.md b/README_EN.md index 3e745da..ea17295 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,9 +1,12 @@ # Freedom DDD Framework + [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/8treenet/freedom/blob/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/8treenet/freedom)](https://goreportcard.com/report/github.com/8treenet/freedom)[![GoDoc](https://godoc.org/github.com/8treenet/freedom?status.svg)](https://godoc.org/github.com/8treenet/freedom) + ###### Freedom is a framework based on a hexagonal architecture that supports the congestion domain model paradigm. ## Overview + - Integrated Iris v12 - Integrated Prometheus - Link Tracing @@ -18,19 +21,23 @@ - Primary Cache & Secondary Cache & Prevent Breakdown ## Install + ```sh $ go install github.com/8treenet/freedom/freedom@latest $ freedom version ``` ## Create Project + ```sh $ freedom new-project [project-name] $ cd [project-name] +$ go mod tidy $ go run server/main.go ``` ## Build Persistent Objects(PO) + ```sh # Configurable address and output directory, using 'freedom new-po -h' to see more $ cd [project-name] @@ -45,8 +52,11 @@ $ freedom new-po --json ./domain/po/schema.json ## Example #### [Basic Tutorial](https://github.com/8treenet/freedom/blob/master/example/base) + #### [Http2 Listening And Dependency Inversion](https://github.com/8treenet/freedom/blob/master/example/http2) + #### [Transaction Components And Custom Components](https://github.com/8treenet/freedom/blob/master/example/infra-example) + #### [Message Events And Domain Events](https://github.com/8treenet/freedom/blob/master/example/event-example) -#### [Electronic Demo(Contains CQS、Aggregation、entity、Domain Events、Repository、Infrastructure)](https://github.com/8treenet/freedom/blob/master/example/fshop) +#### [Electronic Demo(Contains CQS、Aggregation、entity、Domain Events、Repository、Infrastructure)](https://github.com/8treenet/freedom/blob/master/example/fshop) diff --git a/example/base/adapter/controller/default.go b/example/base/adapter/controller/default.go index 07ac3d9..f3c1d67 100644 --- a/example/base/adapter/controller/default.go +++ b/example/base/adapter/controller/default.go @@ -1,7 +1,6 @@ package controller import ( - "fmt" "io" "os" @@ -38,6 +37,7 @@ type Default struct { // Get handles the GET: / route. func (c *Default) Get() freedom.Result { + //curl http://127.0.0.1:8000 c.Worker.Logger().Info("I'm Controller") remote := c.Sev.RemoteInfo() return &infra.JSONResponse{Object: remote} @@ -45,6 +45,7 @@ func (c *Default) Get() freedom.Result { // GetHello handles the GET: /hello route. func (c *Default) GetHello() string { + //curl http://127.0.0.1:8000/hello field := freedom.LogFields{ "framework": "freedom", "like": "DDD", @@ -64,11 +65,13 @@ func (c *Default) GetHello() string { // PutHello handles the PUT: /hello route. func (c *Default) PutHello() freedom.Result { + //curl -X PUT http://127.0.0.1:8000/hello return &infra.JSONResponse{Object: "putHello"} } // PostHello handles the POST: /hello route. func (c *Default) PostHello() freedom.Result { + //curl -X POST -d '{"userName":"freedom","userPassword":"freedom"}' http://127.0.0.1:8000/hello var postJSONData struct { UserName string `json:"userName" validate:"required"` UserPassword string `json:"userPassword" validate:"required"` @@ -77,26 +80,55 @@ func (c *Default) PostHello() freedom.Result { return &infra.JSONResponse{Error: err} } - return &infra.JSONResponse{Object: "postHello"} + return &infra.JSONResponse{Object: postJSONData} } +// PutHello handles the DELETE: /hello route. +func (c *Default) DeleteHello() freedom.Result { + //curl -X DELETE http://127.0.0.1:8000/hello + return &infra.JSONResponse{Object: "deleteHello"} +} + +/* Can use more than one, the factory will make sure +that the correct http methods are being registered for each route +for this controller, uncomment these if you want: + func (c *Default) ConnectHello() {} + func (c *Default) HeadHello() {} + func (c *Default) PatchHello() {} + func (c *Default) OptionsHello() {} + func (c *Default) TraceHello() {} +*/ + // BeforeActivation . func (c *Default) BeforeActivation(b freedom.BeforeActivation) { - b.Handle("ANY", "/custom", "CustomHello") - //b.Handle("GET", "/custom", "CustomHello") - //b.Handle("PUT", "/custom", "CustomHello") - //b.Handle("POST", "/custom", "CustomHello") + b.Handle("GET", "/customPath/{id:int64}/{uid:int}/{username:string}", "CustomPath") + b.Handle("ANY", "/custom", "Custom") + //b.Handle("GET", "/custom", "Custom") + //b.Handle("PUT", "/custom", "Custom") + //b.Handle("POST", "/custom", "Custom") + //b.Handle("DELETE", "/custom", "Custom") +} + +// CustomPath handles the GET: /customPath/{id:int64}/{uid:int}/{username:string} route. +func (c *Default) CustomPath(id int64, uid int, username string) freedom.Result { + //curl http://127.0.0.1:8000/customPath/1/2/freedom + return &infra.JSONResponse{Object: map[string]interface{}{"id": id, "uid": uid, "username": username}} } -// CustomHello handles the POST: /hello route. -func (c *Default) CustomHello() freedom.Result { +// Custom handles the ANY: /custom route. +func (c *Default) Custom() freedom.Result { + //curl http://127.0.0.1:8000/custom + //curl -X PUT http://127.0.0.1:8000/custom + //curl -X DELETE http://127.0.0.1:8000/custom + //curl -X POST http://127.0.0.1:8000/custom method := c.Worker.IrisContext().Request().Method c.Worker.Logger().Info("CustomHello", freedom.LogFields{"method": method}) - return &infra.JSONResponse{Object: method + "CustomHello"} + return &infra.JSONResponse{Object: method + "/Custom"} } // GetUserBy handles the GET: /user/{username:string} route. func (c *Default) GetUserBy(username string) freedom.Result { + //curl 'http://127.0.0.1:8000/user/freedom?token=ftoken123&id=1&ip=192&ip=168&ip=1&ip=1' var query struct { Token string `url:"token" validate:"required"` ID int64 `url:"id" validate:"required"` @@ -120,6 +152,7 @@ func (c *Default) GetUserBy(username string) freedom.Result { // GetAgeByUserBy handles the GET: /age/{age:int}/user/{user:string} route. func (c *Default) GetAgeByUserBy(age int, user string) freedom.Result { + //curl http://127.0.0.1:8000/age/20/user/freedom var result struct { User string Age int @@ -132,6 +165,7 @@ func (c *Default) GetAgeByUserBy(age int, user string) freedom.Result { // PostForm handles the Post: /form route. func (c *Default) PostForm() freedom.Result { + //curl -X POST --data "userName=freedom&mail=freedom@freedom.com&myData=data1&myData=data2" http://127.0.0.1:8000/form var visitor struct { UserName string `form:"userName" validate:"required"` Mail string `form:"mail" validate:"required"` @@ -147,6 +181,7 @@ func (c *Default) PostForm() freedom.Result { // PostFile handles the Post: /file route. func (c *Default) PostFile() freedom.Result { + //curl -X POST -F "file=@example/base/adapter/controller/default.go" http://127.0.0.1:8000/file file, info, err := c.Worker.IrisContext().FormFile("file") if err != nil { return &infra.JSONResponse{Error: err} @@ -159,8 +194,7 @@ func (c *Default) PostFile() freedom.Result { return &infra.JSONResponse{Error: err} } defer out.Close() - fmt.Println("file:", os.TempDir()+fname) _, err = io.Copy(out, file) - return &infra.JSONResponse{Error: err} + return &infra.JSONResponse{Error: err, Object: os.TempDir() + fname} } diff --git a/freedom/cmd/version.go b/freedom/cmd/version.go index a9cb8c9..455aacc 100644 --- a/freedom/cmd/version.go +++ b/freedom/cmd/version.go @@ -7,7 +7,7 @@ import ( ) const ( - versionNum = "v1.9.2" + versionNum = "v1.9.3" ) var ( diff --git a/freedom/template/project/controllers.go b/freedom/template/project/controllers.go index 492c80f..55b68d7 100644 --- a/freedom/template/project/controllers.go +++ b/freedom/template/project/controllers.go @@ -12,6 +12,8 @@ func controllerTemplate() string { package controller import ( + "io" + "os" "github.com/8treenet/freedom" "{{.PackagePath}}/domain" "{{.PackagePath}}/infra" @@ -32,6 +34,7 @@ func controllerTemplate() string { //Get handles the GET: / route. func (c *Default) Get() freedom.Result { + //curl http://127.0.0.1:8000 c.Worker.Logger().Info("I'm Controller") remote := c.Sev.RemoteInfo() return &infra.JSONResponse{Object: remote} @@ -39,6 +42,7 @@ func controllerTemplate() string { //GetHello handles the GET: /hello route. func (c *Default) GetHello() string { + //curl http://127.0.0.1:8000/hello field := freedom.LogFields{ "framework": "freedom", "like": "DDD", @@ -58,11 +62,13 @@ func controllerTemplate() string { //PutHello handles the PUT: /hello route. func (c *Default) PutHello() freedom.Result { + //curl -X PUT http://127.0.0.1:8000/hello return &infra.JSONResponse{Object: "putHello"} } // PostHello handles the POST: /hello route. func (c *Default) PostHello() freedom.Result { + //curl -X POST -d '{"userName":"freedom","userPassword":"freedom"}' http://127.0.0.1:8000/hello var postJSONData struct { UserName string $$wavejson:"userName" validate:"required"$$wave UserPassword string $$wavejson:"userPassword" validate:"required"$$wave @@ -71,26 +77,55 @@ func controllerTemplate() string { return &infra.JSONResponse{Error: err} } - return &infra.JSONResponse{Object: "postHello"} + return &infra.JSONResponse{Object: postJSONData} } + // PutHello handles the DELETE: /hello route. + func (c *Default) DeleteHello() freedom.Result { + //curl -X DELETE http://127.0.0.1:8000/hello + return &infra.JSONResponse{Object: "deleteHello"} + } + + /* Can use more than one, the factory will make sure + that the correct http methods are being registered for each route + for this controller, uncomment these if you want: + func (c *Default) ConnectHello() {} + func (c *Default) HeadHello() {} + func (c *Default) PatchHello() {} + func (c *Default) OptionsHello() {} + func (c *Default) TraceHello() {} + */ + // BeforeActivation . func (c *Default) BeforeActivation(b freedom.BeforeActivation) { - b.Handle("ANY", "/custom", "CustomHello") - //b.Handle("GET", "/custom", "CustomHello") - //b.Handle("PUT", "/custom", "CustomHello") - //b.Handle("POST", "/custom", "CustomHello") + b.Handle("GET", "/customPath/{id:int64}/{uid:int}/{username:string}", "CustomPath") + b.Handle("ANY", "/custom", "Custom") + //b.Handle("GET", "/custom", "Custom") + //b.Handle("PUT", "/custom", "Custom") + //b.Handle("POST", "/custom", "Custom") + //b.Handle("DELETE", "/custom", "Custom") + } + + // CustomPath handles the GET: /customPath/{id:int64}/{uid:int}/{username:string} route. + func (c *Default) CustomPath(id int64, uid int, username string) freedom.Result { + //curl http://127.0.0.1:8000/customPath/1/2/freedom + return &infra.JSONResponse{Object: map[string]interface{}{"id": id, "uid": uid, "username": username}} } - //CustomHello handles the POST: /hello route. - func (c *Default) CustomHello() freedom.Result { + // Custom handles the ANY: /custom route. + func (c *Default) Custom() freedom.Result { + //curl http://127.0.0.1:8000/custom + //curl -X PUT http://127.0.0.1:8000/custom + //curl -X DELETE http://127.0.0.1:8000/custom + //curl -X POST http://127.0.0.1:8000/custom method := c.Worker.IrisContext().Request().Method c.Worker.Logger().Info("CustomHello", freedom.LogFields{"method": method}) - return &infra.JSONResponse{Object: method + "CustomHello"} + return &infra.JSONResponse{Object: method + "/Custom"} } - //GetUserBy handles the GET: /user/{username:string}?token=ftoken123&id=1&ip=192&ip=168&ip=1&ip=1 route. + //GetUserBy handles the GET: /user/{username:string} route. func (c *Default) GetUserBy(username string) freedom.Result { + //curl 'http://127.0.0.1:8000/user/freedom?token=ftoken123&id=1&ip=192&ip=168&ip=1&ip=1' var query struct { /* Equal @@ -120,6 +155,7 @@ func controllerTemplate() string { //GetAgeByUserBy handles the GET: /age/{age:int}/user/{user:string} route. func (c *Default) GetAgeByUserBy(age int, user string) freedom.Result { + //curl http://127.0.0.1:8000/age/20/user/freedom var result struct { User string Age int @@ -129,6 +165,42 @@ func controllerTemplate() string { return &infra.JSONResponse{Object: result} } + + // PostForm handles the Post: /form route. + func (c *Default) PostForm() freedom.Result { + //curl -X POST --data "userName=freedom&mail=freedom@freedom.com&myData=data1&myData=data2" http://127.0.0.1:8000/form + var visitor struct { + UserName string $$waveform:"userName" validate:"required"$$wave + Mail string $$waveform:"mail" validate:"required"$$wave + Data []string $$waveform:"myData" validate:"required"$$wave + } + err := c.Request.ReadForm(&visitor, true) + if err != nil { + return &infra.JSONResponse{Error: err} + } + c.Worker.Logger().Infof("%d, %s, %s, %v", c.Worker.IrisContext().Request().ContentLength, visitor.UserName, visitor.Mail, visitor.Data) + return &infra.JSONResponse{Object: visitor} + } + + // PostFile handles the Post: /file route. + func (c *Default) PostFile() freedom.Result { + //curl -X POST -F "file=@example/base/adapter/controller/default.go" http://127.0.0.1:8000/file + file, info, err := c.Worker.IrisContext().FormFile("file") + if err != nil { + return &infra.JSONResponse{Error: err} + } + + defer file.Close() + fname := info.Filename + out, err := os.OpenFile(os.TempDir()+fname, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) + if err != nil { + return &infra.JSONResponse{Error: err} + } + defer out.Close() + _, err = io.Copy(out, file) + + return &infra.JSONResponse{Error: err, Object: os.TempDir() + fname} + } ` result = strings.ReplaceAll(result, "$$wave", "`")