使用Golang开发的自托管Quora风格Web应用

使用Golang开发的自托管Quora风格Web应用 ui

仓库地址:https://github.com/meloalright/guora

2 回复

干得好,Travis,感谢分享

更多关于使用Golang开发的自托管Quora风格Web应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个很棒的Go语言自托管问答应用项目!从截图和代码库来看,这个应用实现了Quora风格的核心功能。让我分析一下这个项目的技术实现:

项目架构分析

从代码结构看,这是一个典型的Go Web应用,采用了分层架构:

// 主要目录结构
guora/
├── internal/
│   ├── model/      # 数据模型
│   ├── dao/        # 数据访问层
│   └── service/    # 业务逻辑层
├── web/
│   ├── template/   # HTML模板
│   └── static/     # 静态资源
└── main.go         # 应用入口

核心技术栈

1. Web框架使用标准库 + 模板

// 路由处理示例
func questionHandler(w http.ResponseWriter, r *http.Request) {
    // 解析URL参数
    vars := mux.Vars(r)
    id := vars["id"]
    
    // 查询问题
    question, err := dao.GetQuestion(id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }
    
    // 渲染模板
    tmpl, _ := template.ParseFiles("web/template/question.html")
    tmpl.Execute(w, question)
}

2. 数据库层使用GORM

// 模型定义示例
type Question struct {
    ID        uint      `gorm:"primaryKey"`
    Title     string    `gorm:"type:varchar(255);not null"`
    Content   string    `gorm:"type:text;not null"`
    UserID    uint
    Answers   []Answer  `gorm:"foreignKey:QuestionID"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

// 数据访问示例
func GetQuestionWithAnswers(id uint) (Question, error) {
    var question Question
    err := db.Preload("Answers").Preload("Answers.User").
           First(&question, id).Error
    return question, err
}

3. 模板引擎使用html/template

<!-- 问题展示模板示例 -->
{{define "question"}}
<div class="question-card">
    <h2>{{.Title}}</h2>
    <div class="content">{{.Content}}</div>
    <div class="meta">
        <span>提问者: {{.User.Name}}</span>
        <span>时间: {{.CreatedAt.Format "2006-01-02 15:04"}}</span>
    </div>
    
    <!-- 答案列表 -->
    <div class="answers">
        {{range .Answers}}
        <div class="answer">
            <p>{{.Content}}</p>
            <div class="meta">
                <span>回答者: {{.User.Name}}</span>
                <span>赞同: {{.Upvotes}}</span>
            </div>
        </div>
        {{end}}
    </div>
</div>
{{end}}

值得关注的实现特点

1. 认证系统

// 会话管理示例
func loginHandler(w http.ResponseWriter, r *http.Request) {
    // 验证用户
    user, err := service.Authenticate(r.FormValue("email"), 
                                     r.FormValue("password"))
    if err != nil {
        // 返回错误
        return
    }
    
    // 创建会话
    session, _ := store.Get(r, "session-name")
    session.Values["user_id"] = user.ID
    session.Save(r, w)
    
    http.Redirect(w, r, "/", http.StatusFound)
}

2. 富文本处理

// 内容安全处理
func sanitizeContent(content string) string {
    // 使用bluemonday进行HTML净化
    p := bluemonday.UGCPolicy()
    p.AllowAttrs("class").OnElements("pre", "code")
    return p.Sanitize(content)
}

3. 分页实现

// 分页查询
func GetQuestions(page, pageSize int) ([]Question, int64, error) {
    var questions []Question
    var total int64
    
    offset := (page - 1) * pageSize
    db.Model(&Question{}).Count(&total)
    err := db.Order("created_at DESC").
             Limit(pageSize).
             Offset(offset).
             Find(&questions).Error
             
    return questions, total, err
}

性能优化建议

1. 数据库查询优化

// 使用JOIN减少查询次数
func GetQuestionDetail(id uint) (Question, error) {
    var question Question
    err := db.Joins("User").
           Preload("Answers", func(db *gorm.DB) *gorm.DB {
               return db.Joins("User").Order("answers.upvotes DESC")
           }).
           First(&question, id).Error
    return question, err
}

2. 缓存实现

// 使用Redis缓存热门问题
func GetHotQuestions() ([]Question, error) {
    cacheKey := "hot_questions"
    
    // 尝试从缓存获取
    if cached, err := redis.Get(cacheKey); err == nil {
        var questions []Question
        json.Unmarshal(cached, &questions)
        return questions, nil
    }
    
    // 查询数据库
    questions, err := dao.GetHotQuestions()
    if err != nil {
        return nil, err
    }
    
    // 设置缓存
    data, _ := json.Marshal(questions)
    redis.SetEx(cacheKey, data, 300) // 缓存5分钟
    
    return questions, nil
}

这个项目展示了如何使用Go构建一个完整的Web应用,涵盖了用户认证、内容管理、数据库操作等核心功能。代码结构清晰,遵循了Go的最佳实践,是一个很好的学习参考项目。

回到顶部