Iris搭建一个完整的go web项目过程——管理员登录功能开发

目录

一、项目结构

二、数据库

1、管理员表:admin

三、服务器配置

1、配置端口等信息:config.json

2、读取配置文件并加载服务器配置:config.go

3、创建及配置数据库引擎:engine.go

四、后端

1、管理员结构体定义:admin.go

2、管理员控制器定义:admin_controller.go

3、管理员数据提供模块定义:admin_service.go

4、控制器绑定,路由处理 main.go

五、浏览器Post请求测试(使用postman)

1、请求设置及结果

2、处理过程分析


一、项目结构

二、数据库

1、管理员表:admin

CREATE TABLE `admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `admin_name` varchar(32) DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  `status` int(11) NOT NULL DEFAULT '0',
  `avatar` varchar(255) DEFAULT NULL,
  `pwd` varchar(255) DEFAULT NULL,
  `city_name` varchar(12) DEFAULT NULL,
  `city_id` int(11) DEFAULT NULL,
  `admin_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_admin_city_id` (`city_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of admin
-- ----------------------------
INSERT INTO `admin` VALUES ('1', 'davie', '2020-05-03 17:05:27', '1', '', '123', '湖北武汉', '1', null);
INSERT INTO `admin` VALUES ('2', 'lili', '2020-05-21 17:05:36', '2', '2', '123', '湖北随州', '2', null);

说明:id为自增主键

三、服务器配置

1、配置端口等信息:config.json

{
  "app_name": "CmsProject",
  "port": "9000",
  "static_path": "/manage/static",
  "mode": "dev"
}

2、读取配置文件并加载服务器配置:config.go

type AppConfig struct {
	AppName    string `json:"app_name"`
	Port       string `json:"port"`
	StaticPath string `json:"static_path"`
	Mode       string `json:"mode"`
}

var ServConfig AppConfig

//初始化服务器配置
func InitConfig()*AppConfig  {
	file,err := os.Open("config.json")
	if err != nil {
		panic(err.Error())
	}
	decoder := json.NewDecoder(file)
	conf := AppConfig{}
	err = decoder.Decode(&conf)
	if err != nil {
		panic(err.Error())
	}
	return &conf
}

3、创建及配置数据库引擎:engine.go

import (
	_ "github.com/go-sql-driver/mysql" //不能忘记导入
	"github.com/go-xorm/xorm"
	"irisDemo/CmsProject/model"
)

/**
 * 实例化数据库引擎方法:mysql的数据引擎
 */
func NewMysqlEngine() *xorm.Engine {

	//数据库引擎
	engine, err := xorm.NewEngine("mysql", "root:123456@/iris?charset=utf8")

	//根据实体创建表
	//err = engine.CreateTables(new(model.Admin))

	//同步数据库结构:主要负责对数据结构实体同步更新到数据库表
	/**
	 * 自动检测和创建表,这个检测是根据表的名字
	 * 自动检测和新增表中的字段,这个检测是根据字段名,同时对表中多余的字段给出警告信息
	 * 自动检测,创建和删除索引和唯一索引,这个检测是根据索引的一个或多个字段名,而不根据索引名称。因此这里需要注意,如果在一个有大量数据的表中引入新的索引,数据库可能需要一定的时间来建立索引。
	 * 自动转换varchar字段类型到text字段类型,自动警告其它字段类型在模型和数据库之间不一致的情况。
	 * 自动警告字段的默认值,是否为空信息在模型和数据库之间不匹配的情况
	 */
	//Sync2是Sync的基础上优化的方法
	err = engine.Sync2(
		new(model.Admin),
	)

	if err != nil {
		panic(err.Error())
	}

	//设置显示sql语句
	engine.ShowSQL(true)
	engine.SetMaxOpenConns(10)

	return engine
}

四、后端

1、管理员结构体定义:admin.go

