在学习 Go 的过程中,一个非常适合入门的 Web 项目就是 TodoList(任务待办清单) 。它功能简单,但涵盖了 HTTP 路由、数据存储、前后端交互 等核心知识点。本篇我们将实现一个基于 Go 标准库 + HTML 模板 的 TodoList 应用。
一、项目目标
实现一个简易的 任务待办清单 Web 应用:
- ✅ 查看任务列表
- ✅ 添加任务
- ✅ 删除任务
- ✅ 标记任务完成/未完成
- ✅ 数据持久化(存储在 JSON 文件)
二、系统设计
数据结构
go
type Task struct {
ID int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
路由设计
路径 | 方法 | 功能 |
---|---|---|
/ |
GET | 展示任务列表 |
/add |
POST | 添加任务 |
/delete?id= |
GET | 删除任务 |
/toggle?id= |
GET | 切换完成状态 |
存储方式
- 使用 JSON 文件存储所有任务 (
tasks.json
) - 每次操作时更新文件,保证数据持久化
三、完整代码示例
文件名:
main.go
go
package main
import (
"encoding/json"
"html/template"
"net/http"
"os"
"strconv"
"sync"
)
type Task struct {
ID int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var (
tasks []Task
dataFile = "tasks.json"
mutex sync.Mutex
)
// 加载任务
func loadTasks() {
file, err := os.ReadFile(dataFile)
if err != nil {
tasks = []Task{}
return
}
_ = json.Unmarshal(file, &tasks)
}
// 保存任务
func saveTasks() {
data, _ := json.MarshalIndent(tasks, "", " ")
_ = os.WriteFile(dataFile, data, 0644)
}
// 首页:显示任务列表
func indexHandler(w http.ResponseWriter, r *http.Request) {
tmpl := `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Todo List</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.done { text-decoration: line-through; color: gray; }
</style>
</head>
<body>
<h1>任务待办清单 ✅</h1>
<form method="POST" action="/add">
<input type="text" name="title" placeholder="输入任务..." required>
<button type="submit">添加</button>
</form>
<ul>
{{range .}}
<li>
<a href="/toggle?id={{.ID}}">
<span class="{{if .Completed}}done{{end}}">{{.Title}}</span>
</a>
<a href="/delete?id={{.ID}}" style="color:red;">[删除]</a>
</li>
{{end}}
</ul>
</body>
</html>`
t := template.Must(template.New("index").Parse(tmpl))
_ = t.Execute(w, tasks)
}
// 添加任务
func addHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
title := r.FormValue("title")
if title != "" {
mutex.Lock()
id := 1
if len(tasks) > 0 {
id = tasks[len(tasks)-1].ID + 1
}
tasks = append(tasks, Task{ID: id, Title: title, Completed: false})
saveTasks()
mutex.Unlock()
}
}
http.Redirect(w, r, "/", http.StatusFound)
}
// 删除任务
func deleteHandler(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if id, err := strconv.Atoi(idStr); err == nil {
mutex.Lock()
for i, t := range tasks {
if t.ID == id {
tasks = append(tasks[:i], tasks[i+1:]...)
break
}
}
saveTasks()
mutex.Unlock()
}
http.Redirect(w, r, "/", http.StatusFound)
}
// 切换任务完成状态
func toggleHandler(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if id, err := strconv.Atoi(idStr); err == nil {
mutex.Lock()
for i, t := range tasks {
if t.ID == id {
tasks[i].Completed = !tasks[i].Completed
break
}
}
saveTasks()
mutex.Unlock()
}
http.Redirect(w, r, "/", http.StatusFound)
}
func main() {
loadTasks()
http.HandleFunc("/", indexHandler)
http.HandleFunc("/add", addHandler)
http.HandleFunc("/delete", deleteHandler)
http.HandleFunc("/toggle", toggleHandler)
println("服务器启动:http://localhost:8080")
_ = http.ListenAndServe(":8080", nil)
}
四、运行效果
- 启动服务
bash
go run main.go
- 浏览器访问 http://localhost:8080
- 输入任务 → 点击"添加" → 列表中出现
- 点击任务文字 → 切换完成状态(加删除线 ✅)
- 点击
[删除]
→ 删除任务
数据保存在 tasks.json
文件,重启服务数据仍然存在。
五、扩展方向
- 🔄 任务编辑功能:修改任务标题
- 📅 增加截止日期 / 优先级
- 🔍 搜索 & 分类:已完成 / 未完成分组
- 🌐 使用前端框架:Vue/React + Go 后端 API
- 🗄️ 替换存储:SQLite/MySQL/Postgres
六、总结
这个 TodoList Web 应用示例,涵盖了:
- Go 标准库 net/http 的基本用法
- HTML 模板 渲染动态页面
- JSON 文件持久化
- 简单的 并发控制(sync.Mutex)
是非常好的 Go Web 开发入门实战案例。