goku

package module
v0.0.0-...-490624a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2013 License: MIT Imports: 20 Imported by: 0

README ¶

#goku

goku is a Web Mvc Framework for golang, mostly like ASP.NET MVC.

doc & api

##Installation

To install goku, simply run go get github.com/QLeelulu/goku. To use it in a program, use import "github.com/QLeelulu/goku"

To run example "todo" app, just:

$ cd $GOROOT/src/pkg/github.com/QLeelulu/goku/examples/todo/
$ go run app.go

maybe you need run todo.sql first.

##Usage

    package main

    import (
        "github.com/QLeelulu/goku"
        "log"
        "path"
        "runtime"
        "time"
    )

    // routes
    var routes []*goku.Route = []*goku.Route{
        // static file route
        &goku.Route{
            Name:     "static",
            IsStatic: true,
            Pattern:  "/static/(.*)",
        },
        // default controller and action route
        &goku.Route{
            Name:       "default",
            Pattern:    "/{controller}/{action}/{id}",
            Default:    map[string]string{"controller": "home", "action": "index", "id": "0"},
            Constraint: map[string]string{"id": "\\d+"},
        },
    }

    // server config
    var config *goku.ServerConfig = &goku.ServerConfig{
        Addr:           ":8888",
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
        //RootDir:        os.Getwd(),
        StaticPath: "static",
        ViewPath:   "views",
        Debug:      true,
    }

    func init() {
        /**
         * project root dir
         */
        _, filename, _, _ := runtime.Caller(1)
        config.RootDir = path.Dir(filename)

        /**
         * Controller & Action
         */
        goku.Controller("home").
            Get("index", func(ctx *goku.HttpContext) goku.ActionResulter {
            return ctx.Html("Hello World")
        })

    }

    func main() {
        rt := &goku.RouteTable{Routes: routes}
        s := goku.CreateServer(rt, nil, config)
        goku.Logger().Logln("Server start on", s.Addr)
        log.Fatal(s.ListenAndServe())
    }

##Route

    var Routes []*goku.Route = []*goku.Route{
        &goku.Route{
            Name:     "static",
            IsStatic: true,
            Pattern:  "/public/(.*)",
        },
        &goku.Route{
            Name:       "edit",
            Pattern:    "/{controller}/{id}/{action}",
            Default:    map[string]string{"action": "edit"},
            Constraint: map[string]string{"id": "\\d+"},
        },
        &goku.Route{
            Name:    "default",
            Pattern: "/{controller}/{action}",
            Default: map[string]string{"controller": "todo", "action": "index"},
        },
    }
    // create server with the rules
    rt := &goku.RouteTable{Routes: todo.Routes}
    s := goku.CreateServer(rt, nil, nil)
    log.Fatal(s.ListenAndServe())

or

    rt := new(goku.RouteTable)
    rt.Static("staticFile", "/static/(.*)")
    rt.Map(
        "blog-page", // route name
        "/blog/p/{page}", // pattern
        map[string]string{"controller": "blog", "action": "page", "page": "0"}, // default
        map[string]string{"page": "\\d+"} // constraint
    )
    rt.Map(
        "default", // route name
        "/{controller}/{action}", // pattern
        map[string]string{"controller": "home", "action": "index"}, // default
    )

##Controller And Action

    // add a controller named "home"
    goku.Controller("home").
        Filters(new(TestControllerFilter)). // this filter is fot controller(all the actions)
        // home controller's index action
        // for http GET
        Get("index", func(ctx *goku.HttpContext) goku.ActionResulter {
        return ctx.Html("Hello World")
    }).Filters(new(TestActionFilter)). // this filter is for home.index action
        // home controller's about action
        // for http POST
        Post("about", func(ctx *goku.HttpContext) goku.ActionResulter {
        return ctx.Raw("About")
    })
  • get /home/index will return Hello World
  • post /home/index will return 404
  • post /home/about will return About

##ActionResult

ActionResulter is type interface. all the action must return ActionResulter. you can return an ActionResulter in the action like this:

    // ctx is *goku.HttpContext
    ctx.Raw("hi")
    ctx.NotFound("oh no! ):")
    ctx.Redirect("/")
    // or you can return a view that
    // will render a template
    ctx.View(viewModel)
    ctx.Render("viewName", viewModel)

or you can return a ActionResulter by this

    return &ActionResult{
        StatusCode: http.StatusNotFound,
        Headers:    map[string]string{"Content-Type": "text/html"},
        Body:       "Page Not Found",
    }

for more info, check the code.

##View and ViewData

Views are the components that display the application's user interface (UI)

