beego搭建个人博客(一)

上次我准备用Java的ssm框架来搭建一个博客系统,我觉得后来觉得Java实在太罗嗦了,贼多的配置文件。最近接触了go的web开发,框架有beego,gin、revel以及iris,beego虽然很重量级,性能也差iris太远,但是它对国人的学习是十分有好的,首先它的作者是国人,理念呢也还是参照传统的mvc概念,加上详尽的文档是一个非常好的入门go web的框架,所以我决定使用beego搭建一个个人博客,前台展示使用layui,毕竟我比较懒!

准备工作:

a.下载Sublime Text3,安装go插件,在mysql创建数据库db_beego,然后导入db_beego.sql(在github上有,链接在文章最下面),主要就是创建了用户,文章,评论表并且插入几条测试数据,大家随便看下知道就可以了。

b.你的电脑肯定安装了go环境,然后安装beego,可以参考https://blog.csdn.net/suresand/article/details/79548796

$ go get -u github.com/astaxie/beego
$ go get -u github.com/beego/bee

直接安装beego的框架及开发工具

或许还需要安装go-mysql的驱动

go get github.com/go-sql-driver/mysql

c.然后在你的gopath的src目录下执行:

bee new blog

然后看见自动创建的blog文件夹,进入blog文件夹:

bee run

访问http://localhost:8080/出现welcome to beego画面表示准备工作完成,然后就可以开始我们的开发了,当然由于我的水平有限,有模糊的地方请大家详细参考beego文档https://beego.me/docs/intro/

一 配置文件
首先配置app.conf,这个app.conf配置文件可以做很多事,这里我们主要配置数据库的链接信息:

appname = blog
httpport = 8080
runmode = dev

# MYSQL地址
dbhost = localhost

# MYSQL端口
dbport = 3306

# MYSQL用户名
dbuser = root

# MYSQL密码
dbpassword = 你的密码

# MYSQL数据库名称
dbname = db_beego

# MYSQL表前缀
dbprefix = tb_

二 构建登陆逻辑
我在考虑是先把所有的结构搭出来,还是一个一个去实现呢,然后我选择了后者,因为这样可以更快的做出效果提升兴趣,所以我准备一上来就把登陆逻辑做个模版出来

a.首先我们需要将数据库连接注册到beego的orm中,这是各个操作都会用到的,在models文件下新建base.go:

package models

import (
    "github.com/astaxie/beego/orm"
    "github.com/astaxie/beego"
)

func Init() {
    dbhost := beego.AppConfig.String("dbhost")
    dbport := beego.AppConfig.String("dbport")
    dbuser := beego.AppConfig.String("dbuser")
    dbpassword := beego.AppConfig.String("dbpassword")
    dbname := beego.AppConfig.String("dbname")
    if dbport == "" {
        dbport = "3306"
    }
    dsn := dbuser + ":" + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?charset=utf8&loc=Asia%2FShanghai"
    orm.RegisterDataBase("default", "mysql", dsn)
    orm.RegisterModel(new(User))
}

//返回带前缀的表名
func TableName(str string) string {
    return beego.AppConfig.String("dbprefix") + str
}

上面这段代码还是很容易看懂的,就是初始化数据库连接,并且将User注册到orm里去

b.登录当然是跟用户相关了,在models继续新建user.go:

package models

import "time"

type User struct {
    Id         int
    Username   string
    Password   string
    Email      string
    LoginCount int
    LastTime   time.Time
    LastIp     string
    State      int8
    Created    time.Time
    Updated    time.Time
}

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

c.我们要注意不允许在未登录的情况下访问我们的controller,所以需要判断是否已经登录,在controller文件下新建base.go:

package controllers

import (
    "github.com/astaxie/beego"
    "github.com/astaxie/beego/orm"
    "strings"
    "github.com/Echosong/beego_blog/models"
)

type baseController struct {
    beego.Controller
    o orm.Ormer
    controllerName string
    actionName     string
}

func (p *baseController) Prepare()  {
    controllerName, actionName := p.GetControllerAndAction()
    p.controllerName = strings.ToLower(controllerName[0 : len(controllerName)-10])
    p.actionName = strings.ToLower(actionName)
    p.o = orm.NewOrm();
    if strings.ToLower( p.controllerName) == "admin" && strings.ToLower(p.actionName)  !=  "login"{
        if p.GetSession("user") == nil{
            p.History("未登录","/admin/login")
            //p.Ctx.WriteString(p.controllerName +"==="+ p.actionName)
        }
    }

    //初始化前台页面相关元素
    if strings.ToLower( p.controllerName) == "blog"{

        p.Data["actionName"] = strings.ToLower(actionName)
        var result []*models.Config
        p.o.QueryTable(new(models.Config).TableName()).All(&result)
        configs := make(map[string]string)
        for _, v := range result {
            configs[v.Name] = v.Value
        }
        p.Data["config"] = configs
    }

}
//用来做跳转的逻辑展示
func (p *baseController) History(msg string, url string) {
    if url == ""{
        p.Ctx.WriteString("")
        p.StopRun()
    }else{
        p.Redirect(url,302)
    }
}


