Beego开发博客

Beego开发博客

一、bee工具的使用

1、安装bee工具

go get -u github.com/beego/bee/v2
//安装完成后直接在终端输入bee获取环境

安装完之后,bee 可执行文件默认存放在 $GOPATH/bin 里面,所以您需要把 $GOPATH/bin 添加到您的环境变量中,才可以进行下一步。

2、new命令

new 命令是新建一个 Web 项目,我们在命令行下执行 bee new <项目名> 就可以创建一个新的项目。但是注意该命令必须在 $GOPATH/src 下执行。最后会在 $GOPATH/src 相应目录下生成如下目录结构的项目:

>bee new Blog

注:生成api项目的时候使用bee api Blog

3、bee run命令

bee run 命令是监控 beego 的项目,通过 fsnotify监控文件系统。但是注意该命令必须在 $GOPATH/src/appname 下执行。

二、下载前端模板

1、使用bootstrap书写;

2、layui下载;

3、使用模板技术对模板进行修改

举例:引入css,将引入的css代码放在link.html中实现代码公用

{{ template "common/link.html" }}

三、定义路由

本博客使用自动路由

web.AutoRouter(&controllers.ObjectController{})

四、导航条的光标移动

1、执行逻辑之Prepare设置

package controllers

import beego "github.com/beego/beego/v2/server/web"

type BaseController struct{
	beego.Controller
}

func (c *BaseController) Prepare(){
	c.Data["path"]=c.Ctx.Request.RequestURI   //获取网页的路径
}
//然后在模板中获取值
{{ .path }}

2、模板自定义函数

beego 支持用户定义模板函数,但是必须在 web.Run() 调用之前

func initTemplate(){
	beego.AddFuncMap("equrl",func(x string,y string)bool{
         return strings.Compare(x,y)==0   //判断是不是相同
	})
}

func main() {
	initTemplate()   //在Run前面调用模板函数
	beego.Run()
}

直接在模板中调用equrl函数

<ul class="layui-nav pull-left">
<li class="layui-nav-item {{if equrl .path `/Auth/Index`}}layui-this{{ end }} "><a href="/Auth/Index">首页</a></li>
<li class="layui-nav-item {{if equrl .path `/Auth/Message`}}layui-this{{ end }} "><a href="/Auth/Message">留言</a></li>
<li class="layui-nav-item {{if equrl .path `/Auth/About`}}layui-this{{ end }} "><a href="/Auth/About">关于</a></li>
</ul>

五、数据库的初始化

package models

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

var (
	db *gorm.DB
)

func init(){   //初始化数据库连接,创建表结构
	//使用dsn连接到数据库,grom自带的数据库池
	//账号:密码@连接方式(ip地址:端口号)/数据库?语言方式,时区(未设置时区的话采用8小时制度)
	var err error
	dsn := "root:root@tcp(127.0.0.1:3306)/testgorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) //使用mysq连接数据库,第二个参数可以增加更多的配置(可有可无)
	if err != nil {
		fmt.Println(err)
	}
	db.AutoMigrate(&User{}) //创建User表
	//判断如果数据库没有值,则增加管理员
    if res:=db.Find(&User{});res.RowsAffected==0&&res.Error==nil{
    	db.Create(&User{
			Name:"admin",
			Email:"1102394156@qq.com",
			Pwd:"123123",
			Head:"/static/images/item.png",
		})
	}
}

六、Controller错误处理

1、web 框架默认支持 401、403、404、500、503 这几种错误的处理。用户可以自定义相应的错误处理

2、当直接使用Abort出现系统错误界面,使用路由导航后,可以自定义路由错误界面

   //router函数
beego.ErrorController(&controllers.ErrorController{})   //定义错误路由
//errorController
package controllers

type ErrorController struct{
BaseController   //组合预处理的
}

func (e *ErrorController) Error404(){
 	 e.TplName="404.html"
}

3、自定义接口判断错误

原因:因为可能出现不是go语言自带的error错误类型,比如登录错误,所以需要自定义错误类型

设计思路:一般返回json格式(message与code和系统error),最后判断是不是系统出错来输出

(1)定义错误的接口,通过实现这个接口来返回错误,使其标准化

package syserror

type Error interface{
	Code() int
	Error() string
	Syserr() error
}

func New(msg string,err error)Error{    //获取参数返回错误接口
       return SetErr{msg, err}
}

(2)定义错误结构体实现接口,比如505错误,实现接口之后可以调用方法

package syserror

type SetErr struct{
	msg string
	err error
}

func (this SetErr) Code() int{
    return 1000
}
func (this SetErr)Error() string{
	if len(this.msg)==0{
		return "未知错误"
	}
    return this.msg
}
func (this SetErr) Syserr() error{
 	return this.err
}

