上次我准备用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
输入admin 密码123456登录成功:
先不管右边主体的错误,后面我们会完善。
好了到这里我们就搭建完了登录逻辑,这个流程是这样的:
启动项目后,初始化数据库注册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