From b4d90246dbd8d1a24e164d883cd0df2e2443843d Mon Sep 17 00:00:00 2001 From: Yale Date: Wed, 8 Nov 2017 20:03:02 +0800 Subject: [PATCH 01/24] Create README_CN.md Former-commit-id: 985856ee09b8b1f2b10abb263c56ed900623f644 --- README_CN.md | 1093 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1093 insertions(+) create mode 100644 README_CN.md diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 00000000..43a11a89 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,1093 @@ +# [![Logo created by @santoshanand](logo_white_35_24.png)](https://iris-go.com) Iris + +[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)[![Backers on Open Collective](https://opencollective.com/iris/backers/badge.svg?style=flat-square)](#backers)[![Sponsors on Open Collective](https://opencollective.com/iris/sponsors/badge.svg?style=flat-square)](#sponsors)[![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)[![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)[![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples)[![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris)[![CLA assistant](https://cla-assistant.io/readme/badge/kataras/iris?style=flat-square)](https://cla-assistant.io/kataras/iris) + + + Sponsor + + +Iris是一个超快,使用简单并且非常高效的Go语言Web开发框架。 +Iris is a fast, simple and efficient web framework for Go. + +Iris功能很强大,但使用又很简单,它将会是你下一个网站、API服务或者分布式应用基础框架的不二之选。 +Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app. + +看看[别人是如何评价Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A),同时欢迎各位[成为Iris星探](https://github.com/kataras/iris/stargazers),或者关注[Iris facebook主页](https://facebook.com/iris.framework)。 +Learn what [others say about Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A) and [star](https://github.com/kataras/iris/stargazers) this github repository to stay [up to date](https://facebook.com/iris.framework). + +[![Iris vs .NET Core(C#) vs Node.js (Express)](https://iris-go.com/images/benchmark-new-gray.png)](_benchmarks) + +
+上图是第三发机构发布的REST Web框架的基准测试Benchmarks from third-party source over the rest web frameworks + +![Comparison with other frameworks](https://raw.githubusercontent.com/smallnest/go-web-framework-benchmark/4db507a22c964c9bc9774c5b31afdc199a0fe8b7/benchmark.png) + +_Updated at: [Friday, 29 September 2017](_benchmarks)_ +
+ +## Built with ♥️ +## Built with ♥️ + +在发现Iris之前,我想你一定也看过其他Go Web开发框架,或许你已经摩拳擦掌并马上就要用上了,但我会很遗憾的告诉你,不管怎样,你将来还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris非常独特,他能让你成为真正的极客界的摇滚明星。 + +We have no doubt you will able to find other web frameworks written in Go +and even put up a real fight to learn and use them for quite some time but +make no mistake, sooner or later you will be using Iris, not because of the ergonomic, high-performant solution that it provides but its well-documented unique features, as these will transform you to a real rockstar geek. + +No matter what you're trying to build, Iris covers +every type of application, from micro services to large monolithic web applications. +It's actually the best piece of software for back-end web developers +you can find online. + +Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris. + +Accelerated by [KeyCDN](https://www.keycdn.com/), a simple, fast and reliable CDN. + +We are developing this project using the best code editor for Golang; [Visual Studio Code](https://code.visualstudio.com/) supported by [Microsoft](https://www.microsoft.com). + +If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs](https://github.com/expressjs/express) equivalent for Gophers. + +## Table Of Content + +* [Installation](#installation) +* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) +* [Getting started](#getting-started) +* [Learn](_examples/) + * [MVC (Model View Controller)](_examples/#mvc) **NEW** + * [Structuring](_examples/#structuring) **NEW** + * [HTTP Listening](_examples/#http-listening) + * [Configuration](_examples/#configuration) + * [Routing, Grouping, Dynamic Path Parameters, "Macros" and Custom Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) + * [Subdomains](_examples/#subdomains) + * [Wrap `http.Handler/HandlerFunc`](_examples/#convert-httphandlerhandlerfunc) + * [View](_examples/#view) + * [Authentication](_examples/#authentication) + * [File Server](_examples/#file-server) + * [How to Read from `context.Request() *http.Request`](_examples/#how-to-read-from-contextrequest-httprequest) + * [How to Write to `context.ResponseWriter() http.ResponseWriter`](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) + * [Test](_examples/#testing) + * [Cache](_examples/#caching) + * [Sessions](_examples/#sessions) + * [Websockets](_examples/#websockets) + * [Miscellaneous](_examples/#miscellaneous) + * [POC: Convert the medium-sized project "Parrot" from native to Iris](https://github.com/iris-contrib/parrot) + * [POC: Isomorphic react/hot reloadable/redux/css-modules starter kit](https://github.com/kataras/iris-starter-kit) + * [Typescript Automation Tools](typescript/#table-of-contents) + * [Tutorial: A URL Shortener Service using Go, Iris and Bolt](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) + * [Tutorial: Online Visitors](_examples/tutorial/online-visitors) + * [Tutorial: Caddy](_examples/tutorial/caddy) + * [Tutorial: DropzoneJS Uploader](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) + * [Tutorial:Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) +* [Middleware](middleware/) +* [Dockerize](https://github.com/iris-contrib/cloud-native-go) +* [Contributing](CONTRIBUTING.md) +* [FAQ](FAQ.md) +* [What's next?](#now-you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) +* [People](#people) + +## Installation + +The only requirement is the [Go Programming Language](https://golang.org/dl/) + +```sh +$ go get -u github.com/kataras/iris +``` + +Iris takes advantage of the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature. You get truly reproducible builds, as this method guards against upstream renames and deletes. + +## Getting Started + +```go +package main + +import "github.com/kataras/iris" + +func main() { + app := iris.New() + // Load all templates from the "./views" folder + // where extension is ".html" and parse them + // using the standard `html/template` package. + app.RegisterView(iris.HTML("./views", ".html")) + + // Method: GET + // Resource: http://localhost:8080 + app.Get("/", func(ctx iris.Context) { + // Bind: {{.message}} with "Hello world!" + ctx.ViewData("message", "Hello world!") + // Render template file: ./views/hello.html + ctx.View("hello.html") + }) + + // Method: GET + // Resource: http://localhost:8080/user/42 + // + // Need to use a custom regexp instead? + // Easy; + // Just mark the parameter's type to 'string' + // which accepts anything and make use of + // its `regexp` macro function, i.e: + // app.Get("/user/{id:string regexp(^[0-9]+$)}") + app.Get("/user/{id:long}", func(ctx iris.Context) { + userID, _ := ctx.Params().GetInt64("id") + ctx.Writef("User ID: %d", userID) + }) + + // Start the server using a network address. + app.Run(iris.Addr(":8080")) +} +``` + +> Learn more about path parameter's types by clicking [here](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L31). + +```html + + + + Hello Page + + +

{{.message}}

+ + +``` + +```sh +$ go run main.go +> Now listening on: http://localhost:8080 +> Application started. Press CTRL+C to shut down. +``` + +> Wanna re-start your app automatically when source code changes happens? Install the [rizla](https://github.com/kataras/rizla) tool and run `rizla main.go` instead of `go run main.go`. + +Guidelines for bootstrapping applications can be found at the [_examples/structuring](_examples/#structuring). + +### Quick MVC Tutorial + +```go +package main + +import ( + "github.com/kataras/iris" + "github.com/kataras/iris/mvc" +) + +func main() { + app := iris.New() + + app.Controller("/helloworld", new(HelloWorldController)) + + app.Run(iris.Addr("localhost:8080")) +} + +type HelloWorldController struct { + mvc.C + + // [ Your fields here ] + // Request lifecycle data + // Models + // Database + // Global properties +} + +// +// GET: /helloworld + +func (c *HelloWorldController) Get() string { + return "This is my default action..." +} + +// +// GET: /helloworld/{name:string} + +func (c *HelloWorldController) GetBy(name string) string { + return "Hello " + name +} + +// +// GET: /helloworld/welcome + +func (c *HelloWorldController) GetWelcome() (string, int) { + return "This is the GetWelcome action func...", iris.StatusOK +} + +// +// GET: /helloworld/welcome/{name:string}/{numTimes:int} + +func (c *HelloWorldController) GetWelcomeBy(name string, numTimes int) { + // Access to the low-level Context, + // output arguments are optional of course so we don't have to use them here. + c.Ctx.Writef("Hello %s, NumTimes is: %d", name, numTimes) +} +``` + +> The [_examples/mvc](_examples/mvc) and [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) files explain each feature with simple paradigms, they show how you can take advandage of the Iris MVC Binder, Iris MVC Models and many more... + +Every `exported` func prefixed with an HTTP Method(`Get`, `Post`, `Put`, `Delete`...) in a controller is callable as an HTTP endpoint. In the sample above, all funcs writes a string to the response. Note the comments preceding each method. + +An HTTP endpoint is a targetable URL in the web application, such as `http://localhost:8080/helloworld`, and combines the protocol used: HTTP, the network location of the web server (including the TCP port): `localhost:8080` and the target URI `/helloworld`. + +The first comment states this is an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld" to the base URL. The third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld/welcome" to the URL. + +Controller knows how to handle the "name" on `GetBy` or the "name" and "numTimes" at `GetWelcomeBy`, because of the `By` keyword, and builds the dynamic route without boilerplate; the third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) dynamic method that is invoked by any URL that starts with "/helloworld/welcome" and followed by two more path parts, the first one can accept any value and the second can accept only numbers, i,e: "http://localhost:8080/helloworld/welcome/golang/32719", otherwise a [404 Not Found HTTP Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5) will be sent to the client instead. + +### Quick MVC Tutorial #2 + +Iris has a very powerful and **blazing [fast](_benchmarks)** MVC support, you can return any value of any type from a method function +and it will be sent to the client as expected. + +* if `string` then it's the body. +* if `string` is the second output argument then it's the content type. +* if `int` then it's the status code. +* if `error` and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead. +* if `(int, error)` and error is not nil then the response result will be the error's text with the status code as `int`. +* if `bool` is false then it throws 404 not found http error by skipping everything else. +* if `custom struct` or `interface{}` or `slice` or `map` then it will be rendered as json, unless a `string` content type is following. +* if `mvc.Result` then it executes its `Dispatch` function, so good design patters can be used to split the model's logic where needed. + +The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before; + +```go +package main + +import ( + "github.com/kataras/iris" + "github.com/kataras/iris/middleware/basicauth" + "github.com/kataras/iris/mvc" +) + +// Movie is our sample data structure. +type Movie struct { + Name string `json:"name"` + Year int `json:"year"` + Genre string `json:"genre"` + Poster string `json:"poster"` +} + +// movies contains our imaginary data source. +var movies = []Movie{ + { + Name: "Casablanca", + Year: 1942, + Genre: "Romance", + Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg", + }, + { + Name: "Gone with the Wind", + Year: 1939, + Genre: "Romance", + Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg", + }, + { + Name: "Citizen Kane", + Year: 1941, + Genre: "Mystery", + Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg", + }, + { + Name: "The Wizard of Oz", + Year: 1939, + Genre: "Fantasy", + Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg", + }, +} + + +var basicAuth = basicauth.New(basicauth.Config{ + Users: map[string]string{ + "admin": "password", + }, +}) + + +func main() { + app := iris.New() + + app.Use(basicAuth) + + app.Controller("/movies", new(MoviesController)) + + app.Run(iris.Addr(":8080")) +} + +// MoviesController is our /movies controller. +type MoviesController struct { + mvc.C +} + +// Get returns list of the movies +// Demo: +// curl -i http://localhost:8080/movies +func (c *MoviesController) Get() []Movie { + return movies +} + +// GetBy returns a movie +// Demo: +// curl -i http://localhost:8080/movies/1 +func (c *MoviesController) GetBy(id int) Movie { + return movies[id] +} + +// PutBy updates a movie +// Demo: +// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 +func (c *MoviesController) PutBy(id int) Movie { + // get the movie + m := movies[id] + + // get the request data for poster and genre + file, info, err := c.Ctx.FormFile("poster") + if err != nil { + c.Ctx.StatusCode(iris.StatusInternalServerError) + return Movie{} + } + file.Close() // we don't need the file + poster := info.Filename // imagine that as the url of the uploaded file... + genre := c.Ctx.FormValue("genre") + + // update the poster + m.Poster = poster + m.Genre = genre + movies[id] = m + + return m +} + +// DeleteBy deletes a movie +// Demo: +// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 +func (c *MoviesController) DeleteBy(id int) iris.Map { + // delete the entry from the movies slice + deleted := movies[id].Name + movies = append(movies[:id], movies[id+1:]...) + // and return the deleted movie's name + return iris.Map{"deleted": deleted} +} +``` + +### Quick MVC Tutorial #3 + +Nothing stops you from using your favorite **folder structure**. Iris is a low level web framework, it has got MVC first-class support but it doesn't limit your folder structure, this is your choice. + +Structuring depends on your own needs. We can't tell you how to design your own application for sure but you're free to take a closer look to one typical example below; + +[![folder structure example](_examples/mvc/overview/folder_structure.png)](_examples/mvc/overview) + +Shhh, let's spread the code itself. + +#### Data Model Layer + +```go +// file: datamodels/movie.go + +package datamodels + +// Movie is our sample data structure. +// Keep note that the tags for public-use (for our web app) +// should be kept in other file like "web/viewmodels/movie.go" +// which could wrap by embedding the datamodels.Movie or +// declare new fields instead butwe will use this datamodel +// as the only one Movie model in our application, +// for the shake of simplicty. +type Movie struct { + ID int64 `json:"id"` + Name string `json:"name"` + Year int `json:"year"` + Genre string `json:"genre"` + Poster string `json:"poster"` +} +``` + +#### Data Source / Data Store Layer + +```go +// file: datasource/movies.go + +package datasource + +import "github.com/kataras/iris/_examples/mvc/overview/datamodels" + +// Movies is our imaginary data source. +var Movies = map[int64]datamodels.Movie{ + 1: { + ID: 1, + Name: "Casablanca", + Year: 1942, + Genre: "Romance", + Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg", + }, + 2: { + ID: 2, + Name: "Gone with the Wind", + Year: 1939, + Genre: "Romance", + Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg", + }, + 3: { + ID: 3, + Name: "Citizen Kane", + Year: 1941, + Genre: "Mystery", + Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg", + }, + 4: { + ID: 4, + Name: "The Wizard of Oz", + Year: 1939, + Genre: "Fantasy", + Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg", + }, + 5: { + ID: 5, + Name: "North by Northwest", + Year: 1959, + Genre: "Thriller", + Poster: "https://iris-go.com/images/examples/mvc-movies/5.jpg", + }, +} +``` + +#### Repositories + +The layer which has direct access to the "datasource" and can manipulate data directly. + +```go +// file: repositories/movie_repository.go + +package repositories + +import ( + "errors" + "sync" + + "github.com/kataras/iris/_examples/mvc/overview/datamodels" +) + +// Query represents the visitor and action queries. +type Query func(datamodels.Movie) bool + +// MovieRepository handles the basic operations of a movie entity/model. +// It's an interface in order to be testable, i.e a memory movie repository or +// a connected to an sql database. +type MovieRepository interface { + Exec(query Query, action Query, limit int, mode int) (ok bool) + + Select(query Query) (movie datamodels.Movie, found bool) + SelectMany(query Query, limit int) (results []datamodels.Movie) + + InsertOrUpdate(movie datamodels.Movie) (updatedMovie datamodels.Movie, err error) + Delete(query Query, limit int) (deleted bool) +} + +// NewMovieRepository returns a new movie memory-based repository, +// the one and only repository type in our example. +func NewMovieRepository(source map[int64]datamodels.Movie) MovieRepository { + return &movieMemoryRepository{source: source} +} + +// movieMemoryRepository is a "MovieRepository" +// which manages the movies using the memory data source (map). +type movieMemoryRepository struct { + source map[int64]datamodels.Movie + mu sync.RWMutex +} + +const ( + // ReadOnlyMode will RLock(read) the data . + ReadOnlyMode = iota + // ReadWriteMode will Lock(read/write) the data. + ReadWriteMode +) + +func (r *movieMemoryRepository) Exec(query Query, action Query, actionLimit int, mode int) (ok bool) { + loops := 0 + + if mode == ReadOnlyMode { + r.mu.RLock() + defer r.mu.RUnlock() + } else { + r.mu.Lock() + defer r.mu.Unlock() + } + + for _, movie := range r.source { + ok = query(movie) + if ok { + if action(movie) { + loops++ + if actionLimit >= loops { + break // break + } + } + } + } + + return +} + +// Select receives a query function +// which is fired for every single movie model inside +// our imaginary data source. +// When that function returns true then it stops the iteration. +// +// It returns the query's return last known "found" value +// and the last known movie model +// to help callers to reduce the LOC. +// +// It's actually a simple but very clever prototype function +// I'm using everywhere since I firstly think of it, +// hope you'll find it very useful as well. +func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, found bool) { + found = r.Exec(query, func(m datamodels.Movie) bool { + movie = m + return true + }, 1, ReadOnlyMode) + + // set an empty datamodels.Movie if not found at all. + if !found { + movie = datamodels.Movie{} + } + + return +} + +// SelectMany same as Select but returns one or more datamodels.Movie as a slice. +// If limit <=0 then it returns everything. +func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.Movie) { + r.Exec(query, func(m datamodels.Movie) bool { + results = append(results, m) + return true + }, limit, ReadOnlyMode) + + return +} + +// InsertOrUpdate adds or updates a movie to the (memory) storage. +// +// Returns the new movie and an error if any. +func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamodels.Movie, error) { + id := movie.ID + + if id == 0 { // Create new action + var lastID int64 + // find the biggest ID in order to not have duplications + // in productions apps you can use a third-party + // library to generate a UUID as string. + r.mu.RLock() + for _, item := range r.source { + if item.ID > lastID { + lastID = item.ID + } + } + r.mu.RUnlock() + + id = lastID + 1 + movie.ID = id + + // map-specific thing + r.mu.Lock() + r.source[id] = movie + r.mu.Unlock() + + return movie, nil + } + + // Update action based on the movie.ID, + // here we will allow updating the poster and genre if not empty. + // Alternatively we could do pure replace instead: + // r.source[id] = movie + // and comment the code below; + current, exists := r.Select(func(m datamodels.Movie) bool { + return m.ID == id + }) + + if !exists { // ID is not a real one, return an error. + return datamodels.Movie{}, errors.New("failed to update a nonexistent movie") + } + + // or comment these and r.source[id] = m for pure replace + if movie.Poster != "" { + current.Poster = movie.Poster + } + + if movie.Genre != "" { + current.Genre = movie.Genre + } + + // map-specific thing + r.mu.Lock() + r.source[id] = current + r.mu.Unlock() + + return movie, nil +} + +func (r *movieMemoryRepository) Delete(query Query, limit int) bool { + return r.Exec(query, func(m datamodels.Movie) bool { + delete(r.source, m.ID) + return true + }, limit, ReadWriteMode) +} +``` + +#### Services + +The layer which has access to call functions from the "repositories" and "models" (or even "datamodels" if simple application). It should contain the most of the domain logic. + +```go +// file: services/movie_service.go + +package services + +import ( + "github.com/kataras/iris/_examples/mvc/overview/datamodels" + "github.com/kataras/iris/_examples/mvc/overview/repositories" +) + +// MovieService handles some of the CRUID operations of the movie datamodel. +// It depends on a movie repository for its actions. +// It's here to decouple the data source from the higher level compoments. +// As a result a different repository type can be used with the same logic without any aditional changes. +// It's an interface and it's used as interface everywhere +// because we may need to change or try an experimental different domain logic at the future. +type MovieService interface { + GetAll() []datamodels.Movie + GetByID(id int64) (datamodels.Movie, bool) + DeleteByID(id int64) bool + UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) +} + +// NewMovieService returns the default movie service. +func NewMovieService(repo repositories.MovieRepository) MovieService { + return &movieService{ + repo: repo, + } +} + +type movieService struct { + repo repositories.MovieRepository +} + +// GetAll returns all movies. +func (s *movieService) GetAll() []datamodels.Movie { + return s.repo.SelectMany(func(_ datamodels.Movie) bool { + return true + }, -1) +} + +// GetByID returns a movie based on its id. +func (s *movieService) GetByID(id int64) (datamodels.Movie, bool) { + return s.repo.Select(func(m datamodels.Movie) bool { + return m.ID == id + }) +} + +// UpdatePosterAndGenreByID updates a movie's poster and genre. +func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) { + // update the movie and return it. + return s.repo.InsertOrUpdate(datamodels.Movie{ + ID: id, + Poster: poster, + Genre: genre, + }) +} + +// DeleteByID deletes a movie by its id. +// +// Returns true if deleted otherwise false. +func (s *movieService) DeleteByID(id int64) bool { + return s.repo.Delete(func(m datamodels.Movie) bool { + return m.ID == id + }, 1) +} +``` + +#### View Models + +There should be the view models, the structure that the client will be able to see. + +Example: + +```go +import ( + "github.com/kataras/iris/_examples/mvc/overview/datamodels" + + "github.com/kataras/iris/context" +) + +type Movie struct { + datamodels.Movie +} + +func (m Movie) IsValid() bool { + /* do some checks and return true if it's valid... */ + return m.ID > 0 +} +``` + +Iris is able to convert any custom data Structure into an HTTP Response Dispatcher, +so theoretically, something like the following is permitted if it's really necessary; + +```go +// Dispatch completes the `kataras/iris/mvc#Result` interface. +// Sends a `Movie` as a controlled http response. +// If its ID is zero or less then it returns a 404 not found error +// else it returns its json representation, +// (just like the controller's functions do for custom types by default). +// +// Don't overdo it, the application's logic should not be here. +// It's just one more step of validation before the response, +// simple checks can be added here. +// +// It's just a showcase, +// imagine the potentials this feature gives when designing a bigger application. +// +// This is called where the return value from a controller's method functions +// is type of `Movie`. +// For example the `controllers/movie_controller.go#GetBy`. +func (m Movie) Dispatch(ctx context.Context) { + if !m.IsValid() { + ctx.NotFound() + return + } + ctx.JSON(m, context.JSON{Indent: " "}) +} +``` + +However, we will use the "datamodels" as the only one models package because +Movie structure doesn't contain any sensitive data, clients are able to see all of its fields +and we don't need any extra functionality or validation inside it. + +#### Controllers + +Handles web requests, bridge between the services and the client. + +```go +// file: web/controllers/movie_controller.go + +package controllers + +import ( + "errors" + + "github.com/kataras/iris/_examples/mvc/overview/datamodels" + "github.com/kataras/iris/_examples/mvc/overview/services" + + "github.com/kataras/iris" + "github.com/kataras/iris/mvc" +) + +// MovieController is our /movies controller. +type MovieController struct { + mvc.C + + // Our MovieService, it's an interface which + // is binded from the main application. + Service services.MovieService +} + +// Get returns list of the movies. +// Demo: +// curl -i http://localhost:8080/movies +// +// The correct way if you have sensitive data: +// func (c *MovieController) Get() (results []viewmodels.Movie) { +// data := c.Service.GetAll() +// +// for _, movie := range data { +// results = append(results, viewmodels.Movie{movie}) +// } +// return +// } +// otherwise just return the datamodels. +func (c *MovieController) Get() (results []datamodels.Movie) { + return c.Service.GetAll() +} + +// GetBy returns a movie. +// Demo: +// curl -i http://localhost:8080/movies/1 +func (c *MovieController) GetBy(id int64) (movie datamodels.Movie, found bool) { + return c.Service.GetByID(id) // it will throw 404 if not found. +} + +// PutBy updates a movie. +// Demo: +// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 +func (c *MovieController) PutBy(id int64) (datamodels.Movie, error) { + // get the request data for poster and genre + file, info, err := c.Ctx.FormFile("poster") + if err != nil { + return datamodels.Movie{}, errors.New("failed due form file 'poster' missing") + } + // we don't need the file so close it now. + file.Close() + + // imagine that is the url of the uploaded file... + poster := info.Filename + genre := c.Ctx.FormValue("genre") + + return c.Service.UpdatePosterAndGenreByID(id, poster, genre) +} + +// DeleteBy deletes a movie. +// Demo: +// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 +func (c *MovieController) DeleteBy(id int64) interface{} { + wasDel := c.Service.DeleteByID(id) + if wasDel { + // return the deleted movie's ID + return iris.Map{"deleted": id} + } + // right here we can see that a method function can return any of those two types(map or int), + // we don't have to specify the return type to a specific type. + return iris.StatusBadRequest +} +``` + +```go +// file: web/controllers/hello_controller.go + +package controllers + +import ( + "errors" + + "github.com/kataras/iris/mvc" +) + +// HelloController is our sample controller +// it handles GET: /hello and GET: /hello/{name} +type HelloController struct { + mvc.C +} + +var helloView = mvc.View{ + Name: "hello/index.html", + Data: map[string]interface{}{ + "Title": "Hello Page", + "MyMessage": "Welcome to my awesome website", + }, +} + +// Get will return a predefined view with bind data. +// +// `mvc.Result` is just an interface with a `Dispatch` function. +// `mvc.Response` and `mvc.View` are the built'n result type dispatchers +// you can even create custom response dispatchers by +// implementing the `github.com/kataras/iris/mvc#Result` interface. +func (c *HelloController) Get() mvc.Result { + return helloView +} + +// you can define a standard error in order to be re-usable anywhere in your app. +var errBadName = errors.New("bad name") + +// you can just return it as error or even better +// wrap this error with an mvc.Response to make it an mvc.Result compatible type. +var badName = mvc.Response{Err: errBadName, Code: 400} + +// GetBy returns a "Hello {name}" response. +// Demos: +// curl -i http://localhost:8080/hello/iris +// curl -i http://localhost:8080/hello/anything +func (c *HelloController) GetBy(name string) mvc.Result { + if name != "iris" { + return badName + // or + // GetBy(name string) (mvc.Result, error) { + // return nil, errBadName + // } + } + + // return mvc.Response{Text: "Hello " + name} OR: + return mvc.View{ + Name: "hello/name.html", + Data: name, + } +} +``` + +```go +// file: web/middleware/basicauth.go + +package middleware + +import "github.com/kataras/iris/middleware/basicauth" + +// BasicAuth middleware sample. +var BasicAuth = basicauth.New(basicauth.Config{ + Users: map[string]string{ + "admin": "password", + }, +}) +``` + +```html + + + + + {{.Title}} - My App + + + +

{{.MyMessage}}

+ + + +``` + +```html + + + + + {{.}}' Portfolio - My App + + + +

Hello {{.}}

+ + + +``` + +> Navigate to the [_examples/view](_examples/#view) for more examples +like shared layouts, tmpl funcs, reverse routing and more! + +#### Main + +This file creates any necessary component and links them together. + +```go +// file: main.go + +package main + +import ( + "github.com/kataras/iris/_examples/mvc/overview/datasource" + "github.com/kataras/iris/_examples/mvc/overview/repositories" + "github.com/kataras/iris/_examples/mvc/overview/services" + "github.com/kataras/iris/_examples/mvc/overview/web/controllers" + "github.com/kataras/iris/_examples/mvc/overview/web/middleware" + + "github.com/kataras/iris" +) + +func main() { + app := iris.New() + + // Load the template files. + app.RegisterView(iris.HTML("./web/views", ".html")) + + // Register our controllers. + app.Controller("/hello", new(controllers.HelloController)) + + // Create our movie repository with some (memory) data from the datasource. + repo := repositories.NewMovieRepository(datasource.Movies) + // Create our movie service, we will bind it to the movie controller. + movieService := services.NewMovieService(repo) + + app.Controller("/movies", new(controllers.MovieController), + // Bind the "movieService" to the MovieController's Service (interface) field. + movieService, + // Add the basic authentication(admin:password) middleware + // for the /movies based requests. + middleware.BasicAuth) + + // Start the web server at localhost:8080 + // http://localhost:8080/hello + // http://localhost:8080/hello/iris + // http://localhost:8080/movies + // http://localhost:8080/movies/1 + app.Run( + iris.Addr("localhost:8080"), + iris.WithoutVersionChecker, + iris.WithoutServerError(iris.ErrServerClosed), + iris.WithOptimizations, // enables faster json serialization and more + ) +} +``` + +More folder structure guidelines can be found at the [_examples/#structuring](_examples/#structuring) section. + +## Now you are ready to move to the next step and get closer to becoming a pro gopher + +Congratulations, since you've made it so far, we've crafted just for you some next level content to turn you into a real pro gopher 😃 + +> Don't forget to prepare yourself a cup of coffee, or tea, whatever enjoys you the most! + +* [Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) +* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) +* [Iris, a modular web framework](https://medium.com/@corebreaker/iris-web-cd684b4685c7) +* [Go vs .NET Core in terms of HTTP performance](https://medium.com/@kataras/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8) +* [Iris Go vs .NET Core Kestrel in terms of HTTP performance](https://hackernoon.com/iris-go-vs-net-core-kestrel-in-terms-of-http-performance-806195dc93d5) +* [How to Turn an Android Device into a Web Server](https://twitter.com/ThePracticalDev/status/892022594031017988) +* [Deploying a Iris Golang app in hasura](https://medium.com/@HasuraHQ/deploy-an-iris-golang-app-with-backend-apis-in-minutes-25a559bf530b) +* [A URL Shortener Service using Go, Iris and Bolt](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) + +## People + +The author of Iris is [@kataras](https://github.com/kataras), you can reach him via; + +* [Medium](https://medium.com/@kataras) +* [Twitter](https://twitter.com/makismaropoulos) +* [Dev.to](https://dev.to/@kataras) +* [Facebook](https://facebook.com/iris.framework) +* [Mail](mailto:kataras2006@hotmail.com?subject=Iris%20I%20need%20some%20help%20please) + +[List of all Authors](AUTHORS) + +[List of all Contributors](https://github.com/kataras/iris/graphs/contributors) + +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) or [BTC](https://iris-go.com/v8/donate). + +For more information about contributing to the Iris project please check the [CONTRIBUTING.md file](CONTRIBUTING.md). + +### We need your help with translations into your native language + +Iris needs your help, please think about contributing to the translation of the [README](README.md) and https://iris-go.com, you will be rewarded. + +Instructions can be found at: https://github.com/kataras/iris/issues/796 + +### 03, October 2017 | Iris User Experience Report + +Be part of the **first** Iris User Experience Report by submitting a simple form, it won't take more than **2 minutes**. + +The form contains some questions that you may need to answer in order to learn more about you; learning more about you helps us to serve you with the best possible way! + +https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link + +## Contributors + +This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md). + + +## Backers + +Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/iris#backer) + + + +## Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/iris#sponsor) + + + + + + + + + + + + +## License + +Iris is licensed under the 3-Clause BSD [License](LICENSE). Iris is 100% open-source software. + +For any questions regarding the license please [contact us](mailto:kataras2006@hotmail.com?subject=Iris%20License). From 68ab6e890d197bedfdd487b8058baa4048ac6f03 Mon Sep 17 00:00:00 2001 From: Yale Date: Wed, 8 Nov 2017 22:13:57 +0800 Subject: [PATCH 02/24] Update README_CN.md Former-commit-id: 599ef090022c967aeb5dd2c00743ee27a47cf97e --- README_CN.md | 86 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/README_CN.md b/README_CN.md index 43a11a89..2bd68534 100644 --- a/README_CN.md +++ b/README_CN.md @@ -28,31 +28,43 @@ _Updated at: [Friday, 29 September 2017](_benchmarks)_ ## Built with ♥️ ## Built with ♥️ -在发现Iris之前,我想你一定也看过其他Go Web开发框架,或许你已经摩拳擦掌并马上就要用上了,但我会很遗憾的告诉你,不管怎样,你将来还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris非常独特,他能让你成为真正的极客界的摇滚明星。 +在发现Iris之前,我想你一定也看过其它Go Web开发框架,或许你已经摩拳擦掌并马上就要用上了,但我会很遗憾的告诉你,不管怎样,你将来还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris非常独特,他能让你成为真正的极客界的摇滚明星。 We have no doubt you will able to find other web frameworks written in Go and even put up a real fight to learn and use them for quite some time but make no mistake, sooner or later you will be using Iris, not because of the ergonomic, high-performant solution that it provides but its well-documented unique features, as these will transform you to a real rockstar geek. +不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求,Iris可能是你在网上能找到最好的Web后台开发软件了。 + No matter what you're trying to build, Iris covers every type of application, from micro services to large monolithic web applications. It's actually the best piece of software for back-end web developers you can find online. +Iris现在已经到第8版了,但是我们从未停止开发。有很多非常棒的功能已经提上开发日程了,而且我们非常乐意加入很多有创意的想法。 + Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris. +如果你想用CDN加速,我推荐用[KeyCDN](https://www.keycdn.com/),因为KeyCDN简单、速度快而且稳定。 + Accelerated by [KeyCDN](https://www.keycdn.com/), a simple, fast and reliable CDN. +我们用[微软](https://www.microsoft.com)开发的[Visual Studio Code](https://code.visualstudio.com/)来做为开发Golang的IDE。 + We are developing this project using the best code editor for Golang; [Visual Studio Code](https://code.visualstudio.com/) supported by [Microsoft](https://www.microsoft.com). +如果你之前使用[nodejs](https://nodejs.org)做开发,恭喜你,Iris使用基本和[expressjs](https://github.com/expressjs/express)一样。 + If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs](https://github.com/expressjs/express) equivalent for Gophers. +## 内容列表 + ## Table Of Content -* [Installation](#installation) -* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) -* [Getting started](#getting-started) -* [Learn](_examples/) +* [安装](#installation) +* [最近更新](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) +* [快速入门](#getting-started) +* [进阶](_examples/) * [MVC (Model View Controller)](_examples/#mvc) **NEW** * [Structuring](_examples/#structuring) **NEW** * [HTTP Listening](_examples/#http-listening) @@ -78,24 +90,26 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs * [Tutorial: Caddy](_examples/tutorial/caddy) * [Tutorial: DropzoneJS Uploader](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) * [Tutorial:Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) -* [Middleware](middleware/) -* [Dockerize](https://github.com/iris-contrib/cloud-native-go) -* [Contributing](CONTRIBUTING.md) -* [FAQ](FAQ.md) -* [What's next?](#now-you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) -* [People](#people) +* [中间件](middleware/) +* [Docker例子](https://github.com/iris-contrib/cloud-native-go) +* [贡献](CONTRIBUTING.md) +* [常见问题](FAQ.md) +* [更新计划?](#now-you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) +* [人员](#people) -## Installation +## 安装 +仅仅依赖[Go语言](https://golang.org/dl/) The only requirement is the [Go Programming Language](https://golang.org/dl/) ```sh $ go get -u github.com/kataras/iris ``` +Iris使用[vendor](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) 包依赖管理方式。vendor包管理的方式可以有效处理包依赖更新问题 Iris takes advantage of the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature. You get truly reproducible builds, as this method guards against upstream renames and deletes. -## Getting Started +## 入门 ```go package main @@ -104,40 +118,37 @@ import "github.com/kataras/iris" func main() { app := iris.New() - // Load all templates from the "./views" folder - // where extension is ".html" and parse them - // using the standard `html/template` package. +    // 从"./views"目录加载HTML模板 +    // 模板解析html后缀文件 +    // 此方式是用`html/template`标准包(Iris的模板引擎) app.RegisterView(iris.HTML("./views", ".html")) - // Method: GET - // Resource: http://localhost:8080 +    // HTTP方法: GET +    // 路径: http://localhost:8080 app.Get("/", func(ctx iris.Context) { - // Bind: {{.message}} with "Hello world!" +        // {{.message}} 和 "Hello world!" 字串绑定 ctx.ViewData("message", "Hello world!") - // Render template file: ./views/hello.html +        // 映射HTML模板文件路径 ./views/hello.html ctx.View("hello.html") }) - // Method: GET - // Resource: http://localhost:8080/user/42 + // HTTP方法: GET + // 路径: http://localhost:8080/user/42 // - // Need to use a custom regexp instead? - // Easy; - // Just mark the parameter's type to 'string' - // which accepts anything and make use of - // its `regexp` macro function, i.e: - // app.Get("/user/{id:string regexp(^[0-9]+$)}") +    // 想在路径中用正则吗?So easy! +    // 如下所示 +    // app.Get("/user/{id:string regexp(^[0-9]+$)}") app.Get("/user/{id:long}", func(ctx iris.Context) { userID, _ := ctx.Params().GetInt64("id") ctx.Writef("User ID: %d", userID) }) - // Start the server using a network address. +    // 绑定端口并启动服务. app.Run(iris.Addr(":8080")) } ``` -> Learn more about path parameter's types by clicking [here](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L31). +> 想要了解更多关于路径参数配置,戳 [这里](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L31). ```html @@ -153,15 +164,16 @@ func main() { ```sh $ go run main.go -> Now listening on: http://localhost:8080 -> Application started. Press CTRL+C to shut down. +> 在这里监听服务: http://localhost:8080 +> 应用已经启动按键 CTRL+C 停止服务 ``` -> Wanna re-start your app automatically when source code changes happens? Install the [rizla](https://github.com/kataras/rizla) tool and run `rizla main.go` instead of `go run main.go`. +> 想要实现当代码改变后自动重启应用吗?那就装个[rizla](https://github.com/kataras/rizla)工具,启动go文件用 `rizla main.go` 来代替 `go run main.go`. -Guidelines for bootstrapping applications can be found at the [_examples/structuring](_examples/#structuring). +Iris的一些开发约定可以看看这里[_examples/structuring](_examples/#structuring)。 -### Quick MVC Tutorial + +### MVC指南 ```go package main @@ -218,10 +230,14 @@ func (c *HelloWorldController) GetWelcomeBy(name string, numTimes int) { // output arguments are optional of course so we don't have to use them here. c.Ctx.Writef("Hello %s, NumTimes is: %d", name, numTimes) } + ``` +> [_examples/mvc](_examples/mvc) 和 [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) 两个简单的例子可以让你更好的了解 Iris MVC 的使用方式 > The [_examples/mvc](_examples/mvc) and [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) files explain each feature with simple paradigms, they show how you can take advandage of the Iris MVC Binder, Iris MVC Models and many more... +每一个在controller中导出的Go方法名都和HTTP方法(`Get`, `Post`, `Put`, `Delete`...) 一一对应 + Every `exported` func prefixed with an HTTP Method(`Get`, `Post`, `Put`, `Delete`...) in a controller is callable as an HTTP endpoint. In the sample above, all funcs writes a string to the response. Note the comments preceding each method. An HTTP endpoint is a targetable URL in the web application, such as `http://localhost:8080/helloworld`, and combines the protocol used: HTTP, the network location of the web server (including the TCP port): `localhost:8080` and the target URI `/helloworld`. From f43e2cc2c6bd129803a1ce3248c1e9cc0d39e446 Mon Sep 17 00:00:00 2001 From: Yale Date: Wed, 8 Nov 2017 22:39:30 +0800 Subject: [PATCH 03/24] Update README_CN.md Former-commit-id: 1e51aca7613c4f40d7ce8c0dd0e630cfc3b647b6 --- README_CN.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README_CN.md b/README_CN.md index 2bd68534..1341102d 100644 --- a/README_CN.md +++ b/README_CN.md @@ -240,10 +240,17 @@ func (c *HelloWorldController) GetWelcomeBy(name string, numTimes int) { Every `exported` func prefixed with an HTTP Method(`Get`, `Post`, `Put`, `Delete`...) in a controller is callable as an HTTP endpoint. In the sample above, all funcs writes a string to the response. Note the comments preceding each method. +在Web应用中一个HTTP访问的资源就是一个URL,比如`http://localhost:8080/helloworld`是由,HTTP协议、Web服务网络位置(包括TCP端口):`localhost:8080`以及资源名称URI `/helloworld`组成的。 + An HTTP endpoint is a targetable URL in the web application, such as `http://localhost:8080/helloworld`, and combines the protocol used: HTTP, the network location of the web server (including the TCP port): `localhost:8080` and the target URI `/helloworld`. +上面例子第一个方法映射到[HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,访问资源是"/helloworld",第三个方法映射到[HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,访问资源是"/helloworld/welcome" + The first comment states this is an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld" to the base URL. The third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld/welcome" to the URL. + +Controller在处理`GetBy`方法时可以识别‘name’参数,以及`GetWelcomeBy`方法时也可以识别‘name’和‘numTimes’参数,因为Controller在识别`By`关键字后可以动态灵活的处理路由;上面第四个方法指示使用 [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,而且只处理以"/helloworld/welcome"开头的资源位置路径,并且此路径还得包括两部分,第一部分类型没有限制,第二部分只能是数字类型,比如"http://localhost:8080/helloworld/welcome/golang/32719" 是合法的,其它的就会给客户端返回[404 找不到](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5)的提示 + Controller knows how to handle the "name" on `GetBy` or the "name" and "numTimes" at `GetWelcomeBy`, because of the `By` keyword, and builds the dynamic route without boilerplate; the third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) dynamic method that is invoked by any URL that starts with "/helloworld/welcome" and followed by two more path parts, the first one can accept any value and the second can accept only numbers, i,e: "http://localhost:8080/helloworld/welcome/golang/32719", otherwise a [404 Not Found HTTP Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5) will be sent to the client instead. ### Quick MVC Tutorial #2 From ed71632e255e88cdba32f22996741f0960ed6bb4 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 09:45:51 +0800 Subject: [PATCH 04/24] Update README_CN.md Former-commit-id: a7e4dc51976be4dd5172947b0cf5ffa7e39b3ada --- README_CN.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README_CN.md b/README_CN.md index 1341102d..d5914583 100644 --- a/README_CN.md +++ b/README_CN.md @@ -253,21 +253,23 @@ Controller在处理`GetBy`方法时可以识别‘name’参数,以及`GetWelc Controller knows how to handle the "name" on `GetBy` or the "name" and "numTimes" at `GetWelcomeBy`, because of the `By` keyword, and builds the dynamic route without boilerplate; the third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) dynamic method that is invoked by any URL that starts with "/helloworld/welcome" and followed by two more path parts, the first one can accept any value and the second can accept only numbers, i,e: "http://localhost:8080/helloworld/welcome/golang/32719", otherwise a [404 Not Found HTTP Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5) will be sent to the client instead. -### Quick MVC Tutorial #2 +### MVC 快速指南 2 + +Iris对MVC的支持非常 **棒[高性能](_benchmarks)** , 通过方法的返回值,Iris可以给客户端返回任意类型的数据。 Iris has a very powerful and **blazing [fast](_benchmarks)** MVC support, you can return any value of any type from a method function and it will be sent to the client as expected. -* if `string` then it's the body. -* if `string` is the second output argument then it's the content type. -* if `int` then it's the status code. -* if `error` and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead. -* if `(int, error)` and error is not nil then the response result will be the error's text with the status code as `int`. -* if `bool` is false then it throws 404 not found http error by skipping everything else. -* if `custom struct` or `interface{}` or `slice` or `map` then it will be rendered as json, unless a `string` content type is following. -* if `mvc.Result` then it executes its `Dispatch` function, so good design patters can be used to split the model's logic where needed. +* 如果是 `string` 类型,就直接返回字符串 +* 如果第二个返回值是 `string` 类型,那么这个值就是ContentType的值 +* 如果是 `int` 类型,这个值就是HTTP状态码 +* 如果 `error` 值不是空,Iris 将会把这个值作为HTTP400页面的返回值内容 +*  如果是 `(int, error)` 类型,并且error不为空,那么Iris返回error的内容,同时把 `int` 值作为HTTP状态码 +* 如果返回 `bool` 类型,并且值是 false ,Iris直接返回404页面 +* 如果返回自定义` struct` 、 `interface{}` 、 `slice` 及 `map` ,Iris 将按照JSON的方式返回,注意如果第二个返回值是 `string`,那么Iris就按照这个 `string` 值的ContentType处理了(不一定是'application/json') +*  如果 `mvc.Result` 调用了 `Dispatch` 函数, 就会按照自己的逻辑重新处理 -The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before; +下面这些例子仅供参考,生产环境谨慎使用 ```go package main @@ -278,7 +280,7 @@ import ( "github.com/kataras/iris/mvc" ) -// Movie is our sample data structure. +// Movie 是自定义数据结构 type Movie struct { Name string `json:"name"` Year int `json:"year"` @@ -286,7 +288,7 @@ type Movie struct { Poster string `json:"poster"` } -// movies contains our imaginary data source. +// movies 对象模拟数据 var movies = []Movie{ { Name: "Casablanca", @@ -332,7 +334,7 @@ func main() { app.Run(iris.Addr(":8080")) } -// MoviesController is our /movies controller. +// MoviesController 是 /movies controller. type MoviesController struct { mvc.C } From 064741d48782b907d58432021a634c39818997f3 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 10:10:59 +0800 Subject: [PATCH 05/24] Update README_CN.md Former-commit-id: 1edea8d809b5c1f77ddb198a4d0f5b6123e8e788 --- README_CN.md | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/README_CN.md b/README_CN.md index d5914583..5aa6aa51 100644 --- a/README_CN.md +++ b/README_CN.md @@ -288,7 +288,7 @@ type Movie struct { Poster string `json:"poster"` } -// movies 对象模拟数据 +// movies 对象模拟数据源 var movies = []Movie{ { Name: "Casablanca", @@ -339,38 +339,38 @@ type MoviesController struct { mvc.C } -// Get returns list of the movies -// Demo: +// 返回 movies列表 +// 例子: // curl -i http://localhost:8080/movies func (c *MoviesController) Get() []Movie { return movies } -// GetBy returns a movie -// Demo: +// GetBy 返回一个 movie +// 例子: // curl -i http://localhost:8080/movies/1 func (c *MoviesController) GetBy(id int) Movie { return movies[id] } -// PutBy updates a movie -// Demo: +// PutBy 更新一个 movie +// 例子: // curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 func (c *MoviesController) PutBy(id int) Movie { - // get the movie +    // 获取一个 movie m := movies[id] - // get the request data for poster and genre - file, info, err := c.Ctx.FormFile("poster") +    // 获取一个poster文件 +    file, info, err := c.Ctx.FormFile("poster") if err != nil { c.Ctx.StatusCode(iris.StatusInternalServerError) return Movie{} } - file.Close() // we don't need the file - poster := info.Filename // imagine that as the url of the uploaded file... +    file.Close()           // 我们不需要这个文件 +    poster := info.Filename // 比如这就是上传的文件url genre := c.Ctx.FormValue("genre") - // update the poster +    // 更新poster m.Poster = poster m.Genre = genre movies[id] = m @@ -378,19 +378,21 @@ func (c *MoviesController) PutBy(id int) Movie { return m } -// DeleteBy deletes a movie -// Demo: +// DeleteBy 删除一个 movie +// 例子: // curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 func (c *MoviesController) DeleteBy(id int) iris.Map { - // delete the entry from the movies slice - deleted := movies[id].Name +    //从movies slice中删除索引 +    deleted := movies[id].Name movies = append(movies[:id], movies[id+1:]...) - // and return the deleted movie's name - return iris.Map{"deleted": deleted} +    // 返回删除movie的名称 +    return iris.Map{"deleted": deleted} } ``` -### Quick MVC Tutorial #3 +### MVC 快速指南 3 + + Nothing stops you from using your favorite **folder structure**. Iris is a low level web framework, it has got MVC first-class support but it doesn't limit your folder structure, this is your choice. From 4f97344c22c75760ccd7fc89cd271fede3c1859a Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 11:39:14 +0800 Subject: [PATCH 06/24] Update README_CN.md Former-commit-id: 51e771a552dbb768b59c852897a8dbfddbf3c93a --- README_CN.md | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/README_CN.md b/README_CN.md index 5aa6aa51..73ff2366 100644 --- a/README_CN.md +++ b/README_CN.md @@ -392,30 +392,32 @@ func (c *MoviesController) DeleteBy(id int) iris.Map { ### MVC 快速指南 3 - +Iris是一个底层的Web开发框架,如果你喜欢按 **目录结构** 的约定方式开发,那么Iris框架对此毫无影响。 Nothing stops you from using your favorite **folder structure**. Iris is a low level web framework, it has got MVC first-class support but it doesn't limit your folder structure, this is your choice. +你可以根据自己的需求来创建目录结构,但是我建议你还是最好看看如下的目录结构例子: + +[![目录结构例子](_examples/mvc/overview/folder_structure.png)](_examples/mvc/overview) + +好了,直接上代码。 + Structuring depends on your own needs. We can't tell you how to design your own application for sure but you're free to take a closer look to one typical example below; [![folder structure example](_examples/mvc/overview/folder_structure.png)](_examples/mvc/overview) Shhh, let's spread the code itself. -#### Data Model Layer +#### 数据模型层 ```go // file: datamodels/movie.go package datamodels -// Movie is our sample data structure. -// Keep note that the tags for public-use (for our web app) -// should be kept in other file like "web/viewmodels/movie.go" -// which could wrap by embedding the datamodels.Movie or -// declare new fields instead butwe will use this datamodel -// as the only one Movie model in our application, -// for the shake of simplicty. +// Movie是我们例子数据结构 +// 此Movie对象可能会在"web/viewmodels/movie.go"的文件里持有 +// Movie的数据模型在应用中只有一个,这样使用就很简单了 type Movie struct { ID int64 `json:"id"` Name string `json:"name"` @@ -434,7 +436,7 @@ package datasource import "github.com/kataras/iris/_examples/mvc/overview/datamodels" -// Movies is our imaginary data source. +// Movies是模拟的数据源 var Movies = map[int64]datamodels.Movie{ 1: { ID: 1, @@ -474,9 +476,9 @@ var Movies = map[int64]datamodels.Movie{ } ``` -#### Repositories +#### 数据仓库 -The layer which has direct access to the "datasource" and can manipulate data directly. +数据仓库层用来直接访问数据源 ```go // file: repositories/movie_repository.go @@ -490,12 +492,10 @@ import ( "github.com/kataras/iris/_examples/mvc/overview/datamodels" ) -// Query represents the visitor and action queries. +// Query 是数据访问的集合入口 type Query func(datamodels.Movie) bool -// MovieRepository handles the basic operations of a movie entity/model. -// It's an interface in order to be testable, i.e a memory movie repository or -// a connected to an sql database. +// MovieRepository 中会有对movie实体的基本操作 type MovieRepository interface { Exec(query Query, action Query, limit int, mode int) (ok bool) @@ -506,23 +506,21 @@ type MovieRepository interface { Delete(query Query, limit int) (deleted bool) } -// NewMovieRepository returns a new movie memory-based repository, -// the one and only repository type in our example. +// NewMovieRepository 返回movie内存数据 func NewMovieRepository(source map[int64]datamodels.Movie) MovieRepository { return &movieMemoryRepository{source: source} } -// movieMemoryRepository is a "MovieRepository" -// which manages the movies using the memory data source (map). +// movieMemoryRepository 就是 "MovieRepository",它管理movie的内存数据 type movieMemoryRepository struct { source map[int64]datamodels.Movie mu sync.RWMutex } const ( - // ReadOnlyMode will RLock(read) the data . +    // 只读模式 ReadOnlyMode = iota - // ReadWriteMode will Lock(read/write) the data. +    // 写模式 ReadWriteMode ) From ef486790f7cf8b9b7545e38cb8283eb3366c3116 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 17:17:02 +0800 Subject: [PATCH 07/24] Update README_CN.md Former-commit-id: 84e5fd283f13e6a226639f273daefc7deeb4a2b8 --- README_CN.md | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/README_CN.md b/README_CN.md index 73ff2366..de92935b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -478,7 +478,7 @@ var Movies = map[int64]datamodels.Movie{ #### 数据仓库 -数据仓库层用来直接访问数据源 +数据仓库层直接访问数据源 ```go // file: repositories/movie_repository.go @@ -550,6 +550,12 @@ func (r *movieMemoryRepository) Exec(query Query, action Query, actionLimit int, return } +// Select方法返回从模拟数据源找出的一个movie数据。 +// 当找到时就返回true,并停止迭代 +// +// Select 将会返回查询到的最新找到的movie数据,这样可以减少代码量 +// +// 自从我第一次想到用这种简单的原型函数后,我就经常用它了,希望这也对你有用 // Select receives a query function // which is fired for every single movie model inside // our imaginary data source. @@ -568,7 +574,8 @@ func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, fou return true }, 1, ReadOnlyMode) - // set an empty datamodels.Movie if not found at all. +    // 如果没有找到就让datamodels.Movie为空 +    // set an empty datamodels.Movie if not found at all. if !found { movie = datamodels.Movie{} } @@ -576,6 +583,8 @@ func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, fou return } +//如果要查找很多值,用法基本一致,不过会返回datamodels.Movie slice。 +// 如果limit<=0,将返回全部数据 // SelectMany same as Select but returns one or more datamodels.Movie as a slice. // If limit <=0 then it returns everything. func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.Movie) { @@ -587,15 +596,20 @@ func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []da return } +//插入或跟新数据 // InsertOrUpdate adds or updates a movie to the (memory) storage. // +// 返回一个新的movie对象和error对象 // Returns the new movie and an error if any. func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamodels.Movie, error) { id := movie.ID if id == 0 { // Create new action var lastID int64 - // find the biggest ID in order to not have duplications +        // 为了数据不重复,找到最大的ID +        // 生成环境你可以用第三方库生成一个UUID字串 + +        // find the biggest ID in order to not have duplications // in productions apps you can use a third-party // library to generate a UUID as string. r.mu.RLock() @@ -616,8 +630,11 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode return movie, nil } - - // Update action based on the movie.ID, +    //通过movie.ID更新数据 +    //这里举个例子看如果更新poster和genre非空值 +    //其实我们可以直接更新对象r.source[id] = movie +    //用Select的话如下所示 +    // Update action based on the movie.ID, // here we will allow updating the poster and genre if not empty. // Alternatively we could do pure replace instead: // r.source[id] = movie @@ -626,11 +643,12 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode return m.ID == id }) - if !exists { // ID is not a real one, return an error. +    if !exists { // ID不存在,返回error ID is not a real one, return an error. return datamodels.Movie{}, errors.New("failed to update a nonexistent movie") } - // or comment these and r.source[id] = m for pure replace +    // 或者直接对象操作替换 +    // or comment these and r.source[id] = m for pure replace if movie.Poster != "" { current.Poster = movie.Poster } @@ -655,7 +673,9 @@ func (r *movieMemoryRepository) Delete(query Query, limit int) bool { } ``` -#### Services +#### 服务层 + +服务层主要调用“数据仓库”和“数据模型”的方法(即使是数据模型很简单的应用)。这一层将包含主要的数据处理逻辑。 The layer which has access to call functions from the "repositories" and "models" (or even "datamodels" if simple application). It should contain the most of the domain logic. @@ -669,6 +689,9 @@ import ( "github.com/kataras/iris/_examples/mvc/overview/repositories" ) +// MovieService主要包括对movie的CRUID(增删改查)操作。 +// MovieService主要调用movie 数据仓库的方法。 +// // MovieService handles some of the CRUID operations of the movie datamodel. // It depends on a movie repository for its actions. // It's here to decouple the data source from the higher level compoments. From 330ae5cdaea6bb6fb6db4a433e1129bf24ca76e3 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 17:48:17 +0800 Subject: [PATCH 08/24] Update README_CN.md Former-commit-id: 3980198bb98ece5472d90d9dea3aed53e9fcd284 --- README_CN.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README_CN.md b/README_CN.md index de92935b..6775ce93 100644 --- a/README_CN.md +++ b/README_CN.md @@ -691,7 +691,10 @@ import ( // MovieService主要包括对movie的CRUID(增删改查)操作。 // MovieService主要调用movie 数据仓库的方法。 -// +// 下面例子的数据源是从更高级别的组件 +// 这样可以用同样的逻辑可以返回不同的数据仓库 +// MovieService是一个接口,任何实现的地方等能用,这样替换不同的业务逻辑可以用来测试 + // MovieService handles some of the CRUID operations of the movie datamodel. // It depends on a movie repository for its actions. // It's here to decouple the data source from the higher level compoments. @@ -705,7 +708,7 @@ type MovieService interface { UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) } -// NewMovieService returns the default movie service. +// NewMovieService 返回一个 movie 服务. func NewMovieService(repo repositories.MovieRepository) MovieService { return &movieService{ repo: repo, @@ -716,21 +719,22 @@ type movieService struct { repo repositories.MovieRepository } -// GetAll returns all movies. +// GetAll 返回所有 movies. func (s *movieService) GetAll() []datamodels.Movie { return s.repo.SelectMany(func(_ datamodels.Movie) bool { return true }, -1) } -// GetByID returns a movie based on its id. +// GetByID 是通过id找到movie. func (s *movieService) GetByID(id int64) (datamodels.Movie, bool) { return s.repo.Select(func(m datamodels.Movie) bool { return m.ID == id }) } -// UpdatePosterAndGenreByID updates a movie's poster and genre. + +// UpdatePosterAndGenreByID 更新一个 movie的 poster 和 genre. func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) { // update the movie and return it. return s.repo.InsertOrUpdate(datamodels.Movie{ @@ -740,9 +744,9 @@ func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre s }) } -// DeleteByID deletes a movie by its id. +// DeleteByID 通过id删除一个movie // -// Returns true if deleted otherwise false. +// 返回true表示成功,其它都是失败 func (s *movieService) DeleteByID(id int64) bool { return s.repo.Delete(func(m datamodels.Movie) bool { return m.ID == id @@ -750,8 +754,9 @@ func (s *movieService) DeleteByID(id int64) bool { } ``` -#### View Models +#### 视图模型 +视图模型处理给客户端看的 There should be the view models, the structure that the client will be able to see. Example: From f971686123d944e0e30e35a89c24d83b94eefdaa Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 20:40:59 +0800 Subject: [PATCH 09/24] Update README_CN.md Former-commit-id: 59c2c0e4afa5a495db7bc1dab6eb52bd8999b97f --- README_CN.md | 78 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/README_CN.md b/README_CN.md index 6775ce93..323b2504 100644 --- a/README_CN.md +++ b/README_CN.md @@ -652,7 +652,7 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode if movie.Poster != "" { current.Poster = movie.Poster } - + if movie.Genre != "" { current.Genre = movie.Genre } @@ -756,9 +756,10 @@ func (s *movieService) DeleteByID(id int64) bool { #### 视图模型 -视图模型处理给客户端看的 +视图模型将处理结果返回给客户端 There should be the view models, the structure that the client will be able to see. +例子: Example: ```go @@ -773,28 +774,38 @@ type Movie struct { } func (m Movie) IsValid() bool { - /* do some checks and return true if it's valid... */ +    /* 做一些检测,如果ID合法就返回true */ return m.ID > 0 } ``` +Iris允许在HTTP Response Dispatcher中使用任何自定义数据结构,所以理论上下面的代码不建议使用 + Iris is able to convert any custom data Structure into an HTTP Response Dispatcher, so theoretically, something like the following is permitted if it's really necessary; ```go +// Dispatch实现了`kataras/iris/mvc#Result`接口。在函数最后发送了一个`Movie`对象作为http response对象。 +// 如果ID小于等于0就回返回404,或者就返回json数据。 +//(这样就像控制器的方法默认返回自定义类型一样) // Dispatch completes the `kataras/iris/mvc#Result` interface. // Sends a `Movie` as a controlled http response. // If its ID is zero or less then it returns a 404 not found error // else it returns its json representation, // (just like the controller's functions do for custom types by default). // +// 不要在这里写过多的代码,应用的主要逻辑不在这里 +// 在方法返回之前可以做个简单验证处理等等; // Don't overdo it, the application's logic should not be here. // It's just one more step of validation before the response, // simple checks can be added here. // +// 这里只是一个小例子,想想这个优势在设计大型应用是很有作用的 // It's just a showcase, // imagine the potentials this feature gives when designing a bigger application. // +// 这个方法是在`Movie`类型的控制器调用的。 +// 例子在这里:`controllers/movie_controller.go#GetBy`。 // This is called where the return value from a controller's method functions // is type of `Movie`. // For example the `controllers/movie_controller.go#GetBy`. @@ -806,13 +817,14 @@ func (m Movie) Dispatch(ctx context.Context) { ctx.JSON(m, context.JSON{Indent: " "}) } ``` - +然而,我们仅仅用"datamodels"作为一个数据模型包是因为Movie数据结构没有包含敏感数据,客户端可以访问到其所有字段,我们不需要再有额外的功能去做验证处理了 However, we will use the "datamodels" as the only one models package because Movie structure doesn't contain any sensitive data, clients are able to see all of its fields and we don't need any extra functionality or validation inside it. -#### Controllers +#### 控制器 +控制器处理Web请求,它是服务层和客户端之间的桥梁 Handles web requests, bridge between the services and the client. ```go @@ -830,20 +842,21 @@ import ( "github.com/kataras/iris/mvc" ) -// MovieController is our /movies controller. +// MovieController是/movies的控制器 type MovieController struct { mvc.C - // Our MovieService, it's an interface which +    // MovieService是一个接口,主app对象会持有它 +    // Our MovieService, it's an interface which // is binded from the main application. Service services.MovieService } -// Get returns list of the movies. -// Demo: +// 获取movies列表 +// 例子: // curl -i http://localhost:8080/movies // -// The correct way if you have sensitive data: +// 如果你有一些敏感的数据要处理的话,可以按照如下所示的方式: // func (c *MovieController) Get() (results []viewmodels.Movie) { // data := c.Service.GetAll() // @@ -852,47 +865,49 @@ type MovieController struct { // } // return // } -// otherwise just return the datamodels. +//否则直接返回数据模型 func (c *MovieController) Get() (results []datamodels.Movie) { return c.Service.GetAll() } -// GetBy returns a movie. -// Demo: +// GetBy返回一个movie对象 +// 例子: // curl -i http://localhost:8080/movies/1 func (c *MovieController) GetBy(id int64) (movie datamodels.Movie, found bool) { - return c.Service.GetByID(id) // it will throw 404 if not found. +    return c.Service.GetByID(id) // 404 没有找到 } -// PutBy updates a movie. -// Demo: +// PutBy更新一个movie. +// 例子: // curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 func (c *MovieController) PutBy(id int64) (datamodels.Movie, error) { - // get the request data for poster and genre +    // 从请求中获取poster和genre file, info, err := c.Ctx.FormFile("poster") if err != nil { return datamodels.Movie{}, errors.New("failed due form file 'poster' missing") } - // we don't need the file so close it now. - file.Close() +    // 关闭文件 +    file.Close() - // imagine that is the url of the uploaded file... +    //想象这就是一个上传文件的url poster := info.Filename genre := c.Ctx.FormValue("genre") return c.Service.UpdatePosterAndGenreByID(id, poster, genre) } -// DeleteBy deletes a movie. -// Demo: +// DeleteBy删除一个movie对象 +// 例子: // curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 func (c *MovieController) DeleteBy(id int64) interface{} { wasDel := c.Service.DeleteByID(id) if wasDel { - // return the deleted movie's ID +        // 返回要删除的ID return iris.Map{"deleted": id} } - // right here we can see that a method function can return any of those two types(map or int), +    //现在我们可以看到这里可以返回一个有2个返回值(map或int)的函数 +    //我们并没有指定一个返回的类型 +    // right here we can see that a method function can return any of those two types(map or int), // we don't have to specify the return type to a specific type. return iris.StatusBadRequest } @@ -909,8 +924,8 @@ import ( "github.com/kataras/iris/mvc" ) -// HelloController is our sample controller -// it handles GET: /hello and GET: /hello/{name} +// HelloController是控制器的例子 +// 下面会处理GET: /hello and GET: /hello/{name} type HelloController struct { mvc.C } @@ -923,17 +938,16 @@ var helloView = mvc.View{ }, } -// Get will return a predefined view with bind data. +// Get会返回预定义绑定数据的视图 // -// `mvc.Result` is just an interface with a `Dispatch` function. -// `mvc.Response` and `mvc.View` are the built'n result type dispatchers -// you can even create custom response dispatchers by -// implementing the `github.com/kataras/iris/mvc#Result` interface. +// `mvc.Result`是一个含有`Dispatch`方法的接口 +// `mvc.Response` 和 `mvc.View` dispatchers 内置类型 +// 你也可以通过实现`github.com/kataras/iris/mvc#Result`接口来自定义dispatchers func (c *HelloController) Get() mvc.Result { return helloView } -// you can define a standard error in order to be re-usable anywhere in your app. +// 你可以定义一个标准通用的error var errBadName = errors.New("bad name") // you can just return it as error or even better From d6b2a687349264d7b14123f73bd9b2d492240764 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 20:57:03 +0800 Subject: [PATCH 10/24] Update README_CN.md Former-commit-id: 8c54704b8dcd6ae6fa6e4f3ca325a61d5d616001 --- README_CN.md | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/README_CN.md b/README_CN.md index 323b2504..2173f050 100644 --- a/README_CN.md +++ b/README_CN.md @@ -950,24 +950,25 @@ func (c *HelloController) Get() mvc.Result { // 你可以定义一个标准通用的error var errBadName = errors.New("bad name") +//你也可以将error包裹在mvc.Response中,这样就和mvc.Result类型兼容了 // you can just return it as error or even better // wrap this error with an mvc.Response to make it an mvc.Result compatible type. var badName = mvc.Response{Err: errBadName, Code: 400} -// GetBy returns a "Hello {name}" response. -// Demos: +// GetBy 返回 "Hello {name}" response +// 例子: // curl -i http://localhost:8080/hello/iris // curl -i http://localhost:8080/hello/anything func (c *HelloController) GetBy(name string) mvc.Result { if name != "iris" { return badName - // or - // GetBy(name string) (mvc.Result, error) { +        // 或者 +        // GetBy(name string) (mvc.Result, error) { // return nil, errBadName // } } - // return mvc.Response{Text: "Hello " + name} OR: +    // 返回 mvc.Response{Text: "Hello " + name} 或者: return mvc.View{ Name: "hello/name.html", Data: name, @@ -982,7 +983,7 @@ package middleware import "github.com/kataras/iris/middleware/basicauth" -// BasicAuth middleware sample. +// BasicAuth 中间件例 var BasicAuth = basicauth.New(basicauth.Config{ Users: map[string]string{ "admin": "password", @@ -1020,11 +1021,12 @@ var BasicAuth = basicauth.New(basicauth.Config{ ``` -> Navigate to the [_examples/view](_examples/#view) for more examples -like shared layouts, tmpl funcs, reverse routing and more! +> 戳[_examples/view](_examples/#view) 可以找到更多关于layouts,tmpl,routing的例子 -#### Main +#### 程序入口 + +程序入口可以将任何创建的组件包含进来 This file creates any necessary component and links them together. ```go @@ -1045,25 +1047,27 @@ import ( func main() { app := iris.New() - // Load the template files. - app.RegisterView(iris.HTML("./web/views", ".html")) +    // 加载模板文件 +    app.RegisterView(iris.HTML("./web/views", ".html")) - // Register our controllers. - app.Controller("/hello", new(controllers.HelloController)) +    // 注册控制器 +    app.Controller("/hello", new(controllers.HelloController)) - // Create our movie repository with some (memory) data from the datasource. - repo := repositories.NewMovieRepository(datasource.Movies) - // Create our movie service, we will bind it to the movie controller. - movieService := services.NewMovieService(repo) +    // 创建movie 数据仓库,次仓库包含的是内存级的数据源 +    repo := repositories.NewMovieRepository(datasource.Movies) +    // 创建movie服务, 然后将其与控制器绑定 +    movieService := services.NewMovieService(repo) app.Controller("/movies", new(controllers.MovieController), // Bind the "movieService" to the MovieController's Service (interface) field. - movieService, - // Add the basic authentication(admin:password) middleware +        // 将"movieService"绑定在 MovieController的Service接口 +        movieService, +        // 为/movies请求添加basic authentication(admin:password)中间件 +        // Add the basic authentication(admin:password) middleware // for the /movies based requests. middleware.BasicAuth) - // Start the web server at localhost:8080 +    // 启动应用localhost:8080 // http://localhost:8080/hello // http://localhost:8080/hello/iris // http://localhost:8080/movies @@ -1072,13 +1076,16 @@ func main() { iris.Addr("localhost:8080"), iris.WithoutVersionChecker, iris.WithoutServerError(iris.ErrServerClosed), - iris.WithOptimizations, // enables faster json serialization and more - ) +        iris.WithOptimizations, // 可以启用快速json序列化等优化配置 +    ) } ``` +更多指南戳 [_examples/#structuring](_examples/#structuring) + More folder structure guidelines can be found at the [_examples/#structuring](_examples/#structuring) section. +## 现在你已经准备好进入下一个阶段了,又向专家级gopher更近一步了 ## Now you are ready to move to the next step and get closer to becoming a pro gopher Congratulations, since you've made it so far, we've crafted just for you some next level content to turn you into a real pro gopher 😃 From 91a02b7bac3aedece87da1087c5fa11e9dc0da20 Mon Sep 17 00:00:00 2001 From: Yale Date: Thu, 9 Nov 2017 21:08:36 +0800 Subject: [PATCH 11/24] Update README_CN.md Former-commit-id: 98c7b794dadd42be938e7fd6cff7aa2ddfce229a --- README_CN.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index 2173f050..f1e7b23e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1026,7 +1026,7 @@ var BasicAuth = basicauth.New(basicauth.Config{ #### 程序入口 -程序入口可以将任何创建的组件包含进来 +程序入口可以将任何组件包含进来 This file creates any necessary component and links them together. ```go @@ -1088,6 +1088,7 @@ More folder structure guidelines can be found at the [_examples/#structuring](_e ## 现在你已经准备好进入下一个阶段了,又向专家级gopher更近一步了 ## Now you are ready to move to the next step and get closer to becoming a pro gopher +恭喜你看到这里了,我们为你准备了更高水平的内容, Congratulations, since you've made it so far, we've crafted just for you some next level content to turn you into a real pro gopher 😃 > Don't forget to prepare yourself a cup of coffee, or tea, whatever enjoys you the most! From d9708e1dc3fd941d910044c7cca50329019a8437 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 10:29:10 +0800 Subject: [PATCH 12/24] Update README_CN.md Former-commit-id: 659207cd73b669bf37cefe832edc6326b0403b3a --- README_CN.md | 66 ++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/README_CN.md b/README_CN.md index f1e7b23e..b8393a24 100644 --- a/README_CN.md +++ b/README_CN.md @@ -95,7 +95,7 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs * [贡献](CONTRIBUTING.md) * [常见问题](FAQ.md) * [更新计划?](#now-you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) -* [人员](#people) +* [开发者](#people) ## 安装 @@ -1088,24 +1088,25 @@ More folder structure guidelines can be found at the [_examples/#structuring](_e ## 现在你已经准备好进入下一个阶段了,又向专家级gopher更近一步了 ## Now you are ready to move to the next step and get closer to becoming a pro gopher -恭喜你看到这里了,我们为你准备了更高水平的内容, +恭喜你看到这里了,我们为你准备了更高水平的内容,向真正的专家级gopher进军吧😃 Congratulations, since you've made it so far, we've crafted just for you some next level content to turn you into a real pro gopher 😃 +> 准备好咖啡,尽情享受吧 > Don't forget to prepare yourself a cup of coffee, or tea, whatever enjoys you the most! -* [Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) -* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) -* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) -* [Iris, a modular web framework](https://medium.com/@corebreaker/iris-web-cd684b4685c7) -* [Go vs .NET Core in terms of HTTP performance](https://medium.com/@kataras/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8) -* [Iris Go vs .NET Core Kestrel in terms of HTTP performance](https://hackernoon.com/iris-go-vs-net-core-kestrel-in-terms-of-http-performance-806195dc93d5) -* [How to Turn an Android Device into a Web Server](https://twitter.com/ThePracticalDev/status/892022594031017988) -* [Deploying a Iris Golang app in hasura](https://medium.com/@HasuraHQ/deploy-an-iris-golang-app-with-backend-apis-in-minutes-25a559bf530b) -* [A URL Shortener Service using Go, Iris and Bolt](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) +* [Iris Go 矿建+ MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) +* [用DropzoneJS 和 Go来构建表单文件上传](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +* [用DropzoneJS 和 Go来呈现服务器上的问题](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) +* [Iris模块化Web开发框架](https://medium.com/@corebreaker/iris-web-cd684b4685c7) +* [按照 HTTP 性能来比较Go 和 .NET Core](https://medium.com/@kataras/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8) +* [按照 HTTP 性能来比较Go 和 .NET Core Kestrel](https://hackernoon.com/iris-go-vs-net-core-kestrel-in-terms-of-http-performance-806195dc93d5) +* [在Android设备上搭建Web服务器](https://twitter.com/ThePracticalDev/status/892022594031017988) +* [在hasura上部署Iris应用](https://medium.com/@HasuraHQ/deploy-an-iris-golang-app-with-backend-apis-in-minutes-25a559bf530b) +* [用Iris 和 Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) -## People +## 作者 -The author of Iris is [@kataras](https://github.com/kataras), you can reach him via; + Iris的作者是[@kataras](https://github.com/kataras), 你可以通过以下方式来了解作者: * [Medium](https://medium.com/@kataras) * [Twitter](https://twitter.com/makismaropoulos) @@ -1113,42 +1114,46 @@ The author of Iris is [@kataras](https://github.com/kataras), you can reach him * [Facebook](https://facebook.com/iris.framework) * [Mail](mailto:kataras2006@hotmail.com?subject=Iris%20I%20need%20some%20help%20please) -[List of all Authors](AUTHORS) +[作者](AUTHORS) -[List of all Contributors](https://github.com/kataras/iris/graphs/contributors) +[贡献者列表](https://github.com/kataras/iris/graphs/contributors) + +你可以通过[PayPal](https://www.paypal.me/kataras) 或 [BTC](https://iris-go.com/v8/donate)来捐赠这个项目,这样可以促进开发者们创造更棒、更优秀的Iris。 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) or [BTC](https://iris-go.com/v8/donate). +[如何贡献代码](CONTRIBUTING.md) For more information about contributing to the Iris project please check the [CONTRIBUTING.md file](CONTRIBUTING.md). -### We need your help with translations into your native language +### 我们期待你能帮助我们翻译Iris文档 -Iris needs your help, please think about contributing to the translation of the [README](README.md) and https://iris-go.com, you will be rewarded. +Iris需要你的帮助,你可以帮助我们翻译[README](README.md)和https://iris-go.com ,同时你也会得到奖励的。 -Instructions can be found at: https://github.com/kataras/iris/issues/796 +你可以在这里https://github.com/kataras/iris/issues/796 看到详细的有关翻译的信息 -### 03, October 2017 | Iris User Experience Report -Be part of the **first** Iris User Experience Report by submitting a simple form, it won't take more than **2 minutes**. +### Iris 用户体验反馈 | 2017年10月3号 -The form contains some questions that you may need to answer in order to learn more about you; learning more about you helps us to serve you with the best possible way! +**请放心** Iris用户体验反馈就是一些简单的表单提交,**2分钟**就能搞定。 + +这些表单里有些问题是为了更好的了解你,了解你可以让我们更好的为你服务。 https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link -## Contributors +## 贡献者列表 -This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md). +非常感谢所有对Iris的贡献者,没有你们就没有Iris [Contribute](CONTRIBUTING.md) -## Backers +## 资助者 -Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/iris#backer) +万分感谢所有的资助者🙏 [成为资助者](https://opencollective.com/iris#backer) -## Sponsors +## 赞助商 -Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/iris#sponsor) +资助Iris,你将是Iris的赞助商,你的logo将会出现在下面的列表中,[成为赞助商](https://opencollective.com/iris#sponsor) @@ -1161,8 +1166,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l -## License +## 开源许可证 -Iris is licensed under the 3-Clause BSD [License](LICENSE). Iris is 100% open-source software. - -For any questions regarding the license please [contact us](mailto:kataras2006@hotmail.com?subject=Iris%20License). +Iris使用3-Clause BSD [许可证](LICENSE)开源许可 。Iris绝对是100%开源的。 +对这个许可有任何疑问请[联系我们](mailto:kataras2006@hotmail.com?subject=Iris%20License) From c963e91cea1d7cf2db1fbfffdbbac43df6af5f8b Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 11:44:20 +0800 Subject: [PATCH 13/24] Update README_CN.md Former-commit-id: fa2180d8fe9c50283eef754c1a2f009443c7fd60 --- README_CN.md | 181 +++++++++++++-------------------------------------- 1 file changed, 44 insertions(+), 137 deletions(-) diff --git a/README_CN.md b/README_CN.md index b8393a24..e38daada 100644 --- a/README_CN.md +++ b/README_CN.md @@ -66,22 +66,22 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs * [快速入门](#getting-started) * [进阶](_examples/) * [MVC (Model View Controller)](_examples/#mvc) **NEW** - * [Structuring](_examples/#structuring) **NEW** - * [HTTP Listening](_examples/#http-listening) - * [Configuration](_examples/#configuration) - * [Routing, Grouping, Dynamic Path Parameters, "Macros" and Custom Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) - * [Subdomains](_examples/#subdomains) - * [Wrap `http.Handler/HandlerFunc`](_examples/#convert-httphandlerhandlerfunc) - * [View](_examples/#view) - * [Authentication](_examples/#authentication) - * [File Server](_examples/#file-server) - * [How to Read from `context.Request() *http.Request`](_examples/#how-to-read-from-contextrequest-httprequest) - * [How to Write to `context.ResponseWriter() http.ResponseWriter`](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) - * [Test](_examples/#testing) - * [Cache](_examples/#caching) - * [Sessions](_examples/#sessions) +    * [结构](_examples/#structuring) **NEW** +    * [HTTP 监听](_examples/#http-listening) +    * [配置](_examples/#configuration) +    * [路由,分组,动态参数,“宏定义”已经自定义Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) +    * [子域名处理](_examples/#subdomains) +    * [`http.Handler/HandlerFunc` 使用](_examples/#convert-httphandlerhandlerfunc) +    * [视图处理](_examples/#view) +    * [认证](_examples/#authentication) +    * [文件服务器](_examples/#file-server) +    * [如何从`context.Request() *http.Request` 读数据](_examples/#how-to-read-from-contextrequest-httprequest) +    * [如何给`context.ResponseWriter() http.ResponseWriter`写数据](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) +    * [测试](_examples/#testing) +    * [缓存](_examples/#caching) +    * [会话](_examples/#sessions) * [Websockets](_examples/#websockets) - * [Miscellaneous](_examples/#miscellaneous) +    * [其它杂项](_examples/#miscellaneous) * [POC: Convert the medium-sized project "Parrot" from native to Iris](https://github.com/iris-contrib/parrot) * [POC: Isomorphic react/hot reloadable/redux/css-modules starter kit](https://github.com/kataras/iris-starter-kit) * [Typescript Automation Tools](typescript/#table-of-contents) @@ -100,15 +100,12 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs ## 安装 仅仅依赖[Go语言](https://golang.org/dl/) -The only requirement is the [Go Programming Language](https://golang.org/dl/) ```sh $ go get -u github.com/kataras/iris ``` Iris使用[vendor](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) 包依赖管理方式。vendor包管理的方式可以有效处理包依赖更新问题 -Iris takes advantage of the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature. You get truly reproducible builds, as this method guards against upstream renames and deletes. - ## 入门 ```go @@ -148,7 +145,7 @@ func main() { } ``` -> 想要了解更多关于路径参数配置,戳 [这里](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L31). +> 想要了解更多关于路径参数配置,戳[这里](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L31). ```html @@ -168,11 +165,10 @@ $ go run main.go > 应用已经启动按键 CTRL+C 停止服务 ``` -> 想要实现当代码改变后自动重启应用吗?那就装个[rizla](https://github.com/kataras/rizla)工具,启动go文件用 `rizla main.go` 来代替 `go run main.go`. +> 想要实现当代码改变后自动重启应用吗?那就装个[rizla](https://github.com/kataras/rizla)工具,启动go文件用 `rizla main.go` 来代替 `go run main.go`。 Iris的一些开发约定可以看看这里[_examples/structuring](_examples/#structuring)。 - ### MVC指南 ```go @@ -234,37 +230,25 @@ func (c *HelloWorldController) GetWelcomeBy(name string, numTimes int) { ``` > [_examples/mvc](_examples/mvc) 和 [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) 两个简单的例子可以让你更好的了解 Iris MVC 的使用方式 -> The [_examples/mvc](_examples/mvc) and [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) files explain each feature with simple paradigms, they show how you can take advandage of the Iris MVC Binder, Iris MVC Models and many more... - 每一个在controller中导出的Go方法名都和HTTP方法(`Get`, `Post`, `Put`, `Delete`...) 一一对应 -Every `exported` func prefixed with an HTTP Method(`Get`, `Post`, `Put`, `Delete`...) in a controller is callable as an HTTP endpoint. In the sample above, all funcs writes a string to the response. Note the comments preceding each method. - -在Web应用中一个HTTP访问的资源就是一个URL,比如`http://localhost:8080/helloworld`是由,HTTP协议、Web服务网络位置(包括TCP端口):`localhost:8080`以及资源名称URI `/helloworld`组成的。 - -An HTTP endpoint is a targetable URL in the web application, such as `http://localhost:8080/helloworld`, and combines the protocol used: HTTP, the network location of the web server (including the TCP port): `localhost:8080` and the target URI `/helloworld`. +在Web应用中一个HTTP访问的资源就是一个URL(统一资源定位符),比如`http://localhost:8080/helloworld`是由HTTP协议、Web服务网络位置(包括TCP端口):`localhost:8080`以及资源名称URI(统一资源标志符) `/helloworld`组成的。 上面例子第一个方法映射到[HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,访问资源是"/helloworld",第三个方法映射到[HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,访问资源是"/helloworld/welcome" -The first comment states this is an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld" to the base URL. The third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) method that is invoked by appending "/helloworld/welcome" to the URL. +Controller在处理`GetBy`方法时可以识别路径‘name’参数,`GetWelcomeBy`方法可以识别路径‘name’和‘numTimes’参数,因为Controller在识别`By`关键字后可以动态灵活的处理路由;上面第四个方法指示使用 [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,而且只处理以"/helloworld/welcome"开头的资源位置路径,并且此路径还得包括两部分,第一部分类型没有限制,第二部分只能是数字类型,比如"http://localhost:8080/helloworld/welcome/golang/32719" 是合法的,其它的就会给客户端返回[404 找不到](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5)的提示 -Controller在处理`GetBy`方法时可以识别‘name’参数,以及`GetWelcomeBy`方法时也可以识别‘name’和‘numTimes’参数,因为Controller在识别`By`关键字后可以动态灵活的处理路由;上面第四个方法指示使用 [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp)方法,而且只处理以"/helloworld/welcome"开头的资源位置路径,并且此路径还得包括两部分,第一部分类型没有限制,第二部分只能是数字类型,比如"http://localhost:8080/helloworld/welcome/golang/32719" 是合法的,其它的就会给客户端返回[404 找不到](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5)的提示 - -Controller knows how to handle the "name" on `GetBy` or the "name" and "numTimes" at `GetWelcomeBy`, because of the `By` keyword, and builds the dynamic route without boilerplate; the third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) dynamic method that is invoked by any URL that starts with "/helloworld/welcome" and followed by two more path parts, the first one can accept any value and the second can accept only numbers, i,e: "http://localhost:8080/helloworld/welcome/golang/32719", otherwise a [404 Not Found HTTP Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5) will be sent to the client instead. ### MVC 快速指南 2 -Iris对MVC的支持非常 **棒[高性能](_benchmarks)** , 通过方法的返回值,Iris可以给客户端返回任意类型的数据。 +Iris对MVC的支持非常 **棒[高性能](_benchmarks)** , Iris通过方法的返回值,可以给客户端返回任意类型的数据: -Iris has a very powerful and **blazing [fast](_benchmarks)** MVC support, you can return any value of any type from a method function -and it will be sent to the client as expected. - -* 如果是 `string` 类型,就直接返回字符串 -* 如果第二个返回值是 `string` 类型,那么这个值就是ContentType的值 -* 如果是 `int` 类型,这个值就是HTTP状态码 -* 如果 `error` 值不是空,Iris 将会把这个值作为HTTP400页面的返回值内容 -*  如果是 `(int, error)` 类型,并且error不为空,那么Iris返回error的内容,同时把 `int` 值作为HTTP状态码 +* 如果返回的是 `string` 类型,就直接给客户端返回字符串 +* 如果第二个返回值是 `string` 类型,那么这个值就是ContentType(HTTP header)的值 +* 如果返回的是 `int` 类型,这个值就是HTTP状态码 +* 如果返回 `error` 值不是空,Iris 将会把这个值作为HTTP 400页面的返回值内容 +*  如果返回 `(int, error)` 类型,并且error不为空,那么Iris返回error的内容,同时把 `int` 值作为HTTP状态码 * 如果返回 `bool` 类型,并且值是 false ,Iris直接返回404页面 * 如果返回自定义` struct` 、 `interface{}` 、 `slice` 及 `map` ,Iris 将按照JSON的方式返回,注意如果第二个返回值是 `string`,那么Iris就按照这个 `string` 值的ContentType处理了(不一定是'application/json') *  如果 `mvc.Result` 调用了 `Dispatch` 函数, 就会按照自己的逻辑重新处理 @@ -394,19 +378,12 @@ func (c *MoviesController) DeleteBy(id int) iris.Map { Iris是一个底层的Web开发框架,如果你喜欢按 **目录结构** 的约定方式开发,那么Iris框架对此毫无影响。 -Nothing stops you from using your favorite **folder structure**. Iris is a low level web framework, it has got MVC first-class support but it doesn't limit your folder structure, this is your choice. - 你可以根据自己的需求来创建目录结构,但是我建议你还是最好看看如下的目录结构例子: [![目录结构例子](_examples/mvc/overview/folder_structure.png)](_examples/mvc/overview) 好了,直接上代码。 -Structuring depends on your own needs. We can't tell you how to design your own application for sure but you're free to take a closer look to one typical example below; - -[![folder structure example](_examples/mvc/overview/folder_structure.png)](_examples/mvc/overview) - -Shhh, let's spread the code itself. #### 数据模型层 @@ -416,7 +393,7 @@ Shhh, let's spread the code itself. package datamodels // Movie是我们例子数据结构 -// 此Movie对象可能会在"web/viewmodels/movie.go"的文件里持有 +// 此Movie可能会定义在类似"web/viewmodels/movie.go"的文件 // Movie的数据模型在应用中只有一个,这样使用就很简单了 type Movie struct { ID int64 `json:"id"` @@ -520,7 +497,7 @@ type movieMemoryRepository struct { const (    // 只读模式 ReadOnlyMode = iota -    // 写模式 +    // 读写模式 ReadWriteMode ) @@ -556,18 +533,6 @@ func (r *movieMemoryRepository) Exec(query Query, action Query, actionLimit int, // Select 将会返回查询到的最新找到的movie数据,这样可以减少代码量 // // 自从我第一次想到用这种简单的原型函数后,我就经常用它了,希望这也对你有用 -// Select receives a query function -// which is fired for every single movie model inside -// our imaginary data source. -// When that function returns true then it stops the iteration. -// -// It returns the query's return last known "found" value -// and the last known movie model -// to help callers to reduce the LOC. -// -// It's actually a simple but very clever prototype function -// I'm using everywhere since I firstly think of it, -// hope you'll find it very useful as well. func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, found bool) { found = r.Exec(query, func(m datamodels.Movie) bool { movie = m @@ -583,10 +548,8 @@ func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, fou return } -//如果要查找很多值,用法基本一致,不过会返回datamodels.Movie slice。 +// 如果要查找很多值,用法基本一致,不过会返回datamodels.Movie slice。 // 如果limit<=0,将返回全部数据 -// SelectMany same as Select but returns one or more datamodels.Movie as a slice. -// If limit <=0 then it returns everything. func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.Movie) { r.Exec(query, func(m datamodels.Movie) bool { results = append(results, m) @@ -596,22 +559,16 @@ func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []da return } -//插入或跟新数据 -// InsertOrUpdate adds or updates a movie to the (memory) storage. +// 插入或更新数据 // // 返回一个新的movie对象和error对象 -// Returns the new movie and an error if any. func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamodels.Movie, error) { id := movie.ID if id == 0 { // Create new action var lastID int64 -        // 为了数据不重复,找到最大的ID -        // 生成环境你可以用第三方库生成一个UUID字串 - -        // find the biggest ID in order to not have duplications - // in productions apps you can use a third-party - // library to generate a UUID as string. +        // 为了数据不重复,找到最大的ID。 +        // 生产环境你可以用第三方库生成一个UUID字串 r.mu.RLock() for _, item := range r.source { if item.ID > lastID { @@ -631,19 +588,14 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode return movie, nil }    //通过movie.ID更新数据 -    //这里举个例子看如果更新poster和genre非空值 +    //这里举个例子看如果更新非空的poster和genre    //其实我们可以直接更新对象r.source[id] = movie    //用Select的话如下所示 -    // Update action based on the movie.ID, - // here we will allow updating the poster and genre if not empty. - // Alternatively we could do pure replace instead: - // r.source[id] = movie - // and comment the code below; current, exists := r.Select(func(m datamodels.Movie) bool { return m.ID == id }) -    if !exists { // ID不存在,返回error ID is not a real one, return an error. +    if !exists { // ID不存在,返回error ID return datamodels.Movie{}, errors.New("failed to update a nonexistent movie") } @@ -657,8 +609,8 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode current.Genre = movie.Genre } - // map-specific thing - r.mu.Lock() +    // 类map结构的处理 +    r.mu.Lock() r.source[id] = current r.mu.Unlock() @@ -677,7 +629,6 @@ func (r *movieMemoryRepository) Delete(query Query, limit int) bool { 服务层主要调用“数据仓库”和“数据模型”的方法(即使是数据模型很简单的应用)。这一层将包含主要的数据处理逻辑。 -The layer which has access to call functions from the "repositories" and "models" (or even "datamodels" if simple application). It should contain the most of the domain logic. ```go // file: services/movie_service.go @@ -691,16 +642,9 @@ import ( // MovieService主要包括对movie的CRUID(增删改查)操作。 // MovieService主要调用movie 数据仓库的方法。 -// 下面例子的数据源是从更高级别的组件 +// 下面例子的数据源是更高级别的组件 // 这样可以用同样的逻辑可以返回不同的数据仓库 -// MovieService是一个接口,任何实现的地方等能用,这样替换不同的业务逻辑可以用来测试 - -// MovieService handles some of the CRUID operations of the movie datamodel. -// It depends on a movie repository for its actions. -// It's here to decouple the data source from the higher level compoments. -// As a result a different repository type can be used with the same logic without any aditional changes. -// It's an interface and it's used as interface everywhere -// because we may need to change or try an experimental different domain logic at the future. +// MovieService是一个接口,任何实现的地方都能用,这样可以替换不同的业务逻辑用来测试 type MovieService interface { GetAll() []datamodels.Movie GetByID(id int64) (datamodels.Movie, bool) @@ -757,7 +701,6 @@ func (s *movieService) DeleteByID(id int64) bool { #### 视图模型 视图模型将处理结果返回给客户端 -There should be the view models, the structure that the client will be able to see. 例子: Example: @@ -779,36 +722,21 @@ func (m Movie) IsValid() bool { } ``` -Iris允许在HTTP Response Dispatcher中使用任何自定义数据结构,所以理论上下面的代码不建议使用 - -Iris is able to convert any custom data Structure into an HTTP Response Dispatcher, -so theoretically, something like the following is permitted if it's really necessary; +Iris允许在HTTP Response Dispatcher中使用任何自定义数据结构, +所以理论上来说,除非万不得已,下面的代码不建议使用 ```go // Dispatch实现了`kataras/iris/mvc#Result`接口。在函数最后发送了一个`Movie`对象作为http response对象。 // 如果ID小于等于0就回返回404,或者就返回json数据。 //(这样就像控制器的方法默认返回自定义类型一样) -// Dispatch completes the `kataras/iris/mvc#Result` interface. -// Sends a `Movie` as a controlled http response. -// If its ID is zero or less then it returns a 404 not found error -// else it returns its json representation, -// (just like the controller's functions do for custom types by default). // // 不要在这里写过多的代码,应用的主要逻辑不在这里 // 在方法返回之前可以做个简单验证处理等等; -// Don't overdo it, the application's logic should not be here. -// It's just one more step of validation before the response, -// simple checks can be added here. // // 这里只是一个小例子,想想这个优势在设计大型应用是很有作用的 -// It's just a showcase, -// imagine the potentials this feature gives when designing a bigger application. // // 这个方法是在`Movie`类型的控制器调用的。 // 例子在这里:`controllers/movie_controller.go#GetBy`。 -// This is called where the return value from a controller's method functions -// is type of `Movie`. -// For example the `controllers/movie_controller.go#GetBy`. func (m Movie) Dispatch(ctx context.Context) { if !m.IsValid() { ctx.NotFound() @@ -817,15 +745,12 @@ func (m Movie) Dispatch(ctx context.Context) { ctx.JSON(m, context.JSON{Indent: " "}) } ``` -然而,我们仅仅用"datamodels"作为一个数据模型包是因为Movie数据结构没有包含敏感数据,客户端可以访问到其所有字段,我们不需要再有额外的功能去做验证处理了 -However, we will use the "datamodels" as the only one models package because -Movie structure doesn't contain any sensitive data, clients are able to see all of its fields -and we don't need any extra functionality or validation inside it. +然而,我们仅仅用"datamodels"作为一个数据模型包,是因为Movie数据结构没有包含敏感数据,客户端可以访问到其所有字段,我们不需要再有额外的功能去做验证处理了 + #### 控制器 控制器处理Web请求,它是服务层和客户端之间的桥梁 -Handles web requests, bridge between the services and the client. ```go // file: web/controllers/movie_controller.go @@ -847,8 +772,6 @@ type MovieController struct { mvc.C    // MovieService是一个接口,主app对象会持有它 -    // Our MovieService, it's an interface which - // is binded from the main application. Service services.MovieService } @@ -907,8 +830,6 @@ func (c *MovieController) DeleteBy(id int64) interface{} { }    //现在我们可以看到这里可以返回一个有2个返回值(map或int)的函数    //我们并没有指定一个返回的类型 -    // right here we can see that a method function can return any of those two types(map or int), - // we don't have to specify the return type to a specific type. return iris.StatusBadRequest } ``` @@ -951,8 +872,6 @@ func (c *HelloController) Get() mvc.Result { var errBadName = errors.New("bad name") //你也可以将error包裹在mvc.Response中,这样就和mvc.Result类型兼容了 -// you can just return it as error or even better -// wrap this error with an mvc.Response to make it an mvc.Result compatible type. var badName = mvc.Response{Err: errBadName, Code: 400} // GetBy 返回 "Hello {name}" response @@ -1027,7 +946,6 @@ var BasicAuth = basicauth.New(basicauth.Config{ #### 程序入口 程序入口可以将任何组件包含进来 -This file creates any necessary component and links them together. ```go // file: main.go @@ -1059,12 +977,9 @@ func main() {    movieService := services.NewMovieService(repo) app.Controller("/movies", new(controllers.MovieController), - // Bind the "movieService" to the MovieController's Service (interface) field.        // 将"movieService"绑定在 MovieController的Service接口        movieService,        // 为/movies请求添加basic authentication(admin:password)中间件 -        // Add the basic authentication(admin:password) middleware - // for the /movies based requests. middleware.BasicAuth)    // 启动应用localhost:8080 @@ -1083,16 +998,11 @@ func main() { 更多指南戳 [_examples/#structuring](_examples/#structuring) -More folder structure guidelines can be found at the [_examples/#structuring](_examples/#structuring) section. - -## 现在你已经准备好进入下一个阶段了,又向专家级gopher更近一步了 -## Now you are ready to move to the next step and get closer to becoming a pro gopher +## 现在你已经准备好进入下一阶段,又向专家级gopher迈进一步了 恭喜你看到这里了,我们为你准备了更高水平的内容,向真正的专家级gopher进军吧😃 -Congratulations, since you've made it so far, we've crafted just for you some next level content to turn you into a real pro gopher 😃 -> 准备好咖啡,尽情享受吧 -> Don't forget to prepare yourself a cup of coffee, or tea, whatever enjoys you the most! +> 准备好咖啡,尽情享受吧! * [Iris Go 矿建+ MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) * [用DropzoneJS 和 Go来构建表单文件上传](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) @@ -1120,14 +1030,11 @@ Congratulations, since you've made it so far, we've crafted just for you some ne 你可以通过[PayPal](https://www.paypal.me/kataras) 或 [BTC](https://iris-go.com/v8/donate)来捐赠这个项目,这样可以促进开发者们创造更棒、更优秀的Iris。 -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) or [BTC](https://iris-go.com/v8/donate). - [如何贡献代码](CONTRIBUTING.md) -For more information about contributing to the Iris project please check the [CONTRIBUTING.md file](CONTRIBUTING.md). ### 我们期待你能帮助我们翻译Iris文档 -Iris需要你的帮助,你可以帮助我们翻译[README](README.md)和https://iris-go.com ,同时你也会得到奖励的。 +Iris需要你的帮助,帮助我们翻译[README](README.md)和https://iris-go.com ,同时你也会得到奖励的。 你可以在这里https://github.com/kataras/iris/issues/796 看到详细的有关翻译的信息 From 8d33fd670eced4bf36c1136391210ffa128aad9a Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 12:01:43 +0800 Subject: [PATCH 14/24] Update README_CN.md Former-commit-id: 8f10324dc584c877319564de61291b53c0dcc6d0 --- README_CN.md | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/README_CN.md b/README_CN.md index e38daada..946f5ae5 100644 --- a/README_CN.md +++ b/README_CN.md @@ -25,37 +25,20 @@ Learn what [others say about Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A) _Updated at: [Friday, 29 September 2017](_benchmarks)_ -## Built with ♥️ ## Built with ♥️ -在发现Iris之前,我想你一定也看过其它Go Web开发框架,或许你已经摩拳擦掌并马上就要用上了,但我会很遗憾的告诉你,不管怎样,你将来还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris非常独特,他能让你成为真正的极客界的摇滚明星。 +在发现Iris之前,我想你一定也看过其它Go Web开发框架。也许你已经摩拳擦掌并马上要使用了,但我会很遗憾的告诉你,不管怎样你将来还是会使用Iris的,不仅仅因为Iris性能卓越和使用简单,更重要的是Iris独树一帜,他可以让你成为真正的极客界摇滚明星。 -We have no doubt you will able to find other web frameworks written in Go -and even put up a real fight to learn and use them for quite some time but -make no mistake, sooner or later you will be using Iris, not because of the ergonomic, high-performant solution that it provides but its well-documented unique features, as these will transform you to a real rockstar geek. - -不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求,Iris可能是你在网上能找到最好的Web后台开发软件了。 - -No matter what you're trying to build, Iris covers -every type of application, from micro services to large monolithic web applications. -It's actually the best piece of software for back-end web developers -you can find online. +不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求。Iris可能是你在网上能找到最好的Web后台开发软件了。 Iris现在已经到第8版了,但是我们从未停止开发。有很多非常棒的功能已经提上开发日程了,而且我们非常乐意加入很多有创意的想法。 -Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris. - 如果你想用CDN加速,我推荐用[KeyCDN](https://www.keycdn.com/),因为KeyCDN简单、速度快而且稳定。 -Accelerated by [KeyCDN](https://www.keycdn.com/), a simple, fast and reliable CDN. - -我们用[微软](https://www.microsoft.com)开发的[Visual Studio Code](https://code.visualstudio.com/)来做为开发Golang的IDE。 - -We are developing this project using the best code editor for Golang; [Visual Studio Code](https://code.visualstudio.com/) supported by [Microsoft](https://www.microsoft.com). +我们用[微软](https://www.microsoft.com)开发的[Visual Studio Code](https://code.visualstudio.com/)来开发Golang应用。 如果你之前使用[nodejs](https://nodejs.org)做开发,恭喜你,Iris使用基本和[expressjs](https://github.com/expressjs/express)一样。 -If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs](https://github.com/expressjs/express) equivalent for Gophers. ## 内容列表 @@ -82,14 +65,14 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs    * [会话](_examples/#sessions) * [Websockets](_examples/#websockets)    * [其它杂项](_examples/#miscellaneous) - * [POC: Convert the medium-sized project "Parrot" from native to Iris](https://github.com/iris-contrib/parrot) - * [POC: Isomorphic react/hot reloadable/redux/css-modules starter kit](https://github.com/kataras/iris-starter-kit) - * [Typescript Automation Tools](typescript/#table-of-contents) - * [Tutorial: A URL Shortener Service using Go, Iris and Bolt](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) - * [Tutorial: Online Visitors](_examples/tutorial/online-visitors) - * [Tutorial: Caddy](_examples/tutorial/caddy) - * [Tutorial: DropzoneJS Uploader](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) - * [Tutorial:Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) +    * [将"Parrot"项目转换为Iris实现](https://github.com/iris-contrib/parrot) +    * [Iris和react/hot reloadable/redux/css-modules配合使用](https://github.com/kataras/iris-starter-kit) +    * [Typescript自动化操作工具](typescript/#table-of-contents) +    * [指南: 用Iris和Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) +    * [指南: 如何统计在线访问人数](_examples/tutorial/online-visitors) + * [指南: Caddy](_examples/tutorial/caddy) +    * [指南: 如何用DropzoneJS上传文件](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +    * [指南: Iris+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) * [中间件](middleware/) * [Docker例子](https://github.com/iris-contrib/cloud-native-go) * [贡献](CONTRIBUTING.md) From bae8cad58e85a159b946dfff6e1da06ed43f66d0 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 12:05:04 +0800 Subject: [PATCH 15/24] Update README_CN.md Former-commit-id: c3aa159fd658490417cd29b3d737c231ff0ea10c --- README_CN.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index 946f5ae5..a0bbbeab 100644 --- a/README_CN.md +++ b/README_CN.md @@ -48,31 +48,57 @@ Iris现在已经到第8版了,但是我们从未停止开发。有很多非常 * [最近更新](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) * [快速入门](#getting-started) * [进阶](_examples/) - * [MVC (Model View Controller)](_examples/#mvc) **NEW** + +    * [MVC (模型 视图 控制器)](_examples/#mvc) **NEW** +    * [结构](_examples/#structuring) **NEW** +    * [HTTP 监听](_examples/#http-listening) +    * [配置](_examples/#configuration) +    * [路由,分组,动态参数,“宏定义”已经自定义Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) +    * [子域名处理](_examples/#subdomains) +    * [`http.Handler/HandlerFunc` 使用](_examples/#convert-httphandlerhandlerfunc) +    * [视图处理](_examples/#view) +    * [认证](_examples/#authentication) +    * [文件服务器](_examples/#file-server) +    * [如何从`context.Request() *http.Request` 读数据](_examples/#how-to-read-from-contextrequest-httprequest) +    * [如何给`context.ResponseWriter() http.ResponseWriter`写数据](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) +    * [测试](_examples/#testing) +    * [缓存](_examples/#caching) +    * [会话](_examples/#sessions) + * [Websockets](_examples/#websockets) +    * [其它杂项](_examples/#miscellaneous) +    * [将"Parrot"项目转换为Iris实现](https://github.com/iris-contrib/parrot) +    * [Iris和react/hot reloadable/redux/css-modules配合使用](https://github.com/kataras/iris-starter-kit) +    * [Typescript自动化操作工具](typescript/#table-of-contents) +    * [指南: 用Iris和Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) +    * [指南: 如何统计在线访问人数](_examples/tutorial/online-visitors) + * [指南: Caddy](_examples/tutorial/caddy) +    * [指南: 如何用DropzoneJS上传文件](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +    * [指南: Iris+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) + * [中间件](middleware/) * [Docker例子](https://github.com/iris-contrib/cloud-native-go) * [贡献](CONTRIBUTING.md) From 512f7c3cf155f28aaf963d832417bf98e646f8d8 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 12:06:48 +0800 Subject: [PATCH 16/24] Update README_CN.md Former-commit-id: 498b3cd460868f2696fb81a43dfb0c399aa4bd87 --- README_CN.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/README_CN.md b/README_CN.md index a0bbbeab..e65c544c 100644 --- a/README_CN.md +++ b/README_CN.md @@ -48,57 +48,31 @@ Iris现在已经到第8版了,但是我们从未停止开发。有很多非常 * [最近更新](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) * [快速入门](#getting-started) * [进阶](_examples/) -    * [MVC (模型 视图 控制器)](_examples/#mvc) **NEW** -    * [结构](_examples/#structuring) **NEW** -    * [HTTP 监听](_examples/#http-listening) -    * [配置](_examples/#configuration) -    * [路由,分组,动态参数,“宏定义”已经自定义Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) -    * [子域名处理](_examples/#subdomains) -    * [`http.Handler/HandlerFunc` 使用](_examples/#convert-httphandlerhandlerfunc) -    * [视图处理](_examples/#view) -    * [认证](_examples/#authentication) -    * [文件服务器](_examples/#file-server) -    * [如何从`context.Request() *http.Request` 读数据](_examples/#how-to-read-from-contextrequest-httprequest) -    * [如何给`context.ResponseWriter() http.ResponseWriter`写数据](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) -    * [测试](_examples/#testing) -    * [缓存](_examples/#caching) -    * [会话](_examples/#sessions) - * [Websockets](_examples/#websockets) -    * [其它杂项](_examples/#miscellaneous) -    * [将"Parrot"项目转换为Iris实现](https://github.com/iris-contrib/parrot) -    * [Iris和react/hot reloadable/redux/css-modules配合使用](https://github.com/kataras/iris-starter-kit) -    * [Typescript自动化操作工具](typescript/#table-of-contents) -    * [指南: 用Iris和Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) -    * [指南: 如何统计在线访问人数](_examples/tutorial/online-visitors) - * [指南: Caddy](_examples/tutorial/caddy) -    * [指南: 如何用DropzoneJS上传文件](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) -    * [指南: Iris+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) - * [中间件](middleware/) * [Docker例子](https://github.com/iris-contrib/cloud-native-go) * [贡献](CONTRIBUTING.md) From 79a9b67a85c7d34c3625597d81bb36dac447d757 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 14:22:14 +0800 Subject: [PATCH 17/24] Update README_CN.md Former-commit-id: 84e09c053ac7d772a975f36d9aefd866ab7b8801 --- README_CN.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README_CN.md b/README_CN.md index e65c544c..35393bc0 100644 --- a/README_CN.md +++ b/README_CN.md @@ -48,31 +48,31 @@ Iris现在已经到第8版了,但是我们从未停止开发。有很多非常 * [最近更新](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) * [快速入门](#getting-started) * [进阶](_examples/) -    * [MVC (模型 视图 控制器)](_examples/#mvc) **NEW** -    * [结构](_examples/#structuring) **NEW** -    * [HTTP 监听](_examples/#http-listening) -    * [配置](_examples/#configuration) -    * [路由,分组,动态参数,“宏定义”已经自定义Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) -    * [子域名处理](_examples/#subdomains) -    * [`http.Handler/HandlerFunc` 使用](_examples/#convert-httphandlerhandlerfunc) -    * [视图处理](_examples/#view) -    * [认证](_examples/#authentication) -    * [文件服务器](_examples/#file-server) -    * [如何从`context.Request() *http.Request` 读数据](_examples/#how-to-read-from-contextrequest-httprequest) -    * [如何给`context.ResponseWriter() http.ResponseWriter`写数据](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) -    * [测试](_examples/#testing) -    * [缓存](_examples/#caching) -    * [会话](_examples/#sessions) + * [MVC (模型 视图 控制器)](_examples/#mvc) **NEW** + * [结构](_examples/#structuring) **NEW** + * [HTTP 监听](_examples/#http-listening) + * [配置](_examples/#configuration) + * [路由,分组,动态参数,“宏定义”已经自定义Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) + * [子域名处理](_examples/#subdomains) + * [`http.Handler/HandlerFunc` 使用](_examples/#convert-httphandlerhandlerfunc) + * [视图处理](_examples/#view) + * [认证](_examples/#authentication) + * [文件服务器](_examples/#file-server) + * [如何从`context.Request() *http.Request` 读数据](_examples/#how-to-read-from-contextrequest-httprequest) + * [如何给`context.ResponseWriter() http.ResponseWriter`写数据](_examples/#how-to-write-to-contextresponsewriter-httpresponsewriter) + * [测试](_examples/#testing) + * [缓存](_examples/#caching) + * [会话](_examples/#sessions) * [Websockets](_examples/#websockets) -    * [其它杂项](_examples/#miscellaneous) -    * [将"Parrot"项目转换为Iris实现](https://github.com/iris-contrib/parrot) -    * [Iris和react/hot reloadable/redux/css-modules配合使用](https://github.com/kataras/iris-starter-kit) -    * [Typescript自动化操作工具](typescript/#table-of-contents) -    * [指南: 用Iris和Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) -    * [指南: 如何统计在线访问人数](_examples/tutorial/online-visitors) + * [其它杂项](_examples/#miscellaneous) + * [将"Parrot"项目转换为Iris实现](https://github.com/iris-contrib/parrot) + * [Iris和react/hot reloadable/redux/css-modules配合使用](https://github.com/kataras/iris-starter-kit) + * [Typescript自动化操作工具](typescript/#table-of-contents) + * [指南: 用Iris和Bolt实现短连接服务](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) + * [指南: 如何统计在线访问人数](_examples/tutorial/online-visitors) * [指南: Caddy](_examples/tutorial/caddy) -    * [指南: 如何用DropzoneJS上传文件](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) -    * [指南: Iris+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) + * [指南: 如何用DropzoneJS上传文件](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) + * [指南: Iris+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) * [中间件](middleware/) * [Docker例子](https://github.com/iris-contrib/cloud-native-go) * [贡献](CONTRIBUTING.md) From abba1ca4a0f426a0e22007b2ed34b3b8f862604c Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 14:30:07 +0800 Subject: [PATCH 18/24] Update README_CN.md Former-commit-id: 2828260b3a6ab5bc151d5de5ea21eadb074e34c2 --- README_CN.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README_CN.md b/README_CN.md index 35393bc0..c49396cf 100644 --- a/README_CN.md +++ b/README_CN.md @@ -6,26 +6,23 @@ Sponsor -Iris是一个超快,使用简单并且非常高效的Go语言Web开发框架。 -Iris is a fast, simple and efficient web framework for Go. +Iris是一个超快、简单并且高效的Go语言Web开发框架。 -Iris功能很强大,但使用又很简单,它将会是你下一个网站、API服务或者分布式应用基础框架的不二之选。 -Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app. +Iris功能很强大,使用又很简单,它将会是你下一个网站、API服务或者分布式应用基础框架的不二之选。 看看[别人是如何评价Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A),同时欢迎各位[成为Iris星探](https://github.com/kataras/iris/stargazers),或者关注[Iris facebook主页](https://facebook.com/iris.framework)。 -Learn what [others say about Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A) and [star](https://github.com/kataras/iris/stargazers) this github repository to stay [up to date](https://facebook.com/iris.framework). [![Iris vs .NET Core(C#) vs Node.js (Express)](https://iris-go.com/images/benchmark-new-gray.png)](_benchmarks)
-上图是第三发机构发布的REST Web框架的基准测试Benchmarks from third-party source over the rest web frameworks +上图是第三发机构发布的REST Web框架的基准测试 ![Comparison with other frameworks](https://raw.githubusercontent.com/smallnest/go-web-framework-benchmark/4db507a22c964c9bc9774c5b31afdc199a0fe8b7/benchmark.png) _Updated at: [Friday, 29 September 2017](_benchmarks)_
-## Built with ♥️ +## 前言 ♥️ 在发现Iris之前,我想你一定也看过其它Go Web开发框架。也许你已经摩拳擦掌并马上要使用了,但我会很遗憾的告诉你,不管怎样你将来还是会使用Iris的,不仅仅因为Iris性能卓越和使用简单,更重要的是Iris独树一帜,他可以让你成为真正的极客界摇滚明星。 @@ -42,8 +39,6 @@ Iris现在已经到第8版了,但是我们从未停止开发。有很多非常 ## 内容列表 -## Table Of Content - * [安装](#installation) * [最近更新](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857) * [快速入门](#getting-started) @@ -225,7 +220,7 @@ Controller在处理`GetBy`方法时可以识别路径‘name’参数,`GetWelc ### MVC 快速指南 2 -Iris对MVC的支持非常 **棒[高性能](_benchmarks)** , Iris通过方法的返回值,可以给客户端返回任意类型的数据: +Iris对MVC的支持非常 **棒[基准测试](_benchmarks)** ,Iris通过方法的返回值,可以给客户端返回任意类型的数据: * 如果返回的是 `string` 类型,就直接给客户端返回字符串 * 如果第二个返回值是 `string` 类型,那么这个值就是ContentType(HTTP header)的值 @@ -387,7 +382,7 @@ type Movie struct { } ``` -#### Data Source / Data Store Layer +#### 数据层 / 数据存储层 ```go // file: datasource/movies.go From a7f62c94f1be4887de0c85d6fc4c9b5f63992671 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 14:40:30 +0800 Subject: [PATCH 19/24] Update README_CN.md Former-commit-id: d9a508b927e15950543749599f9686eee35c7157 --- README_CN.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README_CN.md b/README_CN.md index c49396cf..d3bf3835 100644 --- a/README_CN.md +++ b/README_CN.md @@ -6,6 +6,7 @@ Sponsor + Iris是一个超快、简单并且高效的Go语言Web开发框架。 Iris功能很强大,使用又很简单,它将会是你下一个网站、API服务或者分布式应用基础框架的不二之选。 @@ -19,7 +20,7 @@ Iris功能很强大,使用又很简单,它将会是你下一个网站、API ![Comparison with other frameworks](https://raw.githubusercontent.com/smallnest/go-web-framework-benchmark/4db507a22c964c9bc9774c5b31afdc199a0fe8b7/benchmark.png) -_Updated at: [Friday, 29 September 2017](_benchmarks)_ +更新于: [2017年9月29,星期五](_benchmarks)_ ## 前言 ♥️ @@ -982,7 +983,7 @@ func main() { > 准备好咖啡,尽情享受吧! -* [Iris Go 矿建+ MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) +* [Iris框架+MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c) * [用DropzoneJS 和 Go来构建表单文件上传](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) * [用DropzoneJS 和 Go来呈现服务器上的问题](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) * [Iris模块化Web开发框架](https://medium.com/@corebreaker/iris-web-cd684b4685c7) From 1110bec9791b0b95f833b2effb65182926955a82 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 14:45:51 +0800 Subject: [PATCH 20/24] Update README_CN.md Former-commit-id: f7538b0d922a46deacf4d941ad38b541fe7fe224 --- README_CN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README_CN.md b/README_CN.md index d3bf3835..f66d298f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -16,8 +16,8 @@ Iris功能很强大,使用又很简单,它将会是你下一个网站、API [![Iris vs .NET Core(C#) vs Node.js (Express)](https://iris-go.com/images/benchmark-new-gray.png)](_benchmarks)
-上图是第三发机构发布的REST Web框架的基准测试 - +上图是第三发机构发布的REST Web框架的基准测试 + ![Comparison with other frameworks](https://raw.githubusercontent.com/smallnest/go-web-framework-benchmark/4db507a22c964c9bc9774c5b31afdc199a0fe8b7/benchmark.png) 更新于: [2017年9月29,星期五](_benchmarks)_ From ccf5cc4d5e88eec55fae397f82f3e36bdbcacda9 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 14:50:00 +0800 Subject: [PATCH 21/24] Update README_CN.md Former-commit-id: af4d3cb162865d778e938defeabe926cdde311a7 --- README_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index f66d298f..5ce197fe 100644 --- a/README_CN.md +++ b/README_CN.md @@ -221,7 +221,7 @@ Controller在处理`GetBy`方法时可以识别路径‘name’参数,`GetWelc ### MVC 快速指南 2 -Iris对MVC的支持非常 **棒[基准测试](_benchmarks)** ,Iris通过方法的返回值,可以给客户端返回任意类型的数据: +Iris对MVC的支持非常**棒[看看基准测试](_benchmarks)** ,Iris通过方法的返回值,可以给客户端返回任意类型的数据: * 如果返回的是 `string` 类型,就直接给客户端返回字符串 * 如果第二个返回值是 `string` 类型,那么这个值就是ContentType(HTTP header)的值 From 346cd1ffc251bdc18153b341f3e0abd038154cf7 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 15:10:45 +0800 Subject: [PATCH 22/24] Update README_CN.md Former-commit-id: b4f37edbe3d93c8cc0ad5f06c684decec64456b0 --- README_CN.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README_CN.md b/README_CN.md index 5ce197fe..b2321f45 100644 --- a/README_CN.md +++ b/README_CN.md @@ -25,7 +25,7 @@ Iris功能很强大,使用又很简单,它将会是你下一个网站、API ## 前言 ♥️ -在发现Iris之前,我想你一定也看过其它Go Web开发框架。也许你已经摩拳擦掌并马上要使用了,但我会很遗憾的告诉你,不管怎样你将来还是会使用Iris的,不仅仅因为Iris性能卓越和使用简单,更重要的是Iris独树一帜,他可以让你成为真正的极客界摇滚明星。 +在发现Iris之前,我想你一定也看过其它Go Web开发框架。也许你已经摩拳擦掌并马上要使用了,但我会很遗憾的告诉你,将来你还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris独树一帜,他可以让你成为真正的极客界摇滚明星。 不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求。Iris可能是你在网上能找到最好的Web后台开发软件了。 @@ -37,7 +37,6 @@ Iris现在已经到第8版了,但是我们从未停止开发。有很多非常 如果你之前使用[nodejs](https://nodejs.org)做开发,恭喜你,Iris使用基本和[expressjs](https://github.com/expressjs/express)一样。 - ## 内容列表 * [安装](#installation) From 9e668b30ea97a9e7d4e443ac262cf5449f64ba0b Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 15:14:38 +0800 Subject: [PATCH 23/24] Update README_CN.md Former-commit-id: b4deb4b6785f4ad94bdd9d692b9596964b2a1a8f --- README_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index b2321f45..fb7b8428 100644 --- a/README_CN.md +++ b/README_CN.md @@ -27,7 +27,7 @@ Iris功能很强大,使用又很简单,它将会是你下一个网站、API 在发现Iris之前,我想你一定也看过其它Go Web开发框架。也许你已经摩拳擦掌并马上要使用了,但我会很遗憾的告诉你,将来你还是会使用Iris的。不仅仅因为Iris性能卓越和使用简单,更重要的是Iris独树一帜,他可以让你成为真正的极客界摇滚明星。 -不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求。Iris可能是你在网上能找到最好的Web后台开发软件了。 +不管你是想开发微服务或者大型Web应用,Iris都能满足你的需求。Iris可能是你在网上能找到最好的Web后台开发软件之一了。 Iris现在已经到第8版了,但是我们从未停止开发。有很多非常棒的功能已经提上开发日程了,而且我们非常乐意加入很多有创意的想法。 From 3b8553cd28d5fc09035a9577b6e3ff19caa9ff04 Mon Sep 17 00:00:00 2001 From: Yale Date: Fri, 10 Nov 2017 15:19:10 +0800 Subject: [PATCH 24/24] Update README_CN.md Former-commit-id: e2868c45a3544aca8a8ff8cc1c1d60967bad3617 --- README_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index fb7b8428..a4718c1e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1027,7 +1027,7 @@ https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVD ## 贡献者列表 -非常感谢所有对Iris的贡献者,没有你们就没有Iris [Contribute](CONTRIBUTING.md) +非常感谢所有对Iris的贡献者,没有你们就没有Iris [贡献者](CONTRIBUTING.md) ## 资助者