日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)GoFrame教程:GoFrame接口開(kāi)發(fā)-回調(diào)處理

自定義回調(diào)處理是最常見(jiàn)的接口開(kāi)發(fā)實(shí)現(xiàn),我們往往只需要對(duì)接口中的部分實(shí)現(xiàn)進(jìn)行替換修改,以在原有的實(shí)現(xiàn)邏輯中注入自定義的邏輯實(shí)現(xiàn)。我們來(lái)看一個(gè)自定義回調(diào)處理的示例,我們需要將所有執(zhí)行的?SQL?語(yǔ)句記錄到?monitor?表中,以方便于進(jìn)行?SQL?審計(jì)。

為簡(jiǎn)化示例編寫,我們這里實(shí)現(xiàn)了一個(gè)自定義的?MySQL?驅(qū)動(dòng),該驅(qū)動(dòng)繼承于?gdb?模塊中已經(jīng)實(shí)現(xiàn)的?DriverMysql?,并按照需要修改覆蓋相應(yīng)的接口方法。由于所有的?SQL?語(yǔ)句執(zhí)行必定會(huì)通過(guò)?DoQuery?或者?DoExec?接口,因此我們?cè)谧远x的驅(qū)動(dòng)中實(shí)現(xiàn)并覆蓋這兩個(gè)接口方法即可。

package driver

import (
	"context"
	"database/sql"
	"github.com/GOgf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/os/gtime"
)

// MyDriver is a custom database driver, which is used for testing only.
// For simplifying the unit testing case purpose, MyDriver struct inherits the mysql driver
// gdb.DriverMysql and overwrites its functions DoQuery and DoExec.
// So if there's any sql execution, it goes through MyDriver.DoQuery/MyDriver.DoExec firstly
// and then gdb.DriverMysql.DoQuery/gdb.DriverMysql.DoExec.
// You can call it sql "HOOK" or "HiJack" as your will.
type MyDriver struct {
	*gdb.DriverMysql
}

var (
	// customDriverName is my driver name, which is used for registering.
	customDriverName = "MyDriver"
)

func init() {
	// It here registers my custom driver in package initialization function "init".
	// You can later use this type in the database configuration.
	if err := gdb.Register(customDriverName, &MyDriver{}); err != nil {
		panic(err)
	}
}

// New creates and returns a database object for mysql.
// It implements the interface of gdb.Driver for extra database driver installation.
func (d *MyDriver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
	return &MyDriver{
		&gdb.DriverMysql{
			Core: core,
		},
	}, nil
}

// DoQuery commits the sql string and its arguments to underlying driver
// through given link object and returns the execution result.
func (d *MyDriver) DoQuery(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
	tsMilli := gtime.TimestampMilli()
	rows, err = d.DriverMysql.DoQuery(ctx, link, sql, args...)
	link.Exec(
		"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
		gdb.FormatSqlWithArgs(sql, args),
		gtime.TimestampMilli()-tsMilli,
		gtime.Now(),
		err,
	)
	return
}

// DoExec commits the query string and its arguments to underlying driver
// through given link object and returns the execution result.
func (d *MyDriver) DoExec(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (result sql.Result, err error) {
	tsMilli := gtime.TimestampMilli()
	result, err = d.DriverMysql.DoExec(ctx, link, sql, args...)
	link.Exec(
		"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
		gdb.FormatSqlWithArgs(sql, args),
		gtime.TimestampMilli()-tsMilli,
		gtime.Now(),
		err,
	)
	return
}

// DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver.
// The parameter `link` specifies the current database connection operation object. You can modify the sql
// string `sql` and its arguments `args` as you wish before they're committed to driver.
func (d *MyDriver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) {
	//Filter sql Step1
	sql_new := gstr.Replace(sql, "\n", "")

	//Filter sql Step2
	sql_new = gstr.Replace(sql_new, "\t", "")
	//... Filter what you want ...

	//Filter args Step1
	for _, v := range args {
		switch v.(type) {
		case gdb.Map:
			//Do it what you wan
		case string:
			//Do it what you wan
		}
	}
	return sql_new, args, nil
}


func (d *MyDriver) ConvertDataForRecord(ctx context.Context, data interface{}) map[string]interface{} {
	//this hook is convert data to map[string]interface{}
	result := make(map[string]interface{}, 0)

	//like this
	switch data.(type) {
	case gdb.Map:
		result = gconv.Map(data)
	case gdb.List:
		for k, v := range data.(gdb.List) {
			result[strconv.Itoa(k)] = gconv.Map(v)
		}
		//case other type,do it what you want
	}
	return result
}

我們看到,這里在包初始化方法?init?中使用了?gdb.Register("MyDriver", &MyDriver{})?來(lái)注冊(cè)了了一個(gè)自定義名稱的驅(qū)動(dòng)。我們也可以通過(guò)?gdb.Register("mysql", &MyDriver{})?來(lái)覆蓋已有的框架?mysql?驅(qū)動(dòng)為自己的驅(qū)動(dòng)。

驅(qū)動(dòng)名稱?mysql?為框架默認(rèn)的?DriverMysql?驅(qū)動(dòng)的名稱。

由于這里我們使用了一個(gè)新的驅(qū)動(dòng)名稱?MyDriver?,因此在?gdb?配置中的?type?數(shù)據(jù)庫(kù)類型時(shí),需要填寫該驅(qū)動(dòng)名稱。以下是一個(gè)使用配置的示例:

database:
  default:
  - link: "MyDriver:root:12345678@tcp(127.0.0.1:3306)/user"

文章題目:創(chuàng)新互聯(lián)GoFrame教程:GoFrame接口開(kāi)發(fā)-回調(diào)處理
網(wǎng)頁(yè)路徑:http://m.5511xx.com/article/cooecsg.html