# 02-数据库和模型设计 ## 目标 实现数据库连接模块和所有数据模型定义,支持多数据库切换。 --- ## 前置要求 - 项目结构已初始化 - 依赖已安装 --- ## 实施步骤 ### 步骤 1:创建配置加载模块 创建 `server/internal/config/config.go`: ```go package config import ( "github.com/spf13/viper" ) type Config struct { Server ServerConfig Database DatabaseConfig JWT JWTConfig AI AIConfig } type ServerConfig struct { Port int Mode string } type DatabaseConfig struct { Driver string SQLite SQLiteConfig Postgres PostgresConfig MySQL MySQLConfig } type SQLiteConfig struct { Path string } type PostgresConfig struct { Host string Port int User string Password string DBName string } type MySQLConfig struct { Host string Port int User string Password string DBName string } type JWTConfig struct { Secret string ExpireHours int `mapstructure:"expire_hours"` } type AIConfig struct { Provider string APIKey string `mapstructure:"api_key"` BaseURL string `mapstructure:"base_url"` } var AppConfig *Config func LoadConfig(path string) error { viper.SetConfigFile(path) if err := viper.ReadInConfig(); err != nil { return err } AppConfig = &Config{} return viper.Unmarshal(AppConfig) } ``` ### 步骤 2:创建数据库连接模块 创建 `server/internal/database/database.go`: ```go package database import ( "fmt" "health-ai/internal/config" "gorm.io/driver/sqlite" "gorm.io/gorm" ) var DB *gorm.DB func InitDatabase(cfg *config.DatabaseConfig) error { var err error switch cfg.Driver { case "sqlite": DB, err = gorm.Open(sqlite.Open(cfg.SQLite.Path), &gorm.Config{}) case "postgres": // TODO: 添加 PostgreSQL 支持 // dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", // cfg.Postgres.Host, cfg.Postgres.Port, cfg.Postgres.User, cfg.Postgres.Password, cfg.Postgres.DBName) // DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) return fmt.Errorf("postgres driver not implemented yet") case "mysql": // TODO: 添加 MySQL 支持 return fmt.Errorf("mysql driver not implemented yet") default: return fmt.Errorf("unsupported database driver: %s", cfg.Driver) } return err } func AutoMigrate(models ...interface{}) error { return DB.AutoMigrate(models...) } ``` ### 步骤 3:创建数据模型 创建 `server/internal/model/user.go`: ```go package model import ( "time" "gorm.io/gorm" ) // User 用户表 type User struct { gorm.Model Phone string `gorm:"uniqueIndex;size:20"` Email string `gorm:"uniqueIndex;size:100"` PasswordHash string `gorm:"size:255"` Nickname string `gorm:"size:50"` Avatar string `gorm:"size:255"` SurveyCompleted bool `gorm:"default:false"` } // HealthProfile 健康档案 type HealthProfile struct { gorm.Model UserID uint `gorm:"uniqueIndex"` Name string `gorm:"size:50"` BirthDate *time.Time Gender string `gorm:"size:10"` // male, female Height float64 // cm Weight float64 // kg BMI float64 BloodType string `gorm:"size:10"` // A, B, AB, O Occupation string `gorm:"size:50"` MaritalStatus string `gorm:"size:20"` // single, married, divorced Region string `gorm:"size:100"` } // LifestyleInfo 生活习惯 type LifestyleInfo struct { gorm.Model UserID uint `gorm:"uniqueIndex"` SleepTime string `gorm:"size:10"` // HH:MM WakeTime string `gorm:"size:10"` SleepQuality string `gorm:"size:20"` // good, normal, poor MealRegularity string `gorm:"size:20"` // regular, irregular DietPreference string `gorm:"size:50"` // 偏好 DailyWaterML int // 每日饮水量 ml ExerciseFrequency string `gorm:"size:20"` // never, sometimes, often, daily ExerciseType string `gorm:"size:100"` ExerciseDurationMin int // 每次运动时长 IsSmoker bool AlcoholFrequency string `gorm:"size:20"` // never, sometimes, often } ``` 创建 `server/internal/model/health.go`: ```go package model import "gorm.io/gorm" // MedicalHistory 既往病史 type MedicalHistory struct { gorm.Model HealthProfileID uint DiseaseName string `gorm:"size:100"` DiseaseType string `gorm:"size:50"` // chronic, surgery, other DiagnosedDate string `gorm:"size:20"` Status string `gorm:"size:20"` // cured, treating, controlled Notes string `gorm:"type:text"` } // FamilyHistory 家族病史 type FamilyHistory struct { gorm.Model HealthProfileID uint Relation string `gorm:"size:20"` // father, mother, grandparent DiseaseName string `gorm:"size:100"` Notes string `gorm:"type:text"` } // AllergyRecord 过敏记录 type AllergyRecord struct { gorm.Model HealthProfileID uint AllergyType string `gorm:"size:20"` // drug, food, other Allergen string `gorm:"size:100"` Severity string `gorm:"size:20"` // mild, moderate, severe ReactionDesc string `gorm:"type:text"` } ``` 创建 `server/internal/model/constitution.go`: ```go package model import ( "time" "gorm.io/gorm" ) // ConstitutionAssessment 体质测评记录 type ConstitutionAssessment struct { gorm.Model UserID uint AssessedAt time.Time Scores string `gorm:"type:text"` // JSON: 各体质得分 PrimaryConstitution string `gorm:"size:20"` // 主要体质 SecondaryConstitutions string `gorm:"type:text"` // JSON: 次要体质 Recommendations string `gorm:"type:text"` // JSON: 调养建议 } // AssessmentAnswer 问卷答案 type AssessmentAnswer struct { gorm.Model AssessmentID uint QuestionID uint Score int // 1-5 } // QuestionBank 问卷题库 type QuestionBank struct { gorm.Model ConstitutionType string `gorm:"size:20"` // 体质类型 QuestionText string `gorm:"type:text"` Options string `gorm:"type:text"` // JSON: 选项 OrderNum int } ``` 创建 `server/internal/model/conversation.go`: ```go package model import "gorm.io/gorm" // Conversation 对话 type Conversation struct { gorm.Model UserID uint Title string `gorm:"size:200"` Messages []Message } // Message 消息 type Message struct { gorm.Model ConversationID uint Role string `gorm:"size:20"` // user, assistant, system Content string `gorm:"type:text"` } ``` ### 步骤 4:创建模型聚合文件 创建 `server/internal/model/models.go`: ```go package model // AllModels 返回所有需要迁移的模型 func AllModels() []interface{} { return []interface{}{ &User{}, &HealthProfile{}, &LifestyleInfo{}, &MedicalHistory{}, &FamilyHistory{}, &AllergyRecord{}, &ConstitutionAssessment{}, &AssessmentAnswer{}, &QuestionBank{}, &Conversation{}, &Message{}, } } ``` ### 步骤 5:更新主程序 更新 `server/cmd/server/main.go`: ```go package main import ( "log" "health-ai/internal/config" "health-ai/internal/database" "health-ai/internal/model" ) func main() { // 加载配置 if err := config.LoadConfig("config.yaml"); err != nil { log.Fatalf("Failed to load config: %v", err) } log.Println("Config loaded") // 初始化数据库 if err := database.InitDatabase(&config.AppConfig.Database); err != nil { log.Fatalf("Failed to init database: %v", err) } log.Println("Database connected") // 自动迁移 if err := database.AutoMigrate(model.AllModels()...); err != nil { log.Fatalf("Failed to migrate: %v", err) } log.Println("Database migrated") log.Println("Health AI Server Ready!") } ``` --- ## 需要创建的文件清单 | 文件路径 | 说明 | |----------|------| | `internal/config/config.go` | 配置加载 | | `internal/database/database.go` | 数据库连接 | | `internal/model/user.go` | 用户相关模型 | | `internal/model/health.go` | 健康相关模型 | | `internal/model/constitution.go` | 体质相关模型 | | `internal/model/conversation.go` | 对话相关模型 | | `internal/model/models.go` | 模型聚合 | --- ## 验收标准 - [ ] 配置文件可正常加载 - [ ] SQLite 数据库文件自动创建 - [ ] 所有表自动迁移成功 - [ ] `data/health.db` 文件生成 --- ## 预计耗时 20-30 分钟 --- ## 下一步 完成后进入 `02-后端开发/03-用户认证模块.md`