Compare commits
No commits in common. "0d054c46fecb4d48647469f9ae2a65df61eb0d33" and "eef39e0163b7a567176589ddc7d4cda4470b55ba" have entirely different histories.
0d054c46fe
...
eef39e0163
|
@ -1 +0,0 @@
|
||||||
package config
|
|
|
@ -1,7 +1,6 @@
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Superdanda/hade/app/provider/database_connect"
|
|
||||||
"github.com/Superdanda/hade/framework"
|
"github.com/Superdanda/hade/framework"
|
||||||
"github.com/Superdanda/hade/framework/gin"
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
)
|
)
|
||||||
|
@ -16,12 +15,5 @@ func NewHttpEngine(container *framework.HadeContainer) (*gin.Engine, error) {
|
||||||
// 业务绑定路由操作
|
// 业务绑定路由操作
|
||||||
Routes(r)
|
Routes(r)
|
||||||
// 返回绑定路由后的Web引擎
|
// 返回绑定路由后的Web引擎
|
||||||
|
|
||||||
// 对业务模型进行注册,通过注册名获取业务模型类型信息
|
|
||||||
TypeRegister(container)
|
|
||||||
|
|
||||||
//绑定服务
|
|
||||||
container.Bind(&database_connect.DatabaseConnectProvider{})
|
|
||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,9 @@ package demo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/Superdanda/hade/app/provider/demo"
|
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func TypeRegister(typeRegister contract.TypeRegisterService) {
|
|
||||||
typeRegister.Register("UserThree", demo.UserThree{})
|
|
||||||
typeRegister.Register("UserTwo", demo.UserTwo{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserModel struct {
|
type UserModel struct {
|
||||||
UserId int
|
UserId int
|
||||||
Name string
|
Name string
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Superdanda/hade/app/http/module/demo"
|
|
||||||
"github.com/Superdanda/hade/framework"
|
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TypeRegister(container framework.Container) {
|
|
||||||
typeRegister := container.MustMake(contract.TypeRegisterKey).(contract.TypeRegisterService)
|
|
||||||
demo.TypeRegister(typeRegister)
|
|
||||||
}
|
|
|
@ -22,7 +22,6 @@ func Routes(core *gin.Engine) {
|
||||||
core.Use(static.Serve("/", static.LocalFile("./dist", false)))
|
core.Use(static.Serve("/", static.LocalFile("./dist", false)))
|
||||||
|
|
||||||
err := demo.Register(core)
|
err := demo.Register(core)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package database_connect
|
|
||||||
|
|
||||||
import "gorm.io/gorm"
|
|
||||||
|
|
||||||
const DatabaseConnectKey = "hade:database_connect"
|
|
||||||
|
|
||||||
type Service interface {
|
|
||||||
LocalDatabaseConnect() *gorm.DB
|
|
||||||
AliDataBaseConnect() *gorm.DB
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package database_connect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Superdanda/hade/framework"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DatabaseConnectProvider struct {
|
|
||||||
framework.ServiceProvider
|
|
||||||
|
|
||||||
c framework.Container
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *DatabaseConnectProvider) Name() string {
|
|
||||||
return DatabaseConnectKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *DatabaseConnectProvider) Register(c framework.Container) framework.NewInstance {
|
|
||||||
return NewDatabaseConnectService
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *DatabaseConnectProvider) IsDefer() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *DatabaseConnectProvider) Params(c framework.Container) []interface{} {
|
|
||||||
return []interface{}{c}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *DatabaseConnectProvider) Boot(c framework.Container) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package database_connect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/Superdanda/hade/framework"
|
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
|
||||||
"github.com/Superdanda/hade/framework/provider/orm"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DatabaseConnectService struct {
|
|
||||||
container framework.Container
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DatabaseConnectService) LocalDatabaseConnect() *gorm.DB {
|
|
||||||
return getDatabaseConnectByYaml("database.local", d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DatabaseConnectService) AliDataBaseConnect() *gorm.DB {
|
|
||||||
return getDatabaseConnectByYaml("database.ali", d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDatabaseConnectService(params ...interface{}) (interface{}, error) {
|
|
||||||
container := params[0].(framework.Container)
|
|
||||||
return &DatabaseConnectService{container: container}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDatabaseConnectByYaml(yamlPath string, d DatabaseConnectService) *gorm.DB {
|
|
||||||
ormService := d.container.MustMake(contract.ORMKey).(contract.ORMService)
|
|
||||||
db, err := ormService.GetDB(orm.WithConfigPath(yamlPath))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(yamlPath + "数据库连接失败,请检查配置")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return db
|
|
||||||
}
|
|
|
@ -1,32 +1 @@
|
||||||
package demo
|
package demo
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// User is gorm model
|
|
||||||
type UserTwo struct {
|
|
||||||
ID uint
|
|
||||||
Name string
|
|
||||||
Email *string
|
|
||||||
Age uint8
|
|
||||||
Birthday *time.Time
|
|
||||||
MemberNumber sql.NullString
|
|
||||||
ActivatedAt sql.NullTime
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// User is gorm model
|
|
||||||
type UserThree struct {
|
|
||||||
ID uint
|
|
||||||
Name string
|
|
||||||
Email *string
|
|
||||||
Age uint8
|
|
||||||
Birthday *time.Time
|
|
||||||
MemberNumber sql.NullString
|
|
||||||
ActivatedAt sql.NullTime
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
const UserKey = "user"
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
// 请在这里定义你的方法
|
||||||
|
Foo() string
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Superdanda/hade/framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserProvider struct {
|
||||||
|
framework.ServiceProvider
|
||||||
|
|
||||||
|
c framework.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *UserProvider) Name() string {
|
||||||
|
return UserKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *UserProvider) Register(c framework.Container) framework.NewInstance {
|
||||||
|
return NewUserService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *UserProvider) IsDefer() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *UserProvider) Params(c framework.Container) []interface{} {
|
||||||
|
return []interface{}{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *UserProvider) Boot(c framework.Container) error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import "github.com/Superdanda/hade/framework"
|
||||||
|
|
||||||
|
type UserService struct {
|
||||||
|
container framework.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserService(params ...interface{}) (interface{}, error) {
|
||||||
|
container := params[0].(framework.Container)
|
||||||
|
return &UserService{container: container}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserService) Foo() string {
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
driver: memory
|
|
|
@ -4,27 +4,12 @@ conn_max_lifetime: 1h # 通用配置,连接数最大生命周期
|
||||||
protocol: tcp # 通用配置,传输协议
|
protocol: tcp # 通用配置,传输协议
|
||||||
loc: Local # 通用配置,时区
|
loc: Local # 通用配置,时区
|
||||||
|
|
||||||
local:
|
default:
|
||||||
driver: mysql # 连接驱动
|
|
||||||
dsn: "" # dsn,如果设置了dsn, 以下的所有设置都不生效
|
|
||||||
host: 127.0.0.1 # ip地址
|
|
||||||
port: 3306 # 端口
|
|
||||||
database: bbs # 数据库
|
|
||||||
username: root # 用户名
|
|
||||||
password: "123456" # 密码
|
|
||||||
charset: utf8mb4 # 字符集
|
|
||||||
collation: utf8mb4_unicode_ci # 字符序
|
|
||||||
timeout: 10s # 连接超时
|
|
||||||
read_timeout: 2s # 读超时
|
|
||||||
write_timeout: 2s # 写超时
|
|
||||||
parse_time: true # 是否解析时间
|
|
||||||
|
|
||||||
ali:
|
|
||||||
driver: mysql # 连接驱动
|
driver: mysql # 连接驱动
|
||||||
dsn: "" # dsn,如果设置了dsn, 以下的所有设置都不生效
|
dsn: "" # dsn,如果设置了dsn, 以下的所有设置都不生效
|
||||||
host: 47.97.21.20 # ip地址
|
host: 47.97.21.20 # ip地址
|
||||||
port: 3306 # 端口
|
port: 3306 # 端口
|
||||||
database: bbs # 数据库
|
database: questionnaire # 数据库
|
||||||
username: root # 用户名
|
username: root # 用户名
|
||||||
password: "kerowsqw34" # 密码
|
password: "kerowsqw34" # 密码
|
||||||
charset: utf8mb4 # 字符集
|
charset: utf8mb4 # 字符集
|
||||||
|
@ -33,7 +18,6 @@ ali:
|
||||||
read_timeout: 2s # 读超时
|
read_timeout: 2s # 读超时
|
||||||
write_timeout: 2s # 写超时
|
write_timeout: 2s # 写超时
|
||||||
parse_time: true # 是否解析时间
|
parse_time: true # 是否解析时间
|
||||||
|
protocol: tcp # 传输协议
|
||||||
|
loc: Local # 时区
|
||||||
|
|
||||||
|
|
||||||
sync:
|
|
||||||
filePath: /app/provider
|
|
|
@ -35,7 +35,7 @@ var cronCommand = &cobra.Command{
|
||||||
Short: "定时任务控制命令",
|
Short: "定时任务控制命令",
|
||||||
Long: "定时任务控制命令,包含展示、重启、启动、常驻状态、停止等命令",
|
Long: "定时任务控制命令,包含展示、重启、启动、常驻状态、停止等命令",
|
||||||
RunE: func(c *cobra.Command, args []string) error {
|
RunE: func(c *cobra.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) != 0 {
|
||||||
c.Help()
|
c.Help()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/Superdanda/hade/framework"
|
|
||||||
"github.com/Superdanda/hade/framework/cobra"
|
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
|
||||||
"github.com/Superdanda/hade/framework/provider/orm"
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func initDatabaseCommand() *cobra.Command {
|
|
||||||
databaseCommand.AddCommand(databaseModelSyncCommand)
|
|
||||||
return databaseCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
var databaseCommand = &cobra.Command{
|
|
||||||
Use: "database",
|
|
||||||
Short: "数据库相关命令",
|
|
||||||
Long: "操控数据库相关命令,同步数据模型到数据库",
|
|
||||||
RunE: func(c *cobra.Command, args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
c.Help()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var databaseModelSyncCommand = &cobra.Command{
|
|
||||||
Use: "modelSync",
|
|
||||||
Short: "同步数据模型到数据库",
|
|
||||||
RunE: func(c *cobra.Command, args []string) error {
|
|
||||||
if len(args) != 1 {
|
|
||||||
fmt.Println("请输入数据库连接名称")
|
|
||||||
}
|
|
||||||
container := c.GetContainer()
|
|
||||||
appService := container.MustMake(contract.AppKey).(contract.App)
|
|
||||||
configService := container.MustMake(contract.ConfigKey).(contract.Config)
|
|
||||||
syncPathFolder := filepath.Join(appService.BaseFolder(), configService.GetString("database.sync.filePath"))
|
|
||||||
|
|
||||||
ormService := container.MustMake(contract.ORMKey).(contract.ORMService)
|
|
||||||
db, err := ormService.GetDB(orm.WithConfigPath("database." + args[0]))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = AutoMigrateStructs(db, syncPathFolder, container)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanStructsInPackage 扫描给定包路径下的所有结构体
|
|
||||||
func ScanStructsInPackage(pkgPath string, container framework.Container) ([]interface{}, error) {
|
|
||||||
var structs []interface{}
|
|
||||||
|
|
||||||
// 遍历包路径下的所有 Go 文件
|
|
||||||
err := filepath.Walk(pkgPath, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只处理 .go 文件
|
|
||||||
if filepath.Ext(path) != ".go" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析 Go 文件,构建 AST
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
node, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历 AST,找到所有类型声明
|
|
||||||
for _, decl := range node.Decls {
|
|
||||||
genDecl, ok := decl.(*ast.GenDecl)
|
|
||||||
if !ok || genDecl.Tok != token.TYPE {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历所有类型声明,找到结构体类型
|
|
||||||
for _, spec := range genDecl.Specs {
|
|
||||||
typeSpec, ok := spec.(*ast.TypeSpec)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否为结构体类型
|
|
||||||
_, ok = typeSpec.Type.(*ast.StructType)
|
|
||||||
if ok {
|
|
||||||
// 创建结构体的零值并添加到结果中
|
|
||||||
structName := typeSpec.Name.Name
|
|
||||||
instance, err := createStructInstance(structName, container)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
if instance != nil {
|
|
||||||
structs = append(structs, instance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return structs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// createStructInstance 使用反射创建结构体的实例
|
|
||||||
func createStructInstance(structName string, container framework.Container) (interface{}, error) {
|
|
||||||
typeRegister := container.MustMake(contract.TypeRegisterKey).(contract.TypeRegisterService)
|
|
||||||
// 假设结构体已导入,使用反射获取类型
|
|
||||||
structType, b := typeRegister.GetType(structName)
|
|
||||||
if b {
|
|
||||||
instance := reflect.New(structType).Interface()
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New(structName + "类型没有注册")
|
|
||||||
}
|
|
||||||
|
|
||||||
func AutoMigrateStructs(db *gorm.DB, pkgPath string, container framework.Container) error {
|
|
||||||
// 扫描包路径下的所有结构体
|
|
||||||
structs, err := ScanStructsInPackage(pkgPath, container)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// 使用 GORM 进行自动迁移
|
|
||||||
for _, model := range structs {
|
|
||||||
if err := db.AutoMigrate(model); err != nil {
|
|
||||||
return fmt.Errorf("自动迁移失败: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("成功迁移模型:%T\n", model)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -20,7 +20,6 @@ func AddKernelCommands(root *cobra.Command) {
|
||||||
root.AddCommand(initNewCommand())
|
root.AddCommand(initNewCommand())
|
||||||
root.AddCommand(initSwaggerCommand())
|
root.AddCommand(initSwaggerCommand())
|
||||||
root.AddCommand(initDeployCommand())
|
root.AddCommand(initDeployCommand())
|
||||||
root.AddCommand(initDatabaseCommand())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 封装通用的命令执行器
|
// 封装通用的命令执行器
|
||||||
|
|
|
@ -3,15 +3,15 @@ package command
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/Superdanda/hade/framework"
|
"github.com/Superdanda/hade/framework"
|
||||||
"github.com/Superdanda/hade/framework/cobra"
|
"github.com/Superdanda/hade/framework/cobra"
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
"github.com/Superdanda/hade/framework/contract"
|
||||||
"github.com/Superdanda/hade/framework/util"
|
"github.com/Superdanda/hade/framework/util"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/jianfengye/collection"
|
"github.com/jianfengye/collection"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -55,8 +55,8 @@ var providerCreateCommand = &cobra.Command{
|
||||||
RunE: func(c *cobra.Command, args []string) error {
|
RunE: func(c *cobra.Command, args []string) error {
|
||||||
container := c.GetContainer()
|
container := c.GetContainer()
|
||||||
fmt.Println("创建一个服务")
|
fmt.Println("创建一个服务")
|
||||||
var name, folder string
|
var name string
|
||||||
interfaceNames := &RouteNode{}
|
var folder string
|
||||||
{
|
{
|
||||||
prompt := &survey.Input{
|
prompt := &survey.Input{
|
||||||
Message: "请输入服务名称(服务凭证):",
|
Message: "请输入服务名称(服务凭证):",
|
||||||
|
@ -101,40 +101,6 @@ var providerCreateCommand = &cobra.Command{
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收集用户输入并填充嵌套映射
|
|
||||||
for {
|
|
||||||
prompt := &survey.Input{
|
|
||||||
Message: "请输入接口路径(格式:/user/login,直接按回车结束输入):",
|
|
||||||
}
|
|
||||||
|
|
||||||
var input string
|
|
||||||
err := survey.AskOne(prompt, &input)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果用户直接按回车,结束输入
|
|
||||||
if strings.TrimSpace(input) == "" {
|
|
||||||
fmt.Println("接口输入结束")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析输入的路径为路径部分
|
|
||||||
pathParts := strings.Split(strings.TrimPrefix(input, "/"), "/")
|
|
||||||
if len(pathParts) == 0 {
|
|
||||||
fmt.Println("路径格式错误,请输入正确格式:/节点/接口")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将路径部分插入到路由树中
|
|
||||||
insertIntoRouteTree(pathParts, []string{}, interfaceNames)
|
|
||||||
fmt.Printf("已添加接口:%s\n", input)
|
|
||||||
}
|
|
||||||
interfaceNames.NeedExtra = false
|
|
||||||
|
|
||||||
// 打印所有添加的接口(测试用)
|
|
||||||
printRouteTree(interfaceNames, 0)
|
|
||||||
|
|
||||||
// 开始创建文件
|
// 开始创建文件
|
||||||
if err := os.Mkdir(filepath.Join(pFolder, folder), 0700); err != nil {
|
if err := os.Mkdir(filepath.Join(pFolder, folder), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -144,31 +110,9 @@ var providerCreateCommand = &cobra.Command{
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"appName": config.GetAppName(),
|
"appName": config.GetAppName(),
|
||||||
"packageName": name,
|
"packageName": name,
|
||||||
"interfaces": interfaceNames,
|
|
||||||
"structName": name,
|
|
||||||
}
|
}
|
||||||
// 创建title这个模版方法
|
// 创建title这个模版方法
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{"title": strings.Title}
|
||||||
"title": strings.Title,
|
|
||||||
"dict": func(values ...interface{}) (map[string]interface{}, error) {
|
|
||||||
if len(values)%2 != 0 {
|
|
||||||
return nil, fmt.Errorf("invalid dict call: missing key or value")
|
|
||||||
}
|
|
||||||
dict := make(map[string]interface{}, len(values)/2)
|
|
||||||
for i := 0; i < len(values); i += 2 {
|
|
||||||
key, ok := values[i].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("dict keys must be strings")
|
|
||||||
}
|
|
||||||
dict[key] = values[i+1]
|
|
||||||
}
|
|
||||||
return dict, nil
|
|
||||||
},
|
|
||||||
"len": func(v interface{}) int {
|
|
||||||
return reflect.ValueOf(v).Len()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// 创建contract.go
|
// 创建contract.go
|
||||||
file := filepath.Join(pFolder, folder, "contract.go")
|
file := filepath.Join(pFolder, folder, "contract.go")
|
||||||
|
@ -208,166 +152,12 @@ var providerCreateCommand = &cobra.Command{
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if interfaceNames.Children == nil || len(interfaceNames.Children) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleFolder := app.HttpModuleFolder()
|
|
||||||
pModuleFolder := filepath.Join(moduleFolder, name)
|
|
||||||
util.EnsureDir(pModuleFolder)
|
|
||||||
{
|
|
||||||
// module 目录下 创建 服务包
|
|
||||||
|
|
||||||
// 创建api 我呢见
|
|
||||||
{
|
|
||||||
// 创建 api.go
|
|
||||||
file := filepath.Join(pModuleFolder, "api.go")
|
|
||||||
f, err := os.Create(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["interfaces"] = interfaceNames // 传递嵌套的接口名称映射
|
|
||||||
t := template.Must(template.New("api").Funcs(funcs).Parse(apiTmp))
|
|
||||||
if err := t.Execute(f, data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建api_controller文件
|
|
||||||
{
|
|
||||||
tmpl := template.Must(template.New("controller").Funcs(funcs).Parse(apiControllerTmp))
|
|
||||||
data["packageName"] = name
|
|
||||||
data["structName"] = name
|
|
||||||
|
|
||||||
// 递归生成控制器文件
|
|
||||||
if err := generateControllers(interfaceNames, []string{}, tmpl, data, pModuleFolder); err != nil {
|
|
||||||
fmt.Println("生成控制器失败:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//创建 dto 文件
|
|
||||||
{
|
|
||||||
// 创建dto.go
|
|
||||||
file := filepath.Join(pModuleFolder, "dto.go")
|
|
||||||
f, err := os.Create(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t := template.Must(template.New("dto").Funcs(funcs).Parse(dtoTmp))
|
|
||||||
if err := t.Execute(f, data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//创建 mapper 文件
|
|
||||||
{
|
|
||||||
// 创建mapper.go
|
|
||||||
file := filepath.Join(pModuleFolder, "mapper.go")
|
|
||||||
f, err := os.Create(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t := template.Must(template.New("mapper").Funcs(funcs).Parse(mapperTmp))
|
|
||||||
if err := t.Execute(f, data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("创建服务成功, 文件夹地址:", filepath.Join(pFolder, folder))
|
fmt.Println("创建服务成功, 文件夹地址:", filepath.Join(pFolder, folder))
|
||||||
fmt.Println("请不要忘记挂载新创建的服务")
|
fmt.Println("请不要忘记挂载新创建的服务")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateControllers(node *RouteNode, pathParts []string, tmpl *template.Template, data map[string]interface{}, moduleFolder string) error {
|
|
||||||
// 更新路径部分
|
|
||||||
newPathParts := append(pathParts, node.Path)
|
|
||||||
|
|
||||||
// 如果当前节点需要生成处理函数
|
|
||||||
if node.NeedExtra {
|
|
||||||
data["interfaceName"] = strings.Join(newPathParts, "_")
|
|
||||||
data["methodName"] = node.HandlerName
|
|
||||||
|
|
||||||
// 生成文件名,例如 api_user_edit_auto.go
|
|
||||||
fileName := "api" + strings.Join(newPathParts, "_") + ".go"
|
|
||||||
filePath := filepath.Join(moduleFolder, fileName)
|
|
||||||
|
|
||||||
// 创建控制器文件
|
|
||||||
file, err := os.Create(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("创建文件失败: %s", filePath)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
// 渲染模板
|
|
||||||
if err := tmpl.Execute(file, data); err != nil {
|
|
||||||
return fmt.Errorf("渲染模板失败: %s", filePath)
|
|
||||||
}
|
|
||||||
fmt.Printf("生成接口控制器文件: %s\n", filePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归处理子节点
|
|
||||||
for _, child := range node.Children {
|
|
||||||
if err := generateControllers(child, newPathParts, tmpl, data, moduleFolder); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertIntoRouteTree(pathParts []string, fullPathParts []string, currentNode *RouteNode) {
|
|
||||||
if len(pathParts) == 0 {
|
|
||||||
currentNode.NeedExtra = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前路径部分
|
|
||||||
part := pathParts[0]
|
|
||||||
fullPathParts = append(fullPathParts, part)
|
|
||||||
|
|
||||||
// 查找是否已存在该路径部分的子节点
|
|
||||||
var child *RouteNode
|
|
||||||
for _, node := range currentNode.Children {
|
|
||||||
if node.Path == part {
|
|
||||||
child = node
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果子节点不存在,则创建新的子节点
|
|
||||||
if child == nil {
|
|
||||||
handlerName := ""
|
|
||||||
for _, v := range fullPathParts {
|
|
||||||
handlerName += strings.Title(v)
|
|
||||||
}
|
|
||||||
child = &RouteNode{
|
|
||||||
Path: part,
|
|
||||||
HandlerName: handlerName,
|
|
||||||
}
|
|
||||||
currentNode.Children = append(currentNode.Children, child)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归处理剩余路径部分
|
|
||||||
insertIntoRouteTree(pathParts[1:], fullPathParts, child)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printRouteTree(node *RouteNode, level int) {
|
|
||||||
indent := strings.Repeat(" ", level)
|
|
||||||
fmt.Printf("%s- %s\n", indent, node.Path)
|
|
||||||
for _, child := range node.Children {
|
|
||||||
printRouteTree(child, level+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteNode struct {
|
|
||||||
Path string // 路由路径
|
|
||||||
Children []*RouteNode // 子路由节点列表
|
|
||||||
NeedExtra bool // 是否需要额外生成接口
|
|
||||||
HandlerName string
|
|
||||||
}
|
|
||||||
|
|
||||||
var contractTmp = `package {{.packageName}}
|
var contractTmp = `package {{.packageName}}
|
||||||
|
|
||||||
const {{.packageName | title}}Key = "{{.appName}}:{{.packageName}}"
|
const {{.packageName | title}}Key = "{{.appName}}:{{.packageName}}"
|
||||||
|
@ -376,8 +166,6 @@ type Service interface {
|
||||||
// 请在这里定义你的方法
|
// 请在这里定义你的方法
|
||||||
Foo() string
|
Foo() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type {{.packageName | title}} struct {}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
var providerTmp = `package {{.packageName}}
|
var providerTmp = `package {{.packageName}}
|
||||||
|
@ -431,80 +219,3 @@ func (s *{{.packageName | title}}Service) Foo() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var apiTmp = `package {{.packageName}}
|
|
||||||
import (
|
|
||||||
"github.com/Superdanda/hade/framework/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type {{.packageName | title}}Api struct{}
|
|
||||||
|
|
||||||
// 注册路由
|
|
||||||
func RegisterRoutes(r *gin.Engine) error {
|
|
||||||
|
|
||||||
api := {{.packageName | title}}Api{}
|
|
||||||
|
|
||||||
if !r.IsBind({{.packageName}}.{{.packageName | title}}Key) {
|
|
||||||
r.Bind(&{{.packageName}}.{{.packageName | title}}Provider{})
|
|
||||||
}
|
|
||||||
|
|
||||||
{{template "registerRoutes" dict "node" .interfaces "groupVar" "r" "apiVar" "api"}}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
{{- define "registerRoutes"}}
|
|
||||||
{{- $node := .node -}}
|
|
||||||
{{- $groupVar := .groupVar -}}
|
|
||||||
{{- $apiVar := .apiVar -}}
|
|
||||||
|
|
||||||
{{- if ne $node.Path "root" -}}
|
|
||||||
{{- $hasChildren := gt (len $node.Children) 0 -}}
|
|
||||||
{{- $groupName := (printf "%sGroup" $node.Path) -}}
|
|
||||||
{{- if $hasChildren -}}
|
|
||||||
{{$groupName}} := {{$groupVar}}.Group("/{{$node.Path}}")
|
|
||||||
{
|
|
||||||
{{- if $node.NeedExtra -}}
|
|
||||||
{{$groupName}}.POST("/", {{$apiVar}}.{{ $node.HandlerName }})
|
|
||||||
{{- end}}
|
|
||||||
{{range $child := $node.Children}}
|
|
||||||
{{template "registerRoutes" dict "node" $child "groupVar" $groupName "apiVar" $apiVar}}
|
|
||||||
{{- end}}
|
|
||||||
}
|
|
||||||
{{- else}}
|
|
||||||
{{- if $node.NeedExtra}}
|
|
||||||
{{$groupVar}}.POST("/{{$node.Path}}", {{$apiVar}}.{{ $node.HandlerName }})
|
|
||||||
{{- end}}
|
|
||||||
{{end}}
|
|
||||||
{{- else}}
|
|
||||||
{{range $child := $node.Children}}
|
|
||||||
{{template "registerRoutes" dict "node" $child "groupVar" $groupVar "apiVar" $apiVar}}
|
|
||||||
{{- end}}
|
|
||||||
{{- end}}
|
|
||||||
{{- end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
var apiControllerTmp = `package {{.packageName}}
|
|
||||||
import (
|
|
||||||
"github.com/Superdanda/hade/framework/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// {{.methodName}} handler
|
|
||||||
func (api *{{.structName | title}}Api) {{.methodName}}(c *gin.Context) {
|
|
||||||
// TODO: Implement {{.methodName}}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
var dtoTmp = `package {{.packageName}}
|
|
||||||
|
|
||||||
type {{.packageName | title}}DTO struct {}
|
|
||||||
`
|
|
||||||
var mapperTmp = `package {{.packageName}}
|
|
||||||
|
|
||||||
func Convert{{.packageName | title}}ToDTO({{.packageName}} *{{.packageName}}.{{.packageName | title}}) *{{.packageName | title}}DTO {
|
|
||||||
if {{.packageName}} == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &{{.packageName | title}}DTO{}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
|
@ -32,9 +32,6 @@ type App interface {
|
||||||
// AppID 表示当前这个app的唯一id, 可以用于分布式锁等
|
// AppID 表示当前这个app的唯一id, 可以用于分布式锁等
|
||||||
AppId() string
|
AppId() string
|
||||||
|
|
||||||
// HttpModuleFolder 表示业务层的模块路径
|
|
||||||
HttpModuleFolder() string
|
|
||||||
|
|
||||||
LoadAppConfig(mapString map[string]string)
|
LoadAppConfig(mapString map[string]string)
|
||||||
|
|
||||||
AppFolder() string
|
AppFolder() string
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package contract
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
const TypeRegisterKey = "hade:typeRegister"
|
|
||||||
|
|
||||||
type TypeRegisterService interface {
|
|
||||||
Register(typeName string, instance interface{})
|
|
||||||
GetType(typeName string) (reflect.Type, bool)
|
|
||||||
}
|
|
|
@ -83,7 +83,7 @@ func (h HadeApp) TestFolder() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HadeApp) HttpFolder() string {
|
func (h HadeApp) HttpFolder() string {
|
||||||
return filepath.Join(h.AppFolder(), "http")
|
return filepath.Join(h.BaseFolder(), "http")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HadeApp) ConsoleFolder() string {
|
func (h HadeApp) ConsoleFolder() string {
|
||||||
|
@ -100,11 +100,6 @@ func (h HadeApp) DeployFolder() string {
|
||||||
return deployFolder
|
return deployFolder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HadeApp) HttpModuleFolder() string {
|
|
||||||
deployFolder := filepath.Join(h.HttpFolder(), "module")
|
|
||||||
return deployFolder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HadeApp) AppId() string {
|
func (h HadeApp) AppId() string {
|
||||||
return h.appId
|
return h.appId
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package type_register
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Superdanda/hade/framework"
|
|
||||||
"github.com/Superdanda/hade/framework/contract"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TypeRegisterProvider struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TypeRegisterProvider) Register(container framework.Container) framework.NewInstance {
|
|
||||||
return NewHadeTypeRegisterService
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TypeRegisterProvider) Boot(container framework.Container) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TypeRegisterProvider) IsDefer() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TypeRegisterProvider) Params(container framework.Container) []interface{} {
|
|
||||||
return []interface{}{container}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TypeRegisterProvider) Name() string {
|
|
||||||
return contract.TypeRegisterKey
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package type_register
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HadeTypeRegisterService struct {
|
|
||||||
mu sync.RWMutex
|
|
||||||
types map[string]reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHadeTypeRegisterService(params ...interface{}) (interface{}, error) {
|
|
||||||
return &HadeTypeRegisterService{
|
|
||||||
types: make(map[string]reflect.Type),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *HadeTypeRegisterService) Register(typeName string, instance interface{}) {
|
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
r.types[typeName] = reflect.TypeOf(instance)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *HadeTypeRegisterService) GetType(typeName string) (reflect.Type, bool) {
|
|
||||||
r.mu.RLock()
|
|
||||||
defer r.mu.RUnlock()
|
|
||||||
typ, exists := r.types[typeName]
|
|
||||||
return typ, exists
|
|
||||||
}
|
|
2
main.go
2
main.go
|
@ -14,7 +14,6 @@ import (
|
||||||
"github.com/Superdanda/hade/framework/provider/orm"
|
"github.com/Superdanda/hade/framework/provider/orm"
|
||||||
"github.com/Superdanda/hade/framework/provider/redis"
|
"github.com/Superdanda/hade/framework/provider/redis"
|
||||||
"github.com/Superdanda/hade/framework/provider/ssh"
|
"github.com/Superdanda/hade/framework/provider/ssh"
|
||||||
"github.com/Superdanda/hade/framework/provider/type_register"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -33,7 +32,6 @@ func main() {
|
||||||
container.Bind(&redis.RedisProvider{})
|
container.Bind(&redis.RedisProvider{})
|
||||||
container.Bind(&cache.HadeCacheProvider{})
|
container.Bind(&cache.HadeCacheProvider{})
|
||||||
container.Bind(&ssh.SSHProvider{})
|
container.Bind(&ssh.SSHProvider{})
|
||||||
container.Bind(&type_register.TypeRegisterProvider{})
|
|
||||||
|
|
||||||
// 将HTTP引擎初始化,并且作为服务提供者绑定到服务容器中
|
// 将HTTP引擎初始化,并且作为服务提供者绑定到服务容器中
|
||||||
if engine, err := http.NewHttpEngine(container); err == nil {
|
if engine, err := http.NewHttpEngine(container); err == nil {
|
||||||
|
|
Loading…
Reference in New Issue