2 回复
这是一个很棒的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的最佳实践,是一个很好的学习参考项目。



