goku

package module
v0.0.0-...-b87fc4c Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2020 License: MIT Imports: 20 Imported by: 24

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{})

SetGlobalViewData adds 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)

AddFilters adds 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

Controller gets 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)

AddActionFilters adds filters for the controller

func (*ControllerInfo) AddFilters

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

AddFilters adds filters for the controller

func (*ControllerInfo) GetAction

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

GetAction gets 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

SupportLayout returns 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)

AddHeader adds 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

Header gets the response header

func (*HttpContext) Html

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

func (*HttpContext) IsAjax

func (ctx *HttpContext) IsAjax() bool

IsAjax gets whether the request is by ajax

func (*HttpContext) Json

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

Json returns 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

RenderPartial renders 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

RenderWithLayout renders 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

View renders 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{})

Map adds 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