Go语言实战案例 — 项目实战篇:图书管理系统(文件存储)

在学习 Go 的过程中,很多同学会做一些小型实战项目来加深理解。本篇带来的案例是一个图书管理系统 ,它采用 文件存储 的方式保存数据(JSON 文件),避免了引入数据库的复杂度,非常适合作为入门级的项目实践。


一、项目目标

我们要实现一个简易的命令行版 图书管理系统,功能如下:

  • ✅ 添加图书(标题、作者、价格)
  • ✅ 删除图书(根据 ID)
  • ✅ 查询图书(按 ID 或标题模糊搜索)
  • ✅ 列出所有图书
  • ✅ 数据持久化(保存到 JSON 文件,程序退出后数据不丢失)

二、系统设计

数据结构:

go 复制代码
type Book struct {
    ID     int     `json:"id"`
    Title  string  `json:"title"`
    Author string  `json:"author"`
    Price  float64 `json:"price"`
}
  • 每本书有唯一 ID
  • 图书列表存放在一个 []Book
  • 数据通过 JSON 序列化存储到 books.json

模块划分:

  1. 数据持久化层:负责加载和保存 JSON 文件
  2. 业务逻辑层:增删改查操作
  3. 命令行交互层:菜单驱动

三、完整代码示例

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

// Book 图书结构体
type Book struct {
	ID     int     `json:"id"`
	Title  string  `json:"title"`
	Author string  `json:"author"`
	Price  float64 `json:"price"`
}

// 全局图书切片
var books []Book
var dataFile = "books.json"

// 加载图书数据
func loadBooks() {
	file, err := ioutil.ReadFile(dataFile)
	if err != nil {
		if os.IsNotExist(err) {
			books = []Book{}
			return
		}
		fmt.Println("加载数据失败:", err)
		return
	}
	_ = json.Unmarshal(file, &books)
}

// 保存图书数据
func saveBooks() {
	data, err := json.MarshalIndent(books, "", "  ")
	if err != nil {
		fmt.Println("保存数据失败:", err)
		return
	}
	_ = ioutil.WriteFile(dataFile, data, 0644)
}

// 添加图书
func addBook(title, author string, price float64) {
	id := 1
	if len(books) > 0 {
		id = books[len(books)-1].ID + 1
	}
	book := Book{ID: id, Title: title, Author: author, Price: price}
	books = append(books, book)
	saveBooks()
	fmt.Println("✅ 图书添加成功:", book)
}

// 删除图书
func deleteBook(id int) {
	index := -1
	for i, b := range books {
		if b.ID == id {
			index = i
			break
		}
	}
	if index == -1 {
		fmt.Println("❌ 未找到该 ID 的图书")
		return
	}
	books = append(books[:index], books[index+1:]...)
	saveBooks()
	fmt.Println("✅ 图书删除成功")
}

// 查询图书
func searchBook(keyword string) {
	keyword = strings.ToLower(keyword)
	found := false
	for _, b := range books {
		if strings.Contains(strings.ToLower(b.Title), keyword) || fmt.Sprintf("%d", b.ID) == keyword {
			fmt.Printf("📖 ID:%d | 标题:%s | 作者:%s | 价格:%.2f\n", b.ID, b.Title, b.Author, b.Price)
			found = true
		}
	}
	if !found {
		fmt.Println("🔍 未找到匹配的图书")
	}
}

// 列出所有图书
func listBooks() {
	if len(books) == 0 {
		fmt.Println("暂无图书")
		return
	}
	fmt.Println("📚 图书列表:")
	for _, b := range books {
		fmt.Printf("ID:%d | 标题:%s | 作者:%s | 价格:%.2f\n", b.ID, b.Title, b.Author, b.Price)
	}
}

// 主菜单
func main() {
	loadBooks()
	for {
		fmt.Println("\n==== 图书管理系统 ====")
		fmt.Println("1. 添加图书")
		fmt.Println("2. 删除图书")
		fmt.Println("3. 查询图书")
		fmt.Println("4. 列出所有图书")
		fmt.Println("5. 退出")
		fmt.Print("请输入选项: ")

		var choice int
		fmt.Scanln(&choice)

		switch choice {
		case 1:
			var title, author string
			var price float64
			fmt.Print("输入标题: ")
			fmt.Scanln(&title)
			fmt.Print("输入作者: ")
			fmt.Scanln(&author)
			fmt.Print("输入价格: ")
			fmt.Scanln(&price)
			addBook(title, author, price)
		case 2:
			var id int
			fmt.Print("输入要删除的图书ID: ")
			fmt.Scanln(&id)
			deleteBook(id)
		case 3:
			var keyword string
			fmt.Print("输入图书ID或标题关键字: ")
			fmt.Scanln(&keyword)
			searchBook(keyword)
		case 4:
			listBooks()
		case 5:
			fmt.Println("退出系统,再见!👋")
			return
		default:
			fmt.Println("无效选项,请重新输入")
		}
	}
}

四、运行效果

bash 复制代码
$ go run main.go
==== 图书管理系统 ====
1. 添加图书
2. 删除图书
3. 查询图书
4. 列出所有图书
5. 退出
请输入选项: 1
输入标题: Go语言实战
输入作者: 张三
输入价格: 59.9
✅ 图书添加成功: {1 Go语言实战 张三 59.9}

再次运行,可以看到数据被保存到 books.json,实现了持久化。


五、总结与扩展

这个简易的图书管理系统涵盖了文件读写、JSON 序列化、数据结构操作、命令行交互等知识点,是 Go 入门的非常好的练手项目。

相关推荐
元闰子2 小时前
OLTP上云,哪种架构最划算?·VLDB'25
数据库·后端·云原生
IT_陈寒2 小时前
Vite 5.0重磅升级:8个性能优化秘诀让你的构建速度飙升200%!🚀
前端·人工智能·后端
hui函数2 小时前
scrapy框架-day02
后端·爬虫·python·scrapy
Moshow郑锴3 小时前
SpringBootCodeGenerator使用JSqlParser解析DDL CREATE SQL 语句
spring boot·后端·sql
小沈同学呀9 小时前
创建一个Spring Boot Starter风格的Basic认证SDK
java·spring boot·后端
方圆想当图灵11 小时前
如何让百万 QPS 下的服务更高效?
分布式·后端
凤山老林11 小时前
SpringBoot 轻量级一站式日志可视化与JVM监控
jvm·spring boot·后端
凡梦千华11 小时前
Django时区感知
后端·python·django
Chan1612 小时前
JVM从入门到实战:从字节码组成、类生命周期到双亲委派及打破双亲委派机制
java·jvm·spring boot·后端·intellij-idea