day9接口 练习7.11

master
独孤伶俜 2022-12-17 23:32:49 +08:00
parent 56bdab679a
commit e6b21f969d
2 changed files with 194 additions and 0 deletions

View File

@ -0,0 +1,193 @@
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)
}

View File

@ -0,0 +1 @@
{"aaaa":11.11,"shoes":50,"socks":5}