//获取用户IP地址
func (p *baseController) getClientIp() string {
    s := strings.Split(p.Ctx.Request.RemoteAddr, ":")
    return s[0]
}

Prepare()方法就是验证用户是否登录。

d.那么我们现在来写我们的登录controller,在controller文件夹下新建admin.go

package controllers

import (
    "github.com/liwd/blog/models"
    "strconv"
    "github.com/liwd/blog/util"
    "fmt"
    "strings"
    "time"
)
//继承baseController
type AdminController struct {
    baseController
}

//后台用户登录
func (c *AdminController) Login() {
    if c.Ctx.Request.Method == "POST" {
        username := c.GetString("username")
        password := c.GetString("password")
        user := models.User{Username:username}
        c.o.Read(&user,"username")

        if user.Password == "" {
            c.History("账号不存在","")
        }

        if util.Md5(password) != strings.Trim(user.Password, " ") {
            c.History("密码错误", "")
        }
        user.LastIp = c.getClientIp()
        user.LoginCount = user.LoginCount +1
        if _, err := c.o.Update(&user); err != nil {
            c.History("登录异常", "")
        } else {
            c.History("登录成功", "/admin/main.html")
        }
        c.SetSession("user", user)
    }
    c.TplName = c.controllerName+"/login.html"
}

//主页
func (c *AdminController) Main() {
    c.TplName = c.controllerName + "/main.tpl"
}

c.TplName相当于http.Handle(http.FileServer())是用来寻找html的。
这里使用了md5对密码加密,我们在util文件下新建function.go:

package util

import (
    "crypto/md5"
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "io"
    "net/url"
    "strings"
)

func Md5(str string) string {
    hash := md5.New()
    hash.Write([]byte(str))
    return fmt.Sprintf("%x", hash.Sum(nil))
}

func Rawurlencode(str string) string {
    return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
}

//生成Guid字串
func UniqueId() string {
    b := make([]byte, 48)

    if _, err := io.ReadFull(rand.Reader, b); err != nil {
        return ""
    }
    return Md5(base64.URLEncoding.EncodeToString(b))
}

e.构建路由

因为Java里面tomcat或者其它server已经帮我们构建好了路由便不需要我们自己构建了,而go自己已经封装好了net/http模块,所以我们自己构建路由也很是方便,修改router.go:

package routers

import (
    "github.com/liwd/blog/controllers"
    "github.com/astaxie/beego"
)

func init() {
    bego.AutoRouter(&controllers.AdminController{})
}

这里 bego.AutoRouter(&controllers.AdminController{})将AdminController的所有方法自动注册为路由了,访问/admin/login.html或者/admin/login都可以跳转到login方法,是不是很简单!

f.编写登录页面和登陆后的主页面
首先新建static文件,将我项目中static文件下的所有资源复制到你的项目中,然后编写登录页面,在view文件夹中新建admin文件夹,在admin文件夹中新建login.html:


<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>后台登录title>
    <link rel="stylesheet" href="/static/plug/layui/css/layui.css">
    <style>

        .main {               
            margin: 0 auto;
            width: 400px;
            border: 1px solid;
            border-color: #eeeeee;
            border-radius: 5px;
            margin-top: 100px;
        }
    style>

head>
<body>
<script type="text/javascript" src="/static/plug/layui/layui.js">script>
<div class="main layui-clear">
    <form action="/admin/login" method="post">
        <div class="fly-panel fly-panel-user" pad20>
            <div class="layui-tab layui-tab-brief">
                <ul class="layui-tab-title">
                    <li class="layui-this">欢迎登录后台系统li>
                ul>
                <div class="layui-form layui-tab-content" id="LAY_ucm" style="padding-top: 20px; padding-left: 50px;  ">

                    <div class="layui-form layui-form-pane">

                        <div class="layui-form-item">
                            <label class="layui-form-label">用户名label>
                            <div class="layui-input-inline">
                                <input type="text" name="username" required lay-verify="username" placeholder="用户名"
                                       autocomplete="off" class="layui-input">
                            div>
                        div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">密码label>
                            <div class="layui-input-inline">
                                <input type="password" name="password" required lay-verify="password"
                                       placeholder="密码" autocomplete="off" class="layui-input">
                            div>
                        div>

                        <div class="layui-form-item" style="float: right; margin-right: 42px;">

                            <input type="checkbox" name="is_top" {{if .post.IsTop}} checked {{end}} value="1"
                                   title="记住密码">

                        div>

                        <div class="layui-form-item">
                            <button lay-submit class="layui-btn btn-submit" style="width: 300px; border-radius:3px"
                                    lay-submit=""
                                    lay-filter="sub">立即登录
                            button>
                        div>
                    div>
                div>
            div>
        div>
    form>
