mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
ok almost finished. We're good at deadlines eventually. Tomorrow at 23:59 an article will be published same time with the dev branch merge to master
Former-commit-id: 42c1bf88cedbddf3cc01366ab769139546902e71
This commit is contained in:
parent
617258890e
commit
1b1661ed53
19
FAQ.md
19
FAQ.md
|
@ -60,17 +60,30 @@ Iris may have reached version 8, but we're not stopping there. We have many feat
|
|||
Yes, not only because you will learn Golang in the same time, but there are some positions
|
||||
open for Iris-specific developers the time we speak.
|
||||
|
||||
- https://glints.id/opportunities/jobs/5553
|
||||
Go to our facebook page, like it and receive notifications about new job offers, we already have couple of them stay at the top of the page: https://www.facebook.com/iris.framework
|
||||
|
||||
<!--
|
||||
## Can Iris be used in production after Dubai purchase?
|
||||
|
||||
Yes, now more than ever.
|
||||
|
||||
https://github.com/kataras/iris/issues/711
|
||||
|
||||
-------
|
||||
|
||||
UPDATE which I could mention by the beginning of the Decemember of 2017:
|
||||
|
||||
Nothing keeps for ever, and we should move on to greater things.
|
||||
|
||||
As you probably know, I was hired to develop an inside Iris version for a Dubai-based startup company's specific requirements in the same time I was developing the open-source Iris repository with your help this time as well!
|
||||
|
||||
As our first deal was to end this agreement via last-time negotiatations by the end of the current year (2017), the
|
||||
agreement ended unofficially at 22 Novemember of 2017 (officially some weeks later, paper work), and after a week I came back to Greece as you may understood from the regularly commits and improvements to the public repository that I pushed.
|
||||
-->
|
||||
|
||||
## Do we have a community Chat?
|
||||
|
||||
Yes, https://kataras.rocket.chat/channel/iris.
|
||||
Yes, https://chat.iris-go.com
|
||||
|
||||
https://github.com/kataras/iris/issues/646
|
||||
|
||||
|
@ -78,4 +91,4 @@ https://github.com/kataras/iris/issues/646
|
|||
|
||||
By normal people like you, who help us by donating small or larger amounts of money.
|
||||
|
||||
Help this project to continue deliver awesome and unique features with the higher code quality as possible by donating any amount via [PayPal](https://www.paypal.me/kataras)!
|
||||
Help this project to continue deliver awesome and unique features with the highest possible code quality as possible by donating any amount via [PayPal](https://www.paypal.me/kataras). Your name will be published [here](https://iris-go.com/donate) after your approval via e-mail.
|
160
HISTORY.md
160
HISTORY.md
|
@ -16,19 +16,161 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
|||
> Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.
|
||||
|
||||
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you.
|
||||
<!--
|
||||
|
||||
# Mo, 01 Jenuary 2018 | v10.0.0
|
||||
|
||||
|
||||
We must thanks [Mrs. Diana](https://www.instagram.com/merry.dii/) for our awesome new [logo](https://iris-go.com/images/logo.svg)!
|
||||
|
||||
You can [contact](mailto:Kovalenkodiana8@gmail.com) her for any design-related enquiries or explore and send a direct message via [instagram](https://www.instagram.com/merry.dii/).
|
||||
|
||||
TODO:
|
||||
<p align="center">
|
||||
<img width="170px" src="https://iris-go.com/images/logo.svg" />
|
||||
</p>
|
||||
|
||||
1. add one more feature, to 'get' auto-created *Route on the mvc by the function name, people need this to change the route's name
|
||||
for reverse routing in the templates, I've already implemented the 'add custom routes' based on any mvc function by its name.
|
||||
At this version we have many internal improvements but just two major changes and one big feature, called **hero**.
|
||||
|
||||
2. list of the changes, we have just one big change,
|
||||
on the mvc re-design but we have some improvements as well
|
||||
I will not list all 70 commits ofc, just the actual changes
|
||||
the end-developer should know. -->
|
||||
> The new version adds 75 plus new commits, read them if you are developing a web framework based on Iris. Why v10? 9 was skipped for undefined reasons.
|
||||
|
||||
## Hero
|
||||
|
||||
The new package [hero](hero) contains features for binding any object or function that `handlers` may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client.
|
||||
|
||||
> You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new `hero` package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran!
|
||||
|
||||
Below you will see some screenshots we prepared for you in order to be easier to understand:
|
||||
|
||||
### 1. Path Parameters - Built'n Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
### 2. Services - Static Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-2-monokai.png)
|
||||
|
||||
### 3. Per-Request - Dynamic Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-3-monokai.png)
|
||||
|
||||
`hero funcs` are very easy to understand and when you start using them **you never go back**.
|
||||
|
||||
Examples:
|
||||
|
||||
- [Basic](_examples/hero/basic/main.go)
|
||||
- [Overview](_examples/hero/overview)
|
||||
|
||||
## MVC
|
||||
|
||||
You have to understand the `hero` package in order to use the `mvc`, because `mvc` uses the `hero` internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well.
|
||||
|
||||
With this version you can register **any controller's methods as routes manually**, you can **get a route based on a method name and change its `Name` (useful for reverse routing inside templates)**, you can use any **dependencies** registered from `hero.Register` or `mvc.New(iris.Party).Register` per mvc application or per-controller, **you can still use `BeginRequest` and `EndRequest`**, you can catch **`BeforeActivation(b mvc.BeforeActivation)` to add dependencies per controller and `AfterActivation(a mvc.AfterActivation)` to make any post-validations**, **singleton controllers when no dynamic dependencies are used**, **Websocket controller, as simple as a `websocket.Connection` dependency** and more...
|
||||
|
||||
Examples:
|
||||
|
||||
**If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE**
|
||||
|
||||
**PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU**
|
||||
|
||||
Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now.
|
||||
|
||||
| NEW | OLD |
|
||||
| -----------|-------------|
|
||||
| [Hello world](_examples/mvc/hello-world/main.go) | [OLD Hello world](https://github.com/kataras/iris/blob/v8/_examples/mvc/hello-world/main.go) |
|
||||
| [Session Controller](_examples/mvc/session-controller/main.go) | [OLD Session Controller](https://github.com/kataras/iris/blob/v8/_examples/mvc/session-controller/main.go) |
|
||||
| [Overview - Plus Repository and Service layers](_examples/mvc/overview) | [OLD Overview - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/overview) |
|
||||
| [Login showcase - Plus Repository and Service layers](_examples/mvc/login) | [OLD Login showcase - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/login) |
|
||||
| [Singleton](_examples/mvc/singleton) | **NEW** |
|
||||
| [Websocket Controller](_examples/mvc/websocket) | **NEW** |
|
||||
| [Vue.js Todo MVC](_examples/tutorial/vuejs-todo-mvc) | **NEW** |
|
||||
|
||||
## context#PostMaxMemory
|
||||
|
||||
Remove the old static variable `context.DefaultMaxMemory` and replace it with the configuration `WithPostMaxMemory`.
|
||||
|
||||
```go
|
||||
// WithPostMaxMemory sets the maximum post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 if you prefer.
|
||||
func WithPostMaxMemory(limit int64) Configurator
|
||||
```
|
||||
|
||||
If you used that old static field you will have to change that single line.
|
||||
|
||||
Usage:
|
||||
|
||||
```go
|
||||
import "github.com/kataras/iris"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// [...]
|
||||
|
||||
app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
|
||||
}
|
||||
```
|
||||
|
||||
## context#UploadFormFiles
|
||||
|
||||
New method to upload multiple files, should be used for common upload actions, it's just a helper function.
|
||||
|
||||
```go
|
||||
// UploadFormFiles uploads any received file(s) from the client
|
||||
// to the system physical location "destDirectory".
|
||||
//
|
||||
// The second optional argument "before" gives caller the chance to
|
||||
// modify the *miltipart.FileHeader before saving to the disk,
|
||||
// it can be used to change a file's name based on the current request,
|
||||
// all FileHeader's options can be changed. You can ignore it if
|
||||
// you don't need to use this capability before saving a file to the disk.
|
||||
//
|
||||
// Note that it doesn't check if request body streamed.
|
||||
//
|
||||
// Returns the copied length as int64 and
|
||||
// a not nil error if at least one new file
|
||||
// can't be created due to the operating system's permissions or
|
||||
// http.ErrMissingFile if no file received.
|
||||
//
|
||||
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
|
||||
// instead and create a copy function that suits your needs, the below is for generic usage.
|
||||
//
|
||||
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
//
|
||||
// See `FormFile` to a more controlled to receive a file.
|
||||
func (ctx *context) UploadFormFiles(
|
||||
destDirectory string,
|
||||
before ...func(string, string),
|
||||
) (int64, error)
|
||||
```
|
||||
|
||||
Example can be found [here](_examples/http_request/upload-files/main.go).
|
||||
|
||||
## context#View
|
||||
|
||||
Just a minor addition, add a second optional variadic argument to the `context#view` method to accept a single value for template binding.
|
||||
When you just want one value and not key-value pairs, you used to use an empty string on the `ViewData`, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain.
|
||||
|
||||
```go
|
||||
func(ctx iris.Context) {
|
||||
ctx.ViewData("", myItem{Name: "iris" })
|
||||
ctx.View("item.html")
|
||||
}
|
||||
```
|
||||
|
||||
Same as:
|
||||
|
||||
```go
|
||||
func(ctx iris.Context) {
|
||||
ctx.View("item.html", myItem{Name: "iris" })
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
Item's name: {{.Name}}
|
||||
```
|
||||
|
||||
## Session#GetString
|
||||
|
||||
`sessions/session#GetString` can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters.
|
22
README.md
22
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
<img align="right" width="170px" src="https://iris-go.com/images/logo.svg" title="logo created by @merry.dii" />
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris) <!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed) [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples) [![release](https://img.shields.io/badge/release%20-v10.0-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples) [![release](https://img.shields.io/badge/release%20-v10.0-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
|
||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||
|
||||
|
@ -41,9 +41,10 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
|
|||
|
||||
## Support
|
||||
|
||||
- [HISTORY](HISTORY.md) file is your best friend, it contains information about all the new features for the current release, you can even search for [older versions](https://github.com/kataras/iris/releases)
|
||||
- [HISTORY](HISTORY.md#mo-01-jenuary-2018--v1000) file is your best friend, it contains information about the latest features and changes
|
||||
- Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues)
|
||||
- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com)
|
||||
- Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
- Do you like the framework? Tweet something about it! The People have spoken:
|
||||
|
||||
<a href="https://twitter.com/gelnior/status/769100480706379776">
|
||||
|
@ -81,15 +82,11 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
|
|||
<img src="https://comments.iris-go.com/comment33_2_mini.png" width="350px">
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/sgryphon/status/912073318928232448">
|
||||
<img src="https://comments.iris-go.com/comment40.png" width="350px">
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/ferarias/status/902468752364773376">
|
||||
<img src="https://comments.iris-go.com/comment41.png" width="350px">
|
||||
</a>
|
||||
|
||||
For more information about contributing to the Iris project please check the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
> For more information about contributing to the Iris project please check the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
|
||||
[List of all Contributors](https://github.com/kataras/iris/graphs/contributors)
|
||||
|
||||
|
@ -103,6 +100,7 @@ First of all, the most correct way to begin with a web framework is to learn the
|
|||
|
||||
### Iris starter kits
|
||||
|
||||
<!-- table form
|
||||
| Description | Link |
|
||||
| -----------|-------------|
|
||||
| Hasura hub starter project with a ready to deploy golang helloworld webapp with IRIS! | https://hasura.io/hub/project/hasura/hello-golang-iris |
|
||||
|
@ -113,6 +111,16 @@ First of all, the most correct way to begin with a web framework is to learn the
|
|||
| Self-hosted Localization Management Platform built with Iris and Angular | https://github.com/iris-contrib/parrot |
|
||||
| Iris + Docker and Kubernetes | https://github.com/iris-contrib/cloud-native-go |
|
||||
| Quickstart for Iris with Nanobox | https://guides.nanobox.io/golang/iris/from-scratch |
|
||||
-->
|
||||
|
||||
1. [A basic web app built in Iris for Go](https://github.com/gauravtiwari/go_iris_app)
|
||||
2. [A mini social-network created with the awesome Iris💖💖](https://github.com/iris-contrib/Iris-Mini-Social-Network)
|
||||
3. [Iris isomorphic react/hot reloadable/redux/css-modules starter kit](https://github.com/iris-contrib/iris-starter-kit)
|
||||
4. [Demo project with react using typescript and Iris](https://github.com/ionutvilie/react-ts)
|
||||
5. [Self-hosted Localization Management Platform built with Iris and Angular](https://github.com/iris-contrib/parrot)
|
||||
6. [Iris + Docker and Kubernetes](https://github.com/iris-contrib/cloud-native-go)
|
||||
7. [Quickstart for Iris with Nanobox](https://guides.nanobox.io/golang/iris/from-scratch)
|
||||
8. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](https://hasura.io/hub/project/hasura/hello-golang-iris)
|
||||
|
||||
> Did you build something similar? Let us [know](https://github.com/kataras/iris/pulls)!
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.5.8:https://github.com/kataras/iris/blob/master/HISTORY.md#th-09-november-2017--v858
|
||||
10.0.0:https://github.com/kataras/iris/blob/master/HISTORY.md#mo-01-jenuary-2018--v1000
|
|
@ -112,6 +112,11 @@ Navigate through examples for a better understanding.
|
|||
* [per-route](routing/writing-a-middleware/per-route/main.go)
|
||||
* [globally](routing/writing-a-middleware/globally/main.go)
|
||||
|
||||
### hero
|
||||
|
||||
- [Basic](hero/basic/main.go)
|
||||
- [Overview](hero/overview)
|
||||
|
||||
### MVC
|
||||
|
||||
![](mvc/web_mvc_diagram.png)
|
||||
|
@ -313,7 +318,8 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
|
|||
|
||||
- [Bind JSON](http_request/read-json/main.go)
|
||||
- [Bind Form](http_request/read-form/main.go)
|
||||
- [Upload/Read Files](http_request/upload-files/main.go)
|
||||
- [Upload/Read File](http_request/upload-file/main.go)
|
||||
- [Upload multiple files with an easy way](http_request/upload-files/main.go)
|
||||
|
||||
> The `context.Request()` returns the same *http.Request you already know, these examples show some places where the Context uses this object. Besides that you can use it as you did before iris.
|
||||
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-2-monokai.png)
|
||||
|
||||
## References
|
||||
## 3. Per-Request - Dynamic Dependencies
|
||||
|
||||
- [explore](https://github.com/kataras/explore)
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-3-monokai.png)
|
73
_examples/http_request/upload-file/main.go
Normal file
73
_examples/http_request/upload-file/main.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
app.RegisterView(iris.HTML("./templates", ".html"))
|
||||
|
||||
// Serve the upload_form.html to the client.
|
||||
app.Get("/upload", func(ctx iris.Context) {
|
||||
// create a token (optionally).
|
||||
|
||||
now := time.Now().Unix()
|
||||
h := md5.New()
|
||||
io.WriteString(h, strconv.FormatInt(now, 10))
|
||||
token := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
// render the form with the token for any use you'd like.
|
||||
// ctx.ViewData("", token)
|
||||
// or add second argument to the `View` method.
|
||||
// Token will be passed as {{.}} in the template.
|
||||
ctx.View("upload_form.html", token)
|
||||
})
|
||||
|
||||
// Handle the post request from the upload_form.html to the server
|
||||
app.Post("/upload", func(ctx iris.Context) {
|
||||
// iris.LimitRequestBodySize(32 <<20) as middleware to a route
|
||||
// or use ctx.SetMaxRequestBodySize(32 << 20)
|
||||
// to limit the whole request body size,
|
||||
//
|
||||
// or let the configuration option at app.Run for global setting
|
||||
// for POST/PUT methods, including uploads of course.
|
||||
|
||||
// Get the file from the request.
|
||||
file, info, err := ctx.FormFile("uploadfile")
|
||||
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
fname := info.Filename
|
||||
|
||||
// Create a file with the same name
|
||||
// assuming that you have a folder named 'uploads'
|
||||
out, err := os.OpenFile("./uploads/"+fname,
|
||||
os.O_WRONLY|os.O_CREATE, 0666)
|
||||
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
io.Copy(out, file)
|
||||
})
|
||||
|
||||
// start the server at http://localhost:8080 with post limit at 32 MB.
|
||||
app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(32<<20))
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Upload file</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data"
|
||||
action="http://127.0.0.1:8080/upload" method="POST">
|
||||
<input type="file" name="uploadfile" /> <input type="hidden"
|
||||
name="token" value="{{.}}" /> <input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
0
_examples/http_request/upload-file/uploads/.gitkeep
Normal file
0
_examples/http_request/upload-file/uploads/.gitkeep
Normal file
|
@ -4,8 +4,9 @@ import (
|
|||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"mime/multipart"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
|
@ -26,46 +27,39 @@ func main() {
|
|||
token := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
// render the form with the token for any use you'd like.
|
||||
ctx.ViewData("", token)
|
||||
ctx.View("upload_form.html")
|
||||
ctx.View("upload_form.html", token)
|
||||
})
|
||||
|
||||
// Handle the post request from the upload_form.html to the server
|
||||
// Handle the post request from the upload_form.html to the server.
|
||||
app.Post("/upload", func(ctx iris.Context) {
|
||||
// iris.LimitRequestBodySize(32 <<20) as middleware to a route
|
||||
// or use ctx.SetMaxRequestBodySize(32 << 20)
|
||||
// to limit the whole request body size,
|
||||
//
|
||||
// or let the configuration option at app.Run for global setting
|
||||
// for POST/PUT methods, including uploads of course.
|
||||
// UploadFormFiles
|
||||
// uploads any number of incoming files (multiple property on the form input).
|
||||
//
|
||||
|
||||
// Get the file from the request.
|
||||
file, info, err := ctx.FormFile("uploadfile")
|
||||
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
fname := info.Filename
|
||||
|
||||
// Create a file with the same name
|
||||
// assuming that you have a folder named 'uploads'
|
||||
out, err := os.OpenFile("./uploads/"+fname,
|
||||
os.O_WRONLY|os.O_CREATE, 0666)
|
||||
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
io.Copy(out, file)
|
||||
// second argument is totally optionally,
|
||||
// it can be used to change a file's name based on the request,
|
||||
// at this example we will showcase how to use it
|
||||
// by prefixing the uploaded file with the current user's ip.
|
||||
ctx.UploadFormFiles("./uploads", beforeSave)
|
||||
})
|
||||
|
||||
// start the server at http://localhost:8080 with post limit at 32 MB.
|
||||
app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(32<<20))
|
||||
}
|
||||
|
||||
func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
|
||||
ip := ctx.RemoteAddr()
|
||||
// make sure you format the ip in a way
|
||||
// that can be used for a file name (simple case):
|
||||
ip = strings.Replace(ip, ".", "_", -1)
|
||||
ip = strings.Replace(ip, ":", "_", -1)
|
||||
|
||||
// you can use the time.Now, to prefix or suffix the files
|
||||
// based on the current time as well, as an exercise.
|
||||
// i.e unixTime := time.Now().Unix()
|
||||
// prefix the Filename with the $IP-
|
||||
// no need for more actions, internal uploader will use this
|
||||
// name to save the file into the "./uploads" folder.
|
||||
file.Filename = ip + "-" + file.Filename
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<body>
|
||||
<form enctype="multipart/form-data"
|
||||
action="http://127.0.0.1:8080/upload" method="POST">
|
||||
<input type="file" name="uploadfile" /> <input type="hidden"
|
||||
<input type="file" name="uploadfile" multiple/> <input type="hidden"
|
||||
name="token" value="{{.}}" /> <input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
//
|
||||
|
||||
//line base.qtpl:3
|
||||
|
||||
package templates
|
||||
|
||||
//line base.qtpl:3
|
||||
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
|
@ -15,12 +17,14 @@ import (
|
|||
)
|
||||
|
||||
//line base.qtpl:3
|
||||
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line base.qtpl:4
|
||||
|
||||
type Partial interface {
|
||||
//line base.qtpl:4
|
||||
Body() string
|
||||
|
@ -29,11 +33,13 @@ type Partial interface {
|
|||
//line base.qtpl:4
|
||||
WriteBody(qq422016 qtio422016.Writer)
|
||||
//line base.qtpl:4
|
||||
|
||||
}
|
||||
|
||||
// Template writes a template implementing the Partial interface.
|
||||
|
||||
//line base.qtpl:11
|
||||
|
||||
func StreamTemplate(qw422016 *qt422016.Writer, p Partial) {
|
||||
//line base.qtpl:11
|
||||
qw422016.N().S(`
|
||||
|
@ -61,9 +67,11 @@ func StreamTemplate(qw422016 *qt422016.Writer, p Partial) {
|
|||
</html>
|
||||
`)
|
||||
//line base.qtpl:30
|
||||
|
||||
}
|
||||
|
||||
//line base.qtpl:30
|
||||
|
||||
func WriteTemplate(qq422016 qtio422016.Writer, p Partial) {
|
||||
//line base.qtpl:30
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
|
@ -72,9 +80,11 @@ func WriteTemplate(qq422016 qtio422016.Writer, p Partial) {
|
|||
//line base.qtpl:30
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line base.qtpl:30
|
||||
|
||||
}
|
||||
|
||||
//line base.qtpl:30
|
||||
|
||||
func Template(p Partial) string {
|
||||
//line base.qtpl:30
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
|
@ -87,21 +97,27 @@ func Template(p Partial) string {
|
|||
//line base.qtpl:30
|
||||
return qs422016
|
||||
//line base.qtpl:30
|
||||
|
||||
}
|
||||
|
||||
// Base template implementation. Other pages may inherit from it if they need
|
||||
// overriding only certain Partial methods.
|
||||
|
||||
//line base.qtpl:35
|
||||
|
||||
type Base struct{}
|
||||
|
||||
//line base.qtpl:36
|
||||
|
||||
func (b *Base) StreamBody(qw422016 *qt422016.Writer) {
|
||||
//line base.qtpl:36
|
||||
qw422016.N().S(`This is the base body`) }
|
||||
|
||||
qw422016.N().S(`This is the base body`)
|
||||
}
|
||||
|
||||
//line base.qtpl:36
|
||||
//line base.qtpl:36
|
||||
|
||||
func (b *Base) WriteBody(qq422016 qtio422016.Writer) {
|
||||
//line base.qtpl:36
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
|
@ -110,9 +126,11 @@ func (b *Base) WriteBody(qq422016 qtio422016.Writer) {
|
|||
//line base.qtpl:36
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line base.qtpl:36
|
||||
|
||||
}
|
||||
|
||||
//line base.qtpl:36
|
||||
|
||||
func (b *Base) Body() string {
|
||||
//line base.qtpl:36
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
|
@ -125,4 +143,5 @@ func (b *Base) Body() string {
|
|||
//line base.qtpl:36
|
||||
return qs422016
|
||||
//line base.qtpl:36
|
||||
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
//
|
||||
|
||||
//line hello.qtpl:3
|
||||
|
||||
package templates
|
||||
|
||||
//line hello.qtpl:3
|
||||
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
|
@ -15,17 +17,20 @@ import (
|
|||
)
|
||||
|
||||
//line hello.qtpl:3
|
||||
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line hello.qtpl:4
|
||||
|
||||
type Hello struct {
|
||||
Vars map[string]interface{}
|
||||
}
|
||||
|
||||
//line hello.qtpl:9
|
||||
|
||||
func (h *Hello) StreamBody(qw422016 *qt422016.Writer) {
|
||||
//line hello.qtpl:9
|
||||
qw422016.N().S(`
|
||||
|
@ -43,9 +48,11 @@ func (h *Hello) StreamBody(qw422016 *qt422016.Writer) {
|
|||
</div>
|
||||
`)
|
||||
//line hello.qtpl:14
|
||||
|
||||
}
|
||||
|
||||
//line hello.qtpl:14
|
||||
|
||||
func (h *Hello) WriteBody(qq422016 qtio422016.Writer) {
|
||||
//line hello.qtpl:14
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
|
@ -54,9 +61,11 @@ func (h *Hello) WriteBody(qq422016 qtio422016.Writer) {
|
|||
//line hello.qtpl:14
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line hello.qtpl:14
|
||||
|
||||
}
|
||||
|
||||
//line hello.qtpl:14
|
||||
|
||||
func (h *Hello) Body() string {
|
||||
//line hello.qtpl:14
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
|
@ -69,4 +78,5 @@ func (h *Hello) Body() string {
|
|||
//line hello.qtpl:14
|
||||
return qs422016
|
||||
//line hello.qtpl:14
|
||||
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
//
|
||||
|
||||
//line index.qtpl:3
|
||||
|
||||
package templates
|
||||
|
||||
//line index.qtpl:3
|
||||
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
|
@ -15,15 +17,18 @@ import (
|
|||
)
|
||||
|
||||
//line index.qtpl:3
|
||||
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line index.qtpl:4
|
||||
|
||||
type Index struct{}
|
||||
|
||||
//line index.qtpl:7
|
||||
|
||||
func (i *Index) StreamBody(qw422016 *qt422016.Writer) {
|
||||
//line index.qtpl:7
|
||||
qw422016.N().S(`
|
||||
|
@ -33,9 +38,11 @@ func (i *Index) StreamBody(qw422016 *qt422016.Writer) {
|
|||
</div>
|
||||
`)
|
||||
//line index.qtpl:12
|
||||
|
||||
}
|
||||
|
||||
//line index.qtpl:12
|
||||
|
||||
func (i *Index) WriteBody(qq422016 qtio422016.Writer) {
|
||||
//line index.qtpl:12
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
|
@ -44,9 +51,11 @@ func (i *Index) WriteBody(qq422016 qtio422016.Writer) {
|
|||
//line index.qtpl:12
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line index.qtpl:12
|
||||
|
||||
}
|
||||
|
||||
//line index.qtpl:12
|
||||
|
||||
func (i *Index) Body() string {
|
||||
//line index.qtpl:12
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
|
@ -59,4 +68,5 @@ func (i *Index) Body() string {
|
|||
//line index.qtpl:12
|
||||
return qs422016
|
||||
//line index.qtpl:12
|
||||
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ import (
|
|||
func main() {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
mvc.Configure(app.Party("/todo"), TodoApp)
|
||||
mvc.Configure(app.Party("/basic"), basicMVC)
|
||||
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
func TodoApp(app *mvc.Application) {
|
||||
func basicMVC(app *mvc.Application) {
|
||||
// You can use normal middlewares at MVC apps of course.
|
||||
app.Router.Use(func(ctx iris.Context) {
|
||||
ctx.Application().Logger().Infof("Path: %s", ctx.Path())
|
||||
|
@ -32,16 +32,16 @@ func TodoApp(app *mvc.Application) {
|
|||
&prefixedLogger{prefix: "DEV"},
|
||||
)
|
||||
|
||||
// GET: http://localhost:8080/todo
|
||||
// GET: http://localhost:8080/todo/custom
|
||||
app.Handle(new(TodoController))
|
||||
// GET: http://localhost:8080/basic
|
||||
// GET: http://localhost:8080/basic/custom
|
||||
app.Handle(new(basicController))
|
||||
|
||||
// All dependencies of the parent *mvc.Application
|
||||
// are cloned to this new child,
|
||||
// thefore it has access to the same session as well.
|
||||
// GET: http://localhost:8080/todo/sub
|
||||
// GET: http://localhost:8080/basic/sub
|
||||
app.Party("/sub").
|
||||
Handle(new(TodoSubController))
|
||||
Handle(new(basicSubController))
|
||||
}
|
||||
|
||||
// If controller's fields (or even its functions) expecting an interface
|
||||
|
@ -64,39 +64,39 @@ func (s *prefixedLogger) Log(msg string) {
|
|||
fmt.Printf("%s: %s\n", s.prefix, msg)
|
||||
}
|
||||
|
||||
type TodoController struct {
|
||||
type basicController struct {
|
||||
Logger LoggerService
|
||||
|
||||
Session *sessions.Session
|
||||
}
|
||||
|
||||
func (c *TodoController) BeforeActivation(b mvc.BeforeActivation) {
|
||||
func (c *basicController) BeforeActivation(b mvc.BeforeActivation) {
|
||||
b.Handle("GET", "/custom", "Custom")
|
||||
}
|
||||
|
||||
func (c *TodoController) AfterActivation(a mvc.AfterActivation) {
|
||||
func (c *basicController) AfterActivation(a mvc.AfterActivation) {
|
||||
if a.Singleton() {
|
||||
panic("TodoController should be stateless, a request-scoped, we have a 'Session' which depends on the context.")
|
||||
panic("basicController should be stateless, a request-scoped, we have a 'Session' which depends on the context.")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *TodoController) Get() string {
|
||||
func (c *basicController) Get() string {
|
||||
count := c.Session.Increment("count", 1)
|
||||
|
||||
body := fmt.Sprintf("Hello from TodoController\nTotal visits from you: %d", count)
|
||||
body := fmt.Sprintf("Hello from basicController\nTotal visits from you: %d", count)
|
||||
c.Logger.Log(body)
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *TodoController) Custom() string {
|
||||
func (c *basicController) Custom() string {
|
||||
return "custom"
|
||||
}
|
||||
|
||||
type TodoSubController struct {
|
||||
type basicSubController struct {
|
||||
Session *sessions.Session
|
||||
}
|
||||
|
||||
func (c *TodoSubController) Get() string {
|
||||
func (c *basicSubController) Get() string {
|
||||
count, _ := c.Session.GetIntDefault("count", 1)
|
||||
return fmt.Sprintf("Hello from TodoSubController.\nRead-only visits count: %d", count)
|
||||
return fmt.Sprintf("Hello from basicSubController.\nRead-only visits count: %d", count)
|
||||
}
|
||||
|
|
|
@ -318,7 +318,7 @@ func WithCharset(charset string) Configurator {
|
|||
// WithPostMaxMemory sets the maximum post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize.
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 if you prefer.
|
||||
func WithPostMaxMemory(limit int64) Configurator {
|
||||
|
@ -478,7 +478,7 @@ type Configuration struct {
|
|||
// PostMaxMemory sets the maximum post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize.
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 if you prefer.
|
||||
PostMaxMemory int64 `json:"postMaxMemory" yaml:"PostMaxMemory" toml:"PostMaxMemory"`
|
||||
|
@ -601,7 +601,7 @@ func (c Configuration) GetCharset() string {
|
|||
// GetPostMaxMemory returns the maximum configured post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize.
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 if you prefer.
|
||||
func (c Configuration) GetPostMaxMemory() int64 {
|
||||
|
|
|
@ -57,7 +57,7 @@ type ConfigurationReadOnly interface {
|
|||
// GetPostMaxMemory returns the maximum configured post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize.
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 if you prefer.
|
||||
GetPostMaxMemory() int64
|
||||
|
|
|
@ -551,7 +551,13 @@ type Context interface {
|
|||
FormFile(key string) (multipart.File, *multipart.FileHeader, error)
|
||||
// UploadFormFiles uploads any received file(s) from the client
|
||||
// to the system physical location "destDirectory".
|
||||
// The root directory must already exists.
|
||||
//
|
||||
// The second optional argument "before" gives caller the chance to
|
||||
// modify the *miltipart.FileHeader before saving to the disk,
|
||||
// it can be used to change a file's name based on the current request,
|
||||
// all FileHeader's options can be changed. You can ignore it if
|
||||
// you don't need to use this capability before saving a file to the disk.
|
||||
//
|
||||
// Note that it doesn't check if request body streamed.
|
||||
//
|
||||
// Returns the copied length as int64 and
|
||||
|
@ -564,7 +570,10 @@ type Context interface {
|
|||
//
|
||||
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
UploadFormFiles(destDirectory string) (int64, error)
|
||||
//
|
||||
// See `FormFile` to a more controlled to receive a file.
|
||||
UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error)
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Custom HTTP Errors |
|
||||
// +------------------------------------------------------------+
|
||||
|
@ -1780,7 +1789,12 @@ func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader,
|
|||
|
||||
// UploadFormFiles uploads any received file(s) from the client
|
||||
// to the system physical location "destDirectory".
|
||||
// The root directory must already exists.
|
||||
//
|
||||
// The second optional argument "before" gives caller the chance to
|
||||
// modify the *miltipart.FileHeader before saving to the disk,
|
||||
// it can be used to change a file's name based on the current request,
|
||||
// all FileHeader's options can be changed. You can ignore it if
|
||||
// you don't need to use this capability before saving a file to the disk.
|
||||
//
|
||||
// Note that it doesn't check if request body streamed.
|
||||
//
|
||||
|
@ -1794,7 +1808,9 @@ func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader,
|
|||
//
|
||||
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
func (ctx *context) UploadFormFiles(destDirectory string) (n int64, err error) {
|
||||
//
|
||||
// See `FormFile` to a more controlled to receive a file.
|
||||
func (ctx *context) UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error) {
|
||||
err = ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -1804,6 +1820,11 @@ func (ctx *context) UploadFormFiles(destDirectory string) (n int64, err error) {
|
|||
if fhs := ctx.request.MultipartForm.File; fhs != nil {
|
||||
for _, files := range fhs {
|
||||
for _, file := range files {
|
||||
|
||||
for _, b := range before {
|
||||
b(ctx, file)
|
||||
}
|
||||
|
||||
n0, err0 := uploadTo(file, destDirectory)
|
||||
if err0 != nil {
|
||||
return 0, err0
|
||||
|
@ -1824,7 +1845,9 @@ func uploadTo(fh *multipart.FileHeader, destDirectory string) (int64, error) {
|
|||
}
|
||||
defer src.Close()
|
||||
|
||||
out, err := os.Create(filepath.Join(destDirectory, fh.Filename))
|
||||
out, err := os.OpenFile(filepath.Join(destDirectory, fh.Filename),
|
||||
os.O_WRONLY|os.O_CREATE, os.FileMode(0666))
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
const (
|
||||
// Version is the string representation of the current local Iris Web Framework version.
|
||||
Version = "8.5.8"
|
||||
Version = "10.0.0"
|
||||
)
|
||||
|
||||
// CheckForUpdates checks for any available updates
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
// https://github.com/kataras/iris/blob/master/HISTORY.md#mo-01-jenuary-2018--v10
|
||||
func (app *Application) Controller(relPath string, c interface{}, _ ...interface{}) []*router.Route {
|
||||
name := mvc.NameOf(c)
|
||||
|
||||
panic(fmt.Errorf(`"Controller" method is DEPRECATED, use the "mvc" subpackage instead.
|
||||
|
||||
PREVIOUSLY YOU USED TO CODE IT LIKE THIS:
|
||||
|
|
4
doc.go
4
doc.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017 The Iris Authors. All rights reserved.
|
||||
// Copyright (c) 2017-2018 The Iris Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
8.5.8
|
||||
10.0.0
|
||||
|
||||
Installation
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user