草庐IT

彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-完善用户管理EP04

刘悦的技术博客 2023-03-28 原文

书接上回,上一回我们完成了用户管理页面的构建,并且通过前端的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 ,与君共觞,和君共勉。

有关彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-完善用户管理EP04的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  5. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  6. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  7. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  8. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  9. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  10. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

随机推荐