Adds flexible render system

This commit is contained in:
Manu Mtz-Almeida 2014-07-15 17:41:56 +02:00
parent 94bc35bb2d
commit 5ea7a92267
3 changed files with 105 additions and 42 deletions

View File

@ -31,3 +31,8 @@ func (c *Context) ParseBody(item interface{}) error {
func (engine *Engine) ServeFiles(path string, root http.FileSystem) {
engine.router.ServeFiles(path, root)
}
// DEPRECATED use gin.LoadHTMLGlob() or gin.LoadHTMLFiles() instead
func (engine *Engine) LoadHTMLTemplates(pattern string) {
engine.LoadHTMLGlob(pattern)
}

73
gin.go
View File

@ -2,11 +2,11 @@ package gin
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
"github.com/julienschmidt/httprouter"
"html/template"
"log"
@ -71,10 +71,10 @@ type (
// Represents the web framework, it wraps the blazing fast httprouter multiplexer and a list of global middlewares.
Engine struct {
*RouterGroup
HTMLTemplates *template.Template
cache sync.Pool
handlers404 []HandlerFunc
router *httprouter.Router
HTMLRender render.Render
cache sync.Pool
handlers404 []HandlerFunc
router *httprouter.Router
}
)
@ -147,8 +147,20 @@ func Default() *Engine {
return engine
}
func (engine *Engine) LoadHTMLTemplates(pattern string) {
engine.HTMLTemplates = template.Must(template.ParseGlob(pattern))
func (engine *Engine) LoadHTMLGlob(pattern string) {
templ := template.Must(template.ParseGlob(pattern))
engine.SetHTTPTemplate(templ)
}
func (engine *Engine) LoadHTMLFiles(files ...string) {
templ := template.Must(template.ParseFiles(files...))
engine.SetHTTPTemplate(templ)
}
func (engine *Engine) SetHTTPTemplate(templ *template.Template) {
engine.HTMLRender = render.HTMLRender{
Template: templ,
}
}
// Adds handlers for NotFound. It return a 404 code by default.
@ -441,58 +453,35 @@ func (c *Context) BindWith(obj interface{}, b binding.Binding) bool {
return true
}
// Serializes the given struct as JSON into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
c.Writer.Header().Set("Content-Type", MIMEJSON)
if code >= 0 {
c.Writer.WriteHeader(code)
}
encoder := json.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
func (c *Context) Render(code int, render render.Render, obj ...interface{}) {
if err := render.Render(c.Writer, code, obj); err != nil {
c.ErrorTyped(err, ErrorTypeInternal, obj)
c.Abort(500)
}
}
// Serializes the given struct as JSON into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
c.Render(code, render.JSON, obj)
}
// Serializes the given struct as XML into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/xml".
func (c *Context) XML(code int, obj interface{}) {
c.Writer.Header().Set("Content-Type", MIMEXML)
if code >= 0 {
c.Writer.WriteHeader(code)
}
encoder := xml.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
c.ErrorTyped(err, ErrorTypeInternal, obj)
c.Abort(500)
}
c.Render(code, render.XML, obj)
}
// Renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, data interface{}) {
c.Writer.Header().Set("Content-Type", MIMEHTML)
if code >= 0 {
c.Writer.WriteHeader(code)
}
if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
c.ErrorTyped(err, ErrorTypeInternal, H{
"name": name,
"data": data,
})
c.Abort(500)
}
func (c *Context) HTML(code int, name string, obj interface{}) {
c.Render(code, c.Engine.HTMLRender, name, obj)
}
// Writes the given string into the response body and sets the Content-Type to "text/plain".
func (c *Context) String(code int, format string, values ...interface{}) {
c.Writer.Header().Set("Content-Type", MIMEPlain)
if code >= 0 {
c.Writer.WriteHeader(code)
}
c.Writer.Write([]byte(fmt.Sprintf(format, values...)))
c.Render(code, render.Plain, format, values)
}
// Writes some data into the body stream and updates the HTTP code.

69
render/render.go Normal file
View File

@ -0,0 +1,69 @@
package render
import (
"encoding/json"
"encoding/xml"
"fmt"
"html/template"
"net/http"
)
type (
Render interface {
Render(http.ResponseWriter, int, ...interface{}) error
}
// JSON binding
jsonRender struct{}
// XML binding
xmlRender struct{}
// Plain text
plainRender struct{}
// form binding
HTMLRender struct {
Template *template.Template
}
)
var (
JSON = jsonRender{}
XML = xmlRender{}
Plain = plainRender{}
)
func writeHeader(w http.ResponseWriter, code int, contentType string) {
if code >= 0 {
w.Header().Set("Content-Type", contentType)
w.WriteHeader(code)
}
}
func (_ jsonRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "application/xml")
encoder := json.NewEncoder(w)
return encoder.Encode(data[0])
}
func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "application/xml")
encoder := xml.NewEncoder(w)
return encoder.Encode(data[0])
}
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
return html.Template.ExecuteTemplate(w, file, obj)
}
func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/plain")
format := data[0].(string)
args := data[1].([]interface{})
_, err := w.Write([]byte(fmt.Sprintf(format, args)))
return err
}