diff --git a/deprecated.go b/deprecated.go index 7b3018f..e20e1f2 100644 --- a/deprecated.go +++ b/deprecated.go @@ -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) +} diff --git a/gin.go b/gin.go index 70108df..aba3298 100644 --- a/gin.go +++ b/gin.go @@ -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. diff --git a/render/render.go b/render/render.go new file mode 100644 index 0000000..cc67aff --- /dev/null +++ b/render/render.go @@ -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 +}