Go实现http同步文件操作 - 增删改查

2023-12-14 23:35:04

http同步文件操作 - 增删改查

1. 前置要求

1.1. 构建结构体 文件名 + 文件内容

1.1.1. 页面结构体

type Page struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}
// ``符号为结构体的标准,可忽略

1.1.2. 为Page结构体绑定方法:Save

// SavePage 页面文件保存方法,保存到数据库,这里保存到页面文件中
// 使用bufio操作文件
// notice: 延时关闭 flush
// 绑定Page指针变量
func (page *Page) SavePage(title string, body string) (err error) {
	title += ".txt"
	// todo 1. 拿到页面文件句柄
	file, err := os.OpenFile(title, os.O_CREATE|os.O_RDWR, fs.ModePerm)
	// todo final step
	defer func() { _ = file.Close() }()
	if err != nil {
		fmt.Println("无法获取到页面文件,error:", err)
		return err
	}
	// todo 2. 打开页面文件
	writer := bufio.NewWriter(file)
	// todo 3. 往页面文件写入内容
	nByteNum, err := writer.Write([]byte(body))
	if err != nil {
		fmt.Println("页面文件保存失败,error:", err)
		return err
	}
	// todo 4. 刷写数据出去
	_ = writer.Flush()
	fmt.Println("写入的内容大小为:", nByteNum, "字节")
	return nil
}
  1. 内容添加文件后缀,固定为.txt

  2. 使用bufio操作文件,可以更换其它方式

  3. *指针变量

  4. 注意事项:

    1. 延时关闭

      defer func() { _ = file.Close() }()

    2. 数据刷写

      _ = writer.Flush()

1.1.3. 对Page结构体支持页面内容查看方法,同时提供页面文件是否存在的方法


// 判断是否存在该页面文件名,不需要加后缀!已经手动添加;也可以优化,多加入参数表示后缀即可
func ExistFile(fileName string) bool {
	if _, err := os.Stat(fileName + ".txt"); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// 查看指定的页面文件内容
// 使用os操作文件
func ViewPage(title string) (page *Page) {
	page = &Page{}
	page.Title = title
	if ExistFile(title) {
		fileContent, err := os.ReadFile(title + ".txt")
		if err != nil {
			fmt.Println("读取页面文件出错, error is :", err)
		} else {
			page.Body = string(fileContent)
		}
	}
	return page
}
  • 上面内容为一个文件,该entity/entity.go文件的全部代码为:
package entity

import (
	"bufio"
	"fmt"
	"io/fs"
	"os"
)

type Page struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}

// SavePage 页面文件保存方法,保存到数据库,这里保存到页面文件中
// 使用bufio操作文件
// notice: 延时关闭 flush
func (page *Page) SavePage(title string, body string) (err error) {
	title += ".txt"
	// todo 1. 拿到页面文件句柄
	file, err := os.OpenFile(title, os.O_CREATE|os.O_RDWR, fs.ModePerm)
	// todo final step
	defer func() { _ = file.Close() }()
	if err != nil {
		fmt.Println("无法获取到页面文件,error:", err)
		return err
	}
	// todo 2. 打开页面文件
	writer := bufio.NewWriter(file)
	// todo 3. 往页面文件写入内容
	nByteNum, err := writer.Write([]byte(body))
	if err != nil {
		fmt.Println("页面文件保存失败,error:", err)
		return err
	}
	// todo 4. 刷写数据出去
	_ = writer.Flush()
	fmt.Println("写入的内容大小为:", nByteNum, "字节")
	return nil
}

// 判断是否存在该页面文件名,不需要加后缀!
func ExistFile(fileName string) bool {
	if _, err := os.Stat(fileName + ".txt"); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// 查看指定的页面文件内容
// 使用os操作文件
func ViewPage(title string) (page *Page) {
	page = &Page{}
	page.Title = title
	if ExistFile(title) {
		fileContent, err := os.ReadFile(title + ".txt")
		if err != nil {
			fmt.Println("读取页面文件出错, error is :", err)
		} else {
			page.Body = string(fileContent)
		}
	}
	return page
}

1.2. 简单验证上面的结构体是否可以直接改变值

func main() {
	// 验证你的结构体是否发生改变 - 指针变量
	page := entity.ViewPage("TestPage")
	fmt.Println(page)
	page.Body = "change"
	fmt.Println(page)
}

使用HTTP来完成对页面的增删改查

1. 增加对页面文件保存的操作

// http方式保存page
// 默认从请求体中获取内容作为body传入文件
// 直接调用/savePage的body默认值为:this is a default value
// 更新操作也会调用该方法,body值为 上传的请求体内容
func saveHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/savePage/"):]
	// todo 2. 填充 body内容
	page := &entity.Page{}
	// important 本人在后面update会遇到坑,默认从请求体中获取body
	// todo 2.1. 优先考虑从请求体获取body
	body := request.FormValue("body")
	// todo 2.2. 请求体为空串,则赋值默认值
	if body == "" {
		body = "this is a default value"
	}
	// todo 3. 将body值写入到页面文件
	err := page.SavePage(title, body)
	// todo 3.1. 展示写入结果
	if err != nil {
		_, _ = responseWriter.Write([]byte("页面文件保存不成功"))
		fmt.Println("页面文件保存不成功,error is :", err)
		return
	} else {
		message := "页面文件保存成功"
		_, _ = responseWriter.Write([]byte(message))
		fmt.Println(message)
	}
}

