mirror of
https://github.com/kataras/iris.git
synced 2025-12-27 23:07:03 +00:00
Update to 8.3.0 | MVC Models and Bindings and fix of #723 , read HISTORY.md
Former-commit-id: d8f66d8d370c583a288333df2a14c6ee2dc56466
This commit is contained in:
@@ -82,7 +82,7 @@ Navigate through examples for a better understanding.
|
||||
|
||||
- [Overview](routing/overview/main.go)
|
||||
- [Basic](routing/basic/main.go)
|
||||
- [Controllers](routing/mvc)
|
||||
- [Controllers](mvc)
|
||||
- [Custom HTTP Errors](routing/http-errors/main.go)
|
||||
- [Dynamic Path](routing/dynamic-path/main.go)
|
||||
* [root level wildcard path](routing/dynamic-path/root-wildcard/main.go)
|
||||
@@ -93,6 +93,66 @@ Navigate through examples for a better understanding.
|
||||
* [new implementation](routing/custom-context/new-implementation/main.go)
|
||||
- [Route State](routing/route-state/main.go)
|
||||
|
||||
### MVC
|
||||
|
||||

|
||||
|
||||
Iris has **first-class support for the MVC (Model View Controller) pattern**, you'll not find
|
||||
these stuff anywhere else in the Go world.
|
||||
|
||||
Iris web framework supports Request data, Models, Persistence Data and Binding
|
||||
with the fastest possible execution.
|
||||
|
||||
**Characteristics**
|
||||
|
||||
All HTTP Methods are supported, for example if want to serve `GET`
|
||||
then the controller should have a function named `Get()`,
|
||||
you can define more than one method function to serve in the same Controller struct.
|
||||
|
||||
Persistence data inside your Controller struct (share data between requests)
|
||||
via `iris:"persistence"` tag right to the field or Bind using `app.Controller("/" , new(myController), theBindValue)`.
|
||||
|
||||
Models inside your Controller struct (set-ed at the Method function and rendered by the View)
|
||||
via `iris:"model"` tag right to the field, i.e ```User UserModel `iris:"model" name:"user"` ``` view will recognise it as `{{.user}}`.
|
||||
If `name` tag is missing then it takes the field's name, in this case the `"User"`.
|
||||
|
||||
Access to the request path and its parameters via the `Path and Params` fields.
|
||||
|
||||
Access to the template file that should be rendered via the `Tmpl` field.
|
||||
|
||||
Access to the template data that should be rendered inside
|
||||
the template file via `Data` field.
|
||||
|
||||
Access to the template layout via the `Layout` field.
|
||||
|
||||
Access to the low-level `context.Context` via the `Ctx` field.
|
||||
|
||||
Flow as you used to, `Controllers` can be registered to any `Party`,
|
||||
including Subdomains, the Party's begin and done handlers work as expected.
|
||||
|
||||
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
||||
useful to call middlewares or when many methods use the same collection of data.
|
||||
|
||||
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
||||
|
||||
Inheritance, see for example our `mvc.SessionController`, it has the `mvc.Controller` as an embedded field
|
||||
and it adds its logic to its `BeginRequest`, [here](https://github.com/kataras/iris/blob/master/mvc/session_controller.go).
|
||||
|
||||
**Using Iris MVC for code reuse**
|
||||
|
||||
By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.
|
||||
|
||||
If you're new to back-end web development read about the MVC architectural pattern first, a good start is that [wikipedia article](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller).
|
||||
|
||||
|
||||
Follow the examples below,
|
||||
|
||||
- [Hello world](mvc/hello-world/main.go)
|
||||
- [Session Controller](mvc/session-controller/main.go)
|
||||
- [A simple but featured Controller with model and views](mvc/controller-with-model-and-view).
|
||||
|
||||
|
||||
|
||||
### Subdomains
|
||||
|
||||
- [Single](subdomains/single/main.go)
|
||||
@@ -213,11 +273,14 @@ iris session manager lives on its own [package](https://github.com/kataras/iris/
|
||||
|
||||
iris websocket library lives on its own [package](https://github.com/kataras/iris/tree/master/websocket).
|
||||
|
||||
The package is designed to work with raw websockets although its API is similar to the famous [socket.io](https://socket.io). I have read an article recently and I felt very contented about my decision to design a **fast** websocket-**only** package for Iris and not a backwards socket.io-like package. You can read that article by following this link: https://medium.com/@ivanderbyl/why-you-don-t-need-socket-io-6848f1c871cd.
|
||||
|
||||
- [Chat](websocket/chat/main.go)
|
||||
- [Native Messages](websocket/native-messages/main.go)
|
||||
- [Connection List](websocket/connectionlist/main.go)
|
||||
- [TLS Enabled](websocket/secure/main.go)
|
||||
- [Custom Raw Go Client](websocket/custom-go-client/main.go)
|
||||
- [Third-Party socket.io](websocket/third-party-socketio/main.go)
|
||||
|
||||
> You're free to use your own favourite websockets package if you'd like so.
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@ package main
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
|
||||
"github.com/kataras/iris/middleware/logger"
|
||||
"github.com/kataras/iris/middleware/recover"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
// Optionally, add two built'n handlers
|
||||
// that can recover from any http-relative panics
|
||||
// and log the requests to the terminal.
|
||||
@@ -21,7 +21,7 @@ func main() {
|
||||
// Method: GET
|
||||
// Resource: http://localhost:8080/
|
||||
app.Handle("GET", "/", func(ctx context.Context) {
|
||||
ctx.HTML("<b>Hello world!</b>")
|
||||
ctx.HTML("<b>Welcome!</b>")
|
||||
})
|
||||
|
||||
// same as app.Handle("GET", "/ping", [...])
|
||||
|
||||
99
_examples/mvc/controller-with-model-and-view/main.go
Normal file
99
_examples/mvc/controller-with-model-and-view/main.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
|
||||
// when we have a path separated by spaces
|
||||
// then the Controller is registered to all of them one by one.
|
||||
//
|
||||
// myDB is binded to the controller's `*DB` field: use only structs and pointers.
|
||||
app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
|
||||
new(ProfileController), myDB) // IMPORTANT
|
||||
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
// UserModel our example model which will render on the template.
|
||||
type UserModel struct {
|
||||
ID int64
|
||||
Username string
|
||||
}
|
||||
|
||||
// DB is our example database.
|
||||
type DB struct {
|
||||
usersTable map[int64]UserModel
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// GetUserByID imaginary database lookup based on user id.
|
||||
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
|
||||
db.mu.RLock()
|
||||
u, found = db.usersTable[id]
|
||||
db.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
var myDB = &DB{
|
||||
usersTable: map[int64]UserModel{
|
||||
1: {1, "kataras"},
|
||||
2: {2, "makis"},
|
||||
42: {42, "jdoe"},
|
||||
},
|
||||
}
|
||||
|
||||
// ProfileController our example user controller which controls
|
||||
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
|
||||
type ProfileController struct {
|
||||
mvc.Controller // IMPORTANT
|
||||
|
||||
User UserModel `iris:"model"`
|
||||
// we will bind it but you can also tag it with`iris:"persistence"`
|
||||
// and init the controller with manual &PorifleController{DB: myDB}.
|
||||
DB *DB
|
||||
}
|
||||
|
||||
// Get method handles all "GET" HTTP Method requests of the controller's paths.
|
||||
func (pc *ProfileController) Get() { // IMPORTANT
|
||||
path := pc.Path
|
||||
|
||||
// requested: /profile path
|
||||
if path == "/profile" {
|
||||
pc.Tmpl = "profile/index.html"
|
||||
return
|
||||
}
|
||||
// requested: /profile/browse
|
||||
// this exists only to proof the concept of changing the path:
|
||||
// it will result to a redirection.
|
||||
if path == "/profile/browse" {
|
||||
pc.Path = "/profile"
|
||||
return
|
||||
}
|
||||
|
||||
// requested: /profile/me path
|
||||
if path == "/profile/me" {
|
||||
pc.Tmpl = "profile/me.html"
|
||||
return
|
||||
}
|
||||
|
||||
// requested: /profile/$ID
|
||||
id, _ := pc.Params.GetInt64("id")
|
||||
|
||||
user, found := pc.DB.GetUserByID(id)
|
||||
if !found {
|
||||
pc.Status = iris.StatusNotFound
|
||||
pc.Tmpl = "profile/notfound.html"
|
||||
pc.Data["ID"] = id
|
||||
return
|
||||
}
|
||||
|
||||
pc.Tmpl = "profile/profile.html"
|
||||
pc.User = user
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Profile Browser</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
This is the main page of the <b>/profile</b> path, we'd use that to browser profiles.
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>My Profile</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
This is the current's user imaginary profile space.
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Not Found</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
User with <b>{{.ID}}</b> doesn't exist!</b>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Profile of {{.User.Username}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
This is the profile of a user with ID: <b>{{.User.ID}}</b> and Username: <b>{{.User.Username}}</b>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
105
_examples/mvc/hello-world/main.go
Normal file
105
_examples/mvc/hello-world/main.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
|
||||
"github.com/kataras/iris/middleware/logger"
|
||||
"github.com/kataras/iris/middleware/recover"
|
||||
)
|
||||
|
||||
// This example is equivalent to the
|
||||
// https://github.com/kataras/iris/blob/master/_examples/hello-world/main.go
|
||||
//
|
||||
// It seems that additional code you
|
||||
// have to write doesn't worth it
|
||||
// but remember that, this example
|
||||
// does not make use of iris mvc features like
|
||||
// the Model, Persistence or the View engine neither the Session,
|
||||
// it's very simple for learning purposes,
|
||||
// probably you'll never use such
|
||||
// as simple controller anywhere in your app.
|
||||
//
|
||||
// The cost we have on this example for using MVC
|
||||
// on the "/hello" path which serves JSON
|
||||
// is ~2MB per 20MB throughput on my personal laptop,
|
||||
// it's tolerated for the majority of the applications
|
||||
// but you can choose
|
||||
// what suits you best with Iris, low-level handlers: performance
|
||||
// or high-level controllers: easier to maintain and smaller codebase on large applications.
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// Optionally, add two built'n handlers
|
||||
// that can recover from any http-relative panics
|
||||
// and log the requests to the terminal.
|
||||
app.Use(recover.New())
|
||||
app.Use(logger.New())
|
||||
|
||||
app.Controller("/", new(IndexController))
|
||||
app.Controller("/ping", new(PingController))
|
||||
app.Controller("/hello", new(HelloController))
|
||||
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/ping
|
||||
// http://localhost:8080/hello
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
// IndexController serves the "/".
|
||||
type IndexController struct {
|
||||
// if you build with go1.9 you can omit the import of mvc package
|
||||
// and just use `iris.Controller` instead.
|
||||
mvc.Controller
|
||||
}
|
||||
|
||||
// Get serves
|
||||
// Method: GET
|
||||
// Resource: http://localhost:8080/
|
||||
func (c *IndexController) Get() {
|
||||
c.Ctx.HTML("<b>Welcome!</b>")
|
||||
}
|
||||
|
||||
// PingController serves the "/ping".
|
||||
type PingController struct {
|
||||
mvc.Controller
|
||||
}
|
||||
|
||||
// Get serves
|
||||
// Method: GET
|
||||
// Resource: http://context:8080/ping
|
||||
func (c *PingController) Get() {
|
||||
c.Ctx.WriteString("pong")
|
||||
}
|
||||
|
||||
// HelloController serves the "/hello".
|
||||
type HelloController struct {
|
||||
mvc.Controller
|
||||
}
|
||||
|
||||
// Get serves
|
||||
// Method: GET
|
||||
// Resource: http://localhost:8080/hello
|
||||
func (c *HelloController) Get() {
|
||||
c.Ctx.JSON(iris.Map{"message": "Hello iris web framework."})
|
||||
}
|
||||
|
||||
/* Can use more than one, the factory will make sure
|
||||
that the correct http methods are being registered for each route
|
||||
for this controller, uncomment these if you want:
|
||||
|
||||
func (c *HelloController) Post() {}
|
||||
func (c *HelloController) Put() {}
|
||||
func (c *HelloController) Delete() {}
|
||||
func (c *HelloController) Connect() {}
|
||||
func (c *HelloController) Head() {}
|
||||
func (c *HelloController) Patch() {}
|
||||
func (c *HelloController) Options() {}
|
||||
func (c *HelloController) Trace() {}
|
||||
*/
|
||||
|
||||
/*
|
||||
func (c *HelloController) All() {}
|
||||
// OR
|
||||
func (c *HelloController) Any() {}
|
||||
*/
|
||||
47
_examples/mvc/session-controller/main.go
Normal file
47
_examples/mvc/session-controller/main.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
|
||||
"github.com/kataras/iris/sessions"
|
||||
)
|
||||
|
||||
type VisitController struct {
|
||||
// if you build with go1.9 you can omit the import of mvc package
|
||||
// and just use `iris.Controller` instead.
|
||||
mvc.SessionController
|
||||
|
||||
StartTime time.Time
|
||||
}
|
||||
|
||||
func (u *VisitController) Get() {
|
||||
// get the visits, before calcuate this new one.
|
||||
visits, _ := u.Session.GetIntDefault("visits", 0)
|
||||
|
||||
// increment the visits counter and set them to the session.
|
||||
visits++
|
||||
u.Session.Set("visits", visits)
|
||||
|
||||
// write the current, updated visits
|
||||
u.Ctx.Writef("%d visits in %0.1f seconds", visits, time.Now().Sub(u.StartTime).Seconds())
|
||||
}
|
||||
|
||||
func main() {
|
||||
mySessionManager := sessions.New(sessions.Config{Cookie: "mysession_cookie_name"})
|
||||
|
||||
app := iris.New()
|
||||
|
||||
// bind our session manager, which is required, to the `VisitController.SessionManager.Manager`
|
||||
// and the time.Now() to the `VisitController.StartTime`.
|
||||
app.Controller("/", new(VisitController), mySessionManager, time.Now())
|
||||
|
||||
// 1. open the browser (no in private mode)
|
||||
// 2. navigate to http://localhost:8080
|
||||
// 3. refresh the page some times
|
||||
// 4. close the browser
|
||||
// 5. re-open the browser and re-play 2.
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)
|
||||
}
|
||||
BIN
_examples/mvc/web_mvc_diagram.png
Normal file
BIN
_examples/mvc/web_mvc_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -1,18 +0,0 @@
|
||||
// +build !go1.9
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/core/router"
|
||||
)
|
||||
|
||||
// Index is our index example controller.
|
||||
type Index struct {
|
||||
router.Controller
|
||||
}
|
||||
|
||||
func (c *Index) Get() {
|
||||
c.Tmpl = "index.html"
|
||||
c.Data["title"] = "Index page"
|
||||
c.Data["message"] = "Hello world!"
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// +build go1.9
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
// Index is our index example controller.
|
||||
type Index struct {
|
||||
iris.Controller
|
||||
}
|
||||
|
||||
func (c *Index) Get() {
|
||||
c.Tmpl = "index.html"
|
||||
c.Data["title"] = "Index page"
|
||||
c.Data["message"] = "Hello world!"
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
// +build !go1.9
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/_examples/routing/mvc/persistence"
|
||||
|
||||
"github.com/kataras/iris/core/router"
|
||||
)
|
||||
|
||||
// User is our user example controller.
|
||||
type User struct {
|
||||
router.Controller
|
||||
|
||||
// All fields with pointers(*) that are not nil
|
||||
// and all fields that are tagged with iris:"persistence"`
|
||||
// are being persistence and kept between the different requests,
|
||||
// meaning that these data will not be reset-ed on each new request,
|
||||
// they will be the same for all requests.
|
||||
CreatedAt time.Time `iris:"persistence"`
|
||||
Title string `iris:"persistence"`
|
||||
DB *persistence.Database `iris:"persistence"`
|
||||
}
|
||||
|
||||
func NewUserController(db *persistence.Database) *User {
|
||||
return &User{
|
||||
CreatedAt: time.Now(),
|
||||
Title: "User page",
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Get serves using the User controller when HTTP Method is "GET".
|
||||
func (c *User) Get() {
|
||||
c.Tmpl = "user/index.html"
|
||||
c.Data["title"] = c.Title
|
||||
c.Data["username"] = "kataras " + c.Params.Get("userid")
|
||||
c.Data["connstring"] = c.DB.Connstring
|
||||
c.Data["uptime"] = time.Now().Sub(c.CreatedAt).Seconds()
|
||||
}
|
||||
|
||||
/* Can use more than one, the factory will make sure
|
||||
that the correct http methods are being registered for this
|
||||
controller, uncommend these if you want:
|
||||
|
||||
func (c *User) Post() {}
|
||||
func (c *User) Put() {}
|
||||
func (c *User) Delete() {}
|
||||
func (c *User) Connect() {}
|
||||
func (c *User) Head() {}
|
||||
func (c *User) Patch() {}
|
||||
func (c *User) Options() {}
|
||||
func (c *User) Trace() {}
|
||||
*/
|
||||
|
||||
/*
|
||||
func (c *User) All() {}
|
||||
// OR
|
||||
func (c *User) Any() {}
|
||||
*/
|
||||
@@ -1,81 +0,0 @@
|
||||
// +build go1.9
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/sessions"
|
||||
)
|
||||
|
||||
// User is our user example controller.
|
||||
type User struct {
|
||||
iris.Controller
|
||||
|
||||
// All fields with pointers(*) that are not nil
|
||||
// and all fields that are tagged with iris:"persistence"`
|
||||
// are being persistence and kept between the different requests,
|
||||
// meaning that these data will not be reset-ed on each new request,
|
||||
// they will be the same for all requests.
|
||||
CreatedAt time.Time `iris:"persistence"`
|
||||
Title string `iris:"persistence"`
|
||||
SessionManager *sessions.Sessions `iris:"persistence"`
|
||||
|
||||
Session *sessions.Session // not persistence
|
||||
}
|
||||
|
||||
func NewUserController(sess *sessions.Sessions) *User {
|
||||
return &User{
|
||||
SessionManager: sess,
|
||||
CreatedAt: time.Now(),
|
||||
Title: "User page",
|
||||
}
|
||||
}
|
||||
|
||||
// Init can be used as a custom function
|
||||
// to init the new instance of controller
|
||||
// that is created on each new request.
|
||||
//
|
||||
// Useful when more than one methods are using the same
|
||||
// request data.
|
||||
func (c *User) Init(ctx iris.Context) {
|
||||
c.Session = c.SessionManager.Start(ctx)
|
||||
// println("session id: " + c.Session.ID())
|
||||
}
|
||||
|
||||
// Get serves using the User controller when HTTP Method is "GET".
|
||||
func (c *User) Get() {
|
||||
c.Tmpl = "user/index.html"
|
||||
c.Data["title"] = c.Title
|
||||
c.Data["username"] = "kataras " + c.Params.Get("userid")
|
||||
c.Data["uptime"] = time.Now().Sub(c.CreatedAt).Seconds()
|
||||
|
||||
visits, err := c.Session.GetInt("visit_count")
|
||||
if err != nil {
|
||||
visits = 0
|
||||
}
|
||||
visits++
|
||||
c.Session.Set("visit_count", visits)
|
||||
c.Data["visit_count"] = visits
|
||||
}
|
||||
|
||||
/* Can use more than one, the factory will make sure
|
||||
that the correct http methods are being registered for this
|
||||
controller, uncommend these if you want:
|
||||
|
||||
func (c *User) Post() {}
|
||||
func (c *User) Put() {}
|
||||
func (c *User) Delete() {}
|
||||
func (c *User) Connect() {}
|
||||
func (c *User) Head() {}
|
||||
func (c *User) Patch() {}
|
||||
func (c *User) Options() {}
|
||||
func (c *User) Trace() {}
|
||||
*/
|
||||
|
||||
/*
|
||||
func (c *User) All() {}
|
||||
// OR
|
||||
func (c *User) Any() {}
|
||||
*/
|
||||
@@ -1,25 +0,0 @@
|
||||
// +build !go1.9
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/routing/mvc/controllers"
|
||||
"github.com/kataras/iris/_examples/routing/mvc/persistence"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
|
||||
db := persistence.OpenDatabase("a fake db")
|
||||
|
||||
app.Controller("/", new(controllers.Index))
|
||||
|
||||
app.Controller("/user/{userid:int}", controllers.NewUserController(db))
|
||||
|
||||
// http://localhost:8080/
|
||||
// http://localhost:8080/user/42
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// +build go1.9
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/routing/mvc/controllers"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/sessions"
|
||||
"github.com/kataras/iris/sessions/sessiondb/boltdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
|
||||
sessionDb, _ := boltdb.New("./sessions/sessions.db", 0666, "users")
|
||||
sess := sessions.New(sessions.Config{Cookie: "sessionscookieid"})
|
||||
sess.UseDatabase(sessionDb.Async(true))
|
||||
|
||||
app.Controller("/", new(controllers.Index))
|
||||
|
||||
app.Controller("/user/{userid:int}", controllers.NewUserController(sess))
|
||||
|
||||
// http://localhost:8080/
|
||||
// http://localhost:8080/user/42
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// User is an example model.
|
||||
type User struct {
|
||||
ID int64
|
||||
Username string
|
||||
Firstname string
|
||||
Lastname string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package persistence
|
||||
|
||||
// Database is our imaginary storage.
|
||||
type Database struct {
|
||||
Connstring string
|
||||
}
|
||||
|
||||
func OpenDatabase(connstring string) *Database {
|
||||
return &Database{Connstring: connstring}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>{{.message}}</h1>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,18 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1> Hello {{.username}} </h1>
|
||||
|
||||
|
||||
All fields inside a controller that are pointers or they tagged as `iris:"persistence"` are marked as persistence data, meaning
|
||||
that they will not be reset-ed on each new request.
|
||||
<h3>Persistence data from *DB.Connstring: {{.connstring}} </h3>
|
||||
<h3>Persistence data from CreatedAt `iris:"persistence"`: {{.uptime}} seconds </h3>
|
||||
<h3>{{.visit_count}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,99 +1,130 @@
|
||||
# Controllers from scratch
|
||||
|
||||
This example folder shows how I started to develop
|
||||
the Controller idea inside the Iris web framework itself.
|
||||
This folder shows how [@kataras](https://github.com/kataras) started to develop
|
||||
the MVC idea inside the Iris web framework itself.
|
||||
|
||||
Now it's built'n feature and can be used as:
|
||||
**Now** it has been enhanced and it's a **built'n** feature and can be used as:
|
||||
|
||||
```go
|
||||
// +build go1.9
|
||||
|
||||
// file main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/routing/mvc/persistence"
|
||||
"sync"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
|
||||
db := persistence.OpenDatabase("a fake db")
|
||||
// when we have a path separated by spaces
|
||||
// then the Controller is registered to all of them one by one.
|
||||
//
|
||||
// myDB is binded to the controller's `*DB` field: use only structs and pointers.
|
||||
app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
|
||||
new(ProfileController), myDB) // IMPORTANT
|
||||
|
||||
app.Controller("/user/{userid:int}", NewUserController(db))
|
||||
|
||||
// http://localhost:8080/
|
||||
// http://localhost:8080/user/42
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// +build go1.9
|
||||
|
||||
// file user_controller.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/_examples/routing/mvc/persistence"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
// User is our user example controller.
|
||||
type UserController struct {
|
||||
iris.Controller
|
||||
|
||||
// All fields that are tagged with iris:"persistence"`
|
||||
// are being persistence and kept between the different requests,
|
||||
// meaning that these data will not be reset-ed on each new request,
|
||||
// they will be the same for all requests.
|
||||
CreatedAt time.Time `iris:"persistence"`
|
||||
Title string `iris:"persistence"`
|
||||
DB *persistence.Database `iris:"persistence"`
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
func NewUserController(db *persistence.Database) *User {
|
||||
return &UserController{
|
||||
CreatedAt: time.Now(),
|
||||
Title: "User page",
|
||||
DB: db,
|
||||
}
|
||||
// UserModel our example model which will render on the template.
|
||||
type UserModel struct {
|
||||
ID int64
|
||||
Username string
|
||||
}
|
||||
|
||||
// Get serves using the User controller when HTTP Method is "GET".
|
||||
func (c *UserController) Get() {
|
||||
c.Tmpl = "user/index.html"
|
||||
c.Data["title"] = c.Title
|
||||
c.Data["username"] = "kataras " + c.Params.Get("userid")
|
||||
c.Data["connstring"] = c.DB.Connstring
|
||||
c.Data["uptime"] = time.Now().Sub(c.CreatedAt).Seconds()
|
||||
// DB is our example database.
|
||||
type DB struct {
|
||||
usersTable map[int64]UserModel
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// GetUserByID imaginary database lookup based on user id.
|
||||
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
|
||||
db.mu.RLock()
|
||||
u, found = db.usersTable[id]
|
||||
db.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
var myDB = &DB{
|
||||
usersTable: map[int64]UserModel{
|
||||
1: {1, "kataras"},
|
||||
2: {2, "makis"},
|
||||
42: {42, "jdoe"},
|
||||
},
|
||||
}
|
||||
|
||||
// ProfileController our example user controller which controls
|
||||
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
|
||||
type ProfileController struct {
|
||||
mvc.Controller // IMPORTANT
|
||||
|
||||
User UserModel `iris:"model"`
|
||||
// we will bind it but you can also tag it with`iris:"persistence"`
|
||||
// and init the controller with manual &PorifleController{DB: myDB}.
|
||||
DB *DB
|
||||
}
|
||||
|
||||
// Get method handles all "GET" HTTP Method requests of the controller's paths.
|
||||
func (pc *ProfileController) Get() { // IMPORTANT
|
||||
path := pc.Path
|
||||
|
||||
// requested: /profile path
|
||||
if path == "/profile" {
|
||||
pc.Tmpl = "profile/index.html"
|
||||
return
|
||||
}
|
||||
// requested: /profile/browse
|
||||
// this exists only to proof the concept of changing the path:
|
||||
// it will result to a redirection.
|
||||
if path == "/profile/browse" {
|
||||
pc.Path = "/profile"
|
||||
return
|
||||
}
|
||||
|
||||
// requested: /profile/me path
|
||||
if path == "/profile/me" {
|
||||
pc.Tmpl = "profile/me.html"
|
||||
return
|
||||
}
|
||||
|
||||
// requested: /profile/$ID
|
||||
id, _ := pc.Params.GetInt64("id")
|
||||
|
||||
user, found := pc.DB.GetUserByID(id)
|
||||
if !found {
|
||||
pc.Status = iris.StatusNotFound
|
||||
pc.Tmpl = "profile/notfound.html"
|
||||
pc.Data["ID"] = id
|
||||
return
|
||||
}
|
||||
|
||||
pc.Tmpl = "profile/profile.html"
|
||||
pc.User = user
|
||||
}
|
||||
|
||||
/* Can use more than one, the factory will make sure
|
||||
that the correct http methods are being registered for this
|
||||
controller, uncommend these if you want:
|
||||
that the correct http methods are being registered for each route
|
||||
for this controller, uncomment these if you want:
|
||||
|
||||
func (c *User) Post() {}
|
||||
func (c *User) Put() {}
|
||||
func (c *User) Delete() {}
|
||||
func (c *User) Connect() {}
|
||||
func (c *User) Head() {}
|
||||
func (c *User) Patch() {}
|
||||
func (c *User) Options() {}
|
||||
func (c *User) Trace() {}
|
||||
func (pc *ProfileController) Post() {}
|
||||
func (pc *ProfileController) Put() {}
|
||||
func (pc *ProfileController) Delete() {}
|
||||
func (pc *ProfileController) Connect() {}
|
||||
func (pc *ProfileController) Head() {}
|
||||
func (pc *ProfileController) Patch() {}
|
||||
func (pc *ProfileController) Options() {}
|
||||
func (pc *ProfileController) Trace() {}
|
||||
*/
|
||||
|
||||
/*
|
||||
func (c *User) All() {}
|
||||
func (c *ProfileController) All() {}
|
||||
// OR
|
||||
func (c *User) Any() {}
|
||||
func (c *ProfileController) Any() {}
|
||||
*/
|
||||
```
|
||||
|
||||
Example can be found at: [_examples/routing/mvc](https://github.com/kataras/iris/tree/master/_examples/routing/mvc).
|
||||
Example can be found at: [_examples/mvc](https://github.com/kataras/iris/tree/master/_examples/mvc).
|
||||
44
_examples/websocket/third-party-socketio/main.go
Normal file
44
_examples/websocket/third-party-socketio/main.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
|
||||
"github.com/googollee/go-socket.io"
|
||||
)
|
||||
|
||||
/*
|
||||
go get -u github.com/googollee/go-socket.io
|
||||
*/
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
server, err := socketio.NewServer(nil)
|
||||
if err != nil {
|
||||
app.Logger().Fatal(err)
|
||||
}
|
||||
|
||||
server.On("connection", func(so socketio.Socket) {
|
||||
app.Logger().Infof("on connection")
|
||||
so.Join("chat")
|
||||
so.On("chat message", func(msg string) {
|
||||
app.Logger().Infof("emit: %v", so.Emit("chat message", msg))
|
||||
so.BroadcastTo("chat", "chat message", msg)
|
||||
})
|
||||
so.On("disconnection", func() {
|
||||
app.Logger().Infof("on disconnect")
|
||||
})
|
||||
})
|
||||
|
||||
server.On("error", func(so socketio.Socket, err error) {
|
||||
app.Logger().Errorf("error: %v", err)
|
||||
})
|
||||
|
||||
// serve the socket.io endpoint.
|
||||
app.Any("/socket.io/{p:path}", iris.FromStd(server))
|
||||
|
||||
// serve the index.html and the javascript libraries at
|
||||
// http://localhost:8080
|
||||
app.StaticWeb("/", "./public")
|
||||
|
||||
app.Run(iris.Addr("localhost:8080"))
|
||||
}
|
||||
38
_examples/websocket/third-party-socketio/public/index.html
Normal file
38
_examples/websocket/third-party-socketio/public/index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Socket.IO chat</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font: 13px Helvetica, Arial; }
|
||||
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
|
||||
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
|
||||
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
|
||||
#messages { list-style-type: none; margin: 0; padding: 0; }
|
||||
#messages li { padding: 5px 10px; }
|
||||
#messages li:nth-child(odd) { background: #eee; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ul id="messages"></ul>
|
||||
<form action="">
|
||||
<input id="m" autocomplete="off" /><button>Send</button>
|
||||
</form>
|
||||
<script src="/socket.io-1.3.7.js"></script>
|
||||
<script src="/jquery-1.11.1.js"></script>
|
||||
<script>
|
||||
var socket = io();
|
||||
$('form').submit(function(){
|
||||
socket.emit('chat message with ack', $('#m').val(), function(data){
|
||||
$('#messages').append($('<li>').text('ACK CALLBACK: ' + data));
|
||||
});
|
||||
socket.emit('chat message', $('#m').val());
|
||||
$('#m').val('');
|
||||
return false;
|
||||
});
|
||||
socket.on('chat message', function(msg){
|
||||
$('#messages').append($('<li>').text(msg));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
10309
_examples/websocket/third-party-socketio/public/jquery-1.11.1.js
vendored
Normal file
10309
_examples/websocket/third-party-socketio/public/jquery-1.11.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user