实战 图书馆系统管理案例

这篇具有很好参考价值的文章主要介绍了实战 图书馆系统管理案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

实战 图书馆系统管理案例,golang

  • config :敏感的配置一般都是在配置中心配置,比如consul或者阿波罗上面
  • controller :写一些handler的,拿到参数要去调用service层的逻辑。(只负责接受参数,怎么绑定参数,要去调用哪个service的,handler的一个入口
  • service:service层才是正真的业务处理层。调用dao层的增删改查操作
  • dao:只关心数据库的一个操作,其实你有数据库和es都在dao层
  • db:负责数据库,中间件层的初始化
  • middleware:存放gin的中间件,在注册路由的时候将中间件引入进来

go常用项目结构 


实战 图书馆系统管理案例,golang

dao层只关心数据库的操作,db层只做Mysql层的初始化。model去定义表结构,定义中间表,多对多的结构体。 

中间件有个token的验证。

controller层,先去找路由,这个项目有多少的接口(router.go),每个接口到哪些对应的handler。

controller层接收完参数之后,再看调用到哪个service,service再去干了什么增删改查操作。

数据库增删改查就去dao层查看。

这一层一层非常的分明。上面可以理解为日常开发的目录结构最佳实践。

创建数据库


mysql> create database books charset utf8;

图书管理服务 


用户服务:登录,注册
书籍服务:对书籍的增删改查的操作
主要有两个维度,一个是书籍维度,一个是用户维度。用户维度要去写两个功能,一个功能是登入,一个功能是注册。
注册就是数据库插入一条数据。登入就是一个校验。配合token中间件去做一个校验。
在新增书籍的时候要去关联用户,这本书属于谁?书籍的增删改查都需要关联这个用户。这里就涉及到1对多的关系。
开发的时候是从最底层开始,往上开发。第一个先去定义数据库的model层。

  

model层 定义数据库结构


binding标签表示是必填项,token是可以为空的,因为一开始注册的时候token的为空。只有登入的时候才有token。

user.go

package model

type User struct {
	ID       int64  `gorm:"primaryKey" json:"id"`
	UserName string `gorm:"not null" json:"username" binding:"required"`
	PassWord string `gorm:"not null" json:"password" binding:"required"`
	Token    string `json:"token"`
}

func (*User) TableName() string {
	return "user"
}

book.go

package model

type Book struct {
	ID    int64  `gorm:"primaryKey" json:"id"`
	Name  string `gorm:"not null" json:"name" binding:"required"`
	Desc  string `json:"desc"`
	Users []User `gorm:"many2many:book_users"`
}

func (*Book) TableName() string {
	return "book"
}

多对多关系可以在user这层定义也行,在book这一层定义也可以。这个主要看你的一个实际使用的场景,这里在book模型里面去定义就行了。

还需要去定义一个中间表的模型user_m2m_book.go

package model

type BookUser struct {
	UserID int64 `gorm:"primaryKey"`
	BookID int64 `gorm:"primaryKey"`
}

这里不需要自定义表名,它只有一个主键,也没有其他属性了。它也是永了外键,也是使用了那两个模型的主键。

实战 图书馆系统管理案例,golang

DB层


模型定义好之后去做数据库的初始化,这里需要预留,因为可能不仅仅只有MySQL的初始化。

实战 图书馆系统管理案例,golang

这样赋值到一个全局变量,之后使用mysql.DB就可以在任何地方去使用了。 

package mysql

import (
	"book/model"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// DB 要将DB实例放到全局变量,这样就可以使用mysql.DB在任何地方去使用了.
var DB *gorm.DB

func InitMysql() {
	dsn := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/books?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

	//这个地方Log和panic都是可以的
	if err != nil {
		fmt.Println(err)
	}

	DB = db
	
	err = DB.AutoMigrate(model.Book{}, model.User{}, model.BookUser{})
	if err != nil {
		fmt.Println(err)
	}
}

DAO层


初始化好之后在dao层开始写,dao层的操作就是数据库的增删改查

package dao

import (
	"book/db/mysql"
	"book/model"
	"errors"
	"fmt"
	"github.com/wonderivan/logger"
	"gorm.io/gorm"
)

//定义user结构体,以及User变量,能够直接跨包调用user下面的方法
//只需要一次初始化即可,不用每次调用的都是先初始化

var User user

type user struct {
}

// Add 新增 用于注册
func (*user) Add(user *model.User) error {
	if tx := mysql.DB.Create(user); tx.Error != nil {
		//打印错误提示
		logger.Error(fmt.Sprintf("添加User失败,错误信息:%s", tx.Error))
		return errors.New(fmt.Sprintf("添加User失败,错误信息:%s", tx.Error))
	}
	return nil
}

// Has 查询 基于name 用于新增
func (*user) Has(name string) (*model.User, bool, error) {
	//初始化要申请内存,不然会报错
	data := &model.User{}
	tx := mysql.DB.Where("username = ?", name).Find(data)

	//如果记录没有查询到,报错是从tx.error里面拿到的,相当于tx.Error = gorm.ErrRecordNotFound
	if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
		return nil, false, nil
	}
	//等会去调用的时候,不会先去判断有没有,要先去判断error,有error就是真正的错误,没有判断是不是false
	if tx.Error != nil {
		logger.Error(fmt.Sprintf("查询用户失败,错误信息:%s", tx.Error))
		return nil, false, errors.New(fmt.Sprintf("查询用户失败,错误信息:%s", tx.Error))
	}

	return data, true, nil
}

// GetByToken 基于token查询,用于中间件token校验
func (*user) GetByToken(token string) (*model.User, bool, error) {
	//初始化要申请内存,不然会报错
	data := &model.User{}
	tx := mysql.DB.Where("token = ?", token).Find(data)

	//如果记录没有查询到,报错是从tx.error里面拿到的,相当于tx.Error = gorm.ErrRecordNotFound
	if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
		return nil, false, nil
	}
	if tx.Error != nil {
		logger.Error(fmt.Sprintf("查询用户失败%s", tx.Error))
		return nil, false, errors.New(fmt.Sprintf("查询用户失败%v/n", tx.Error))
	}
	return data, true, nil
}