To render a view, you can just return a ViewResut which implement the ActionResulter interface. just like this:

    goku.Controller("blog").
        Get("page", func(ctx *goku.HttpContext) goku.ActionResulter {
        blog := GetBlogByid(10)

        // you can add any val to ViewData
        // then you can use it in template
        // like this: {{ .Data.SiteName }}
        ctx.ViewData["SiteName"] = "My Blog"

        // or you can pass a struct to ViewModel
        // then you can use it in template
        // like this: {{ .Model.Title }}
        // that same as blog.Title
        return ctx.View(blog)
    })

ctx.View() will find the view in these rules:

  1. /{ViewPath}/{Controller}/{action}
  2. /{ViewPath}/shared/{action}

for example, ServerConfig.ViewPath is set to "views", and return ctx.View() in home controller's about action, it will find the view file in this rule:

  1. {ProjectDir}/views/home/about.html
  2. {ProjectDir}/views/shared/about.html

if you want to return a view that specified view name, you can use ctx.Render:

    // it will find the view in these rules:
    //      1. /{ViewPath}/{Controller}/{viewName}
    //      2. /{ViewPath}/shared/{viewName}
    // if viewName start with '/',
    // it will find the view direct by viewpath:
    //      1. /{ViewPath}/{viewName}
    ctx.Render("viewName", ViewModel)

##ViewEngine & Template

    // you can add any val to ViewData
    // then you can use it in template
    // like this: {{ .Data.SiteName }}
    ctx.ViewData["SiteName"] = "My Blog"

    blogs := GetBlogs()
    // or you can pass a struct to ViewModel
    // then you can use it in template
    // like this: {{range .Model}} {{ .Title }} {{end}}
    return ctx.View(blogs)

default template engine is golang's template.

    <div class="box todos">
        <h2 class="box">{{ .Data.SiteName }}</h2>
        <ul>
          {{range .Model}}
            <li id="blog-{{.Id}}">
              {{.Title}}
            </li>
          {{end}}
        </ul>
    </div>

####Layout

layout.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Goku</title>
        {{template "head"}}
    </head>
    <body>
      {{template "body" .}}
    </body>
    </html>

body.html

    {{define "head"}}
        <!-- add css or js here -->
    {{end}}

    {{define "body"}}
        I'm main content.
    {{end}}

note the dot in {{template "body" .}} , it will pass the ViewData to the sub template.

HtmlHelper?

####More Template Engine Support

if you want to use mustache template, check mustache.goku

##HttpContext

    type HttpContext struct {
        Request        *http.Request       // http request
        responseWriter http.ResponseWriter // http response
        Method         string              // http method

        //self fields
        RouteData *RouteData             // route data
        ViewData  map[string]interface{} // view data for template
        Data      map[string]interface{} // data for httpcontex
        Result    ActionResulter         // action result
        Err       error                  // process error
        User      string                 // user name
        Canceled  bool                   // cancel continue process the request and return
    }

#Form Validation

you can create a form, to valid the user's input, and get the clean value.

    import "github.com/QLeelulu/goku/form"

    func CreateCommentForm() *goku.Form {
        name := NewCharField("name", "Name", true).Range(3, 10).Field()
        nickName := NewCharField("nick_name", "Nick Name", false).Min(3).Max(20).Field()
        age := NewIntegerField("age", "Age", true).Range(18, 50).Field()
        content := NewTextField("content", "Content", true).Min(10).Field()

        form := NewForm(name, nickName, age, content)
        return form
    }

and then you can use this form like this:

    f := CreateCommentForm()
    f.FillByRequest(ctx.Request)

    if f.Valid() {
        // after valid, we can get the clean values
        m := f.CleanValues()
        // and now you can save m to database
    } else {
        // if not valid
        // we can get the valid errors
        errs := f.Errors()
    }

checkout form_test.go

##DataBase

simple database api.

    db, err := OpenMysql("mymysql", "tcp:localhost:3306*test_db/lulu/123456")

    // you can use all the api in golang's database/sql
    _, err = db.Query("select 1")

    // or you can use some simple api provide by goku
    r, err := db.Select("test_blog", SqlQueryInfo{
        Fields: "id, title, content",
        Where:  "id>?",
        Params: []interface{}{0},
        Limit:  10,
        Offset: 0,
        Group:  "",
        Order:  "id desc",
    })

    // insert map
    vals := map[string]interface{}{
        "title": "golang",
        "content": "Go is an open source programming environment that " +
            "makes it easy to build simple, reliable, and efficient software.",
        "create_at": time.Now(),
    }
    r, err := db.Insert("test_blog", vals)

    // insert struct
    blog := TestBlog{
        Title:    "goku",
        Content:  "a mvc framework",
        CreateAt: time.Now(),
    }
    r, err = db.InsertStruct(&blog)

    // get struct
    blog := &TestBlog{}
    err = db.GetStruct(blog, "id=?", 3)

    // get struct list
    qi := SqlQueryInfo{}
    var blogs []Blog
    err := db.GetStructs(&blogs, qi)

    // update by map
    vals := map[string]interface{}{
        "title": "js",
    }
    r, err2 := db.Update("test_blog", vals, "id=?", blog.Id)

    // delete
    r, err := db.Delete("test_blog", "id=?", 8)

