Golang开源论坛新选择
Golang开源论坛新选择 为了更深入地学习Go语言,几个月前我开始编写一个论坛。现在它已具备基本功能,希望能得到大家的建议。
目前这个论坛还很简单,我也希望保持这种简洁。例如:
- 不使用任何框架(如beego、gin等)
- 不使用ORM,仅使用database/sql
- 从
hello world开始编写 …
最不满意的是界面不够酷炫。希望我们能互相学习。
1 回复
更多关于Golang开源论坛新选择的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个很棒的Go语言学习项目!基于你的要求,我来分享一些纯标准库的实现建议和代码示例:
路由处理优化
使用http.ServeMux实现更清晰的路由结构:
// router.go
func setupRoutes() *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/topic/", topicHandler)
mux.HandleFunc("/user/", userHandler)
mux.HandleFunc("/api/posts", apiPostsHandler)
// 静态文件服务
fs := http.FileServer(http.Dir("./static"))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
return mux
}
// 中间件示例
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
数据库操作封装
// db.go
type DB struct {
*sql.DB
}
func NewDB(dataSourceName string) (*DB, error) {
db, err := sql.Open("mysql", dataSourceName)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, err
}
return &DB{db}, nil
}
// 帖子模型
type Post struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
AuthorID int `json:"author_id"`
CreatedAt time.Time `json:"created_at"`
}
func (db *DB) CreatePost(post *Post) error {
query := `INSERT INTO posts (title, content, author_id, created_at)
VALUES (?, ?, ?, ?)`
result, err := db.Exec(query, post.Title, post.Content, post.AuthorID, time.Now())
if err != nil {
return err
}
id, err := result.LastInsertId()
if err != nil {
return err
}
post.ID = int(id)
return nil
}
func (db *DB) GetPosts(limit, offset int) ([]Post, error) {
query := `SELECT id, title, content, author_id, created_at
FROM posts ORDER BY created_at DESC LIMIT ? OFFSET ?`
rows, err := db.Query(query, limit, offset)
if err != nil {
return nil, err
}
defer rows.Close()
var posts []Post
for rows.Next() {
var post Post
err := rows.Scan(&post.ID, &post.Title, &post.Content, &post.AuthorID, &post.CreatedAt)
if err != nil {
return nil, err
}
posts = append(posts, post)
}
return posts, nil
}
模板渲染增强
// template.go
type TemplateData struct {
Title string
Posts []Post
User *User
Error string
Success string
}
func renderTemplate(w http.ResponseWriter, tmpl string, data *TemplateData) error {
templatePath := fmt.Sprintf("templates/%s.html", tmpl)
baseTemplate := "templates/base.html"
// 解析模板
t, err := template.ParseFiles(baseTemplate, templatePath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return err
}
// 设置默认标题
if data.Title == "" {
data.Title = "Go Discourse"
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
return t.Execute(w, data)
}
// 使用示例
func homeHandler(w http.ResponseWriter, r *http.Request) {
posts, err := db.GetPosts(10, 0)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := &TemplateData{
Title: "首页",
Posts: posts,
}
if err := renderTemplate(w, "home", data); err != nil {
log.Printf("模板渲染错误: %v", err)
}
}
JSON API 响应
// api.go
type APIResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
func writeJSON(w http.ResponseWriter, status int, data interface{}) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
return json.NewEncoder(w).Encode(data)
}
func apiPostsHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
posts, err := db.GetPosts(20, 0)
if err != nil {
writeJSON(w, http.StatusInternalServerError, APIResponse{
Success: false,
Error: "获取帖子失败",
})
return
}
writeJSON(w, http.StatusOK, APIResponse{
Success: true,
Data: posts,
})
case "POST":
var post Post
if err := json.NewDecoder(r.Body).Decode(&post); err != nil {
writeJSON(w, http.StatusBadRequest, APIResponse{
Success: false,
Error: "无效的请求数据",
})
return
}
if err := db.CreatePost(&post); err != nil {
writeJSON(w, http.StatusInternalServerError, APIResponse{
Success: false,
Error: "创建帖子失败",
})
return
}
writeJSON(w, http.StatusCreated, APIResponse{
Success: true,
Data: post,
})
default:
writeJSON(w, http.StatusMethodNotAllowed, APIResponse{
Success: false,
Error: "方法不允许",
})
}
}
主函数整合
// main.go
func main() {
// 初始化数据库
db, err := NewDB("user:password@/forum?parseTime=true")
if err != nil {
log.Fatal("数据库连接失败:", err)
}
defer db.Close()
// 设置路由
mux := setupRoutes()
// 添加中间件
handler := loggingMiddleware(mux)
log.Println("服务器启动在 :8080")
if err := http.ListenAndServe(":8080", handler); err != nil {
log.Fatal("服务器启动失败:", err)
}
}
这些代码展示了如何在不使用框架的情况下构建一个功能完整的论坛后端。项目结构清晰,易于扩展,完全符合你坚持使用标准库的学习目标。