// UPDateToken 更新token,这里其实就是找到user的条件去更新就行了
// 第一个参数可以是id也可以是用户名,如果用户名唯一,只要保证找到指定用户即可
// 除了查询的操作以外,增删改只需要返回一个error即可,判断操作有没有成功
func (*user) UPDateToken(user *model.User, token string) error {
	tx := mysql.DB.Model(user).
		Where("username= ? and password = ?", user.UserName, user.PassWord).
		Update("token", token)
	if tx.Error != nil {
		logger.Error(fmt.Sprintf("更新user token失败,错误信息:%s", tx.Error))
		return errors.New(fmt.Sprintf("更新user token失败,错误信息:%s", tx.Error))
	}
	return nil
}

service层


和dao层一样,都定义了相同的结构体,不同的包使用相同的结构体变量,但是点出来的方法都是不同的。

package service

import (
	"book/dao"
	"book/model"
	"errors"
	"github.com/google/uuid"
)

var User user

type user struct {
}

// Add 这里的返回error是因为在进行数据库操作的时候也会返回error
// 这里的error返回到最上层,controller层
func (*user) Add(user *model.User) error {
	//先去校验是否存在
	_, has, err := dao.User.Has(user.UserName)
	if err != nil {
		return err
	}

	if has {
		return errors.New("该用户已经存在,请不要重复添加")
	}

	//校验完毕,添加用户
	if err = dao.User.Add(user); err != nil {
		return err
	}

	return nil
}

// Login  登入其实就是去更新token
func (*user) Login(name, password string) error {
	//先去校验是否存在,如果不存着就不能登入
	data, has, err := dao.User.Has(name)
	if err != nil {
		return err
	}

	if !has {
		return errors.New("该用户不存在")
	}

	if data.PassWord != password {
		return errors.New("用户名或密码错误")
	}

	return nil
}

func (*user) UpDateToken(user *model.User) error {
	token := uuid.New().String()
	//这个是字符串类型的uuid
	//因为这个dao里面方法也是返回error的,所以可以保持一致的
	return dao.User.UPDateToken(user, token)
}

controller层


 service层写好了之后那么就是controller层。主要就是gin的handler的逻辑。 

controller层负责handler的逻辑,同时调用service层,如果调用service层失败或者成功那么将错误信息或者自定义成功信息返回给客户端。

上面的注册逻辑就由各个层组装好了,controller去调用service层,service去调用dao层。

controller主要就是handler,handler第一步是通过shouldbind去获取结构体,之后根据逻辑是否正确返回客户端json字符串。

package controller

import (
	"book/model"
	"book/service"
	"github.com/gin-gonic/gin"
	"net/http"
)

type User user

type user struct {
}

func (*user) Register(c *gin.Context) {
	u := &model.User{}
	//专门用于标签为json的参数接受,也就是POST PUT DELETE这种带body的
	if err := c.ShouldBindJSON(u); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "90400",
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	//创建用户
	if err := service.User.Add(u); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "90500",
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	c.JSON(http.StatusBadRequest, gin.H{
		"code": "90400",
		"msg":  "创建注册成功",
		"data": nil,
	})
}

