一.封装上传图片方法
在models/tools.go文件下封装一个上传图片的方法
//图片上传
func UploadImg(c *gin.Context, picName string) (string, error) {
//1.获取上传文件
file, err := c.FormFile(picName)
//判断上传文件上否存在
if err != nil { //说明上传文件不存在
return "", nil
}
//2.获取后缀名,判断后缀是否正确: .jpg,.png,.gif,.jpeg
extName := path.Ext(file.Filename)
//设置后缀map
allowExtMap := map[string]bool{
".jpg": true,
".png": true,
".gif": true,
".jpeg": true,
}
//判断后缀是否合法
if _, ok := allowExtMap[extName]; !ok {
return "", errors.New("文件后缀名不合法")
}
//3.创建图片保存目录 ./static/upload/20230203
//获取日期
day := GetDay()
//拼接目录
dir := "./static/upload/" + day
//创建目录:MkdirAll 目录不存在,会一次性创建多层
err = os.MkdirAll(dir, 0666)
if err != nil {
return "", err
}
//4.生成文件名称和文件保存目录: models.GetUnixNano() 获取时间戳(int64) 纳秒:防止速度过快而上传图片失败; strconv.FormatInt() 把时间戳(int64)转换成字符串
filename := strconv.FormatInt(GetUnixNano(), 10) + extName
//5.执行上传
dst := path.Join(dir, filename)
//上传文件到指定目录
c.SaveUploadedFile(file, dst)
return dst, nil
}
//获取年月日
func GetDay() string {
template := "20060102"
return time.Now().Format(template)
}
二.轮播图的增删改查
-
创建轮播图模型
在models目录下创建focus.go轮播图模型
package models
//轮播图
type Focus struct {
Id int
Title string
FocusType int // 1 网站, 2 app, 3 小程序
FocusImg string
Link string
Sort int
Status int
AddTime int
}
func (Focus) TableName() string {
return "focus"
}
2.创建轮播图控制器
在controllers/admin下创建FocusController.go轮播图控制器
package admin
import (
"fmt"
"github.com/gin-gonic/gin"
"goshop/models"
"net/http"
"os"
"strings"
)
type FocusController struct {
BaseController
}
func (con FocusController) Index(c *gin.Context) {
//获取轮播图列表
focusList := []models.Focus{}
models.DB.Find(&focusList)
c.HTML(http.StatusOK, "admin/focus/index.html", gin.H{
"focusList": focusList,
})
}
func (con FocusController) Add(c *gin.Context) {
c.HTML(http.StatusOK, "admin/focus/add.html", gin.H{})
}
func (con FocusController) DoAdd(c *gin.Context) {
//获取请求的表单数据
title := strings.Trim(c.PostForm("title"), " ")
focusType, err1 := models.Int(c.PostForm("focus_type"))
link := strings.Trim(c.PostForm("link"), " ")
sort, err2 := models.Int(c.PostForm("sort"))
status, err3 := models.Int(c.PostForm("status"))
if err1 != nil || err3 != nil {
con.Error(c, "非法请求", "/admin/focus/add")
return
}
if err2 != nil {
con.Error(c, "请输入正确的排序值", "/admin/focus/add")
return
}
//文件上传操作
focusImgSrc, err := models.UploadImg(c, "focus_img")
if err != nil {
con.Error(c, "图片上传失败", "/admin/focus/add")
return
}
//实例化focus模型
focus := models.Focus{
Title: title,
FocusType: focusType,
FocusImg: focusImgSrc,
Link: link,
Sort: sort,
Status: status,
AddTime: int(models.GetUnix()),
}
err = models.DB.Create(&focus).Error
if err != nil {
con.Error(c, "增加轮播图失败", "/admin/focus/add")
return
}
con.Success(c, "增加轮播图成功", "/admin/focus")
}
func (con FocusController) Edit(c *gin.Context) {
//获取要修改的轮播图id
id, err := models.Int(c.Query("id"))
if err != nil {
con.Error(c, "传入数据错误", "/admin/focus")
return
}
focus := models.Focus{Id: id}
models.DB.Find(&focus)
c.HTML(http.StatusOK, "admin/focus/edit.html", gin.H{
"focus": focus,
})
}
func (con FocusController) DoEdit(c *gin.Context) {
//获取请求的表单数据
id, err := models.Int(c.PostForm("id"))
title := strings.Trim(c.PostForm("title"), " ")
focusType, err1 := models.Int(c.PostForm("focus_type"))
link := strings.Trim(c.PostForm("link"), " ")
sort, err2 := models.Int(c.PostForm("sort"))
status, err3 := models.Int(c.PostForm("status"))
if err != nil || err1 != nil || err3 != nil {
con.Error(c, "非法请求", "/admin/focus")
return
}
if err2 != nil {
con.Error(c, "请输入正确的排序值", "/admin/focus/edit?id="+models.String(id))
return
}
//文件上传操作
focusImgSrc, err11 := models.UploadImg(c, "focus_img")
if err11 != nil {
con.Error(c, "图片上传失败", "/admin/focus/edit?id="+models.String(id))
return
}
focus := models.Focus{Id: id}
models.DB.Find(&focus)
focus.Title = title
focus.FocusType = focusType
focus.Status = status
focus.Sort = sort
focus.Link = link
if focusImgSrc != "" {
focus.FocusImg = focusImgSrc
}
err4 := models.DB.Save(&focus).Error
if err4 != nil {
con.Error(c, "修改轮播图失败", "/admin/focus/edit?id="+models.String(id))
return
}
con.Success(c, "修改轮播图成功", "/admin/focus")
}
//删除
func (con FocusController) Delete(c *gin.Context) {
//获取提交的表单数据
id, err := models.Int(c.Query("id"))
if err != nil {
con.Error(c, "传入数据错误", "/admin/focus")
return
}
//查询数据是否存在
focus := models.Focus{Id: id}
models.DB.Find(&focus)
//需要对文件进行删除吗?
if focus.FocusImg != "" {
fmt.Println(focus.FocusImg)
os.Remove(focus.FocusImg)
}
err = models.DB.Delete(&focus).Error
if err != nil {
con.Error(c, "删除数据失败", "/admin/focus")
return
}
con.Success(c, "删除数据成功", "/admin/focus")
}
3.创建轮播图html
在templates/admin/focus下创建轮播图相关html
index.html
{{ define "admin/focus/index.html" }}
{{ template "admin/public/page_header.html" .}}
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr class="th">
<th>轮播图名称</th>
<th>轮播图类型</th>
<th>轮播图图片</th>
<th>跳转地址</th>
<th class="text-center">排序</th>
<th class="text-center">状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{{range $key,$value := .focusList}}
<tr>
<td>{{$value.Title}}</td>
<td>
{{if eq $value.FocusType 1}}
网站
{{else if eq $value.FocusType 2}}
APP
{{else}}
小程序
{{end}}
</td>
<td>
{{if ne $value.FocusImg ""}}
<img src="/{{$value.FocusImg}}" width="200" />
{{end}}
</td>
<td>{{$value.Link}}</td>
<td class="text-center">
<span class="chSpanNum" data-id="{{$value.Id}}" data-table="focus" data-field="sort">{{$value.Sort}}</span>
</td>
<td align="center">
{{if eq $value.Status 1}}
<img class="chStatus" data-id="{{$value.Id}}" data-table="focus" data-field="status" src="/static/admin/images/yes.gif" />
{{else}}
<img class="chStatus" data-id="{{$value.Id}}" data-table="focus" data-field="status" src="/static/admin/images/no.gif" />
{{end}}
</td>
<td class="text-center">
<a href="/admin/focus/edit?id={{$value.Id}}" />修改</a>
<a class="delete" href="/admin/focus/delete?id={{$value.Id}}" />删除</a>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</body>
</html>
{{end}}
add.html
{{ define "admin/focus/add.html" }}
{{ template "admin/public/page_header.html" .}}
<div class="panel panel-default">
<div class="panel-heading">
增加轮播图
</div>
<div class="panel-body">
<div class="table-responsive input-form">
<form action="/admin/focus/doAdd" method="post" enctype="multipart/form-data">
<ul>
<li> 名 称: <input type="text" name="title"/></li>
<li> 类 型:
<select name="focus_type" id="type">
<option value="1">网站</option>
<option value="2">APP</option>
<option value="3">小程序</option>
</select>
</li>
<li> 跳转地址: <input type="text" name="link"/></li>
<li> 轮 播 图: <input type="file" name="focus_img"/></li>
<li> 排 序: <input type="text" name="sort" value="100"/></li>
<li> 状 态:
<input type="radio" name="status" checked value="1" id="a"/> <label for="a">显示</label>
<input type="radio" name="status" value="0" id="b"/><label for="b">隐藏</label> </li>
<li>
<br/>
<button type="submit" class="btn btn-primary">提交</button>
</li>
</ul>
</form>
</div>
</div>
</div>
</body>
</html>
{{end}}
edit.html
{{ define "admin/focus/edit.html" }}
{{ template "admin/public/page_header.html" .}}
<div class="panel panel-default">
<div class="panel-heading">
修改轮播图
</div>
<div class="panel-body">
<div class="table-responsive input-form">
<form action="/admin/focus/doEdit" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{.focus.Id}}"/>
<ul>
<li> 名 称: <input type="text" name="title" value="{{.focus.Title}}"/></li>
<li> 类 型:
<select name="focus_type" id="type">
<option {{if eq .focus.FocusType 1}} selected {{end}} value="1">网站</option>
<option {{if eq .focus.FocusType 2}} selected {{end}} value="2">APP</option>
<option {{if eq .focus.FocusType 3}} selected {{end}} value="3">小程序</option>
</select>
</li>
<li> 跳转地址: <input type="text" name="link" value="{{.focus.Link}}"/></li>
<li> 轮 播 图:
<input type="file" name="focus_img" />
{{if ne .focus.FocusImg ""}}
<img src="/{{.focus.FocusImg}}" width="200" />
{{end}}
</li>
<li> 排 序: <input type="text" name="sort" value="{{.focus.Sort}}"/></li>
<li> 状 态:
<input type="radio" name="status" {{if eq .focus.Status 1}} checked {{end}} value="1" id="a"/> <label for="a">显示</label>
<input type="radio" name="status" {{if eq .focus.Status 0}} checked {{end}} value="0" id="b"/><label for="b">隐藏</label> </li>
<li>
<br/>
<button type="submit" class="btn btn-primary">提交</button>
</li>
</ul>
</form>
</div>
</div>
</div>
</body>
</html>
{{end}}
4.配置路由
在routes/adminRouters.go下配置轮播图路由
package routers
import (
"goshop/controllers/admin"
"goshop/middlewares"
"github.com/gin-gonic/gin"
)
//设置admin后台路由
func AdminRoutersInit(r *gin.Engine) {
//路由分组: 配置全局中间件:middlewares.InitMiddleware
adminRouters := r.Group("/admin", middlewares.InitAdminAuthMiddleware)
{
//后台首页
adminRouters.GET("/", admin.MainController{}.Index)
adminRouters.GET("/welcome", admin.MainController{}.Welcome)
//登录页面
adminRouters.GET("/login", admin.LoginController{}.Index) // 实例化控制器,并访问其中方法
adminRouters.POST("/doLogin", admin.LoginController{}.DoIndex)
adminRouters.GET("/loginOut", admin.LoginController{}.LoginOut)
//验证码
adminRouters.GET("/captcha", admin.LoginController{}.Captcha)
//管理员路由
adminRouters.GET("/manager", admin.ManagerController{}.Index)
adminRouters.GET("/manager/add", admin.ManagerController{}.Add)
adminRouters.POST("/manager/doAdd", admin.ManagerController{}.DoAdd)
adminRouters.GET("/manager/edit", admin.ManagerController{}.Edit)
adminRouters.POST("/manager/doEdit", admin.ManagerController{}.DoEdit)
adminRouters.GET("/manager/delete", admin.ManagerController{}.Delete)
//轮播图路由
adminRouters.GET("/focus", admin.FocusController{}.Index)
adminRouters.GET("/focus/add", admin.FocusController{}.Add)
adminRouters.POST("/focus/doAdd", admin.FocusController{}.DoAdd)
adminRouters.GET("/focus/edit", admin.FocusController{}.Edit)
adminRouters.POST("/focus/doEdit", admin.FocusController{}.DoEdit)
adminRouters.GET("/focus/delete", admin.FocusController{}.Delete)
//角色路由
adminRouters.GET("/role", admin.RoleController{}.Index)
adminRouters.GET("/role/add", admin.RoleController{}.Add)
adminRouters.POST("/role/doAdd", admin.RoleController{}.DoAdd)
adminRouters.GET("/role/edit", admin.RoleController{}.Edit)
adminRouters.POST("/role/doEdit", admin.RoleController{}.DoEdit)
adminRouters.GET("/role/delete", admin.RoleController{}.Delete)
adminRouters.GET("/role/auth", admin.RoleController{}.Auth)
adminRouters.POST("/role/doAuth", admin.RoleController{}.DoAuth)
//权限路由
adminRouters.GET("/access", admin.AccessController{}.Index)
adminRouters.GET("/access/add", admin.AccessController{}.Add)
adminRouters.POST("/access/doAdd", admin.AccessController{}.DoAdd)
adminRouters.GET("/access/edit", admin.AccessController{}.Edit)
adminRouters.POST("/access/doEdit", admin.AccessController{}.DoEdit)
adminRouters.GET("/access/delete", admin.AccessController{}.Delete)
}
}
5.界面展示如下
列表
新增
编辑
删除
三.封装公共Api接口
封装公共Api接口,实现公共的ajax: 异步修改状态, 异步修改排序
以轮播图为例:
当点击状态图标时,修改状态图标(正常/失效)
当点击排序栏时,生成焦点文本框,输入排序数字,鼠标点击其他地方,失去焦点时,发送请求,修改排序
-
index.html页面修改排序,状态相关代码
{{ define "admin/focus/index.html" }}
{{ template "admin/public/page_header.html" .}}
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr class="th">
<th>轮播图名称</th>
<th>轮播图类型</th>
<th>轮播图图片</th>
<th>跳转地址</th>
<th class="text-center">排序</th>
<th class="text-center">状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{{range $key,$value := .focusList}}
<tr>
<td>{{$value.Title}}</td>
<td>
{{if eq $value.FocusType 1}}
网站
{{else if eq $value.FocusType 2}}
APP
{{else}}
小程序
{{end}}
</td>
<td>
{{if ne $value.FocusImg ""}}
<img src="/{{$value.FocusImg}}" width="200" />
{{end}}
</td>
<td>{{$value.Link}}</td>
<td class="text-center">
<!-- 排序 -->
<span class="chSpanNum" data-id="{{$value.Id}}" data-table="focus" data-field="sort">{{$value.Sort}}</span>
</td>
<td align="center">
<!-- 状态 -->
{{if eq $value.Status 1}}
<img class="chStatus" data-id="{{$value.Id}}" data-table="focus" data-field="status" src="/static/admin/images/yes.gif" />
{{else}}
<img class="chStatus" data-id="{{$value.Id}}" data-table="focus" data-field="status" src="/static/admin/images/no.gif" />
{{end}}
</td>
<td class="text-center">
<a href="/admin/focus/edit?id={{$value.Id}}" />修改</a>
<a class="delete" href="/admin/focus/delete?id={{$value.Id}}" />删除</a>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</body>
</html>
{{end}}
-
static/admin/js/base.js增加修改排序,状态的方法
$(function () {
baseApp.init();
//当窗口重置时,重新计算窗口高度
$(window).resize(function () {
baseApp.resizeIframe();
})
})
var baseApp = {
init: function () {
this.initAside()
this.confirmDelete()
this.resizeIframe()
this.changeStatus()
this.changeNum()
},
initAside: function () { //左侧菜单栏隐藏显示子栏
$(".aside h4").click(function () {
$(this).sibling("ul").slideToggle();
})
},
resizeIframe: function() { // 设置iframe高度
$("rightMain").height($(window).height()-80)
},
confirmDelete: function () { // 删除提示
$(".delete").click(function () {
var flag = confirm("确定要删除该项?")
return flag
})
},
changeStatus: function () { // 改变状态
//点击事件
$(".chStatus").click(function () {
var $this = $(this);
var id = $this.attr("data-id");
var table = $this.attr("data-table");
var field = $this.attr("data-field");
console.log(field);
$.get("/admin/changeStatus", {id: id, table: table, field: field}, function (res) {
if (res.success) {
if ($this.attr("src").indexOf("yes") != -1){
$this.attr("src", "/static/admin/images/no.gif");
} else {
$this.attr("src", "/static/admin/images/yes.gif");
}
} else {
alert(res.message);
}
})
})
},
changeNum: function () { // 修改排序数字
/*
1、获取el里面的值 var spanNum=$(this).html()
2、创建一个input的dom节点 var input=$("<input value='' />");
3、把input放在el里面 $(this).html(input);
4、让input获取焦点 给input赋值 $(input).trigger('focus').val(val);
5、点击input的时候阻止冒泡
$(input).click(function(e){
e.stopPropagation();
})
6、鼠标离开的时候给span赋值,并触发ajax请求
$(input).blur(function(){
var inputNum=$(this).val();
spanEl.html(inputNum);
触发ajax请求
})
*/
$(".chSpanNum").click(function () {
// 1、获取el 以及el里面的属性值
var id = $(this).attr("data-id")
var table = $(this).attr("data-table")
var field = $(this).attr("data-field")
var num = $(this).html().trim()
var spanEl = $(this)
//2、创建一个input的dom节点 var input=$("<input value='' />");
var input = $("<input style='width:60px' value='' />");
// 3、把input放在el里面 $(this).html(input);
$(this).html(input);
//4、让input获取焦点 给input赋值 $(input).trigger('focus').val(val);
$(input).trigger("focus").val(num);
//5、点击input的时候阻止冒泡
$(input).click(function (e) {
e.stopPropagation();
})
//6、鼠标离开的时候给span赋值,并触发ajax请求
$(input).blur(function () {
var inputNum = $(this).val()
spanEl.html(inputNum)
//触发ajax请求
$.get("/admin/changeNum", { id: id, table: table, field: field, num: inputNum }, function (response) {
if (response.success) {
alert(response.message)
} else {
alert(response.message)
}
})
})
})
}
}
-
封装公共api接口方法
在controllers/MainController.go文件中封装公共方法:改变状态,改变排序
//公共方法:改变表状态的
func (con MainController) ChangeStatus(c *gin.Context) {
id, err := models.Int(c.Query("id"))
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "id参数错误",
})
return
}
table := c.Query("table")
field := c.Query("field")
//修改
err1 := models.DB.Exec("update "+ table +" set " + field + " = ABS(" + field + " - 1) where id = ?", id).Error
if err1 != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "修改失败,请重试",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "操作成功",
})
}
//公共方法:改变排序数字
func (con MainController) ChangeNum(c *gin.Context) {
id, err := models.Int(c.Query("id"))
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "id参数错误",
})
return
}
table := c.Query("table")
field := c.Query("field")
num := c.Query("num")
//修改
err1 := models.DB.Exec("update "+ table +" set " + field + " = " + num + " where id = ?", id).Error
if err1 != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "修改失败,请重试",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "操作成功",
})
}
4.配置路由
在routers/adminRouters.go中配置修改状态以及修改排序的路由
adminRouters.GET("/changeStatus", admin.MainController{}.ChangeStatus)
adminRouters.GET("/changeNum", admin.MainController{}.ChangeNum)
[上一节][golang gin框架] 14.Gin 商城项目-RBAC管理