div>

body>
<script>
    //Demo
    layui.use('form', function () {
    });
script>
html>

这里主要使用layui的模版,layui的学习门槛是极低的,关于layui的具体使用和特性可以去官网学习http://www.layui.com/doc/。

同样在admin文件夹下新建main.tpl:


<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="Keywords" content="">
    <meta name="Description" content="">
    <title>后台管理系统title>
    <link rel="stylesheet" href="/static/plug/layui/css/layui.css">
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
head>

<body>

<div class="layui-layout layui-layout-admin">
    
    <div class="layui-header">
        <div class="layui-main">
            
            <a href="/" style="color: #c2c2c2; font-size: 18px; line-height: 60px;">后台管理系统a>
            
            <ul class="layui-nav" style="position: absolute; top: 0; right: 0; background: none;">
                <li class="layui-nav-item">
                    <a href="javascript:;">

                    a>
                li>
                <li class="layui-nav-item">
                    <a href="javascript:;">
                        admin,欢迎你!
                    a>
                    <dl class="layui-nav-child">
                        <dd>
                            <a href="/admin/logout">
                                退出系统
                            a>
                        dd>
                    dl>
                li>
            ul>
        div>
    div>

    
    <div class="layui-side layui-bg-black">
        <div class="layui-side-scroll">
            <ul class="layui-nav layui-nav-tree " lay-filter="left-nav" style="border-radius: 0;">
            ul>
        div>
    div>

    
    <div class="layui-body">
        
        <div class="layui-tab layui-tab-brief" lay-filter="top-tab" lay-allowClose="true" style="margin: 0;">
            <ul class="layui-tab-title">ul>
            <div class="layui-tab-content">div>
        div>
    div>

    
    <div class="layui-footer" style="text-align: center; line-height: 44px;">
        Copyright ©无鞋
    div>
div>

<script src="/static/plug/layui/lay/lib/jquery.js" type="text/javascript" charset="utf-8">script>
<script type="text/javascript" src="/static/plug/layui/layui.js">script>
<script type="text/javascript">
    /**
     * 对layui进行全局配置
     */
    layui.config({
        base: '/static/js/'
    });

    layui.use('form', function() {
        var $ = layui.jquery,
            form = layui.form();
    });

    /**
     * 初始化整个系统骨架
     */
    layui.use(['cms'], function() {
        var cms = layui.cms('left-nav', 'top-tab');
        cms.addNav([
            { id: 1, pid: 0, node: ' 系统管理', url: '#' },
            { id: 7, pid: 1, node: '   系统设置', url: '/admin/config.html' },
            { id: 2, pid: 0, node: ' 内容管理', url: '#' },
            { id: 3, pid: 2, node: '   分类管理', url: '/admin/category.html' },
            { id: 5, pid: 2, node: '   博文列表', url: '/admin/index.html' },
            { id: 6, pid: 2, node: '   博文添加', url: '/admin/article.html' },
        ], 0, 'id', 'pid', 'node', 'url');
        cms.bind(60 + 41 + 20 + 44); //头部高度 + 顶部切换卡标题高度 + 顶部切换卡内容padding + 底部高度
        cms.clickLI(1);

    });

    function addTab(title, src, id,closeId){
        if(closeId){
//                  debugger;
            closeTab(closeId);
        }
        layui.use(['cms'], function() {
            var cms = layui.cms('left-nav', 'top-tab');
            cms.addTab(title,src,id);
        });
    }

    function closeTab(id,refreshId){
        layui.use(['cms'], function() {
            var cms = layui.cms('left-nav', 'top-tab');
            cms.closeTab(id,refreshId);
        });
    }

script>
body>

html>

进入blog目录,运行bee run命令,访问http://localhost:8088/admin/login
beego搭建个人博客(一)_第1张图片

输入admin 密码123456登录成功:

beego搭建个人博客(一)_第2张图片

先不管右边主体的错误,后面我们会完善。

好了到这里我们就搭建完了登录逻辑,这个流程是这样的:
启动项目后,初始化数据库注册orm的相关model,然后通过router.go来注册路由,当我们访问http://localhost:8088/admin/login会先到baseController的Prepare方法验证是否已经登录(我们设置了session,如果已经登录可以直接访问http://localhost:8088/admin/main.html进入后台管理页面,没登陆成功或者session失效肯定是不行的),如果没登录会进入login.html页面,输入帐号密码通过自动绑定的路由自动跳转到AdminController的Login方法,验证帐号密码的正确与否再去判断逻辑

github地址:https://github.com/lightTrace/beego-blog

你可能感兴趣的:(golang)