//定义管理员结构体
type Admin struct {
	//如果field名称为Id,而且类型为int64,并没有定义tag,则会被xorm视为主键,并且拥有自增属性
	AdminId    int64     `xorm:"pk autoincr 'id'"  json:"id"` // 主键 自增
	AdminName  string    `xorm:"varchar(32)" json:"admin_name"`
	CreateTime time.Time `xorm:"DateTime" json:"create_time"`
	Status     int64     `xorm:"default 0" json:"status"`
	Avatar     string    `xorm:"varchar(255)" json:"avatar"`
	Pwd        string    `xorm:"varchar(255)" json:"pwd"`      //管理员密码
	CityName   string    `xorm:"varchar(12)" json:"city_name"` //管理员所在城市名称
	CityId     int64     `xorm:"index" json:"city_id"`
	//City       *City     `xorm:"- <- ->"` //所对应的城市结构体(基础表结构体)
}

2、管理员控制器定义:admin_controller.go

我们使用mvc包模式来进行功能开发,在进行了结构体定义以后,我们接着定义控制器。控制器负责来完成我们请求的逻辑流程控制,是我们功能开发的核心枢纽。在AdminController定义中,包含iris.Context上下文处理对象用于数据功能处理的管理员模块功能实现AdminService,还有用于session管理的对象。定义PostLogin方法来处理用户登陆请求

/**
 * 管理员控制器
 */
type AdminController struct {
	//iris框架自动为每个请求都绑定上下文对象:可作为接受参数
	Ctx iris.Context

	//admin功能实体:引入Service接口
	Service service.AdminService

	//session对象:存储session信息
	Session *sessions.Session
}

const (
	ADMIN = "admin"   //管理员登录成功后存储的session信息的key
)

//将发送请求的字段映射为指定字段
type AdminLogin struct {
	UserName string `json:"user_name"`
	Password string `json:"password"`
}

/**
 * 管理员登录功能:json请求格式
 * 接口:/admin/login
 */
func (ac *AdminController) PostLogin(context iris.Context) mvc.Result {

	var adminLogin AdminLogin
	ac.Ctx.ReadJSON(&adminLogin)  //自动将请求的json字符串映射为AdminLogin结构体

	//数据参数检验
	if adminLogin.UserName == "" || adminLogin.Password == "" {
		return mvc.Response{
			Object: map[string]interface{}{
				"status":  "0",
				"success": "登录失败",
				"message": "用户名或密码为空,请重新填写后尝试登录",
			},
		}
	}

	//根据用户名、密码到数据库中查询对应的管理信息
	admin, exist := ac.Service.GetByAdminNameAndPassword(adminLogin.UserName, adminLogin.Password)

	//管理员不存在
	if !exist {
		return mvc.Response{
			Object: map[string]interface{}{
				"status":  "1",
				"success": "登录失败",
				"message": "用户名或者密码错误,请重新登录",
			},
		}
	}

	//管理员存在 设置session
	userByte, _ := json.Marshal(admin)
	ac.Session.Set(ADMIN, userByte)

	return mvc.Response{
		Object: map[string]interface{}{
			"status":  "1",
			"success": "登录成功",
			"message": "管理员登录成功",
		},
	}
}

3、管理员数据提供模块定义:admin_service.go

//定义AdminService接口
type AdminService interface {
	//通过管理员用户名+密码 获取管理员实体 如果查询到,返回管理员实体,并返回true
	//否则 返回 nil ,false
	GetByAdminNameAndPassword(username, password string) (models.Admin, bool)
}

//在我们实际的开发过程中,我们往往将数据提供服务模块设计成接口,这样设计的目的是接口定义和具体
//的功能编程实现了分离,有助于我们在不同的实现方案之间进行切换,成本非常小
func NewAdminService(db *xorm.Engine) AdminService {
	return &adminSevice{
		engine: db,
	}
}

/**
 * 管理员的服务实现结构体
 */
type adminSevice struct {
	engine *xorm.Engine
}

/**
 * 通过用户名和密码查询管理员
 */
func (ac *adminSevice) GetByAdminNameAndPassword(username, password string) (models.Admin, bool) {
	var admin models.Admin

	ac.engine.Where("admin_name = ? and pwd = ? ", username, password).Get(&admin)

	fmt.Println(admin,"............",admin.AdminId != 0)

	return admin, admin.AdminId != 0
}

4、控制器绑定,路由处理 main.go

管理员结构体,控制器和功能逻辑实现了以后,我们需要在程序入口处做控制器绑定,指定我们定义的管理员控制器进行路由处理,具体的绑定操作如下:

