GolangStudy/src/study/day9Interface/Practice/7.11.go

195 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"strconv"
)
// 增加额外的handler让客户端可以创建读取更新和删除数据库记录。
// 例如,一个形如 /update?item=socks&price=6
// 的请求会更新库存清单里一个货品的价格并且当这个货品不存在或价格无效时返回一个错误值。
//(注意:这个修改会引入变量同时更新的问题)
// TODO:
// 1. 将数据保存到本地json文件
// 2. 开启web服务时读取本地json文件
// 3. 读取数据时如果本地json文件不存在则从默认值获取数据
// 4. 实现web服务器
// 5. 实现增删改查
// 6. 关闭服务器时保存数据到本地json文件
type dollars float32
func (d dollars) String() string {
return fmt.Sprintf("$%.2f", d)
}
type database map[string]dollars
// list 货物清单
func (db database) list(w http.ResponseWriter, req *http.Request) {
for item, price := range db {
fmt.Fprintf(w, "%s: %s\n", item, price)
}
}
// price 价格
func (db database) price(w http.ResponseWriter, req *http.Request) {
item := req.URL.Query().Get("item")
price, ok := db[item]
if !ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "no such item: %q\n", item)
return
}
fmt.Fprintf(w, "%s\n", price)
}
// create 创建
func (db database) create(w http.ResponseWriter, req *http.Request) {
item := req.URL.Query().Get("item")
price := req.URL.Query().Get("price")
_, ok := db[item]
if ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "item 已经存在: %q\n", item)
return
}
// string to float
priceF, err := strconv.ParseFloat(price, 32)
if err != nil {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "price is invalid: %q\n", price)
return
}
db[item] = dollars(priceF)
fmt.Fprintf(w, "create item: %q\n", item)
fmt.Fprintf(os.Stdout, "item create: %q\n", db)
}
// update 更新
func (db database) update(w http.ResponseWriter, req *http.Request) {
item := req.URL.Query().Get("item")
price := req.URL.Query().Get("price")
_, ok := db[item]
if !ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "item 不存在: %q\n", item)
return
}
// string to float
priceF, err := strconv.ParseFloat(price, 32)
if err != nil {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "price is invalid: %q\n", price)
return
}
db[item] = dollars(priceF)
fmt.Fprintf(w, "update item: %q\n", item)
fmt.Fprintf(os.Stdout, "item update: %q\n", db)
}
// delete 删除
func (db database) delete(w http.ResponseWriter, req *http.Request) {
item := req.URL.Query().Get("item")
_, ok := db[item]
if !ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "item 不存在: %q\n", item)
return
}
delete(db, item)
fmt.Fprintf(w, "delete item: %q\n", item)
fmt.Fprintf(os.Stdout, "item delete: %q\n", db)
}
// 默认数据
var defaultDB database = database{"shoes": 50, "socks": 5}
// 数据库
var db database
func loadDB() error {
path := "/Users/dugulingping/code/Golang/Study/src/study/day9Interface/Practice/db.json"
// 打开文件
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return err
}
// 关闭文件
defer file.Close()
// 读取文件, 解析json文件
decoder := json.NewDecoder(file)
if err := decoder.Decode(&db); err != nil {
// 如果文件为空,则从默认值获取数据
if err == io.EOF {
// 从默认值获取数据
fmt.Fprintln(os.Stdout, "从默认值获取数据")
db = defaultDB
return nil
} else {
// 如果文件不为空,但是解析失败,则返回错误
return err
}
}
return nil
}
// saveDB 保存数据到本地json文件
func saveDB() {
path := "/Users/dugulingping/code/Golang/Study/src/study/day9Interface/Practice/db.json"
// 打开文件
file, err := os.OpenFile(path, os.O_RDWR, 0755)
if err != nil {
panic(err)
}
// 关闭文件
defer file.Close()
// 清空文件
file.Truncate(0)
// 从头开始写入
file.Seek(0, 0)
// 编码json文件
encoder := json.NewEncoder(file)
if err := encoder.Encode(db); err != nil {
panic(err)
}
fmt.Fprintf(os.Stdout, "save db: %q", db)
}
func main() {
// 从本地json文件读取数据
err := loadDB()
if err != nil {
fmt.Fprintf(os.Stdout, "loadDB err: %q", err)
}
// 创建通道
c := make(chan os.Signal)
// 监听指定信号 ctrl+c kill
signal.Notify(c, os.Interrupt)
// 启动一个协程
// 目的是当接收到指定信号时,执行保存数据库
go func() {
select {
case sig := <-c:
fmt.Printf("Got %s signal. Aborting...\n", sig)
// 保存数据库
saveDB()
// 退出程序
os.Exit(1)
}
}()
// 创建路由
http.HandleFunc("/list", db.list)
http.HandleFunc("/price", db.price)
http.HandleFunc("/create", db.create)
http.HandleFunc("/update", db.update)
http.HandleFunc("/delete", db.delete)
// 监听端口
http.ListenAndServe("localhost:8000", nil)
}