基于golang构建简易图书管理平台(前端+后端)

后端代码:

package main

import (
	"html/template"
	"net/http"
	"strconv"
)

type Book struct {
	Title       string   // 标题
	Price       float64  // 价格
	Publisher   string   // 出版商
	PublishDate string   // 发布日期
	Authors     []string // 作者
}

// Books 定义切片将值存入切片
var Books []*Book

var Temps = make(map[string]*template.Template, 8)

func init() {
	// 自定义一个add函数用于前端页面index+1使序号从1开始
	myAdd := func(a, b int) int {
		return a + b
	}
	// isIn函数用于前端页面判断作者是否存在,如果存在那么在编辑页面作者一栏会显示作者名字
	isIn := func(a string, list []string) bool {
		for _, s := range list {
			if s == a {
				return true
			}
		}
		return false
	}
	Temps["home"] = template.Must(template.ParseFiles("./static/htmls/home.html"))
	Temps["login"] = template.Must(template.ParseFiles("./static/htmls/home.html", "./static/htmls/login.html"))
	Temps["list"] = template.Must(template.New("book_list.html").Funcs(template.FuncMap{"add": myAdd}).ParseFiles("./static/htmls/home.html", "./static/htmls/book_list.html"))
	Temps["add"] = template.Must(template.ParseFiles("./static/htmls/home.html", "./static/htmls/book_add.html"))
	Temps["edit"] = template.Must(template.New("book_edit.html").Funcs(template.FuncMap{"isIn": isIn}).ParseFiles("./static/htmls/home.html", "./static/htmls/book_edit.html"))

}

// 全局校验
func loginAuth(fn func(w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		cookie, _ := r.Cookie("admin")
		if cookie == nil || cookie.Value != "adminValue" {
			http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
		}
		fn(w, r)
	}
}

// Authors Publishers 直接给定值
var Authors = []string{"张三", "李四"}
var Publishers = []string{"人民出版社", "北京出版社"}

func main() {
	// 定义路由
	http.HandleFunc("/", home)
	http.HandleFunc("/login", login)
	http.HandleFunc("/book_list", list)
	http.HandleFunc("/book_add", loginAuth(add))
	http.HandleFunc("/book_edit/", loginAuth(edit))
	http.HandleFunc("/book_delete/", loginAuth(delete))
	// 将文件暴露出来否则找不到字体
	//http.Handle("/static/", http.FileServer(http.Dir(".")))
	http.ListenAndServe("localhost:8080", nil)
}

func login(w http.ResponseWriter, r *http.Request) {
	tmp := Temps["login"]
	switch r.Method {
	case "GET":

		tmp.Execute(w, nil)
	case "POST":
		// 登录 校验逻辑
		name := r.PostFormValue("username")
		pwd := r.PostFormValue("password")
		if name == "admin" && pwd == "admin" {
			cookie := &http.Cookie{Name: "admin", Value: "adminValue"}
			http.SetCookie(w, cookie)
			http.Redirect(w, r, "/book_list", 302)
		} else {

			tmp.Execute(w, "用户名或密码错误")
		}

	}

}

// 前端首页的后端逻辑
func home(w http.ResponseWriter, r *http.Request) {
	// ParseFiles方法: 创建一个新模板,并从中解析模板定义
	tmp := Temps["home"]
	tmp.Execute(w, nil)
}

// 前端图书列表的后端逻辑
func list(w http.ResponseWriter, r *http.Request) {
	// Books = append(Books, &Book{"人生", 19.8, "北京出版社", "2023-2-5", []string{"张三"}})
	// tmp, _ := template.ParseFiles("home.html", "book_list.html")
	tmp, _ := Temps["list"]
	tmp.Execute(w, Books)
}

// 前端增加图书的后端逻辑
func add(w http.ResponseWriter, r *http.Request) {
	// 校验cookie
	//cookie, _ := r.Cookie("admin")
	//if cookie == nil || cookie.Value != "adminValue" {
	//	// http.NotFound(w, r)
	//	http.Redirect(w, r, "login", http.StatusTemporaryRedirect)
	//	return
	//}
	switch r.Method {
	case "GET":
		tmp := Temps["add"]
		info := map[string][]string{"authors": Authors, "publishers": Publishers}
		tmp.Execute(w, info)
	case "POST":
		// 保存数据,增加一个Book放在Books
		// ParseFloat方法: 将字符串转换为浮点数
		// FormValue方法: 返回查询的命名组件的第一个值
		price, _ := strconv.ParseFloat(r.FormValue("price"), 64)
		book := &Book{
			Title:       r.FormValue("title"),
			Price:       price,
			Publisher:   r.FormValue("publisher"),
			PublishDate: r.FormValue("publish_date"),
			Authors:     r.PostForm["authors"],
		}
		Books = append(Books, book)
		// 跳转
		http.Redirect(w, r, "/book_list", 302)
	}

}

// 前端编辑页面的后端逻辑
func edit(w http.ResponseWriter, r *http.Request) {
	// 将图书的索引index(id)通过切片的方式切出来
	// 因为完整的URL为/book_edit/x(x表示id),所以将/book_edit/切掉就得到了id
	idStr := r.URL.Path[len("/book_edit/"):]
	// 将id从字符串类型转换成int类型
	id, _ := strconv.Atoi(idStr)
	// 如果id大于书籍数量就返回错误终止掉程序
	if id >= len(Books) {
		http.NotFound(w, r)
		return
	}
	// Method方法: 用于指定HTTP方法(GET,POST,PUT等)
	switch r.Method {
	case "GET":
		// tmp, _ := template.ParseFiles("home.html", "book_edit.html")
		// New方法: 使用给定的名称分配一个新的HTML模板
		// Func方法: 将参数映射的元素添加到模板的函数映射中
		// FuncMap方法: 是定义从名称到函数的映射的映射类型
		// ParseFiles解析命名文件并生成模板
		tmp := Temps["edit"]
		// interface方法: 指定接收的类型为所有的类型
		info := map[string]interface{}{"authors": Authors, "publishers": Publishers, "book": Books[id], "id": id}
		// Execute方法: 将解析的模板应用于指定的数据对象
		tmp.Execute(w, info)
	case "POST":
		// 编辑索引为id的book
		book := Books[id]
		// 将前端页面返回的字符串转换为浮点数
		price, _ := strconv.ParseFloat(r.FormValue("price"), 64)
		// 更新数据
		book.Price = price
		book.Title = r.FormValue("title")
		book.PublishDate = r.FormValue("publish_date")
		book.Publisher = r.FormValue("publisher")
		book.Authors = r.PostForm["authors"]
		http.Redirect(w, r, "/book_list", 307)
	}

}

func delete(w http.ResponseWriter, r *http.Request) {
	// 将图书的索引index(id)通过切片的方式切出来
	// 因为完整的URL为/book_edit/x(x表示id),所以将/book_edit/切掉就得到了id
	idStr := r.URL.Path[len("/book_delete/"):]
	// 将id从字符串类型转换成int类型
	id, _ := strconv.Atoi(idStr)
	// 如果id大于书籍数量就返回错误终止掉程序
	if id >= len(Books) {
		http.NotFound(w, r)
		return
	}
	// 将索引为id的元素从Books中删除
	// 下述代码的解释为:首先将0-id的值切出来然后将id+1及以后的值切出来然后将二者结合达到删除id的效果
	Books = append(Books[:id], Books[id+1:]...)
	http.Redirect(w, r, "/book_list", 307)
}

前端代码:首页

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>BMS</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<!--    <link rel="stylesheet" href="../font-awesome-4.7.0/css/font-awesome.min.css">-->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</head>
<body>
<div class="container-fluid">
    <div class="row" style="margin-top: 70px;">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">Book Manage System</h3>
                </div>
                <div class="panel-body">
                    {{block "content" .}}
                    <div class="jumbotron">
                        <h1>欢迎来到电子信息图书平台</h1>
                        <p>你想要的书籍全都有</p>
                        <p><a class="btn btn-primary btn-lg" role="button" href="/book_list">点击阅读吧~</a></p>
                    </div>
                    {{end}}
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

图书列表界面:

{{template "home.html" .}}


{{define "content"}}
<a href="/book_add" class="btn btn-success">添加</a>
<br>
<br>
<table class="table table-hover table-striped">
    <thead>
    <tr>
        <th>ID</th>
        <th>书名</th>
        <th>价格</th>
        <th>出版社</th>
        <th>出版日期</th>
        <th>作者</th>
        <th>操作</th>
    </tr>
    </thead>
    <tboby>
        {{range $index, $book := .}}
        <tr>
            <td>{{add $index 1}}</td>
            <td>{{$book.Title}}</td>
            <td>{{$book.Price}}</td>
            <td>{{$book.Publisher}}</td>
            <td>{{$book.PublishDate}}</td>
            <td>
                {{range $author := $book.Authors}}
                {{$author}},
                {{end}}

            </td>
            <td>
                <a href="/book_edit/{{$index}}" class="btn btn-primary btn-xs">编辑</a>
                <button class="btn btn-danger btn-xs" onclick="del({{$index}})">删除</button>
            </td>
        </tr>
        {{end}}
    </tboby>
</table>

<script>
    function del(id) {
        swal({
            title: "温馨提示",
            text: "您确认要删除该图书吗?",
            icon: "warning",
            buttons: true,
            dangerMode: true,
        })
            .then((willDelete) => {
                if (willDelete) {
                    swal("删除成功!", {
                        icon: "success",
                    });
                    window.location.href = "/book_delete/" + id
                } else {
                    swal("取消成功!");
                }
            });
    }

</script>


{{end}}

增加图书界面:

{{template "home.html" .}}


{{define "content"}}
<h1 class="text-center">书籍添加</h1>
<form action="/book_add" method="post">
    <p>
        书名
        <input type="text" name="title" class="form-control">
    </p>
    <p>
        价格
        <input type="text" name="price" class="form-control">
    </p>
    <p>
        出版日期
        <input type="date" name="publish_data" class="form-control">
    </p>
    <p>
        出版社
        <select name="publisher" id="" class="form-control">
            {{range $p := .publishers}}
            <option value="{{$p}}">{{$p}}</option>
            {{end}}
        </select>
    </p>
    <p>
        作者
        <select name="authors" id="" multiple class="form-control">
            {{range $a := .authors}}
            <option value="{{$a}}">{{$a}}</option>
            {{end}}
        </select>
    </p>
    <input type="submit" value="新增" class="btn btn-primary btn-block">
</form>
{{end}}

编辑图书界面:

{{template "home.html" .}}


{{define "content"}}
<h1 class="text-center">编辑书籍</h1>
<form action="/book_edit/{{.id}}" method="post">
    <p>
        书名
        <input type="text" name="title" class="form-control" value="{{.book.Title}}">
    </p>
    <p>
        价格
        <input type="text" name="price" class="form-control" value="{{.book.Price}}">
    </p>
    <p>
        出版日期
        <input type="date" name="publish_date" class="form-control" value="{{.book.PublishDate}}">
    </p>
    <p>
        出版社
        {{$publisher := .book.Publisher}}
        <select name="publisher" id="" class="form-control">
            {{range $p := .publishers}}
            {{if eq $p $publisher}}
            <option value="{{$p}}" selected>{{$p}}</option>
            {{else}}
            <option value="{{$p}}">{{$p}}</option>
            {{end}}
            {{end}}
        </select>
    </p>
    <p>
        作者
        {{$authors := .book.Authors}}
        <select name="authors" id="" multiple class="form-control">
            {{range $a := .authors}}
            {{if isIn $a $authors}}
            <option value="{{$a}}" selected>{{$a}}</option>
            {{else}}
            <option value="{{$a}}">{{$a}}</option>
            {{end}}
            {{end}}
        </select>
    </p>
    <input type="submit" value="编辑" class="btn btn-primary btn-block">
</form>
{{end}}

登录界面:

{{template "home.html" .}}


{{define "content"}}

<h1 class="test-center">登录</h1>
<form action="/login" method="post">
    <p>
        用户名:
        <input type="text" name="username" class="form-control">
    </p>
    <p>
        密码:
        <input type="password" name="password" class="form-control">
    </p>
    <input type="submit" value="登录" class="btn btn-primary btn-block">
    <p style="color: crimson">{{ . }}</p>
</form>



{{end}}

代码运行以后,浏览器访问localhost:8080即可,默认管理员账户密码均为:admin

 

 

 

 

 

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值