checkout db_test.go

####DataBase SQL Debug

if you want to debug what the sql query is, set db.Debug to true

    db, err := OpenMysql("mymysql", "tcp:localhost:3306*test_db/username/pwd")
    db.Debug = true

after you set db.Debug to true, while you run a db command, it will print the sql query to the log, juse like this:

2012/07/30 20:58:03 SQL: UPDATE `user` SET friends=friends+? WHERE id=?;
                    PARAMS: [[1 2]]

##Action Filter

    type TestActionFilter struct {
    }

    func (tf *TestActionFilter) OnActionExecuting(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
        ctx.WriteString("OnActionExecuting - TestActionFilter \n")
        return
    }
    func (tf *TestActionFilter) OnActionExecuted(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
        ctx.WriteString("OnActionExecuted - TestActionFilter \n")
        return
    }

    func (tf *TestActionFilter) OnResultExecuting(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
        ctx.WriteString("    OnResultExecuting - TestActionFilter \n")
        return
    }

    func (tf *TestActionFilter) OnResultExecuted(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
        ctx.WriteString("    OnResultExecuted - TestActionFilter \n")
        return
    }

Order of the filters execution is:

  1. OnActionExecuting
  2. -> Execute Action -> return ActionResulter
  3. OnActionExecuted
  4. OnResultExecuting
  5. -> ActionResulter.ExecuteResult
  6. OnResultExecuted

##Middleware

    type TestMiddleware struct {
    }

    func (tmd *TestMiddleware) OnBeginRequest(ctx *goku.HttpContext) (goku.ActionResulter, error) {
        ctx.WriteString("OnBeginRequest - TestMiddleware \n")
        return nil, nil
    }

    func (tmd *TestMiddleware) OnBeginMvcHandle(ctx *goku.HttpContext) (goku.ActionResulter, error) {
        ctx.WriteString("  OnBeginMvcHandle - TestMiddleware \n")
        return nil, nil
    }
    func (tmd *TestMiddleware) OnEndMvcHandle(ctx *goku.HttpContext) (goku.ActionResulter, error) {
        ctx.WriteString("  OnEndMvcHandle - TestMiddleware \n")
        return nil, nil
    }

    func (tmd *TestMiddleware) OnEndRequest(ctx *goku.HttpContext) (goku.ActionResulter, error) {
        ctx.WriteString("OnEndRequest - TestMiddleware \n")
        return nil, nil
    }

Order of the middleware event execution is:

  1. OnBeginRequest
  2. OnBeginMvcHandle(if not the static file request)
  3. => run controller action (if not the static file request)
  4. OnEndMvcHandle(if not the static file request)
  5. OnEndRequest

##Log

To use logger in goku, just:

goku.Logger().Logln("i", "am", "log")
goku.Logger().Errorln("oh", "no!", "Server Down!")

this will log like this:

2012/07/14 20:07:46 i am log
2012/07/14 20:07:46 [ERROR] oh no! Server Down!

Authors

License

View the LICENSE file.

Documentation ¶

Overview ¶

a golang web mvc framework, mostly like asp.net mvc. Base Features:

  • mvc (Lightweight model)
  • route
  • multi template engine and layout
  • simple database api
  • form validation
  • filter for controller or action
  • middleware

Example:

package main

import (
    "github.com/QLeelulu/goku"
    "log"
    "path"
    "runtime"
)

/**
 * Controller & Action
 */
var _ = goku.Controller("home").
    Get("index", func(ctx *goku.HttpContext) goku.ActionResulter {
    return ctx.Html("Hello World")
})

// routes
var routes []*goku.Route = []*goku.Route{
    &goku.Route{
        Name:    "default",
        Pattern: "/{controller}/{action}/",
        Default: map[string]string{"controller": "home", "action": "index"},
    },
}

// server config
var config *goku.ServerConfig = &goku.ServerConfig{Addr: ":8080"}

func init() {
    // project root dir, this code can not put to main func
    _, filename, _, _ := runtime.Caller(1)
    config.RootDir = path.Dir(filename)
}

func main() {
    rt := &goku.RouteTable{Routes: routes}
    s := goku.CreateServer(rt, nil, config)

    goku.Logger().Logln("Server start on", s.Addr)
    log.Fatal(s.ListenAndServe())
}

Index ¶

Constants ¶

