update travis for adding mysql password; add custom view feature for ghttp.Response

This commit is contained in:
john 2019-11-20 12:09:26 +08:00
parent a4f191c1c6
commit ad540f7c25
11 changed files with 83 additions and 75 deletions

View File

@ -32,6 +32,7 @@ install:
before_script: before_script:
- find . -name "*.go" | xargs gofmt -w - find . -name "*.go" | xargs gofmt -w
- git diff --name-only --exit-code || exit 1 - git diff --name-only --exit-code || exit 1
- echo "USE mysql;\nUPDATE user SET password=PASSWORD('12345678') WHERE user='root';\nFLUSH PRIVILEGES;\n" | mysql -u root
- psql -c 'create database travis_ci_test;' -U postgres - psql -c 'create database travis_ci_test;' -U postgres
script: script:

View File

@ -16,7 +16,6 @@ import (
) )
var ( var (
// 数据库对象/接口
msdb gdb.DB msdb gdb.DB
) )
@ -44,7 +43,6 @@ func InitMssql() {
msdb = r msdb = r
} }
// 创建默认用户表
createTableMssql("t_user") createTableMssql("t_user")
//msdb.SetDebug(true) //msdb.SetDebug(true)
} }
@ -74,7 +72,6 @@ func createTableMssql(table ...string) (name string) {
//msdb.Exec("DROP DATABASE test") //msdb.Exec("DROP DATABASE test")
//msdb.Exec("CREATE DATABASE test") //msdb.Exec("CREATE DATABASE test")
// 选择操作数据库
msdb.SetSchema("test") msdb.SetSchema("test")
//msdb.SetDebug(true) //msdb.SetDebug(true)
@ -102,7 +99,6 @@ func createInitTableMssql(table ...string) (name string) {
return return
} }
// 删除指定表.
func dropTableMssql(table string) { func dropTableMssql(table string) {
if _, err := msdb.Exec(fmt.Sprintf(` if _, err := msdb.Exec(fmt.Sprintf(`
IF EXISTS (SELECT * FROM sysobjects WHERE name='%s' and xtype='U') IF EXISTS (SELECT * FROM sysobjects WHERE name='%s' and xtype='U')

View File

@ -8,8 +8,6 @@ package gdb_test
import ( import (
"fmt" "fmt"
"os"
"github.com/gogf/gf/container/garray" "github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g" "github.com/gogf/gf/frame/g"
@ -19,25 +17,22 @@ import (
) )
const ( const (
INIT_DATA_SIZE = 10 // 初始化表数据量 INIT_DATA_SIZE = 10
TABLE = "user" // 测试数据表 TABLE = "user"
SCHEMA1 = "test1" // 测试数据库1 SCHEMA1 = "test1"
SCHEMA2 = "test2" // 测试数据库2 SCHEMA2 = "test2"
) )
var ( var (
// 测试包变量ORM对象
db gdb.DB db gdb.DB
) )
// 初始化连接参数。
// 测试前需要修改连接参数。
func InitMysql() { func InitMysql() {
node := gdb.ConfigNode{ node := gdb.ConfigNode{
Host: "127.0.0.1", Host: "127.0.0.1",
Port: "3306", Port: "3306",
User: "root", User: "root",
Pass: "", Pass: "12345678",
Name: "", Name: "",
Type: "mysql", Type: "mysql",
Role: "master", Role: "master",
@ -47,10 +42,6 @@ func InitMysql() {
MaxOpenConnCount: 10, MaxOpenConnCount: 10,
MaxConnLifetime: 600, MaxConnLifetime: 600,
} }
// 作者本地测试hack
if hostname, _ := os.Hostname(); hostname == "ijohn" {
node.Pass = "12345678"
}
gdb.AddConfigNode("test", node) gdb.AddConfigNode("test", node)
gdb.AddConfigNode(gdb.DEFAULT_GROUP_NAME, node) gdb.AddConfigNode(gdb.DEFAULT_GROUP_NAME, node)
if r, err := gdb.New(); err != nil { if r, err := gdb.New(); err != nil {
@ -58,24 +49,21 @@ func InitMysql() {
} else { } else {
db = r db = r
} }
// 准备测试数据结构:数据库
schemaTemplate := "CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8" schemaTemplate := "CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8"
if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA1)); err != nil { if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA1)); err != nil {
gtest.Error(err) gtest.Error(err)
} }
// 多个数据库,用于测试数据库切换
if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA2)); err != nil { if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA2)); err != nil {
gtest.Error(err) gtest.Error(err)
} }
// 设置默认操作数据库
db.SetSchema(SCHEMA1) db.SetSchema(SCHEMA1)
// 创建默认用户表
createTable(TABLE) createTable(TABLE)
} }
// 创建指定名称的user测试表当table为空时创建随机的表名。
// 创建的测试表默认没有任何数据。
// 执行完成后返回该表名。
func createTable(table ...string) (name string) { func createTable(table ...string) (name string) {
if len(table) > 0 { if len(table) > 0 {
name = table[0] name = table[0]
@ -85,11 +73,11 @@ func createTable(table ...string) (name string) {
dropTable(name) dropTable(name)
if _, err := db.Exec(fmt.Sprintf(` if _, err := db.Exec(fmt.Sprintf(`
CREATE TABLE %s ( CREATE TABLE %s (
id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', id int(10) unsigned NOT NULL AUTO_INCREMENT,
passport varchar(45) NULL COMMENT '账号', passport varchar(45) NULL,
password char(32) NULL COMMENT '密码', password char(32) NULL,
nickname varchar(45) NULL COMMENT '昵称', nickname varchar(45) NULL,
create_time timestamp NULL COMMENT '创建时间/注册时间', create_time timestamp NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, name)); err != nil { `, name)); err != nil {
@ -98,7 +86,6 @@ func createTable(table ...string) (name string) {
return return
} }
// 创建测试表,并初始化默认数据。
func createInitTable(table ...string) (name string) { func createInitTable(table ...string) (name string) {
name = createTable(table...) name = createTable(table...)
array := garray.New(true) array := garray.New(true)
@ -120,7 +107,6 @@ func createInitTable(table ...string) (name string) {
return return
} }
// 删除指定表.
func dropTable(table string) { func dropTable(table string) {
if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil { if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
gtest.Error(err) gtest.Error(err)

View File

@ -17,7 +17,6 @@ import (
) )
var ( var (
// 数据库对象/接口
oradb gdb.DB oradb gdb.DB
) )
@ -46,7 +45,6 @@ func InitOracle() {
oradb = r oradb = r
} }
// 创建默认用户表
createTableOracle("t_user") createTableOracle("t_user")
} }
@ -94,7 +92,6 @@ func createInitTableOracle(table ...string) (name string) {
return return
} }
// 删除指定表.
func dropTableOracle(table string) { func dropTableOracle(table string) {
count, err := oradb.GetCount("SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", strings.ToUpper(table)) count, err := oradb.GetCount("SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", strings.ToUpper(table))

View File

@ -16,12 +16,9 @@ import (
) )
var ( var (
// 数据库对象/接口
pgdb gdb.DB pgdb gdb.DB
) )
// 初始化连接参数。
// 测试前需要修改连接参数。
func InitPgsql() { func InitPgsql() {
node := gdb.ConfigNode{ node := gdb.ConfigNode{
Host: "127.0.0.1", Host: "127.0.0.1",
@ -64,10 +61,6 @@ func InitPgsql() {
} }
// 创建指定名称的user测试表当table为空时创建随机的表名。
// 创建的测试表默认没有任何数据。
// 执行完成后返回该表名。
// TODO 支持更多数据库
func createTablePgsql(table ...string) (name string) { func createTablePgsql(table ...string) (name string) {
if len(table) > 0 { if len(table) > 0 {
name = table[0] name = table[0]
@ -91,7 +84,6 @@ func createTablePgsql(table ...string) (name string) {
return return
} }
// 创建测试表,并初始化默认数据。
func createInitTablePgsql(table ...string) (name string) { func createInitTablePgsql(table ...string) (name string) {
name = createTablePgsql(table...) name = createTablePgsql(table...)
array := garray.New(true) array := garray.New(true)
@ -113,7 +105,6 @@ func createInitTablePgsql(table ...string) (name string) {
return return
} }
// 删除指定表.
func dropTablePgsql(table string) { func dropTablePgsql(table string) {
if _, err := pgdb.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", table)); err != nil { if _, err := pgdb.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", table)); err != nil {
gtest.Fatal(err) gtest.Fatal(err)

View File

@ -315,6 +315,9 @@ func Test_Model_Safe(t *testing.T) {
}) })
gtest.Case(t, func() { gtest.Case(t, func() {
table := createInitTable()
defer dropTable(table)
md1 := db.Table(table).Where("id>", 0).Safe() md1 := db.Table(table).Where("id>", 0).Safe()
md2 := md1.Where("id in (?)", g.Slice{1, 3}) md2 := md1.Where("id in (?)", g.Slice{1, 3})
md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) md3 := md1.Where("id in (?)", g.Slice{4, 5, 6})

View File

@ -11,6 +11,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/gogf/gf/os/gview"
"net/http" "net/http"
"github.com/gogf/gf/os/gres" "github.com/gogf/gf/os/gres"
@ -20,13 +21,14 @@ import (
"github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gconv"
) )
// Response is the writer for response buffer. // Response is the http response manager.
// Note that it implements the http.ResponseWriter interface with buffering feature. // Note that it implements the http.ResponseWriter interface with buffering feature.
type Response struct { type Response struct {
*ResponseWriter // Underlying ResponseWriter. *ResponseWriter // Underlying ResponseWriter.
Server *Server // Parent server. Server *Server // Parent server.
Writer *ResponseWriter // Alias of ResponseWriter. Writer *ResponseWriter // Alias of ResponseWriter.
Request *Request // According request. Request *Request // According request.
view *gview.View // Custom template view engine object for this response.
} }
// newResponse creates and returns a new Response object. // newResponse creates and returns a new Response object.
@ -162,7 +164,7 @@ func (r *Response) ServeFile(path string, allowIndex ...bool) {
r.Server.serveFile(r.Request, serveFile, allowIndex...) r.Server.serveFile(r.Request, serveFile, allowIndex...)
} }
// ServeFileDownload serves file as file downloading to the response. // ServeFileDownload serves file downloading to the response.
func (r *Response) ServeFileDownload(path string, name ...string) { func (r *Response) ServeFileDownload(path string, name ...string) {
serveFile := (*staticServeFile)(nil) serveFile := (*staticServeFile)(nil)
downloadName := "" downloadName := ""
@ -194,29 +196,29 @@ func (r *Response) ServeFileDownload(path string, name ...string) {
r.Server.serveFile(r.Request, serveFile) r.Server.serveFile(r.Request, serveFile)
} }
// RedirectTo redirects client to another location. // RedirectTo redirects client to another location using http status 302.
func (r *Response) RedirectTo(location string) { func (r *Response) RedirectTo(location string) {
r.Header().Set("Location", location) r.Header().Set("Location", location)
r.WriteHeader(http.StatusFound) r.WriteHeader(http.StatusFound)
r.Request.Exit() r.Request.Exit()
} }
// RedirectBack redirects client back to referer. // RedirectBack redirects client back to referer using http status 302.
func (r *Response) RedirectBack() { func (r *Response) RedirectBack() {
r.RedirectTo(r.Request.GetReferer()) r.RedirectTo(r.Request.GetReferer())
} }
// BufferString returns the buffer content as []byte. // BufferString returns the buffered content as []byte.
func (r *Response) Buffer() []byte { func (r *Response) Buffer() []byte {
return r.buffer.Bytes() return r.buffer.Bytes()
} }
// BufferString returns the buffer content as string. // BufferString returns the buffered content as string.
func (r *Response) BufferString() string { func (r *Response) BufferString() string {
return r.buffer.String() return r.buffer.String()
} }
// BufferLength returns the length of the buffer content. // BufferLength returns the length of the buffered content.
func (r *Response) BufferLength() int { func (r *Response) BufferLength() int {
return r.buffer.Len() return r.buffer.Len()
} }
@ -237,6 +239,5 @@ func (r *Response) Output() {
if r.Server.config.ServerAgent != "" { if r.Server.config.ServerAgent != "" {
r.Header().Set("Server", r.Server.config.ServerAgent) r.Header().Set("Server", r.Server.config.ServerAgent)
} }
//r.handleGzip()
r.Writer.OutputBuffer() r.Writer.OutputBuffer()
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gconv"
) )
// CORSOptions is the options for CORS feature.
// See https://www.w3.org/TR/cors/ . // See https://www.w3.org/TR/cors/ .
type CORSOptions struct { type CORSOptions struct {
AllowDomain []string // Used for allowing requests from custom domains AllowDomain []string // Used for allowing requests from custom domains
@ -70,7 +71,7 @@ func (r *Response) CORS(options CORSOptions) {
} }
} }
// CORSAllowed checks whether the current request origin is allowed CORS. // CORSAllowed checks whether the current request origin is allowed cross-domain.
func (r *Response) CORSAllowedOrigin(options CORSOptions) bool { func (r *Response) CORSAllowedOrigin(options CORSOptions) bool {
if options.AllowDomain == nil { if options.AllowDomain == nil {
return true return true

View File

@ -13,7 +13,25 @@ import (
"github.com/gogf/gf/util/gmode" "github.com/gogf/gf/util/gmode"
) )
// 展示模板,可以给定模板参数,及临时的自定义模板函数 // SetView sets template view engine object for this response.
func (r *Response) SetView(view *gview.View) {
r.view = view
}
// GetView returns the template view engine object for this response.
func (r *Response) GetView() *gview.View {
view := r.view
if view == nil {
view = r.Server.config.View
}
if view == nil {
gview.Instance()
}
return view
}
// WriteTpl parses and responses given template file.
// The parameter <params> specifies the template variables for parsing.
func (r *Response) WriteTpl(tpl string, params ...gview.Params) error { func (r *Response) WriteTpl(tpl string, params ...gview.Params) error {
if b, err := r.ParseTpl(tpl, params...); err != nil { if b, err := r.ParseTpl(tpl, params...); err != nil {
if !gmode.IsProduct() { if !gmode.IsProduct() {
@ -26,7 +44,22 @@ func (r *Response) WriteTpl(tpl string, params ...gview.Params) error {
return nil return nil
} }
// 展示模板内容,可以给定模板参数,及临时的自定义模板函数 // WriteTplDefault parses and responses the default template file.
// The parameter <params> specifies the template variables for parsing.
func (r *Response) WriteTplDefault(params ...gview.Params) error {
if b, err := r.ParseTplDefault(params...); err != nil {
if !gmode.IsProduct() {
r.Write("Template Parsing Error: " + err.Error())
}
return err
} else {
r.Write(b)
}
return nil
}
// WriteTplContent parses and responses the template content.
// The parameter <params> specifies the template variables for parsing.
func (r *Response) WriteTplContent(content string, params ...gview.Params) error { func (r *Response) WriteTplContent(content string, params ...gview.Params) error {
if b, err := r.ParseTplContent(content, params...); err != nil { if b, err := r.ParseTplContent(content, params...); err != nil {
if !gmode.IsProduct() { if !gmode.IsProduct() {
@ -39,23 +72,24 @@ func (r *Response) WriteTplContent(content string, params ...gview.Params) error
return nil return nil
} }
// 解析模板文件,并返回模板内容 // ParseTpl parses given template file <tpl> with given template variables <params>
// and returns the parsed template content.
func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) { func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {
if r.Server.config.View != nil { return r.GetView().Parse(tpl, r.buildInVars(params...))
return r.Server.config.View.Parse(tpl, r.buildInVars(params...))
}
return gview.Instance().Parse(tpl, r.buildInVars(params...))
} }
// 解析并返回模板内容 // ParseDefault parses the default template file with params.
func (r *Response) ParseTplDefault(params ...gview.Params) (string, error) {
return r.GetView().ParseDefault(r.buildInVars(params...))
}
// ParseTplContent parses given template file <file> with given template parameters <params>
// and returns the parsed template content.
func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) { func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {
if r.Server.config.View != nil { return r.GetView().ParseContent(content, r.buildInVars(params...))
return r.Server.config.View.ParseContent(content, r.buildInVars(params...))
}
return gview.Instance().ParseContent(content, r.buildInVars(params...))
} }
// 内置变量/对象 // buildInVars merges build-in variables into <params> and returns the new template variables.
func (r *Response) buildInVars(params ...map[string]interface{}) map[string]interface{} { func (r *Response) buildInVars(params ...map[string]interface{}) map[string]interface{} {
var vars map[string]interface{} var vars map[string]interface{}
if len(params) > 0 && params[0] != nil { if len(params) > 0 && params[0] != nil {

View File

@ -14,13 +14,13 @@ import (
"net/http" "net/http"
) )
// Custom ResponseWriter, which is used for controlling the output buffer. // ResponseWriter is the custom writer for http response.
type ResponseWriter struct { type ResponseWriter struct {
Status int // HTTP status. Status int // HTTP status.
writer http.ResponseWriter // The underlying ResponseWriter. writer http.ResponseWriter // The underlying ResponseWriter.
buffer *bytes.Buffer // The output buffer. buffer *bytes.Buffer // The output buffer.
hijacked bool // Mark this request is hijacked or not. hijacked bool // Mark this request is hijacked or not.
wroteHeader bool // Is header wrote, avoiding error: superfluous/multiple response.WriteHeader call. wroteHeader bool // Is header wrote or not, avoiding error: superfluous/multiple response.WriteHeader call.
} }
// RawWriter returns the underlying ResponseWriter. // RawWriter returns the underlying ResponseWriter.

View File

@ -48,9 +48,8 @@ type fileCacheItem struct {
content string content string
} }
// ParseContent parses given template file <file> // Parse parses given template file <file> with given template variables <params>
// with given template parameters <params> and function map <funcMap> // and returns the parsed template content.
// and returns the parsed string content.
func (view *View) Parse(file string, params ...Params) (result string, err error) { func (view *View) Parse(file string, params ...Params) (result string, err error) {
var tpl *template.Template var tpl *template.Template
// It caches the file, folder and its content to enhance performance. // It caches the file, folder and its content to enhance performance.
@ -143,8 +142,7 @@ func (view *View) ParseDefault(params ...Params) (result string, err error) {
return view.Parse(view.defaultFile, params...) return view.Parse(view.defaultFile, params...)
} }
// ParseContent parses given template content <content> // ParseContent parses given template content <content> with template variables <params>
// with given template parameters <params> and function map <funcMap>
// and returns the parsed content in []byte. // and returns the parsed content in []byte.
func (view *View) ParseContent(content string, params ...Params) (string, error) { func (view *View) ParseContent(content string, params ...Params) (string, error) {
err := (error)(nil) err := (error)(nil)
@ -201,7 +199,7 @@ func (view *View) ParseContent(content string, params ...Params) (string, error)
// getTemplate returns the template object associated with given template folder <path>. // getTemplate returns the template object associated with given template folder <path>.
// It uses template cache to enhance performance, that is, it will return the same template object // It uses template cache to enhance performance, that is, it will return the same template object
// with the same given <path>. It will also refresh the template cache // with the same given <path>. It will also automatically refresh the template cache
// if the template files under <path> changes (recursively). // if the template files under <path> changes (recursively).
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) { func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
r := templates.GetOrSetFuncLock(path, func() interface{} { r := templates.GetOrSetFuncLock(path, func() interface{} {
@ -237,7 +235,7 @@ func (view *View) getTemplate(path string, pattern string) (tpl *template.Templa
return return
} }
// searchFile returns the found absolute path for <file>, and its template folder path. // searchFile returns the found absolute path for <file> and its template folder path.
func (view *View) searchFile(file string) (path string, folder string, resource *gres.File, err error) { func (view *View) searchFile(file string) (path string, folder string, resource *gres.File, err error) {
// Firstly checking the resource manager. // Firstly checking the resource manager.
if !gres.IsEmpty() { if !gres.IsEmpty() {