手摸手教你用beego实现留言本之四(实现留言本)

wujiangwei · 2019-01-16 15:02:48 · 1894 次点击 · 预计阅读时间 8 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-01-16 15:02:48 的文章,其中的信息可能已经有所发展或是发生改变。

留言本实现流程:

  1. 用户登录,填写留言
  2. 展示留言列表 (分页查询和搜索)
  3. 实现留言增删改查

1. 增加留言表

CREATE TABLE `leave_message` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL DEFAULT '0' COMMENT '来自用户表user的id',
  `content` text NOT NULL COMMENT '留言内容',
  `status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '是否展示 0 否 1是',
  `create_at` datetime NOT NULL COMMENT '创建时间',
  `update_at` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `uid` (`uid`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='留言表';

2. 增加路由

beego.Router("/msg/", &controllers.MessageController{},"get:Index")
beego.Router("/msg/list", &controllers.MessageController{},"get:List")
beego.Router("/msg/addmsg", &controllers.MessageController{},"post:AddMsg")
beego.Router("/msg/delmsg", &controllers.MessageController{},"post:DelMsg")

第一个是视图模板文件,第二个是获取列表,一般查询用get,数据修改用 post

3. 增加控制器

type MessageController struct {
    beego.Controller
}

func (c *MessageController) List() {
    msg :=  models.LeaveMessage{}
    limit,_ := c.GetInt("limit")
    page,_ := c.GetInt("page")
    content := c.Input().Get("content")
    response := ResponseJson{}
    response.Message = "ok"
    response.State = 0
    if messages, err:= msg.GetList(limit,page,content) ; err != nil {
        response.Message = err.Error()
        response.State = 500
    } else {
        response.Data = messages
    }
    c.Data["json"] = response
    c.ServeJSON()
    //c.TplName = "message.tpl"
}

func (c *MessageController) Index()  {
    c.TplName = "message.tpl"
}

func (c *MessageController)AddMsg()  {
    username := c.GetSession("Username")
    content := c.Input().Get("content")
    id, _ := c.GetInt("id",0)
    response := ResponseJson{}
    response.Message = "ok"
    response.State = 0
    if content == "" {
        response.Message = "留言内容不能为空"
        response.State = 500
        c.Data["json"] = response
        c.ServeJSON()
        return
    }
    if username == "" || username == nil {
        response.Message = "当前用户尚未登录,请先登录"
        response.State = 501
        c.Data["json"] = response
        c.ServeJSON()
        return
    }
    msg := models.LeaveMessage{}
    msg.Content = content
    msg.Id = id
    if id,err :=  msg.SaveMessage(username.(string)); err != nil {
        response.Message = "保存失败,请稍后再试"
        response.State = 503
    } else {
        response.Data = id
    }
    c.Data["json"] = response
    c.ServeJSON()
    return
}

func (c *MessageController)DelMsg() {
    username := c.GetSession("Username")
    id, _ := c.GetInt("id",0);
    response := ResponseJson{}
    response.Message = "ok"
    response.State = 0
    msg := models.LeaveMessage{}
    msg.Id = id
    if username == "" || username == nil {
        response.Message = "当前用户尚未登录,请先登录"
        response.State = 501
        c.Data["json"] = response
        c.ServeJSON()
        return
    }
    if err :=  msg.DelMsg(username.(string)); err != nil {
        response.Message = "删除失败,请稍后再试"
        response.State = 503
    }
    c.Data["json"] = response
    c.ServeJSON()
    return
}

需要说明一下的是:

  1. c.Input().Get('content') 返回的是字符串,如果需要接收id之类的整型可以使用 c.GetInt('id',0) 这个函数返回值有两个,参数也是两个 可以使用 _ 占位符跳过第二个err的接收
  2. 如果我们调用 c.ServeJSON() 想提前返回,一定要注意后面紧跟 return, 否则后面的代码可能会接着执行

3. 模型

package models

import (
    "errors"
    "github.com/astaxie/beego/orm"
    "log"
    "time"
)

type LeaveMessage struct {
    Id       int
    Uid      int
    Content  string
    Status   int
    CreateAt time.Time `orm:"type(datetime)"`
    UpdateAt time.Time `orm:"type(datetime)"`
}

type MsgData struct {
    Id       int
    Content  string
    Name     string
    CreateAt time.Time
}
type MessageList struct {
    Count int
    List  []MsgData
}

func init() {
    orm.RegisterModel(new(LeaveMessage))
}

/**
  添加留言
 */
func (msg *LeaveMessage) SaveMessage(username string) (int, error) {
    o := orm.NewOrm()
    user := User{Name: username}
    if err := user.GetUserId(); err != nil {
        return 0, err
    }

    msg.Uid = user.Id
    msg.Status = 1
    msg.UpdateAt = time.Now()

    if msg.Id > 0 {
        //需要判断是否是自己的留言 注意 这里读到的可能会覆盖自己的 结构 重新开启一个
        msgr := LeaveMessage{Id:msg.Id,Uid:msg.Uid}
        if err := o.Read(&msgr, "uid", "id"); err != nil {
            log.Printf("update user %v error,error info is %v ,is not yourself \n", msg, err)
            return 0, errors.New("不能修改别人的留言")
        }
        msg.CreateAt = time.Now()
        if num, err := o.Update(msg, "content","update_at"); num == 0 || err != nil {
            log.Printf("update user %v error,error info is %v \n", msg, err)
            return 0, errors.New("保存失败,请稍后再试")
        }
    } else {
        if id, err := o.Insert(msg); err != nil || id <= 0 {
            log.Printf("insert user %v error,error info is %v \n", msg, err)
            return 0, errors.New("保存失败,请稍后再试")
        }
    }
    return msg.Id, nil
}

/**
   搜索留言 分页
   1. 联表查询记录列表
   2. 筛选符合条件的结果
   3. 加入分页
 */

func (msg LeaveMessage) GetList(limit, page int, content string) (MessageList, error) {
    qb, _ := orm.NewQueryBuilder("mysql")
    qb2, _ := orm.NewQueryBuilder("mysql")
    if limit == 0 {
        limit = 20
    }
    offset := 0
    if page > 0 {
        offset = (page - 1) * limit
    }
    qb.Select("count(*) ").
        From("leave_message").
        LeftJoin("user").On("leave_message.uid = user.id")
    if content != "" {
        qb.Where("content like '%" + content + "%' ")
    }

    qb2.Select("user.name,leave_message.id,leave_message.content,leave_message.create_at").
        From("leave_message").
        LeftJoin("user").On("leave_message.uid = user.id")
    if content != "" {
        qb2.Where("content like '%" + content + "%' ")
    }
    qb2.OrderBy("leave_message.id desc").Limit(limit).Offset(offset)

    sqlCount := qb.String()
    sqlRows := qb2.String()

    o := orm.NewOrm()
    var messageList MessageList
    var count []int
    var msgDatas []MsgData
    if num, err := o.Raw(sqlCount).QueryRows(&count); err != nil || num == 0 {
        return MessageList{}, errors.New("查询失败,请稍后再试")
    }
    messageList.Count = count[0]
    if num, err := o.Raw(sqlRows).QueryRows(&msgDatas); err != nil || num == 0 {
        return MessageList{}, errors.New("查询失败,请稍后再试")
    }
    messageList.List = msgDatas
    return messageList, nil
}

/**
  删除留言
 */
func (msg *LeaveMessage) DelMsg(username string) error {
    o := orm.NewOrm()
    user := User{Name: username}
    if err := user.GetUserId(); err != nil {
        return err
    }
    msg.Uid = user.Id
    msg.Status = 1
    msg.CreateAt = time.Now()
    msg.UpdateAt = time.Now()

    if msg.Id > 0 {
        //需要判断是否是自己的留言
        if err := o.Read(msg, "uid", "id"); err != nil {
            log.Printf("delete user %v error,error info is %v ,is not yourself \n", msg, err)
            return errors.New("不能删除别人的留言")
        }
        if num,err := o.Delete(msg,"id");err != nil || num == 0{
            log.Printf("delete user %v error,error info is %v ,is not yourself \n", msg, err)
            return errors.New("删除失败,请稍后再试")
        }
        return nil
    } else {
        return errors.New("请选择你要删除的留言")
    }
}

需要说明一下的是:

  1. list需要联表查询,orm的高级查询比较复杂,可以使用构造查询 具体文档可参见: https://www.kancloud.cn/hello123/beego/126107 其中有一个bug,不知道是什么原因, where中使用 content like '%?%'?参数不能被 识别,导致无法进行参数替换,本例直接拼装了条件(注意这里会有sql注入)请自行进行参数过滤

  2. 修改之前需要查询留言是否是自己的,这时尤其要注意我们orm 的传参基本上是指针地址传参 如果传入原对象,会直接将数据库读到的数据重新覆盖掉传进来的数据,所以务必使用新变量存储

  3. 使用orm原生sql查询,返回的是一个切片类型,不管你是查一条还是查多条,这里注意一定 传入的是切片,否则会报错

4. 模板

具体参见github:https://github.com/wujiangweiphp/beegostudy 运行截图:

本教程完结,如果觉得对你有帮助,麻烦github上打个


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1894 次点击  
加入收藏 微博
被以下专栏收入,发现更多相似内容
1 回复  |  直到 2020-10-10 15:20:52
ZhaoJY
ZhaoJY · #1 · 4年之前

你好, response.Data = messages这一段中message报错 Cannot use 'messages' (type MessageList) as type int

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传