View Source
const (
	LOG_LEVEL_NO = iota
	LOG_LEVEL_ERROR
	LOG_LEVEL_WARN
	LOG_LEVEL_NOTICE
	LOG_LEVEL_LOG
)

Variables ¶

This section is empty.

Functions ¶

func GetVersion ¶

func GetVersion() string

func Logger ¶

func Logger() logger

func SetGlobalViewData ¶

func SetGlobalViewData(key string, val interface{})

add a view data to the global, that all the view can use it by {{.Global.key}}

func SetLogger ¶

func SetLogger(l logger)

Types ¶

type ActionInfo ¶

type ActionInfo struct {
	Name       string
	Controller *ControllerInfo
	Handler    func(ctx *HttpContext) ActionResulter
	Filters    []Filter
}

info about the action

func (*ActionInfo) AddFilters ¶

func (ai *ActionInfo) AddFilters(filters ...Filter)

add filters to the action

type ActionResult ¶

type ActionResult struct {
	StatusCode int
	Headers    map[string]string
	Body       *bytes.Buffer
	// contains filtered or unexported fields
}

func (*ActionResult) ExecuteResult ¶

func (ar *ActionResult) ExecuteResult(ctx *HttpContext)

type ActionResulter ¶

type ActionResulter interface {
	ExecuteResult(ctx *HttpContext)
}

type ContentResult ¶

type ContentResult struct {
	FilePath string
}

func (*ContentResult) ExecuteResult ¶

func (cr *ContentResult) ExecuteResult(ctx *HttpContext)

type ControllerBuilder ¶

type ControllerBuilder struct {
	// contains filtered or unexported fields
}

for build controller and action

func Controller ¶

func Controller(name string) *ControllerBuilder

get a controller builder that the controller named "name" for reg actions and filters

func (*ControllerBuilder) Action ¶

