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的原因,感覺挺麻煩的,有什麼好的方法歡迎指教~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章