(3)判断Abort的错误类型,如果是error记录日志,如果是自定义错误,返回json字符串

func (e *ErrorController) Error500(){
	e.TplName="500.html"
	err,ok:=e.Data["error"].(error)    //类型断言,判断是否是系统的error错误,不是系统错误就需要自定义
	if !ok{
        err=syserror.New("未知错误",nil)   //因为接口Error接口实现了接口error的Error方法
	}
	serr,ok:=err.(syserror.Error)    //判断是不是自定义错误,不是就返回系统错误
	if !ok{
		serr=syserror.New(err.Error(),nil)
	}
	if serr.Syserr()!=nil{   //返回的系统错误不为空,则直接记录日志
         log.Info(serr.Syserr(),serr.Error())
	}
	if e.IsAjax() { //???
         e.jsonErr(serr)
	}else{
         e.Data["content"]=serr.Error()   //返回自定义错误
	}
}
func (e *ErrorController) jsonErr(serr syserror.Error){   //传入接口封装
	e.Ctx.Output.SetStatus(200) //设置状态码为200
	e.Data["json"] = map[string]interface{}{
		"code": serr.Code(),
		"msg":  serr.Error(),   //返回自定义错误
	}
	e.ServeJSON()
}

七、配置session

1、直接定义函数设置session

func initSession(){
	beego.BConfig.WebConfig.Session.SessionOn = true //设置是否开启 Session,默认是 false,配置文件对应的参数名:sessionon。
	beego.BConfig.WebConfig.Session.SessionName="Blog"   //设置 cookies 的名字,Session 默认是保存在用户的浏览器 cookies 里面的,默认名是 beegosessionID,配置文件对应的参数名是:sessionname。
	beego.BConfig.WebConfig.Session.SessionProvider="file"   //设置 Session 的引擎,默认是 memory,目前支持还有 file、mysql、redis 等,配置文件对应的参数名:sessionprovider。
	beego.BConfig.WebConfig.Session.SessionProviderConfig="data/session" //设置对应 file、mysql、redis 引擎的保存路径或者链接地址,默认值是空,配置文件对应的参数:sessionproviderconfig。
}
func main() {
	initSession()
	initTemplate()   //在Run前面调用模板函数
	beego.Run()
}

2、配置文件修改

在conf中新建session.conf文件,设置配置文件

SessionOn=true                          #是否开启Session
SessionName="Blog"                      #设置Session的名字
SessionProvider="file"                  #设置储存在文件中
SessionProviderConfig="data/session"    #设置储存目录
//设置完成后,在app.conf中调用
include "session.conf"     #调用配置文件

八、用户登录功能

1、数据库交互查询用户是否存在

(1) 通过前端获取参数;

//单个参数
GetString(key string) string
GetStrings(key string) []string
GetInt(key string) (int64, error)
GetBool(key string) (bool, error)
GetFloat(key string) (float64, error)
//表单解析到结构体
定义 structtype user struct {
    Id    int         `form:"-"`
    Name  interface{} `form:"username"`
    Age   int         `form:"age"`
    Email string
}
表单:
名字:<input name="username" type="text" />
年龄:<input name="age" type="text" />
邮箱:<input name="Email" type="text" />
<input type="submit" value="提交" />
Controller 里解析:
func (this *MainController) Post() {
    u := user{}
    if err := this.ParseForm(&u); err != nil {
        //handle error
    }
}

(3) 用户鉴权

//判断用户账号密码不为空
    u.JugeNull(user.UserName,"账号不能为空")
    u.JugeNull(user.PassWord,"密码不能为空")
//查询数据库中的是否有匹配的值
//首先判断是什么请求,如果是get直接跳转登录页面,post请求在获取值
if u.Ctx.Input.IsPost()
//获取到值,在定义的对象结构中封装函数查询自己
func QueryUser(name string,pwd string)(int64,error,User){
	var user User
	res:=db.Where("name=? and pwd=?",name,pwd).Take(&User{}).Scan(&user)   //查询值并且扫描
	return res.RowsAffected,res.Error,user
}
//判断
		num,err,val:=models.QueryUser(user.UserName,user.PassWord)
		if err!=nil||num==0{
			fmt.Println(err)
			u.Abort500(errors.New("账号或者密码错误"))
		}
		_ = u.SetSession(SESSION_USER_KEY, val)                           //将获得的user保存到session中
		u.Redirect(beego.URLFor("AuthController.Index"), http.StatusFound) //重定向到首页
//记得登录成功后设置session
_ = u.SetSession(SESSION_USER_KEY, val)         //将获得的user保存到session中

