書接上回,上一回我們完成了用戶管理頁面的構建,並且通過前端的Vue.js框架動態地獲取表單數據,同時非同步請求後端Iris介面進行入庫操作,過程中使用函數封裝可復用的邏輯。 本回我們將繼續完善用戶管理功能。 唯一索引 雖然在之前的章節中已經完成了用戶添加(註冊)的功能,然而我們忽略了一個重要的細節,那 ...
書接上回,上一回我們完成了用戶管理頁面的構建,並且通過前端的Vue.js框架動態地獲取表單數據,同時非同步請求後端Iris介面進行入庫操作,過程中使用函數封裝可復用的邏輯。 本回我們將繼續完善用戶管理功能。
唯一索引
雖然在之前的章節中已經完成了用戶添加(註冊)的功能,然而我們忽略了一個重要的細節,那就是用戶名(username)應該是全局唯一的欄位,而添加邏輯中並未做唯一性校驗,事實上唯一性校驗有兩種方案,一種是入庫之前做一次查詢,但這樣會浪費一次磁碟的IO操作,另外一種就是通過唯一索引進行攔截操作,這裡我們採用後者,修改model.go文件:
package model
import (
"time"
"github.com/jinzhu/gorm"
)
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
type User struct {
gorm.Model
Username string `gorm:"unique;not null"`
Password string
}
這裡為User結構體的欄位Username添加unique索引,隨後將user表刪除,重新進行資料庫遷移操作:
db.AutoMigrate(&model.User{})
接著查看表結構:
MySQL [irisblog]> SHOW CREATE TABLE user;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user | CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `idx_user_deleted_at` (`deleted_at`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
發現username欄位已經被Gorm添加了唯一索引:UNIQUE KEY `username` (`username`)
隨後修改用戶添加邏輯:
app.Post("/admin/user_action/", func(ctx iris.Context) {
username := ctx.PostValue("username")
password := ctx.PostValue("password")
fmt.Println(username, password)
md5str := mytool.Make_password(password)
user := &model.User{Username: username, Password: md5str}
res := db.Create(user)
if res.Error != nil {
fmt.Println(res.Error)
ret := map[string]string{
"errcode": "1",
"msg": "用戶名不能重覆",
}
ctx.JSON(ret)
return
}
ret := map[string]string{
"errcode": "0",
"msg": "ok",
}
ctx.JSON(ret)
})
這裡res結構體中的Error欄位來返回錯誤,如果Error不等於nil,說明被唯一索引攔截了下來。
隨後構建 ret 字典,聲明錯誤碼和提示信息,然後使用ctx.JSON函數序列化為Json格式返回給前端,註意別忘了用return關鍵字結束邏輯,否則代碼會繼續執行,返回值樣例:
{
errcode: "1",
msg: "用戶名不能重覆"
}
前端接收到返回值之後,可以通過alert方法列印返回值:
submit:function(){
this.myaxios("http://localhost:5000/admin/user_action/","post",{"username":this.username,"password":this.password}).then(data => {
console.log(data)
alert(data.msg);
});
}
如圖所示:
用戶更新與刪除
用戶更新指的是密碼的修改,首先需要構造新密碼的表單變數:
data() {
return {
//用戶名
username: "",
//密碼
password:"",
//用戶列表
userlist:[],
//新密碼
newpass:[]
};
},
註意,這裡是動態表單,因為每一個表單會對應一個用戶:
for(let i=0,l=this.userlist.length;i<l;i++){
this.newpass.push({"value":""})
}
這裡每返回一個用戶,就會為該用戶對應生成一個value欄位。
隨後在迴圈中綁定該欄位:
<table class="gridtable">
<tr>
<th>用戶id</th>
<th>用戶名</th>
<th>新密碼</th>
<th>添加時間</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in userlist">
<td>{{ item.ID }}</td>
<td>{{ item.Username }}</td>
<td><input type="password" v-model="newpass[index].value" /></td>
<td>{{ item.CreatedAt }}</td>
<td><button @click="update(index)">更新密碼</button></td>
</tr>
</table>
如圖所示:
隨後綁定單擊事件,向後端iris傳遞參數:
update:function(i){
console.log(this.userlist[i].ID);
console.log(this.newpass[i].value);
if(this.newpass[i].value == ""){
alert("新密碼不能為空");
return false;
}
this.myaxios("http://localhost:5000/admin/user_action/","put",{"id":this.userlist[i].ID,"password":this.newpass[i].value}).then(data => {
console.log(data)
alert(data.msg);
});
}
這裡傳遞的參數是用戶id以及用戶的新密碼,註意請求方式使用Put。
隨後在後端Iris中添加更新邏輯:
app.Put("/admin/user_action/", func(ctx iris.Context) {
ID := ctx.PostValue("id")
Password := ctx.PostValue("password")
user := &model.User{}
db.First(&user, ID)
user.Password = mytool.Make_password(Password)
db.Save(&user)
ret := map[string]string{
"errcode": "0",
"msg": "更新密碼成功",
}
ctx.JSON(ret)
})
這裡使用Put函數監聽路由,隨後接受參數ID和Password,註意Put和Post方式都採用ctx.PostValue函數來獲取參數。
接著使用db.First(&user, ID)函數來進行主鍵查詢,查出用戶的結構體變數對象,最後調用db.Save函數來存儲更新結果:
MySQL [irisblog]> select * from user where id = 16\G
*************************** 1. row ***************************
id: 16
created_at: 2022-08-22 19:41:40
updated_at: 2022-08-23 15:41:09
deleted_at: NULL
username: admin
password: 202cb962ac59075b964b07152d234b70
1 row in set (0.00 sec)
MySQL [irisblog]>
可以看到,password和updated_at兩個欄位已經同步更新了。
接著是刪除操作,首先前端添加刪除按鈕:
<tr v-for="(item,index) in userlist">
<td>{{ item.ID }}</td>
<td>{{ item.Username }}</td>
<td><input type="password" v-model="newpass[index].value" /></td>
<td>{{ item.CreatedAt }}</td>
<td>
<button @click="update(index)">更新密碼</button>
<button @click="del(index)">刪除用戶</button>
</td>
</tr>
隨後綁定刪除事件:
del:function(i){
var r=confirm("您確定要刪除嗎?");
if (r==true){
this.myaxios("http://localhost:5000/admin/user_action/","delete",{"id":this.userlist[i].ID}).then(data => {
console.log(data)
alert(data.msg);
});
}
},
註意這裡的請求方式是delete。
如圖所示:
隨後編寫後端刪除邏輯:
app.Delete("/admin/user_action/", func(ctx iris.Context) {
ID := ctx.URLParamIntDefault("id", 0)
db.Delete(&model.User{}, ID)
ret := map[string]string{
"errcode": "0",
"msg": "刪除用戶成功",
}
ctx.JSON(ret)
})
這裡使用Delete函數來監聽路由,同時通過ctx.URLParamIntDefault函數獲取前端請求的參數,註意Get和Delete方式獲取參數的請求函數是一致的,同理,Post方式和Put方式也是相同的。
接著使用db.Delete(&model.User{}, ID)函數通過用戶結構體做主鍵刪除。
結語
至此,完成了用戶結構體的增:用戶添加(唯一索引攔截);刪(主鍵刪除);改(動態表單綁定修改密碼);查(結構體單項和批量查詢)。該項目已開源在Github:https://github.com/zcxey2911/IrisBlog ,與君共觴,和君共勉。