Эта статья была впервые опубликована вISLAND
Раньше я использовал базу данных для добавления кратких ответов и функций запроса, сегодня я снова использую базу данных для выполнения некоторых других функций, таких как загрузка и отображение аватаров.
📷Добавить аватар пользователя
Когда пользователь вошел в систему, пользователь текущего пользователя будет отображаться в правом верхнем углу страницы.email
. Ниже делаем кликemail
Войдите на страницу сведений о пользователе и измените информацию.
Сначала улучшите внутренний интерфейс. со стороны пользователяid
чтобы получить данные пользователя, и в то же время мы написали страницу с ошибкойerror.tmpl
, чтобы отобразить сообщение об ошибке.
userHandler.go
func UserProfile(context *gin.Context) {
id := context.Query("id")
var user model.UserModel
i, err := strconv.Atoi(id)
u, e := user.QueryById(i)
if e != nil || err != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": e,
})
}
context.HTML(http.StatusOK, "user_profile.tmpl", gin.H{
"user": u,
})
}
Получите идентификатор, переданный внешним интерфейсом в коде, черезstrconv.Atoi()
Преобразование типа String в тип int.user.QueryById()
Наш метод - это метод, используемый для идентификатора запроса.
в ходе выполненияQueryById
метод, мы должныuser
Структура и база данных делают простую модификацию.
type UserModel struct {
Id int `form:"id"`
Email string `form:"email" binding:"email"`
Password string `form:"password" `
Avatar sql.NullString
}
Добавляем новую строкуAvatar
, типsql.NullString
. Зачемsql.NullString
? Поскольку поле в нашей базе данных изначальноnull
,а такжеstring
тип не приемлемnull
тип, поэтому мы можем использовать толькоNullString
иди прямоnull
Строки обрабатываются.
При этом для добавления в базу добавить новый столбецavatar
поле.
база данных после модификации
create table user
(
id int auto_increment
primary key,
email varchar(30) not null,
password varchar(40) not null,
avatar varchar(100) null
)
comment '用户表';
После завершения предыдущей работы по модификации можно заняться остальными.
🕵️Получить информацию о пользователе
существуетuserModel.go
Получить информацию о пользователе изQueryById
метод
func (user *UserModel) QueryById(id int) (UserModel, error) {
u := UserModel{}
row := initDB.Db.QueryRow("select * from user where id = ?;", id)
e := row.Scan(&u.Id, &u.Email, &u.Password, &u.Avatar)
if e != nil {
log.Panicln(e)
}
return u, e
}
Этот метод в основном аналогичен методу запроса пользователей по почтовому ящику в предыдущем разделе.
Как только этот метод завершен, мы можем добавить наш маршрут.
userRouter.GET("/profile/", handler.UserProfile)
На этом фоновая работа завершена, осталось доработать интерфейс.
Первое, что нужно сделать, это переписать и разделить блоки внешнего кода.
template
|
|-error.tmpl
|-header.tmpl
|-index.tmpl
|-login.tmpl
|-nav.tmpl
|-user_profile.tmpl
мы будемindex
серединаhead
Код в разделе ярлыков перемещен вheader
в, будетheader
Исходный код был перемещен вnav.tmpl
середина.
index.tmpl
{{template "header"}}
<header>
{{template "nav" .}}
</header>
<main>
</main>
header.tmpl
{{ define "header" }}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="/statics/css/bootstrap.min.css">
<link rel="stylesheet" href="/statics/css/bootstrap-grid.min.css">
<link rel="stylesheet" href="/statics/css/bootstrap-reboot.min.css">
<script src="/statics/js/jquery.min.js" rel="script"></script>
<script src="/statics/js/Popper.js" rel="script"></script>
<script rel="script" src="/statics/js/bootstrap.bundle.js"></script>
<title>Gin Hello</title>
</head>
{{end}}
существуетnav.tmpl
середина
{{ if .email }}
<ul class="navbar-nav ">
<li class="nav-item">
<a class="nav-link" href="/user/profile?id={{.id}}">{{ .email }}</a>
</li>
</ul>
{{ else }}
<ul class="navbar-nav ">
<li class="nav-item">
<a class="nav-link" data-toggle="modal" data-target="#login-modal">登录</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="modal" data-target="#register-modal">注册</a>
</li>
</ul>
{{end}}
через путь/user/profile?id={{ .id }}
будетid
Бэкэнд передачи данных.
Когда данные будут получены успешно, они перейдут кuser_profile.tmpl
середина
user_profile.tmpl
{{template "header"}}
{{template "nav"}}
<div class="container">
<div class="row">
<div class="col-sm">
<div>
<img src="{{ .user.Avatar.String }}" alt="avatar" class="rounded-circle">
</div>
</div>
<div class="col-sm">
<form method="post" action="/user/update" enctype="multipart/form-data">
<div class="form-group" hidden>
<label for="user-id">id</label>
<input type="text" id="user-id"
name="id"
value="{{ .user.Id }}">
</div>
<div class="form-group">
<label for="user-email">Email</label>
<input type="email" class="form-control" id="user-email" aria-describedby="emailHelp"
name="email"
readonly
placeholder="Enter email"
value="{{ .user.Email }}">
</div>
<div class="form-group">
<label for="user-password">密码</label>
<input type="password" class="form-control" id="user-password" placeholder="密码" name="password"
value="{{.user.Password}}">
</div>
<div class="form-group">
<label for="user-avatar">上传头像</label>
<input type="file" class="form-control-file" id="user-avatar" name="avatar-file">
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
<div class="col-sm"></div>
</div>
</div>
Электронная почта на этой странице не может быть отредактирована, пароль может быть изменен, а аватар может быть загружен.
На этом наша страница готова.
🛫 Загрузить аватар
После заполнения основной страницы пришло время загрузить аватар.
существуетuserHandler.go
Добавить кUpdateUserProfile
метод
func UpdateUserProfile(context *gin.Context) {
var user model.UserModel
if err := context.ShouldBind(&user); err != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": err.Error(),
})
log.Panicln("绑定发生错误 ", err.Error())
}
file, e := context.FormFile("avatar-file")
if e != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": e,
})
log.Panicln("文件上传错误", e.Error())
}
}
по привязке данныхid
email
Привязать с паролем, затем пройтиcontext.FormFile()
Получить данные файла.
Данные файла можно получить, затем полученный файл следует сохранить.
Сначала напишите класс инструмента, чтобы получить корневой путь нашего проекта.
создать новыйutils
папка,utils
ЧжунсинpathUtils.go
package utils
import (
"log"
"os"
"os/exec"
"strings"
)
func RootPath() string {
s, err := exec.LookPath(os.Args[0])
if err != nil {
log.Panicln("发生错误",err.Error())
}
i := strings.LastIndex(s, "\\")
path := s[0 : i+1]
return path
}
Напишите класс инструмента, чтобы мы могли использовать его напрямую в будущем.
// 省略部分代码
path := utils.RootPath()
path = path + "avatar\\"
e = os.MkdirAll(path, os.ModePerm)
if e != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": e,
})
log.Panicln("无法创建文件夹", e.Error())
}
fileName := strconv.FormatInt(time.Now().Unix(), 10) + file.Filename
e = context.SaveUploadedFile(file, path+fileName)
if e != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": e,
})
log.Panicln("无法保存文件", e.Error())
}
Получением текущего времени обеспечивается уникальность изображения, и загруженное изображение не будет перезаписано из-за того же имени.
Вот вопрос для размышления.Так как мы загрузили аватар, нам нужно отобразить его на странице.Отображению аватара нужно получить адрес, так как же получить адрес после сохранения изображения?
При настройке маршрута ранее мы один раз задали каталог статического файла, и изображение аватара также является статическим файлом, поэтому нам нужно снова установить каталог загрузки.
initRouter.go
router.StaticFS("/avatar", http.Dir(utils.RootPath()+"avatar/"))
Мы отображаем путь, который мы загрузили, как/avatar
После этого мы можем получить доступ к ресурсам, изменив путь.
Завершите наш окончательный код
avatarUrl := "http://localhost:8080/avatar/" + fileName
user.Avatar = sql.NullString{String: avatarUrl}
e = user.Update(user.Id)
if e != nil {
context.HTML(http.StatusOK, "error.tmpl", gin.H{
"error": e,
})
log.Panicln("数据无法更新", e.Error())
}
context.Redirect(http.StatusMovedPermanently, "/user/profile?id="+strconv.Itoa(user.Id))
Когда изображение сообщает об ошибке, мы снова перенаправляем на/user/profile
Routing, на этой странице также будут отображаться наши новые данные.
✍Резюме
Благодаря обучению в этой главе некоторые операции с базой данных используются снова, а также изучается загрузка файлов и улучшается отображение статических файлов на странице.
👩💻 Код для этой главы
историческая статья
Джин (1): Привет
Джин (2): маршрутизатор маршрутизации
Джин (три): шаблон tmpl
Джин (четыре): проверка отправки формы и привязка модели
Джин (5): подключиться к MySQL
Джин (шесть): загрузка файла
Джин (семь): использование и определение промежуточного программного обеспечения
Джин (8): использование файлов cookie
Личный публичный аккаунт
Я только недавно подал заявку на публичный аккаунт, и в будущем статьи будут отправляться синхронно.Приглашаю всех обратить внимание