func (cb *ControllerBuilder) Action(httpMethod string, actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ControllerBuilder

@param httpMethod: if "all", will match all http method, but Priority is low The return value is the ControllerBuilder, so calls can be chained

func (*ControllerBuilder) Delete ¶

func (cb *ControllerBuilder) Delete(httpMethod string, actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ControllerBuilder

reg http "delete" method action The return value is the ControllerBuilder, so calls can be chained

func (*ControllerBuilder) Filters ¶

func (cb *ControllerBuilder) Filters(filters ...Filter) *ControllerBuilder

The return value is the ControllerBuilder, so calls can be chained

func (*ControllerBuilder) Get ¶

func (cb *ControllerBuilder) Get(actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ControllerBuilder

reg http "get" method action The return value is the ControllerBuilder, so calls can be chained

func (*ControllerBuilder) Post ¶

func (cb *ControllerBuilder) Post(actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ControllerBuilder

reg http "post" method action The return value is the ControllerBuilder, so calls can be chained

func (*ControllerBuilder) Put ¶

func (cb *ControllerBuilder) Put(httpMethod string, actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ControllerBuilder

reg http "put" method action The return value is the ControllerBuilder, so calls can be chained

type ControllerFactory ¶

type ControllerFactory struct {
	Controllers map[string]*ControllerInfo
}

for get action in the registered controllers

func (*ControllerFactory) GetAction ¶

func (cf *ControllerFactory) GetAction(httpMethod string, controller string, action string) *ActionInfo

type ControllerInfo ¶

type ControllerInfo struct {
	Name    string
	Actions map[string]*ActionInfo
	Filters []Filter
}

hold the info about controller's actions and filters

func (*ControllerInfo) AddActionFilters ¶

func (ci *ControllerInfo) AddActionFilters(httpMethod string, actionName string, filters ...Filter)

add filters for the controller

func (*ControllerInfo) AddFilters ¶

func (ci *ControllerInfo) AddFilters(filters ...Filter)

add filters for the controller

func (*ControllerInfo) GetAction ¶

func (ci *ControllerInfo) GetAction(method string, name string) *ActionInfo

get a action e.g. ci.GetAction("get", "index"), will found the registered action "index" for http method "get" in this controller, if not found, will found the action "index" for all the http method

func (*ControllerInfo) Init ¶

func (ci *ControllerInfo) Init() *ControllerInfo

func (*ControllerInfo) RegAction ¶

func (ci *ControllerInfo) RegAction(httpMethod string, actionName string,
	handler func(ctx *HttpContext) ActionResulter) *ActionInfo

register a action to the controller

type DB ¶

type DB struct {
	sql.DB
	// if Debug set to true,
	// will print the sql
	Debug bool
}

base db

func (*DB) Count ¶

func (db *DB) Count(table string, where string, whereParams ...interface{}) (count int64, err error)

func (*DB) Delete ¶

func (db *DB) Delete(table string, where string, params ...interface{}) (result sql.Result, err error)

func (*DB) Exec ¶

func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error)

func (*DB) GetStruct ¶

func (db *DB) GetStruct(s interface{}, where string, params ...interface{}) error

query by s and set the result value to s field mapping rule is: HelloWorld => hello_world mean that struct's field "HelloWorld" in database table's field is "hello_world" table name mapping use the same rule as field

func (*DB) GetStructs ¶

func (db *DB) GetStructs(slicePtr interface{}, qi SqlQueryInfo) error

query by s and return a slice by type s field mapping rule is: HelloWorld => hello_world mean that struct's field "HelloWorld" in database table's field is "hello_world" table name mapping use the same rule as field @param slicePtr: a pointer to a slice

var blogs []Blog
err := db.GetStructs(&blogs, SqlQueryInfo{})

func (*DB) Insert ¶

func (db *DB) Insert(table string, vals map[string]interface{}) (result sql.Result, err error)

insert into table with values from vals Example:

data := map[string]interface{}{
    "title": "hello golang",
    "content": "just wonderful",
}
rerult, err := db.Insert("blog", data)
id, err := result.LastInsertId()

func (*DB) InsertStruct ¶

func (db *DB) InsertStruct(i interface{}) (sql.Result, error)

insert struct to database if i is pointer to struct and has a int type field named "Id" the field "Id" will set to the last insert id if has LastInsertId

field mapping rule is: HelloWorld => hello_world mean that struct's field "HelloWorld" in database table's field is "hello_world" table name mapping use the same rule as field

func (*DB) Query ¶

func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error)

func (*DB) QueryRow ¶

func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row

func (*DB) Select ¶

func (db *DB) Select(table string, qi SqlQueryInfo) (*sql.Rows, error)

select from db.table with qi Example:

qi := &SqlQueryInfo{
        Fields: "*",
        Where: "id > ?",
        Params: []interface{}{ 3 }
        Limit: 10,
        Offset: 0,
        Group: "age",
        Order: "id desc",
}
rows, err := db.Select("blog", qi)

func (*DB) Update ¶

func (db *DB) Update(table string, vals map[string]interface{}, where string, whereParams ...interface{}) (result sql.Result, err error)

type DefaultLogger ¶

type DefaultLogger struct {
	Logger    *log.Logger
	LOG_LEVEL int
}

func (*DefaultLogger) Error ¶

func (l *DefaultLogger) Error(args ...interface{})

func (*DefaultLogger) Errorf ¶

func (l *DefaultLogger) Errorf(format string, args ...interface{})

func (*DefaultLogger) Errorln ¶

func (l *DefaultLogger) Errorln(args ...interface{})

func (*DefaultLogger) Log ¶

func (l *DefaultLogger) Log(args ...interface{})

func (*DefaultLogger) LogLevel ¶

func (l *DefaultLogger) LogLevel() int

func (*DefaultLogger) Logf ¶

func (l *DefaultLogger) Logf(format string, args ...interface{})

func (*DefaultLogger) Logln ¶

func (l *DefaultLogger) Logln(args ...interface{})

func (*DefaultLogger) Notice ¶

func (l *DefaultLogger) Notice(args ...interface{})

func (*DefaultLogger) Noticef ¶

func (l *DefaultLogger) Noticef(format string, args ...interface{})

func (*DefaultLogger) Noticeln ¶

func (l *DefaultLogger) Noticeln(args ...interface{})

func (*DefaultLogger) Warn ¶

func (l *DefaultLogger) Warn(args ...interface{})

func (*DefaultLogger) Warnf ¶

func (l *DefaultLogger) Warnf(format string, args ...interface{})

func (*DefaultLogger) Warnln ¶

func (l *DefaultLogger) Warnln(args ...interface{})

type DefaultMiddlewareHandle ¶

type DefaultMiddlewareHandle struct {
	Middlewares []Middlewarer
}

the defaultmiddleware handler

func (*DefaultMiddlewareHandle) AddMiddleware ¶

func (mh *DefaultMiddlewareHandle) AddMiddleware(mw Middlewarer)

func (*DefaultMiddlewareHandle) BeginMvcHandle ¶

func (mh *DefaultMiddlewareHandle) BeginMvcHandle(ctx *HttpContext) (ar ActionResulter, err error)

func (*DefaultMiddlewareHandle) BeginRequest ¶

func (mh *DefaultMiddlewareHandle) BeginRequest(ctx *HttpContext) (ar ActionResulter, err error)

func (*DefaultMiddlewareHandle) EndMvcHandle ¶

func (mh *DefaultMiddlewareHandle) EndMvcHandle(ctx *HttpContext) (ar ActionResulter, err error)

func (*DefaultMiddlewareHandle) EndRequest ¶

func (mh *DefaultMiddlewareHandle) EndRequest(ctx *HttpContext) (ar ActionResulter, err error)

type DefaultTemplateEngine ¶

type DefaultTemplateEngine struct {
	ExtName       string
	UseCache      bool
	TemplateCache map[string]*template.Template
}

DefaultTemplateEngine

func CreateDefaultTemplateEngine ¶

func CreateDefaultTemplateEngine(useCache bool) *DefaultTemplateEngine

create a default TemplateEnginer.

func (*DefaultTemplateEngine) Ext ¶

func (te *DefaultTemplateEngine) Ext() string

template file ext name, default is ".html"

func (*DefaultTemplateEngine) Render ¶

func (te *DefaultTemplateEngine) Render(filepath string, layoutPath string, viewData *ViewData, wr io.Writer)

func (*DefaultTemplateEngine) SupportLayout ¶

func (te *DefaultTemplateEngine) SupportLayout() bool

return whether the tempalte support layout

type DefaultViewEngine ¶

type DefaultViewEngine struct {
	ExtName               string // template file ext name, default is ".html"
	RootDir               string // view's root dir, must set
	Layout                string // template layout name, default is "layout"
	ViewLocationFormats   []string
	LayoutLocationFormats []string
	UseCache              bool              // whether cache the viewfile
	Caches                map[string]string // controller & action & view to the real-file-path cache
}

DefaultViewEngine

func CreateDefaultViewEngine ¶

func CreateDefaultViewEngine(viewDir, layout, extName string, useCache bool) *DefaultViewEngine

create a default ViewEnginer. some default value:

  • Layout: "layout"
  • ExtName: ".html"
  • ViewLocationFormats: []string{"{1}/{0}", "shared/{0}"} , {1} is controller, {0} is action or a viewName
  • LayoutLocationFormats: []string{"{1}/{0}", "shared/{0}"}

func (*DefaultViewEngine) FindView ¶

func (ve *DefaultViewEngine) FindView(vi *ViewInfo) (viewPath string, layoutPath string)

type Filter ¶

type Filter interface {
	OnActionExecuting(ctx *HttpContext) (ActionResulter, error)
	OnActionExecuted(ctx *HttpContext) (ActionResulter, error)
	OnResultExecuting(ctx *HttpContext) (ActionResulter, error)
	OnResultExecuted(ctx *HttpContext) (ActionResulter, error)
}

Order of the filters execution is:

  1. OnActionExecuting
  2. -> Execute Action -> return ActionResulter
  3. OnActionExecuted
  4. OnResultExecuting
  5. -> ActionResulter.ExecuteResult
  6. OnResultExecuted

type HttpContext ¶

type HttpContext struct {
	Request *http.Request // http request

	Method string // http method

	//self fields
	RouteData *RouteData             // route data
	ViewData  map[string]interface{} // view data for template
	Data      map[string]interface{} // data for httpcontex
	Result    ActionResulter         // action result
	Err       error                  // process error
	User      string                 // user name
	Canceled  bool                   // cancel continue process the request and return
	// contains filtered or unexported fields
}

http context

func (*HttpContext) AddHeader ¶

func (ctx *HttpContext) AddHeader(key string, value string)

add response header

func (*HttpContext) ContentType ¶

func (ctx *HttpContext) ContentType(ctype string)

func (*HttpContext) Error ¶

func (ctx *HttpContext) Error(err interface{}) ActionResulter

func (*HttpContext) Get ¶

func (ctx *HttpContext) Get(name string) string

get the requert param, get from RouteData first, if no, get from Requet.FormValue

func (*HttpContext) GetHeader ¶

func (ctx *HttpContext) GetHeader(key string) string

func (*HttpContext) Header ¶

func (ctx *HttpContext) Header() http.Header

get the response header

func (*HttpContext) Html ¶

func (ctx *HttpContext) Html(data string) ActionResulter

func (*HttpContext) IsAjax ¶

func (ctx *HttpContext) IsAjax() bool

get whether the request is by ajax

func (*HttpContext) Json ¶

func (ctx *HttpContext) Json(data interface{}, contentType ...string) ActionResulter

return json string result ctx.Json(obj) or ctx.Json(obj, "text/html")

func (*HttpContext) NotFound ¶

func (ctx *HttpContext) NotFound(message string) ActionResulter

page not found

func (*HttpContext) NotModified ¶

func (ctx *HttpContext) NotModified() ActionResulter

content not modified

func (*HttpContext) Raw ¶

func (ctx *HttpContext) Raw(data string) ActionResulter

func (*HttpContext) Redirect ¶

func (ctx *HttpContext) Redirect(url_ string) ActionResulter

func (*HttpContext) RedirectPermanent ¶

func (ctx *HttpContext) RedirectPermanent(url_ string) ActionResulter

func (*HttpContext) Render ¶

func (ctx *HttpContext) Render(viewName string, viewModel interface{}) *ViewResult

render the view and return a *ViewResult. it will find the view in these rules:

  1. /{ViewPath}/{Controller}/{viewName}
  2. /{ViewPath}/shared/{viewName}

if viewName start with '/', it will find the view direct by viewpath:

  1. /{ViewPath}/{viewName}

func (*HttpContext) RenderPartial ¶

func (ctx *HttpContext) RenderPartial(viewName string, viewModel interface{}) *ViewResult

render a Partial view and return a *ViewResult. this is not use layout. it will find the view in these rules:

  1. /{ViewPath}/{Controller}/{viewName}
  2. /{ViewPath}/shared/{viewName}

func (*HttpContext) RenderWithLayout ¶

func (ctx *HttpContext) RenderWithLayout(viewName, layout string, viewModel interface{}) *ViewResult

render the view and return a *ViewResult it will find the view in these rules:

  1. /{ViewPath}/{Controller}/{viewName}
  2. /{ViewPath}/shared/{viewName}

func (*HttpContext) ResponseWriter ¶

func (ctx *HttpContext) ResponseWriter() http.ResponseWriter

Try not to use this unless you know exactly what you are doing

func (*HttpContext) RootDir ¶

func (ctx *HttpContext) RootDir() string

func (*HttpContext) SetCookie ¶

func (ctx *HttpContext) SetCookie(cookie *http.Cookie)

set response cookie header

func (*HttpContext) SetHeader ¶

func (ctx *HttpContext) SetHeader(key string, value string)

set the response header

func (*HttpContext) StaticPath ¶

func (ctx *HttpContext) StaticPath() string

func (*HttpContext) Status ¶

func (ctx *HttpContext) Status(code int)

func (*HttpContext) View ¶

func (ctx *HttpContext) View(viewData interface{}) *ViewResult

render the view and return a *ViewResult it will find the view in these rules:

  1. /{ViewPath}/{Controller}/{action}
  2. /{ViewPath}/shared/{action}

func (*HttpContext) ViewPath ¶

func (ctx *HttpContext) ViewPath() string

func (*HttpContext) Write ¶

func (ctx *HttpContext) Write(b []byte) (int, error)

func (*HttpContext) WriteBuffer ¶

func (ctx *HttpContext) WriteBuffer(bf *bytes.Buffer)

func (*HttpContext) WriteHeader ¶

func (ctx *HttpContext) WriteHeader(code int)

func (*HttpContext) WriteString ¶

func (ctx *HttpContext) WriteString(content string)

type MiddlewareHandler ¶

type MiddlewareHandler interface {
	BeginRequest(ctx *HttpContext) (ar ActionResulter, err error)
	BeginMvcHandle(ctx *HttpContext) (ar ActionResulter, err error)
	EndMvcHandle(ctx *HttpContext) (ar ActionResulter, err error)
	EndRequest(ctx *HttpContext) (ar ActionResulter, err error)
}

middleware handler, handle the middleware how tu execute

type Middlewarer ¶

type Middlewarer interface {
	OnBeginRequest(ctx *HttpContext) (ActionResulter, error)
	OnBeginMvcHandle(ctx *HttpContext) (ActionResulter, error)
	OnEndMvcHandle(ctx *HttpContext) (ActionResulter, error)
	OnEndRequest(ctx *HttpContext) (ActionResulter, error)
}

middlewarer interface execute order: OnBeginRequest -> OnBeginMvcHandle -> {controller} -> OnEndMvcHandle -> OnEndRequest notice:

OnBeginRequest & OnEndRequest: All requests will be through these
OnBeginMvcHandle & OnEndMvcHandle: not matched route & static file are not through these

type MysqlDB ¶

type MysqlDB struct {
	DB
}

mysql db

func OpenMysql ¶

func OpenMysql(driverName, dataSourceName string) (db *MysqlDB, err error)

open mysql db, and return MysqlDB struct

type RequestHandler ¶

type RequestHandler struct {
	RouteTable        *RouteTable
	MiddlewareHandler MiddlewareHandler
	ServerConfig      *ServerConfig
	ViewEnginer       ViewEnginer
	TemplateEnginer   TemplateEnginer
}

request handler, the main handler for all the requests

func (*RequestHandler) ServeHTTP ¶

func (rh *RequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

implement the http.Handler interface the main entrance of the request handler

type Route ¶

type Route struct {
	Name       string            // the router name
	Pattern    string            // url pattern config, eg. /{controller}/{action}/{id}
	Default    map[string]string // default value for Pattern
	Constraint map[string]string // constraint for Pattern, value is regexp str
	IsStatic   bool              // whether the route is for static file
	// contains filtered or unexported fields
}

Route config

var rt = &Route {
    Name: "default",
    Pattern: "/{controller}/{action}/{id}",
    Default: map[string]string { "controller": "home", "action": "index", "id": "0", },
    Constraint: map[string]string { "id": "\\d+" }
}

and then, must init the router

rt.Init()

and then, you can use it

rt.Match("/home/index")

func (*Route) Init ¶

func (router *Route) Init()

func (*Route) Match ¶

func (router *Route) Match(url string) (rd *RouteData, matched bool)

type RouteData ¶

type RouteData struct {
	Url        string
	Route      *Route // is this field need ?
	Controller string
	Action     string
	Params     map[string]string
	FilePath   string // if is a static file route, this will be set
}

func (*RouteData) Get ¶

func (rd *RouteData) Get(name string) (val string, ok bool)

type RouteTable ¶

type RouteTable struct {
	Routes []*Route
}

func (*RouteTable) AddRoute ¶

func (rt *RouteTable) AddRoute(route *Route)

func (*RouteTable) Map ¶

func (rt *RouteTable) Map(name string, url string, args ...interface{})

add a new route params:

  • name: route name
  • url: url pattern
  • default: map[string]string, default value for url pattern
  • constraint: map[string]string, constraint for url pattern

func (*RouteTable) Match ¶

func (rt *RouteTable) Match(url string) (rd *RouteData, matched bool)

func (*RouteTable) Static ¶

func (rt *RouteTable) Static(name string, pattern string)

static file route match if has group ,return group 1, else return the url e.g.

pattern: /static/.*  , url: /static/logo.gif , static path: /static/logo.gif
pattern: /static/(.*)  , url: /static/logo.gif , static path: logo.gif

type SQLLiteral ¶

type SQLLiteral string

type Server ¶

type Server struct {
	http.Server
}

server inherit from http.Server

func CreateServer ¶

func CreateServer(routeTable *RouteTable, middlewares []Middlewarer, sc *ServerConfig) *Server

create a server to handle the request routeTable is about the rule map a url to a controller action middlewares are the way you can process request during handle request sc is the config how the server work

type ServerConfig ¶

type ServerConfig struct {
	Addr           string        // TCP address to listen on, ":http" if empty
	ReadTimeout    time.Duration // maximum duration before timing out read of the request
	WriteTimeout   time.Duration // maximum duration before timing out write of the response
	MaxHeaderBytes int           // maximum size of request headers, DefaultMaxHeaderBytes if 0

	RootDir    string // project root dir
	StaticPath string // static file dir, "static" if empty
	ViewPath   string // view file dir, "views" if empty
	Layout     string // template layout, "layout" if empty

	ViewEnginer     ViewEnginer
	TemplateEnginer TemplateEnginer

	Logger   *log.Logger
	LogLevel int

	Debug bool
}

all the config to the web server

type SqlQueryInfo ¶

type SqlQueryInfo struct {
	Fields string
	Join   string
	Where  string
	Params []interface{}
	Limit  int
	Offset int
	Group  string
	Order  string
}

type TemplateEnginer ¶

type TemplateEnginer interface {
	// render the view with viewData and write to w
	Render(viewpath string, layoutPath string, viewData *ViewData, w io.Writer)
	// return whether the tempalte support layout
	SupportLayout() bool
	// template file ext name, default is ".html"
	Ext() string
}

TemplateEnginer interface

type ViewData ¶

type ViewData struct {
	Data    map[string]interface{}
	Model   interface{}
	Globals map[string]interface{}
	Body    interface{} // if in layout template, this will set
}

type ViewEnginer ¶

type ViewEnginer interface {
	// find the view and layout
	// if template engine not suppot layout, just return empty string
	FindView(vi *ViewInfo) (viewPath string, layoutPath string)
}

ViewEnginer interface. For how to find the view file.

type ViewInfo ¶

type ViewInfo struct {
	Controller, Action, View, Layout string
	IsPartial                        bool
}

type ViewResult ¶

type ViewResult struct {
	ActionResult

	ViewEngine     ViewEnginer
	TemplateEngine TemplateEnginer
	ViewData       map[string]interface{}
	ViewModel      interface{}
	ViewName       string
	Layout         string
	IsPartial      bool // if is Partial, not use layout
}

func (*ViewResult) ExecuteResult ¶

func (vr *ViewResult) ExecuteResult(ctx *HttpContext)

func (*ViewResult) Render ¶

func (vr *ViewResult) Render(ctx *HttpContext, wr io.Writer)

Directories ¶

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL