网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
//无误
response = gin.H{"code": 1, "message": "ok"}
} else {
logger.Error("AddArticlePost failed", zap.Any("error", err))
response = gin.H{"code": 0, "message": "error"}
}
c.JSON(http.StatusOK, response)
}
// 展示文章
func ShowArticleGet(c *gin.Context) {
isLogin := c.MustGet(“is_login”)
idStr := c.Param(“id”)
// 查询文章
article, err := models.QueryArticleWithId(idStr)
if err != nil {
logger.Error("QueryArticleWithId failed", zap.Any("error", err))
c.String(http.StatusOK, "bad id")
return
}
if article == nil {
c.String(http.StatusOK, "bad id")
return
}
// 增加文章的阅读数
err = logic.IncArticleReadCount(idStr)
if err != nil {
logger.Error("ArticleReadCountIncr failed", zap.Any("error", err))
}
c.HTML(http.StatusOK, "show\_article.html", gin.H{"isLogin": isLogin, "Title": article.Title, "Content": article.Content})
}
// UpdateArticleGet 更新文章
func UpdateArticleGet(c *gin.Context) {
isLogin := c.MustGet(“is_login”)
idStr := c.Query(“id”)
//获取id所对应的文章信息
article, err := models.QueryArticleWithId(idStr)
if err != nil {
logger.Error("QueryArticleWithId failed", zap.Any("error", err))
c.String(http.StatusOK, "bad id")
return
}
if article == nil {
c.String(http.StatusOK, "bad id")
return
}
c.HTML(http.StatusOK, "write\_article.html", gin.H{"isLogin": isLogin, "article": article})
}
// 更新文章
func UpdateArticlePost(c *gin.Context) {
// 获取浏览器传输的数据,通过表单的name属性获取值
idStr := c.PostForm(“id”)
id, err := strconv.Atoi(idStr)
if err != nil {
c.JSON(http.StatusOK, “bad id”)
}
title := c.PostForm(“title”)
tags := c.PostForm(“tags”)
short := c.PostForm(“short”)
content := c.PostForm(“content”)
// 实例化model,修改数据库
art := &models.Article{
Id: id,
Title: title,
Tags: tags,
Short: short,
Content: content,
}
logger.Debug("UpdateArticlePost", zap.Any("article", \*art))
\_, err = models.UpdateArticle(art)
//返回数据给浏览器
response := gin.H{}
if err == nil {
//无误
response = gin.H{"code": 1, "message": "更新成功"}
} else {
response = gin.H{"code": 0, "message": "更新失败"}
}
c.JSON(http.StatusOK, response)
}
// 删除文章
func DeleteArticle(c *gin.Context) {
idStr := c.Query(“id”)
_, err := models.DeleteArticle(idStr)
if err != nil {
logger.Error(“DeleteArticle failed”, zap.Any(“error”, err))
}
c.Redirect(http.StatusFound, “/home”)
}
// 按照阅读数排行返回前n篇文章的id和title
func ArticleTopN(c *gin.Context) {
nStr := c.Param(“n”)
n, err := strconv.ParseInt(nStr, 0, 16)
if err != nil {
logger.Error(“ArticleTopN”, zap.Any(“error”, err))
n = 5
}
// 调用业务逻辑层 获取返回数据结果
articleList := logic.GetArticleReadCountTopN(n)
// 3. 返回
c.JSON(http.StatusOK, gin.H{
"code": 2000,
"msg": "success",
"data": articleList,
})
return
}
* code\_msg.go
package controllers
const (
CodeSuccess = 2000
CodeBadRequest = 2001
CodeInvalidParam = 2002
CodeFailed = 5000
CodeError = 5001
)
var MsgMap = map[int]string{
CodeSuccess: “success”,
CodeBadRequest: “bad request”,
CodeInvalidParam: “无效的参数”,
CodeFailed: “请求失败”,
CodeError:“啊哦,服务器走丢了”,
}
func ShowMsg(code int)string{
v, ok:= MsgMap[code]
if !ok {
return MsgMap[CodeError]
}
return v
}
* home.go
package controllers
import (
“blogweb_gin/logger”
“blogweb_gin/models”
“github.com/gin-gonic/gin”
“go.uber.org/zap”
“net/http”
“strconv”
)
// 获取首页
func HomeGet(c *gin.Context) {
//获取session,判断用户是否登录
isLogin := c.MustGet(“is_login”).(bool)
username := c.MustGet(“login_user”).(string)
page, _ := strconv.Atoi(c.Query(“page”))
if page <= 0 {
page = 1
}
logger.Debug("HomeGet", zap.Int("page", page))
articleList, err := models.QueryCurrUserArticleWithPage(username, page)
if err != nil {
logger.Error("models.QueryCurrUserArticleWithPage failed", zap.Any("error", err))
}
logger.Debug("models.QueryCurrUserArticleWithPage", zap.Any("articleList", articleList))
data := models.GenHomeBlocks(articleList, isLogin)
pageData := models.GenHomePagination(page)
logger.Debug("models.GenHomeBlocks", zap.Any("data", data))
c.HTML(http.StatusOK, "home.html", gin.H{"isLogin": isLogin, "data": data, "pageData": pageData})
}
* index.go
package controllers
import (
“blogweb_gin/logger”
“blogweb_gin/models”
“github.com/gin-gonic/gin”
“go.uber.org/zap”
“net/http”
)
// 索引页
func IndexGet(c *gin.Context) {
articleList, err := models.QueryAllArticle()
if err != nil {
logger.Error(“models.QueryCurrUserArticleWithPage failed”, zap.Any(“error”, err))
}
logger.Debug(“models.QueryCurrUserArticleWithPage”, zap.Any(“articleList”, articleList))
c.HTML(http.StatusOK, “index.html”, gin.H{“articleList”: articleList})
}
* login.go
package controllers
import (
“blogweb_gin/logger”
“blogweb_gin/models”
“blogweb_gin/utils”
“fmt”
“github.com/gin-contrib/sessions”
“github.com/gin-gonic/gin”
“go.uber.org/zap”
“net/http”
)
// get登陆页
func LoginGet(c *gin.Context) {
//返回html
c.HTML(http.StatusOK, “login.html”, gin.H{“title”: “登录页”})
}
// 提交登陆
func LoginPost(c *gin.Context) {
// 取出请求数据
// 校验用户名密码是否正确
// 返回响应
username := c.PostForm(“username”)
password := c.PostForm(“password”)
logger.Debug(“login”, zap.String(“username”, username), zap.String(“password”, password))
// 去数据库查,注意查找的时候,密码是MD5之后的密码查找
id := models.QueryUserWithParam(username, utils.MD5(password))
fmt.Println("id:", id)
// 登陆成功
if id > 0 {
// 给响应种上Cookie
session := sessions.Default(c)
session.Set("login\_user", username) // 在session中保存k-v,然后写入cookie
session.Save()
c.Redirect(http.StatusFound, "/home") // 浏览器收到这个就会跳转到我指定的页面
c.JSON(http.StatusOK, gin.H{"code": 200, "message": "登录成功"})
} else {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "登录失败"})
}
}
// 登出
func LogoutHandler(c *gin.Context) {
//清除该用户登录状态的数据
session := sessions.Default©
session.Delete(“login_user”)
session.Save()
c.Redirect(http.StatusFound, "/login")
}
* register.go
package controllers
import (
“blogweb_gin/logger”
“blogweb_gin/models”
“blogweb_gin/utils”
“fmt”
“github.com/gin-gonic/gin”
“net/http”
“time”
)
// 获取注册
func RegisterGet(c *gin.Context) {
// 返回html
c.HTML(http.StatusOK, “register.html”, gin.H{“title”: “注册页”})
}
// 注册提交
func RegisterPost(c *gin.Context) {
// 取出请求的数据
// 判断注册是否重复 --> 拿着用户名去数据库查一下有没有
// 写入数据库
// 获取表单信息
username := c.PostForm(“username”)
password := c.PostForm(“password”)
repassword := c.PostForm(“repassword”)
logger.Debug(fmt.Sprintf(“%s %s %s”, username, password, repassword))
// 注册之前先判断该用户名是否已经被注册,如果已经注册,返回错误
id := models.QueryUserWithUsername(username)
fmt.Println("id:", id)
if id > 0 {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户名已经存在"})
return
}
// 注册用户名和密码
// 存储的密码是md5后的数据,那么在登录的验证的时候,也是需要将用户的密码md5之后和数据库里面的密码进行判断
password = utils.MD5(password)
logger.Debug(fmt.Sprintf("password after md5:%s", password))
user := models.User{
Username: username,
Password: password,
Status: 0,
CreateTime: time.Now().Unix(),
}
\_, err := models.InsertUser(&user)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "注册失败"})
} else {
c.JSON(http.StatusOK, gin.H{"code": 1, "message": "注册成功"})
}
}
#### dao
* mysql.go
package dao
import (
“blogweb_gin/config”
“blogweb_gin/logger”
“fmt”
_ “github.com/go-sql-driver/mysql”
sql “github.com/jmoiron/sqlx”
)
var db *sql.DB
func InitMySQL(cfg *config.MySQLConfig) (err error) {
logger.Info(“InitMySQL…”)
if db == nil {
dsn := fmt.Sprintf(“%s:%s@tcp(%s:%d)/%s”, cfg.Username, cfg.Password, cfg.Host, cfg.Port, cfg.DB)
db, err = sql.Connect(“mysql”, dsn)
if err != nil {
return
}
}
err = CreateTableWithUser() // 创建用户表
if err != nil {
return
}
err = CreateTableWithArticle() // 创建文章表
if err != nil {
return
}
err = CreateTableWithAlbum() // 创建图片表
if err != nil {
return
}
return
}
//创建用户表
func CreateTableWithUser() (err error) {
sqlStr := CREATE TABLE IF NOT EXISTS users( id INT(4) PRIMARY KEY AUTO\_INCREMENT NOT NULL, username VARCHAR(64), password VARCHAR(64), status INT(4), create\_time INT(10) );
\_, err = ModifyDB(sqlStr)
return
}
// 创建文章表
func CreateTableWithArticle() (err error) {
sqlStr := create table if not exists article( id int(4) primary key auto\_increment not null, title varchar(30), author varchar(20), tags varchar(30), short varchar(255), content longtext, create\_time int(10), status int(4) );
_, err = ModifyDB(sqlStr)
return
}
// 创建图片表
func CreateTableWithAlbum() (err error) {
sqlStr := create table if not exists album( id int(4) primary key auto\_increment not null, filepath varchar(255), filename varchar(64), status int(4), create\_time int(10) );
_, err = ModifyDB(sqlStr)
return
}
// 操作数据库
func ModifyDB(sql string, args …interface{}) (int64, error) {
result, err := db.Exec(sql, args…)
if err != nil {
fmt.Println(err)
return 0, err
}
count, err := result.RowsAffected()
if err != nil {
fmt.Println(err)
return 0, err
}
return count, nil
}
// 查询
func QueryRowDB(dest interface{}, sql string, args …interface{}) error {
return db.Get(dest, sql, args…)
}
// 查询多条
func QueryRows(dest interface{}, sql string, args …interface{}) error {
return db.Select(dest, sql, args…)
}
* redis.go
package dao
import (
“blogweb_gin/config”
“fmt”
“github.com/go-redis/redis”
)
var (
Client *redis.Client
)
// 初始化连接
func InitRedis(cfg *config.RedisConfig) (err error) {
Client = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf(“%s:%d”, cfg.Host, cfg.Port),
Password: cfg.Password, // no password set
DB: cfg.DB, // use default DB
})
\_, err = Client.Ping().Result()
if err != nil {
return err
}
return nil
}
* redis\_key.go
package dao
const (
KeyArticleCount = “blog:article:read:count:%s” // 24小时文章阅读数key eq:blog:article:count:20200315
)
#### logger
* logger.go
package logger
import (
“blogweb_gin/config”
“github.com/gin-gonic/gin”
“github.com/natefinch/lumberjack”
“go.uber.org/zap”
“go.uber.org/zap/zapcore”
“net”
“net/http”
“net/http/httputil”
“os”
“runtime/debug”
“strings”
“time”
)
var Logger *zap.Logger // 我们在项目用都使用这个日志对象
// 初始化Logger
func InitLogger(cfg *config.LogConfig) (err error) {
ws := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge) // 做日志切割第三方包
encoder := getEncoder() // 日志输出的格式
var level = new(zapcore.Level)
err = level.UnmarshalText([]byte(cfg.Level))
if err != nil {
return
}
core := zapcore.NewCore(encoder, ws, level)
Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
return
}
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 时间字符串
encoderConfig.TimeKey = “time”
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder // 函数调用
return zapcore.NewJSONEncoder(encoderConfig) // JSON格式
}
func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: filename,
MaxSize: maxSize,
MaxBackups: maxBackup,
MaxAge: maxAge,
}
return zapcore.AddSync(lumberJackLogger)
}
// 参考:gin-zap 这个库
// GinLogger 接收gin框架默认的日志
func GinLogger(logger *zap.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
query := c.Request.URL.RawQuery
c.Next()
cost := time.Since(start)
logger.Info(path,
zap.Int("status", c.Writer.Status()),
zap.String("method", c.Request.Method),
zap.String("path", path),
zap.String("query", query),
zap.String("ip", c.ClientIP()),
zap.String("user-agent", c.Request.UserAgent()),
zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
zap.Duration("cost", cost),
)
}
}
// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
func GinRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// Check for a broken connection, as it is not really a
// condition that warrants a panic stack trace.
var brokenPipe bool
if ne, ok := err.(*net.OpError); ok {
if se, ok := ne.Err.(*os.SyscallError); ok {
if strings.Contains(strings.ToLower(se.Error()), “broken pipe”) || strings.Contains(strings.ToLower(se.Error()), “connection reset by peer”) {
brokenPipe = true
}
}
}
httpRequest, \_ := httputil.DumpRequest(c.Request, false)
if brokenPipe {
logger.Error(c.Request.URL.Path,
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
// If the connection is dead, we can't write a status to it.
c.Error(err.(error)) // nolint: errcheck
c.Abort()
return
}
if stack {
logger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
zap.String("stack", string(debug.Stack())),
)
} else {
logger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
}
c.AbortWithStatus(http.StatusInternalServerError)
}
}()
c.Next()
}
}
func Debug(msg string, fields …zap.Field) {
Logger.Debug(msg, fields…) // logger.go
}
func Info(msg string, fields …zap.Field) {
Logger.Info(msg, fields…)
}
func Warn(msg string, fields …zap.Field) {
Logger.Warn(msg, fields…)
}
func Error(msg string, fields …zap.Field) {
Logger.Error(msg, fields…)
}
#### logic
* logic.go
package logic
import (
“blogweb_gin/dao”
“blogweb_gin/logger”
“blogweb_gin/models”
“fmt”
“go.uber.org/zap”
“strconv”
“time”
)
// 点击文章,阅读数加 1
// 每次请求/article/show/:id
URL的时候 执行redis命令 zincrby code_language 1 golang
// 给指定文章的阅读数+1
func IncArticleReadCount(articleId string) error {
// zincrby code_language 1 golang
todayStr := time.Now().Format(“20060102”)
key := fmt.Sprintf(dao.KeyArticleCount, todayStr)
return dao.Client.ZIncrBy(key, 1, articleId).Err()
}
// 获取阅读排行榜排名前N的文章
func GetArticleReadCountTopN(n int64) []*models.Article {
// 1. zrevrange Key 0 n-1 从redis取出前n位的文章id
todayStr := time.Now().Format(“20060102”)
key := fmt.Sprintf(dao.KeyArticleCount, todayStr)
idStrs, err := dao.Client.ZRevRange(key, 0, n-1).Result()
if err != nil {
logger.Error(“ZRevRange”, zap.Any(“error”, err))
}
// 2. 根据上一步获取的文章id查询数据库取文章标题 ["3" "1" "5"]
// select id, title from article where id in (3, 1, 5); // 文章的顺序对吗? 不对
// 1. 让MySQL排序
// select id, title from article where id in (3, 1, 5) order by FIND\_IN\_SET(id, (3, 1, 5));
// 2. 查询出来自己排序
// 先准备好要查询的ID Slice
var ids = make([]int64, len(idStrs))
for \_, idStr := range idStrs {
id, err := strconv.ParseInt(idStr, 0, 16)
if err != nil {
logger.Warn("ArticleTopN:strconv.ParseInt failed", zap.Any("error", err))
continue
}
ids = append(ids, id)
}
articleList, err := models.QueryArticlesByIds(ids, idStrs)
if err != nil {
logger.Error("queryArticlesByIds", zap.Any("error", err))
}
return articleList
}
#### middlewares
* auth.go
package middlewares
import (
“github.com/gin-contrib/sessions”
“github.com/gin-gonic/gin”
“net/http”
)
// 最基础的认证校验 只要cookie中带了login_user标识就认为是登录用户
func BasicAuth() func(c *gin.Context) {
return func(c *gin.Context) {
// c代表了请求相关的所有内容,获取当前请求对应的session数据
session := sessions.Default©
loginUser := session.Get("login\_user")
// 请求对应的session中找不到我想要的数据,说明不是登录的用户
if loginUser == nil {
c.Redirect(http.StatusFound, "/login")
c.Abort() // 终止当前请求的处理函数调用链
return // 终止当前处理函数
}
// 根据loginUser 去数据库里用户对象取出来 gob是go语言里面二进制的数据格式
// 如果是一个登录的用户,我就在c上设置两个自定义的键值对!!!
c.Set("is\_login", true)
c.Set("login\_user", loginUser)
c.Next()
}
}
#### models
* album.go
package models
import “blogweb_gin/dao”
type Album struct {
Id int
Filepath string
Filename string
Status int
CreateTime int64 db:"create\_time"
}
// 增加图片
func AddAlbum(album *Album) (int64, error) {
return dao.ModifyDB(“insert into album(filepath,filename,status,create_time)values(?,?,?,?)”,
album.Filepath, album.Filename, album.Status, album.CreateTime)
}
// 获取图片
func QueryAlbum() (dest []*Album, err error) {
sqlStr := “select id,filepath,filename,status,create_time from album”
err = dao.QueryRows(&dest, sqlStr)
return
}
* article.go
package models
import (
“blogweb_gin/dao”
“blogweb_gin/logger”
sql “github.com/jmoiron/sqlx”
“go.uber.org/zap”
“strings”
)
const (
pageSize = 4
)
type Article struct {
Id int json:"id",form:"id"
Title string json:"title",form:"title"
Tags string json:"tags",form:"tags"
Short string json:"short",form:"short"
Content string json:"content",form:"content"
Author string
CreateTime int64 db:"create\_time"
Status int // Status=0为正常,1为删除,2为冻结
}
//-----------数据库操作---------------
// 增加文章
func AddArticle(article *Article) (int64, error) {
return dao.ModifyDB(“insert into article(title,tags,short,content,author,create_time,status) values(?,?,?,?,?,?,?)”,
article.Title, article.Tags, article.Short, article.Content, article.Author, article.CreateTime, article.Status)
}
// 更新文章
func UpdateArticle(article *Article) (int64, error) {
sqlStr := “update article set title=?,tags=?,short=?,content=? where id=?”
return dao.ModifyDB(sqlStr, article.Title, article.Tags, article.Short, article.Content, article.Id)
}
// 删除文章
func DeleteArticle(id string) (int64, error) {
sqlStr := “delete from article where id=?”
return dao.ModifyDB(sqlStr, id)
}
// 查询所有文章
/**
分页查询数据库
limit分页查询语句,
语法:limit m,n
m代表从多少位开始获取,与id值无关
n代表获取多少条数据
总共有10条数据,每页显示4条。 --> 总共需要(10-1)/4+1 页。
问第2页数据是哪些? --> 5,6,7,8 (2-1)*4,4
*/
// 查询数据库文章
func QueryAllArticle() ([]*Article, error) {
sqlStr := “select id,title,tags,short,content,author,create_time from article”
var articleList []*Article
err := dao.QueryRows(&articleList, sqlStr)
if err != nil {
return nil, err
}
return articleList, nil
}
// 根据Page查询文章
func QueryCurrUserArticleWithPage(username string, pageNum int) (articleList []*Article, err error) {
sqlStr := “select id,title,tags,short,content,author,create_time from article where author=? limit ?,?”
articleList, err = queryArticleWithCon(pageNum, sqlStr, username)
if err != nil {
logger.Debug("queryArticleWithCon, ", zap.Any("error", err))
return nil, err
}
logger.Debug("QueryCurrUserArticleWithPage,", zap.Any("articleList", articleList))
return articleList, nil
}
// 根据Id查询文章
func QueryArticleWithId(id string) (article *Article, err error) {
article = new(Article)
sqlStr := “select id,title,tags,short,content,author,create_time from article where id=?”
err = dao.QueryRowDB(article, sqlStr, id)
return
}
// 根据查询条件查询指定页数有的文章
func queryArticleWithCon(pageNum int, sqlStr string, args …interface{}) (articleList []*Article, err error) {
pageNum–
args = append(args, pageNum*pageSize, pageSize)
logger.Debug(“queryArticleWithCon”, zap.Any(“pageNum”, pageNum), zap.Any(“args”, args))
err = dao.QueryRows(&articleList, sqlStr, args…)
logger.Debug(“dao.QueryRows result”, zap.Any(“articleList”, articleList))
return
}
// 查询文章的总条数
func QueryArticleRowNum() (num int, err error) {
err = dao.QueryRowDB(&num, “select count(id) from article”)
return
}
// 根据id查文章 按顺序
func QueryArticlesByIds(ids []int64, idStrs []string) ([]*Article, error) {
// 让MySQL排序
query, args, err := sql.In(“select id, title from article where id in (?) order by FIND_IN_SET(id, ?)”, ids, strings.Join(idStrs, “,”))
if err != nil {
logger.Error(“QueryArticlesByIds”, zap.Any(“error”, err))
return nil, err
}
var dest []\*Article
err = dao.QueryRows(&dest, query, args...)
return dest, err
}
* home.go
package models
import (
“blogweb_gin/logger”
“blogweb_gin/utils”
“fmt”
“go.uber.org/zap”
“strconv”
“strings”
)
type HomeBlockParam struct {
Article *Article
TagLinks []\*TagLink
CreateTimeStr string
//查看文章的地址
Link string
//修改文章的地址
UpdateLink string
DeleteLink string
//记录是否登录
IsLogin bool
}
type TagLink struct {
TagName string
TagUrl string
}
// HomePagination 分页器
type HomePagination struct {
HasPre bool
HasNext bool
ShowPage string
PreLink string
NextLink string
}
//将tags字符串转化成首页模板所需要的数据结构
func createTagsLinks(tagStr string) []*TagLink {
var tagLinks = make([]*TagLink, 0, strings.Count(tagStr, “&”))
tagList := strings.Split(tagStr, “&”)
for _, tag := range tagList {
tagLinks = append(tagLinks, &TagLink{tag, “/?tag=” + tag})
}
return tagLinks
}
// 生成home页面数据结构
func GenHomeBlocks(articleList []*Article, isLogin bool) (ret []*HomeBlockParam) {
// 内存申请一次到位
ret = make([]*HomeBlockParam, 0, len(articleList))
for _, art := range articleList {
// 将数据库model转换为首页模板所需要的model
homeParam := HomeBlockParam{
Article: art,
IsLogin: isLogin,
}
homeParam.TagLinks = createTagsLinks(art.Tags)
homeParam.CreateTimeStr = utils.SwitchTimeStampToStr(art.CreateTime)
homeParam.Link = fmt.Sprintf("/article/show/%d", art.Id)
homeParam.UpdateLink = fmt.Sprintf("/article/update?id=%d", art.Id)
homeParam.DeleteLink = fmt.Sprintf("/article/delete?id=%d", art.Id)
ret = append(ret, &homeParam) // 不再需要动态扩容
}
return
}
// 生成home页面分页数据结构
func GenHomePagination(page int) *HomePagination {
pageObj := new(HomePagination)
// 查询出总的条数
num, \_ := QueryArticleRowNum()
// 从配置文件中读取每页显示的条数
// 计算出总页数
allPageNum := (num-1)/pageSize + 1
pageObj.ShowPage = fmt.Sprintf("%d/%d", page, allPageNum)
//当前页数小于等于1,那么上一页的按钮不能点击
if page <= 1 {
pageObj.HasPre = false
} else {
pageObj.HasPre = true
}
//当前页数大于等于总页数,那么下一页的按钮不能点击
if page >= allPageNum {
pageObj.HasNext = false
} else {
pageObj.HasNext = true
}
pageObj.PreLink = "/?page=" + strconv.Itoa(page-1)
pageObj.NextLink = "/?page=" + strconv.Itoa(page+1)
logger.Debug("GenHomePagination", zap.Any("pageObj", \*pageObj))
return pageObj
}
* user.go
package models
import (
“blogweb_gin/dao”
)
// 定义 模型 与 数据库中的表相对应
type User struct {
Id int
Username string
Password string
Status int // 0 正常状态, 1删除
CreateTime int64
}
//--------------数据库操作-----------------
// 插入新注册的用户
func InsertUser(user *User) (int64, error) {
return dao.ModifyDB(“insert into users(username,password,status,create_time) values (?,?,?,?)”,
user.Username, user.Password, user.Status, user.CreateTime)
}
// 根据用户名查询id
func QueryUserWithUsername(username string) int {
var user User
err := dao.QueryRowDB(&user, “select id from users where username=?”, username)
if err != nil {
return 0
}
return user.Id
}
//根据用户名和密码,查询id
func QueryUserWithParam(username, password string) int {
var user User
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
o
package models
import (
"blogweb\_gin/dao"
)
// 定义 模型 与 数据库中的表相对应
type User struct {
Id int
Username string
Password string
Status int // 0 正常状态, 1删除
CreateTime int64
}
//--------------数据库操作-----------------
// 插入新注册的用户
func InsertUser(user \*User) (int64, error) {
return dao.ModifyDB("insert into users(username,password,status,create\_time) values (?,?,?,?)",
user.Username, user.Password, user.Status, user.CreateTime)
}
// 根据用户名查询id
func QueryUserWithUsername(username string) int {
var user User
err := dao.QueryRowDB(&user, "select id from users where username=?", username)
if err != nil {
return 0
}
return user.Id
}
//根据用户名和密码,查询id
func QueryUserWithParam(username, password string) int {
var user User
[外链图片转存中...(img-5uAOeQby-1715550642008)]
[外链图片转存中...(img-X3nmxlra-1715550642008)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**