2、用户名称的实现

//beego的预定义Prepare函数中封装session
func (c *BaseController) Prepare(){
	c.Data["path"]=c.Ctx.Request.RequestURI   //获取网页的路径
	u,ok:=c.GetSession(SESSION_USER_KEY).(models.User)   //判断获取的session是不是User类型
	c.IsLogin=false   //设置值
	if ok{
		c.User=u
		c.IsLogin=true
		c.Data["User"]=c.User
	}
	c.Data["IsLogin"]=c.IsLogin
}
//使用模板技术获取值然后渲染页面
 <i class="layui-icon layui-icon-username">
      <span>{{ if .IsLogin }}{{ .User.Name }}{{ end }}</span>
 </i>

3、登录重定向或者Abort报错

4、登出功能

func (c *UserController) LoginOut(){
	_ = c.DelSession(SESSION_USER_KEY) //删除session
	c.Redirect(beego.URLFor("UserController.Login"),302)
}

九、用户注册功能

(1)表单提交获取;

(2)鉴权;

//注册信息不能为空
//查询判断是否有重复账号
//

十、文章录入功能

1、写入页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>写文章</title>
    {{ assets_css "/static/bootstrap-4.5.0/css/bootstrap.min.css" }}
</head>
<body>
<div class="container">
    <div class="form-group row offset-4 col-4 mt-4">
           <h2>文章发表</h2>
    </div>
  <div class="form-group row">
      <label class="col-form-label col-2">文章标题:</label>
      <input class="form-control col-8" name="title" placeholder="请输入文章标题" value="" />

</div>
    <div class="form-group row">
        <div class="form-group">
            <input type="submit" class="btn btn-primary" value="上传文章"/>
        </div>
    </div>
</div>
</body>
</html>

2、管理员才允许更新文章

//在baseController中定义接口,实现这个接口的方法
type NestPrepare interface {
	NestPrepare()
}
//在Prepare里面预定义,判断当前组合结构体是否实现了NestPrepare这个接口,如果实现了,就调用这个方法的函数
	if a,ok:=c.AppController.(NestPrepare);ok{
           a.NestPrepare()
	}   
//在更新文章的node路由上设置
type NodeController struct{
	 BaseController
}
func (c *NodeController) NestPrepare(){
	c.MustLogin()
	if c.User.Role!=0{
		fmt.Println(c.User)
		c.Abort500(errors.New("用户权限不足"))
	}
}

3、wangEditor3编辑器的使用

//官方网址
https://www.kancloud.cn/wangfupeng/wangeditor3/332599

4、发送json给后台(可以通过表单)

<script language="JavaScript">
    layui.use(['form','jquery'], function(){
        var form = layui.form,
            $=layui.$;
        form.render();
        //监听提交
        form.on('submit(send)', function(rdata){
            rdata.field.content=editor.txt.html();
            $.post("/node/save",rdata.field,function (data){
                if (data.code===0){
                    layer.msg("保存成功");
                    if(data.action){
                        setTimeout(function (){
                            window.location.href=data.action
                        },300)
                    }
                }else {
                    layer.msg("保存失败");
                }
            },"json").error(function (){
                layer.msg("网络异常");
            })
            return false;
        })
    })
</script>

5、防止多次点击(uuid的使用)

//"github.com/satori/go.uuid"
func (c *BaseController) UUID()string{
	u:=uuid.NewV4() //随机生成uuid
    return u.String()
}

6、保存标题和内容(判断文章是否存在?保存:新增)

	if c.Ctx.Input.IsPost(){
		var node models.Node
		key:=c.Ctx.Input.Params()  //路由设置的时候可以设置参数,可以获取相关的参数
		fmt.Println("获取到的key值为",key["0"])
        title:=c.JugeNull("title","标题不能为空")
        content:=c.JugeNull("content","文章不能为空")
        num,node,err:=models.QueryNodeByKey(key["0"])  //通过key查询是否存在
        if err!=nil{
        	//if err==gorm.ErrRecordNotFound   //找不到数据的情况
			if num!=0{   //存在文章
				node.Title=title
				node.Content=content
			}else {     //没有这篇文章
				node=models.Node{
					UserId: int(c.User.ID),
					Uuid:key["0"],
					Title: title,
					Content: content,
				}
			}
		}
		err=models.SaveNode(node)
		if err!=nil{
			c.Abort500(err)
		}
		c.Data["json"]=map[string]interface{}{
			"code":0,
			"action":"/auth/index",
		}
		_ = c.ServeJSON()
	}

7、goquery进行摘要解析