增加mian方法,进行测试

func main() {
    // url路径要对应,当然你也可以更改;
    // 若修改viewPage,上面的viewHandler方法也要对应改变
	http.HandleFunc("/savePage/", saveHandler)
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		fmt.Println("端口异常")
	}
}
  • 运行程序,然后到浏览器访问:localhost:8989/viewPage/myFirst2

    • 结果会展示

      • 在这里插入图片描述

      • 页面也会展示成功的提示

    • 项目目录下会生成myFirst2.txt文件,内容为:

      this is a default value
      

2. 增加对页面文件进行查看内容的操作

// http 方式查看特定的page内容
// 使用硬编码页面
func viewHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/viewPage/"):]
	// todo 2. 判断是否已经存在该页面文件
	if !entity.ExistFile(title) {
		// todo 2.1. 不存在该页面文件就结束
		fmt.Printf("不存在%v页面文件", title)
		_, _ = responseWriter.Write([]byte("不存在该页面文件"))
		return
	}
	// todo 2.2. 获取该页面的内容
	page := entity.ViewPage(title)
	body := []byte(page.Body)
	// todo 3. 页面展示内容
	_, _ = responseWriter.Write(body)
}

增加mian方法,进行测试

func main() {
    // url路径要对应,当然你也可以更改;
    // 若修改viewPage,上面的viewHandler方法也要对应改变
    http.HandleFunc("/savePage/", saveHandler)
	http.HandleFunc("/viewPage/", viewHandler)
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		fmt.Println("端口异常")
	}
}
  • 运行程序,到浏览器输入 localhost:8989/viewPage/myFirst2

    • 会查看当前项目下是否存在myFirst2.txt文件,如果存在,则会返回页面文件内容。反之会展示不存在该页面文件内容

      • 我们前面生成了myFirst2.txt文件,效果为:

        • 在这里插入图片描述

        • 页面展示的内容为文件的内容

      • 我们访问没有对应的文件url:localhost:8989/viewPage/myFirst3

        • 效果为:

          在这里插入图片描述

        • 即页面展示不存在该文件。你也可以再利用savePage来生成一个myFirst3.txt文件

3. 增加对页面文件删除操作

// http方式删除页面文件
func deleteHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/deletePage/"):]
	// todo 2. 判断是否存在该页面文件
	if !entity.ExistFile(title) {
		_, _ = responseWriter.Write([]byte("页面文件不存在,无法删除"))
		return
	} else {
		// todo 3. 移除页面文件
		err := os.Remove(title + ".txt")
		if err != nil {
			_, _ = responseWriter.Write([]byte("页面文件删除异常,请检查你的权限,或者联系管理员"))
			return
		}
		_, _ = responseWriter.Write([]byte("页面文件删除成功"))
	}
}

增加mian方法,进行测试

func main() {
    // url路径要对应,当然你也可以更改;
    // 若修改viewPage,上面的viewHandler方法也要对应改变
    http.HandleFunc("/savePage/", saveHandler)
	http.HandleFunc("/viewPage/", viewHandler)
    http.HandleFunc("/deletePage/", deleteHandler)
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		fmt.Println("端口异常")
	}
}
  • 运行程序,到浏览器输入 localhost:8989/deletePage/myFirst2

    • 程序会删除myFirst2文件,效果为:

      在这里插入图片描述

      • 项目下的文件已经被删除,若此时再次执行则会提示无法删除

        在这里插入图片描述

4. 增加对页面文件内容更新的操作

// http方式更新页面文件
func updateHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/updatePage/"):]
	// todo 2. 查看该页面文件
	page := entity.ViewPage(title)
	// todo 3. 填充html页面,硬编码
	fmt.Fprintf(responseWriter, "<h1>Editing %s</h1>"+
		// 直接调用了 saveHandler
		// todo 4. 再次保存该页面文件
		"<form action=\"/savePage/%s\" method=\"POST\">"+
		"<textarea name=\"body\">%s</textarea><br>"+
		"<input type=\"submit\" value=\"Save\">"+
		"</form>",
		page.Title, page.Title, page.Body)
}
  • notice :todo的第四步,保存后会出发/savePage的访问动作

增加mian方法,进行测试

func main() {
    // url路径要对应,当然你也可以更改;
    // 若修改viewPage,上面的viewHandler方法也要对应改变
    http.HandleFunc("/savePage/", saveHandler)
    http.HandleFunc("/viewPage/", viewHandler)
    http.HandleFunc("/deletePage/", deleteHandler)
    http.HandleFunc("/updatePage/", updateHandler)
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		fmt.Println("端口异常")
	}
}
  • 运行程序,到浏览器输入 localhost:8989/updatePage/myFirst2

    • 页面会返回一个html页面,效果为:

      在这里插入图片描述

      • 尝试在文本框输入内容,这里输入hello,java页 可乐 唱跳rap,然后点击Save进行保存。

        • 然后页面会进行跳转到保存页面,效果图为:

          在这里插入图片描述

增删改查的操作保存在一个文件里,内容如下

package main

import (
	"fmt"
	"goland-setting/test/webapp/entity"
	"net/http"
	"os"
)

// http 方式查看特定的page
// 使用硬编码页面
func viewHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/viewPage/"):]
	// todo 2. 判断是否已经存在该页面文件
	if !entity.ExistFile(title) {
		// todo 2.1. 不存在该页面文件就结束
		fmt.Printf("不存在%v页面文件", title)
		_, _ = responseWriter.Write([]byte("不存在该页面文件"))
		return
	}
	// todo 2.2. 获取该页面的内容
	page := entity.ViewPage(title)
	body := []byte(page.Body)
	// todo 3. 页面展示内容
	_, _ = responseWriter.Write(body)
}

// http方式保存page
// 默认从请求体中获取body
// 直接调用/savePage的body默认值为:this is a default value
// 更新操作也会调用该方法,body值为 上传的请求体内容
func saveHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/savePage/"):]
	// todo 2. 填充 body内容
	page := &entity.Page{}
	// important 本人在后面update会遇到坑,默认从请求体中获取body
	// todo 2.1. 优先考虑从请求体获取body
	body := request.FormValue("body")
	// todo 2.2. 请求体为空串,则赋值默认值
	if body == "" {
		body = "this is a default value"
	}
	// todo 3. 将body值写入到页面文件
	err := page.SavePage(title, body)
	// todo 3.1. 展示写入结果
	if err != nil {
		_, _ = responseWriter.Write([]byte("页面文件保存不成功"))
		fmt.Println("页面文件保存不成功,error is :", err)
		return
	} else {
		message := "页面文件保存成功"
		_, _ = responseWriter.Write([]byte(message))
		fmt.Println(message)
	}
}

// http方式删除页面文件
func deleteHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/deletePage/"):]
	// todo 2. 判断是否存在该页面文件
	if !entity.ExistFile(title) {
		_, _ = responseWriter.Write([]byte("页面文件不存在,无法删除"))
		return
	} else {
		// todo 3. 移除页面文件
		err := os.Remove(title + ".txt")
		if err != nil {
			_, _ = responseWriter.Write([]byte("页面文件删除异常,请检查你的权限,或者联系管理员"))
			return
		}
		_, _ = responseWriter.Write([]byte("页面文件删除成功"))
	}
}

// http方式更新页面文件
func updateHandler(responseWriter http.ResponseWriter, request *http.Request) {
	// todo 1. 在url中获取 page的title值
	title := request.URL.Path[len("/updatePage/"):]
	// todo 2. 查看该页面文件
	page := entity.ViewPage(title)
	// todo 3. 填充html页面
	fmt.Fprintf(responseWriter, "<h1>Editing %s</h1>"+
		// 直接调用了 saveHandler
		// todo 4. 再次保存该页面文件
		"<form action=\"/savePage/%s\" method=\"POST\">"+
		"<textarea name=\"body\">%s</textarea><br>"+
		"<input type=\"submit\" value=\"Save\">"+
		"</form>",
		page.Title, page.Title, page.Body)
}

func main() {
	http.HandleFunc("/savePage/", saveHandler)
	http.HandleFunc("/deletePage/", deleteHandler)
	http.HandleFunc("/updatePage/", updateHandler)
	http.HandleFunc("/viewPage/", viewHandler)
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		fmt.Println("端口异常")
	}
}

一个简单的webApp就完成了。

other

  • 对于更新操作,服务器硬编码html太难了,可以使用html/template来渲染,这样会好很多。

文章来源:https://blog.csdn.net/liguanhaoyonghu/article/details/134885211
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。