func (*User) Login(c *gin.Context) {
	u := &model.User{}
	if err := c.ShouldBindJSON(u); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "90400",
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	//校验账号密码,这里传入结构体或者用户名密码都行,看个人习惯
	//如果不return就会继续往下执行,逻辑就会错误
	if err := service.User.Login(u.UserName, u.PassWord); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "90500",
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	if err := service.User.UpDateToken(u); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "90500",
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	c.JSON(http.StatusBadRequest, gin.H{
		"code": "90400",
		"msg":  "用户登入成功",
		"data": nil,
	})
}

 router层


功能写好之后就是去注册路由,文章来源地址https://www.toymoban.com/news/detail-679839.html

到了这里,关于实战 图书馆系统管理案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于JavaWeb的图书馆管理系统

    🍅 作者主页:

    2024年02月05日
    浏览(34)
  • C++图书馆管理系统(简单版)

    实用的图书馆管理系统应该至少包括一下功能: 1、上传:新进图书以及基本信息的输入 2、删除:旧图书以及基本信息的删除 3、显示:显示图书馆已有的所有图书 4、查找:查询要借阅的图书信息 5、借阅:实现用户办理借阅手续 6、归还:实现用户办理归还手续 系统以菜单

    2024年02月09日
    浏览(37)
  • 用C++实现一个图书馆管理系统

    下图为普通读者的功能 下图为图书馆管理员所拥有的功能 图中所示功能均已实现,不再一一展示,文末有项目源码 1 、 用户进入系统 用户进入系统的前提是必须先登录或者注册 2、 不同身份有不同功能的使用权 普通读者权限较小,图书管理者拥有较高权限,还设有高级管

    2023年04月13日
    浏览(32)
  • c语言课程设计(图书馆管理系统)

    大一c语言课程设计:图书馆管理系统。 图书管理系统,功能齐全拿来就能用 1.主界面   代码段  2.图书录入界面 运用文件录入多次使用   代码段  3.图书查询界面 根据输入书的数据与文件中数据进行比对 ,查找后输出。 代码段 4.图书修改 输入修改图书数据并在文件中查找

    2024年02月11日
    浏览(28)
  • 基于Python的图书馆管理系统的开发

    开发工具: python3.10 数据库: Python内置的SQLite3数据库,SQLite是一种嵌入式数据库,体积很小,它的数据库就是一个文件。本文 建立了Library数据库,存储系统内的管理员、图书、读者、借阅相关信息。         传统人工方式管理文件档案存在着许多缺点,如:效率低、保

    2024年02月04日
    浏览(43)
  • Java语言------图书馆管理系统(入门简略版)

    目录 一.图书管理系统分析 1.1系统设计要求  1.2设计思路 二.操作代码的实现  2.1书架书籍代码实现 2.2用户操作代码实现 2.2.1增加书籍 2.2.2移除书籍 2.2.3查询书籍 2.2.4展示书架书籍信息 2.2.5借阅书籍代码 2.2.6归还图书代码 2.2.7退出系统 3.用户登录操作  四.主函数的调用 总结

    2023年04月13日
    浏览(37)
  • 基于JAVA图书馆管理系统设计与实现

    【后台管理员功能】 广告管理:设置小程序首页轮播图广告和链接 留言列表:所有用户留言信息列表,支持删除 会员列表:查看所有注册会员信息,支持删除 资讯分类:录入、修改、查看、删除资讯分类 录入资讯:录入资讯标题、内容等信息 管理资讯:查看已录入资讯列

    2024年02月13日
    浏览(39)
  • asp.net937-图书馆座位管理系统

    项目编号:asp.net937-图书馆座位管理系统 运行环境:VS+SQL 开发工具:VS2010及以上版本 数据库:SQL2008及以上版本 使用技术:HTML+JS+HTML 开发语言:C#,框架:asp.net 图书馆座位预约管理系统是用于校园、图书馆、阅览室、会场等公共座位资源进行分配、预约、查询显示、智能管理与

    2023年04月15日
    浏览(28)
  • 学校图书馆管理系统的架构设计与实现

    随着大学生越来越多,学校图书馆的管理变得愈发复杂。为了更好地管理和服务于学生和教职工,学校需要建立一个高效的图书馆管理系统。本文将介绍学校图书馆管理系统的架构设计与实现。 1. 架构设计 学校图书馆管理系统的架构设计主要分为三个部分: 展示层:展示层

    2024年02月22日
    浏览(39)
  • 微信小程序图书馆座位预约管理系统

    开发工具:IDEA、微信小程序 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 前端技术:vue、uniapp 服务端技术:springboot+mybatis 本系统分微信小程序和管理后台两部分,项目采用前后端分离 项目功能描述: 1.微信小程序:登录、注册、主页、公告、轮播图、图书馆预约

    2023年04月18日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包