func main() {
	app := newApp()

	//应用App设置
	configation(app)

	//路由设置
	mvcHandle(app)

	config := config.InitConfig()
	addr := "localhost:" + config.Port
	app.Run(
		iris.Addr(addr),                               //在端口8080进行监听
		iris.WithoutServerError(iris.ErrServerClosed), //无服务错误提示
		iris.WithOptimizations,                        //对json数据序列化更快的配置
	)
}

//构建App
func newApp() *iris.Application {
	app := iris.New()

	//设置日志级别  开发阶段为debug
	app.Logger().SetLevel("debug")

	//注册静态资源
	app.HandleDir("/static", "./static")
	app.HandleDir("/manage/static", "./static")
	app.HandleDir("/img", "./static/img")

	//注册视图文件
	app.RegisterView(iris.HTML("./static", ".html"))
	app.Get("/", func(context context.Context) {
		context.View("index.html")
	})

	return app
}

/**
 * 项目设置
 */
func configation(app *iris.Application) {

	//配置 字符编码
	app.Configure(iris.WithConfiguration(iris.Configuration{
		Charset: "UTF-8",
	}))

	//错误配置
	//未发现错误
	app.OnErrorCode(iris.StatusNotFound, func(context context.Context) {
		context.JSON(iris.Map{
			"errmsg": iris.StatusNotFound,
			"msg":    " not found ",
			"data":   iris.Map{},
		})
	})

	app.OnErrorCode(iris.StatusInternalServerError, func(context context.Context) {
		context.JSON(iris.Map{
			"errmsg": iris.StatusInternalServerError,
			"msg":    " interal error ",
			"data":   iris.Map{},
		})
	})
}

//MVC 架构模式处理
func mvcHandle(app *iris.Application) {
	//启用session
	sessManager := sessions.New(sessions.Config{
		Cookie:  "sessioncookie",
		Expires: 24 * time.Hour,
	})

	engine := datasource.NewMysqlEngine()

	//管理员模块功能
	adminService := service.NewAdminService(engine)

	admin := mvc.New(app.Party("/admin"))//设置路由组
	admin.Register(
		adminService,
		sessManager.Start,
	)
	//通过mvc的Handle方法进行控制器的指定
	admin.Handle(new(controller.AdminController))
}

五、浏览器Post请求测试(使用postman)

1、请求设置及结果

2、处理过程分析

从main函数的执行开始分析

(1)通过iris构建App:返回*iris.Application

  • app := iris.New()
  • 设置日志级别:app.Logger().SetLevel("debug")
  • 注册静态资源和视图文件:app.HandleDir、app.RegisterView
  • 设置默认请求:app.Get("/", func(context context.Context) {…………})

(2)项目设置

  • 配置 字符编码
  • 配置错误……

(3)MVC 架构模式处理/路由设置

  • 启用session:sessions.New
  • 加载数据库引擎的设置 :engine := datasource.NewMysqlEngine() 
  • 管理员模块功能 :adminService := service.NewAdminService(engine)
  • 设置路由组:app.Party
  • 通过mvc的Handle方法进行控制器的指定

(4)初始化服务器配置

  • 调用config.InitConfig()->实际读取了config.json中的配置信息

(5)设置iris的Addr并运行

  • app.Run

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·

说明:本案例使用的是go mod,导入的包不能再有本地的导入,导入本地的再有本地的导入直接失效,即使你用了replace,程序也会无视,而直接去代理服务器傻乎乎的下载你显示制定的本地包。。。。。。。。。。

我这目前无解了,只能用最最麻烦的笨方法了,也就是:A引用了本地B,B又引用了本地C,C又引用了本地D,要想A不出错,那么A引入了B以后,必须还要在A的mod.go的replace中必须重复声明C D不然就出错,也就是在A中引入了B,那么GO会无视B的mod.go中的replace内容必须要在A中重新再声明一次,如果都是本地的引用A->B->C->D->E这种笨方法可想而知A中得加了多少重复的东西,但也没办法,不然就报错,真是都疯了!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·

go mod怎么导入本地其他自定义模块可参考我的另一篇博客:https://blog.csdn.net/qq_38151401/article/details/105780251

这就是我的每个模块中都有go.mod的原因,感觉挺麻烦的,有什么好的方法欢迎指教~~~~

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值