//"github.com/PuerkitoBio/goquery"
//使用goquery获取摘要
func getSummary(html string)(string,error){
	var buf bytes.Buffer
	if _,err:=buf.Write([]byte(html));err!=nil{
       return "",err
	}
	doc,err:=goquery. NewDocumentFromReader(&buf)
	if err!=nil{
		return "",err
	}
	htmlstr:=doc.Find("p").Text()//获取p标签下的文档
	if len(htmlstr)>30{   //将前30个字符当成摘要
		htmlstr=htmlstr[:30]
	}
	return htmlstr,nil
}

8、数据库查询分页功能

//使用数据库的offset查询,渲染首页
if c.Ctx.Input.IsGet(){
		limit:=3  //设置每页数量
		page,err:=c.GetInt("page")
		seaStr:=c.GetString("search")
		if err!=nil||page<1{
			page=1
		}
		nodes, err:= models.QueryNodeByPage(seaStr,page, limit)
		if err!=nil{
			c.Abort500(err)
		}
		//查询总条数,由此算出一共多少page
		num,_:=models.QueryAllCount(seaStr)
		allpage:=int(num)/limit
		if int(num)%limit!=0{
			allpage=allpage+1
		}
		c.Data["allpage"]=allpage
		c.Data["page"]=page
		c.Data["nodes"]=nodes  //返回前端查询数据
		c.TplName="index.html"
	}
	//数据库查询功能
	func QueryNodeByPage(str string,page ,limit int)(nodes []Node,err error){
	res:=db.Where("title like ?",fmt.Sprintf("%%%s%%",str)).Offset((page-1)*limit).Limit(limit).Find(&nodes)
    return nodes,res.Error
    //扫描分页的数据,并且返回错误
}
	func QueryAllCount(str string)(int64,error){
     var count int64
     return count,db.Where("title like ?",fmt.Sprintf("%%%s%%",str)).Model(&Node{}).Count(&count).Error
}
//前端使用模板技术的{{range nodes}}渲染出页面
//使用search可以增加搜索功能

9、展示全文功能

//通过Uuid的唯一性当作key值传递
func (c *NodeController)Details(){
	key:=c.GetString("key")
	_,node,err:=models.QueryNodeByKey(key)
	if err!=nil{
       c.Abort500(err)
	}
	c.Data["node"]=node
	c.TplName="details.html"
}

10、文章的修改

通过key值传递,修改

逻辑和保存一样,只需压迫跳转到save方法,进行信息修改就行了

11、文章的删除

需要使用uuid和userid一起判断,只使用uuid可能删除多个文章

func (c *NodeController) Del(){
	key:=c.GetString("key")   //获取key值
	userid:=c.User.ID
    err:=models.DeleteNode(key,int(userid))
    if err!=nil{
    	c.Abort500(err)
	}
	c.Redirect(beego.URLFor("AuthController.Index"),302)
}
func DeleteNode(key string,userid int)error{
	 res:=db.Where("uuid=? and user_id=?",key,userid).Delete(&Node{})   //根据key值删除
	 return res.Error
}

12、文章的评论

新建评论结构体保存数据库(包含文章,userid,user,Praise)

type Message struct{

}

13、文章的留言

文章的留言和评论异曲同工,只是判断是否有文章的Uuid,如果有文章的Uuid就是这篇文章的评论,如果没有这篇文章的Uuid,就是文章的留言

func (c *AuthController) Message(){
	if c.Ctx.Input.IsGet(){
		pageno,err:=c.GetInt("pageno")
		if err!=nil||pageno<1{
			pageno=1
		}
		pagesize:=5
		num,messages,err:=models.QueryAllMessage(pageno,pagesize)
		if err!=nil{
			c.Abort500(err)
		}
		counts,_:=models.QueryAllMessageCount()
		allpage:=int(counts)/pagesize
		if int(counts)%pagesize!=0{
			allpage=allpage+1
		}
		c.Data["num"]=num
		c.Data["allpage"]=allpage
		c.Data["page"]=pageno
		c.Data["messages"]=messages
		c.TplName="message.html"
	}
    if c.Ctx.Input.IsPost(){
    	content:=c.GetString("content")
		message:=&models.Message{
			Content:content,
			UserId:int(c.User.ID),
			User:c.User,
		}
		err:=models.SaveMessage(message)
		if err!=nil{
			c.Abort500(err)
		}
		c.Data["json"]=map[string]interface{}{
			"code":0,
			"action":"/Auth/Message",
		}
		_ = c.ServeJSON()
	}
}

程序源码位置

gitee地址: https://gitee.com/casyy/beego-realizes-blog.git

后续会有更新,如果看完对自己有所帮助,请点赞支持

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值