Giter Club home page Giter Club logo

comments's Introduction

comments

comments's People

Contributors

hellokaton avatar

Watchers

 avatar  avatar

Forkers

guoyu07

comments's Issues

Blade 实战指南:初始化 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/initialize.html

所有Blade程序都需要创建一个 Blade 对象实例。Web服务器使用了内置的Netty Web服务,把接收客户端的请求都转交给它处理,创建一个 Blade 对象实例只需要写如下一行代码: Blade blade = Blade.me(); 工程结构 在前面的章节中我们学习了如何创建一个 Blade 工程,通常我们创建好的工程结构大致如下: ☁ project . ├── package.xml ├── pom.xml ├── src │   ├── main │   │   └── java │ │ ├─── com.example.blog │ │ ├──── model │ │ ├──── service │ │ ├──── controller │ │ ├──── context │ │ ├─── Application.java │   │   └──── resources │   │   └── static │   │    └── templates │   │   └── app.properties └───└── test    └── java 这是一个很常规的项目结构。我们推荐把启动类Application.java放在根包中(即com.example.blog里面),这样可以避免一些奇怪的问题。 我们可以把静态资源文件放在 static 目录中,将模板文件放在 templates 目录,但这并不是绝对的,我们可以通过配置文件app.properties来修改这些配置以及其他的配置。 启动流程 当你编写好了一个 Blade 实例,只需要调用它的 start 方法即可启动一个web服务。Blade的初始化步骤是这样的: 输出环境信息 加载配置文件配置 加载命令行配置 初始化配置 初始化上下文 初始化 IOC 容器 6.1 初始化中间件 6.2 注册路由 6.3 执行 BeanProcessor preHandle 6.4 执行 BeanProcessor processor 启动一个Web服务 上面看起来可能有些繁琐,但对于使用者几乎只需要关心如何注入 Bean 就可以了。 上一篇:Mvc应用架构 下一篇:注册路由 系列目录:Blade 实战指南

跟我学Golang:(六)函数 | 开发者秘籍_开发者提升

https://dev-cheats.com/golang/function.html

这是跟我学Golang系列教程的第六篇。 函数是完成一个特定任务的代码块。一个函数接受输入,对输入进行一些运算并产生输出。 函数声明 在 Go 中声明一个函数的语法为: func functionname(parametername type) returntype { //function body } 函数声明以关键字 func 开头,后面是函数名字,接着是在 ( 和 ) 之间指定的参数列表,然后是函数的返回类型。指定参数的语法为参数名称后面跟着参数类型。可以指定任意数量的参数,形式为:(parameter1 type, parameter2 type)。最后是由 { 和 } 以及它们之间的代码块组成的函数体。 在一个函数中,参数和返回值是可选的。因此下面的语法也是合法的函数声明: func functionname() { } 函数的例子 让我们写一个函数,它以单个产品的价格和产品数量作为输入参数,并以总价格(单个产品的价格与产品数量的乘积)作为返回值。 func calculateBill(price int, no int) int { var totalPrice = price * no return totalPrice } 上面的函数接受两个 int 类型的输入参数:price 和 no,并返回 totalPrice(price 与 no 的乘积) 。返回值的类型也是 int。 如果连续的参数具有相同的类型,我们可以避免每次都写出它们的类型,只需要在结束的时候写一次就可以了,比如:price int, no int 可以写成:price, no int。 于是上面的函数可以写成: func calculateBill(price, no int) int { var totalPrice = price * no return totalPrice } 我们已经定义好了我们函数,现在让我们在代码中调用它。调用函数的语法为:functionname(parameters)。上面定义的函数 calculateBill 可以通过下面的代码调用: calculateBill(10, 5) 下面是完整的程序,它调用 calculateBill 并计算总价格。 package main import ( "fmt" ) func calculateBill(price, no int) int { var totalPrice = price * no return totalPrice } func main() { price, no := 90, 6 totalPrice := calculateBill(price, no) fmt.Println("Total price is ", totalPrice) } 多个返回值 一个函数可以返回多个值。让我们写一个函数 rectProps,它接受一个矩形的长和宽,并返回该矩形的面积和周长。矩形的面积为长与宽的积。周长为长与宽的和的 2 倍。 package main import ( "fmt" ) func rectProps(length, width float64)(float64, float64) { var area = length * width var perimeter = (length + width) * 2 return area, perimeter } func main() { area, perimeter := rectProps(10.8, 5.6) fmt.Printf("Area %f Perimeter %f", area, perimeter) } 如果一个函数有多个返回值,那么这些返回值应该用小括号()括起来,比如:func rectProps(length, width float64)(float64, float64) 接受两个类型为 float64 的参数(length 和 width),并且同样返回两个类型为 float64 的返回值。上面程序的输出为:Area 60.480000 Perimeter 32.800000 具名返回值 可以给一个函数的返回值指定名字。如果指定了一个返回值的名字,则可以视为在该函数的第一行中定义了该名字的变量。 上面的 rectProps 函数可以用具名返回值的形式重写如下: func rectProps(length, width float64)(area, perimeter float64) { area = length * width perimeter = (length + width) * 2 return //no explicit return value } 在上面的函数中,area 和 perimeter 是具名返回值。注意 return 语句没有指定任何返回值。因为在函数声明时已经指定 area 和 perimeter 是返回值,在遇到 return 语句时它们会自动从函数中返回。 译者注:在Go中,有返回值的函数,无论是具名返回值还是普通形式的返回值,函数中必须包含 return 语句。 空指示符 在 Go 中,下划线(_)表示空指示符(blank identifier)。它可以用于代替任何类型的任何值。让我们看看如何使用空指示符。 我们知道上面定义的函数 rectProps 返回矩形的面积(area)和周长(perimeter)。如果我们只需要获取 area 而想要忽略 perimeter 该怎么办呢?这时候就可以使用空指示符。 下面的程序仅接收 rectProps 返回的 area: package main import ( "fmt" ) func rectProps(length, width float64) (float64, float64) { var area = length * width var perimeter = (length + width) * 2 return area, perimeter } func main() { area, _ := rectProps(10.8, 5.6) // perimeter is discarded fmt.Printf("Area %f ", area) } 在 area, _ := rectProps(10.8, 5.6) 这一行,我们仅仅获取了 area,而使用空指示符 _ 来忽略第二个返回值(perimeter)。 函数的介绍到此结束。感谢阅读。 上一篇:跟我学Golang:(五)常量) 下一篇:跟我学Golang:(七)包 系列目录:跟我学习 Go 语言 原文出处:https://golangbot.com/hello-world

Blade 实战指南:简介 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/intro.html

Blade 意为利刃,刀剑;在**冷兵器中刀剑的杀伤力可谓锐不可当,对它的名字没有很刻意的去琢磨,碰巧看到这个单词觉得比较喜欢,当然我希望它日后能够成为一把锐利的杀手锏。我个人的追求简洁和优雅的,所以在设计上不追求过度抽象。 Blade 借鉴了很多优秀mvc框架的设计,它是为java开发人员提供的便捷易用快速上手的一款框架,你可以用它快速开发API、Web 及后端服务等各种应用,漂亮大方的博客系统 tale 正是基于 Blade 驱动。

Blade 实战指南:Mvc应用架构 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/mvc-architecture.html

我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢?在后端程序中又是如何体现的? 对于普通的上网过程,系统其实是这样做的:浏览器本身是一个客户端,当你输入URL的时候,首先浏览器会去请求DNS服务器,通过DNS获取相应的域名对应的IP,然后通过IP地址找到IP对应的服务器后,要求建立TCP连接,等浏览器发送完HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包,服务器调用自身服务,返回HTTP Response(响应)包;客户端收到来自服务器的响应后开始渲染这个Response包里的主体(body),等收到全部的内容随后断开与该服务器之间的TCP连接。 一个Web服务器也被称为HTTP服务器,它通过HTTP协议与客户端通信。这个客户端通常指的是Web浏览器(其实手机端客户端内部也是浏览器实现的)。 Web服务器的工作原理可以简单地归纳为: 客户机通过TCP/IP协议建立到服务器的TCP连接 客户端向服务器发送HTTP协议请求包,请求服务器里的资源文档 服务器向客户机发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端 客户机与服务器断开。由客户端解释HTML文档,在客户端屏幕上渲染图形结果 一个简单的HTTP事务就是这样实现的,看起来很复杂,原理其实是挺简单的。需要注意的是客户机与服务器之间的通信是非持久连接的,也就是当服务器发送了应答后就与客户机断开连接,等待下一次请求。 MVC架构 MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。 MVC模式最早由Trygve Reenskaug在1978年提出,是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构。MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。专业人员可以通过自身的专长分组: 控制器(Controller)- 负责转发请求,对请求进行处理 视图(View)- 直接和用户进行交互的界面,在web应用中就是HTML网页,由控制器将数据呈现到页面。通常可能使用JSP, 模板引擎等。 模型(Model)- 模型层负责管理应用的数据,它用于响应来自视图的请求,并且还接受来自控制器的数据来更新自身 Model(模型) 用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“ Model ”有对数据直接访问的权力,例如对数据库的访问。“Model”不依赖“View”和“Controller”,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,从而,View 可以了解在数据 Model 上发生的改变。 View(视图) 能够实现数据有目的的显示(理论上,这不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。 Controller(控制器) 起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 Model 上的改变。 优点 在最初的JSP网页中,像数据库查询语句(SQL query)这样的数据层代码和像HTML这样的表示层代码是混在一起。虽然有着经验比较丰富的开发者会将数据从表示层分离开来,但这样的良好设计通常并不是很容易做到的,实现它需要精心地计划和不断的尝试。MVC可以从根本上强制性地将它们分开。尽管构造MVC应用程序需要一些额外的工作,但是它带给我们的好处是毋庸置疑的。 首先,多个 View 能共享一个 Model 。如今,同一个Web应用程序会提供多种用户界面,例如用户希望既能够通过浏览器来收发电子邮件,还希望通过手机来访问电子邮箱,这就要求Web网站同时能提供Internet界面和WAP界面。在MVC设计模式中, Model 响应用户请求并返回响应数据,View 负责格式化数据并把它们呈现给用户,业务逻辑和表示层分离,同一个 Model 可以被不同的 View 重用,所以大大提高了代码的可重用性。 其次,Controller 是自包含(self-contained)指高独立内聚的对象,与 Model 和 View 保持相对独立,所以可以方便的改变应用程序的数据层和业务规则。例如,把数据库从MySQL移植到Oracle,或者把RDBMS数据源改变成LDAP数据源,只需改变 Model 即可。一旦正确地实现了控制器,不管数据来自数据库还是LDAP服务器,View 都会正确地显示它们。由于MVC模式的三个模块相互独立,改变其中一个不会影响其他两个,所以依据这种设计**能构造良好的少互扰性的构件。 此外,Controller 提高了应用程序的灵活性和可配置性。Controller 可以用来连接不同的 Model 和 View 去完成用户的需求,也可以构造应用程序提供强有力的手段。给定一些可重用的 Model 、 View 和Controller 可以根据用户的需求选择适当的 Model 进行处理,然后选择适当的的 View 将处理结果显示给用户。 适用范围 MVC模式在概念上强调 Model, View, Controller 的分离,各个模块也遵循着由 Controller 来处理消息,Model 掌管数据源,View 负责数据显示的职责分离原则,因此在实现上,MVC 模式的 Framework 通常会将 MVC 三个部分分离实现: Model 负责数据访问,较现代的 Framework 都会建议使用独立的数据对象 (DTO, POCO, POJO 等) 来替代弱类型的集合对象。数据访问的代码会使用 Data Access 的代码或是 ORM-based Framework,也可以进一步使用 Repository Pattern 与 Unit of Works Pattern 来切割数据源的相依性。 Controller 负责处理消息,较高级的 Framework 会有一个默认的实现来作为 Controller 的基础,例如 Spring 的 DispatcherServlet 或是 ASP.NET MVC 的 Controller 等,在职责分离原则的基础上,每个 Controller 负责的部分不同,因此会将各个 Controller 切割成不同的文件以利维护。 View 负责显示数据,这个部分多为前端应用,而 Controller 会有一个机制将处理的结果 (可能是 Model, 集合或是状态等) 交给 View,然后由 View 来决定怎么显示。例如 Spring Framework 使用 JSP 或相应技术,ASP.NET MVC 则使用 Razor 处理数据的显示。 上一篇:运行Hello World 下一篇:初始化 系列目录:Blade 实战指南

跟我学Golang:(三)变量 | 开发者秘籍_开发者提升

https://dev-cheats.com/golang/variables.html

这是本Golang系列教程的第三篇。本篇介绍Golang中的变量。 你可以阅读 跟我学Golang:(二)Hello World 来学习如何建立 Go 工作空间以及编写和运行 hello world 程序。 什么是变量 变量(Variable)是给某个内存地址起的一个名字。我们用变量来存储某个特定类型的值。在 Go 中有多种声明变量的语法。 声明单一变量 声明一个变量的语法为:var name type,例如: package main import "fmt" func main() { var age int // variable declaration fmt.Println("my age is", age) } 语句 var age int 声明了一个类型为 int,名称为 age 的变量。在这里我们没有给它赋任何值。如果一个变量没有被赋予任何值,Go 会自动将这个变量初始化为其类型的 0值,比如这里的 age 将被赋值为 0(译者注:int的0值为0)。运行这个程序,将得到如下输出: my age is 0 一个变量可以被赋予其类型的任何值。例如,在上例中,age 可以被赋予任何整型值: package main import "fmt" func main() { var age int // variable declaration fmt.Println("my age is ", age) age = 29 //assignment fmt.Println("my age is", age) age = 54 //assignment fmt.Println("my new age is", age) } 上面的程序输出如下: my age is 0 my age is 29 my new age is 54 声明一个带初值的变量 在声明变量时可以指定其初始值。 声明一个带初值的变量的语法为:var name type = initialvalue,例如: package main import "fmt" func main() { var age int = 29 // variable declaration with initial value fmt.Println("my age is", age) } 在上面的程序中, age 是一个 int 型的变量,初始值为 29。运行上面的程序,输出如下。可以看到 age 的初始值确实为 29。 my age is 29 类型推导 如果声明一个变量时提供了初始值,Go可以根据该初始值来自动推导变量的类型。因此如果声明变量时提供了初始值,就可以不必指定其类型。 也就是说,如果声明变量的形式为:var name = initialvalue,Go将根据 initialvalue 自动推导变量 name 的类型。 在下面的例子中,你可以看到声明变量 age 时并没有指定其类型。因为 age 的初值为 29,Go 自动推断其类型为 int。 package main import "fmt" func main() { var age = 29 // type will be inferred fmt.Println("my age is", age) } 多变量声明 多个变量可以在一条语句中声明。 多变量声明的语法为:var name1, name2 type = initialvalue1, initialvalue2,例如: package main import "fmt" func main() { var width, height int = 100, 50 //declaring multiple variables fmt.Println("width is", width, "height is", height) } 如果指定了初始值,则 type 可以省略。下面的程序利用类型推导声明了多个变量: package main import "fmt" func main() { var width, height = 100, 50 //"int" is dropped fmt.Println("width is", width, "height is", height) } 运行上面的程序,可以看到输出结果为: width is 100 height is 50 正如你猜想的那样,如果不指定 width 和 height 的初值,它们将自动被赋值为 0,也就是说它们将以 0 作为初值: package main import "fmt" func main() { var width, height int fmt.Println("width is", width, "height is", height) width = 100 height = 50 fmt.Println("new width is", width, "new height is ", height) } 上面的程序将会输出: width is 0 height is 0 new width is 100 new height is 50 有些时候我们需要在一条语句中声明多个不同类型的变量。我们可以使用下面的语法达到此目的: var ( name1 = initialvalue1, name2 = initialvalue2 ) 下面的程序就用上面的语法声明了多个不同类型的变量: package main import "fmt" func main() { var ( name = "naveen" age = 29 height int ) fmt.Println("my name is", name, ", age is", age, "and height is", height) } 这里我们声明了一个字符串类型的变量 name,以及两个整型的变量 age 和 height。(我们将在下一篇教程中讨论 Golang 中可用的类型)。运行上面的程序将会产生如下输出: my name is naveen , age is 29 and height is 0 速记声明 Go 提供了另一种简洁的声明变量的方式。这种方式称为速记声明(shorthand declaratiion)。速记声明使用 := 操作符来声明变量。 速记声明的语法为:name := initialvalue,例如: package main import "fmt" func main() { name, age := "naveen", 29 //short hand declaration fmt.Println("my name is", name, "age is", age) } 运行上面的程序,输出如下: my name is naveen age is 29 速记声明要求必须给声明的每一个变量都提供初始值。下面的 程序 将会报错:assignment count mismatch: 2 = 1。这是因为 没有给 age 提供初始值。 package main import "fmt" func main() { name, age := "naveen" //error fmt.Println("my name is", name, "age is", age) } 速记声明要求在 := 的左边必须至少有一个变量是新声明的。考虑如下程序: package main import "fmt" func main() { a, b := 20, 30 // declare variables a and b fmt.Println("a is", a, "b is", b) b, c := 40, 50 // b is already declared but c is new fmt.Println("b is", b, "c is", c) b, c = 80, 90 // assign new values to already declared variables b and c fmt.Println("changed b is", b, "c is", c) } 上面的程序中,在 b, c := 40, 50 这一行,虽然变量 b 在之前已经被声明了,但是 c 却是新声明的变量,因此这是合法的。该程序的输出为: a is 20 b is 30 b is 40 c is 50 changed b is 80 c is 90 但是当我们运行下面的程序: package main import "fmt" func main() { a, b := 20, 30 //a and b declared fmt.Println("a is", a, "b is", b) a, b := 40, 50 //error, no new variables } 将会报错:8: no new variables on left side of := 。这是因为变量 a 和变量 b 都是已经声明过的变量,在 := 左侧并没有新的变量被声明。 译者注:速记声明只能用在函数中。 变量可以被赋予运行时产生的值。考虑下面的程序: package main import ( "fmt" "math" ) func main() { a, b := 145.8, 543.8 c := math.Min(a, b) fmt.Println("minimum value is ", c) } 在上面的程序中, c 的值为 a 和 b 的最小值,该值是在运行时计算的。 一个变量不能被赋予与其类型不同的值。下面的程序将报错:cannot use "naveen" (type string) as type int in assignment。这是因为 age 被声明为 int 类型,但是我们试图将 string 类型的值赋给它。 package main func main() { age := 29 // age is int age = "naveen" // error since we are trying to assign a string to a variable of type int } 感谢阅读。下一篇教程 跟我学Golang:(四)类型 将介绍 Golang 中的类型。 上一篇:跟我学Golang:(二)Hello World 下一篇:跟我学Golang:(四)类型 系列目录:跟我学习 Go 语言 原文出处:https://golangbot.com/hello-world

为何要为开源贡献力量? | 开发者秘籍_开发者提升

https://dev-cheats.com/opensource/how-to-contribute.html

为何要为开源贡献力量? 在 [自由代码] 下工作,让我学习到了职业生涯中非常重要的技能,无论是大学还是实际的工作,我认为从开源项目中得到的收获的远大於我的贡献! — @errietta, “我为何是如此的热衷于为开源软件贡献力量” 为开源贡献力量,得到的回报就是能够学习到很多、受教很多、且能够锻炼任何你能够想到的经验。

Blade 实战指南:Hello World | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/hello-world.html

运行Hello World 我们就在默认生成的 App.java 文件中写上程序员入门必备的 Hello World。 /** * Hello world! */ public class App { public static void main(String[] args) { Blade.me() .get("/", (request, response) -> response.text("Hello World")) .start(App.class, args); } } 运行 main 函数,此时你会在控制台看到这样的输出信息 2017-06-21 00:02:26:630 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: jdk.version => 1.8.0_101 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: user.dir => /Users/biezhi/Documents/workspace-sts-3.8.3.RELEASE/first-blade-app 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: java.io.tmpdir => /var/folders/y7/fdpr6jzx1rs6x0jmty2h6lvw0000gn/T/ 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: user.timezone => Asia/Shanghai 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: file.encoding => UTF-8 2017-06-21 00:02:26:636 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: classpath => /Users/biezhi/Documents/workspace-sts-3.8.3.RELEASE/first-blade-app/target/classes/ _, , , __, __, |) | /\ | \ | |) | , | | |/ | ~ ~~~ ~ ~ ~ ~~~ :: Blade :: (v2.0.5-BETA1) 2017-06-21 00:02:26:661 INFO - [ (:3」∠) ] c.b.m.r.RouteMatcher | Add route => GET / 2017-06-21 00:02:26:667 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Register bean: [com.blade.Environment@215fea12] 2017-06-21 00:02:26:866 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Blade initialize successfully, Time elapsed: 252 ms 2017-06-21 00:02:26:866 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Blade start with 0.0.0.0:9000 2017-06-21 00:02:26:867 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Open your web browser and navigate to http://127.0.0.1:9000 ⚡ 我们打开浏览器访问 http://127.0.0.1:9000 惊喜的看到 Hello World 输出在网页上! 上一篇:创建一个Blade工程 下一篇:Mvc应用架构 系列目录:Blade 实战指南

Blade 实战指南:启动服务 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/start-server.html

启动一个 Blade 应用非常简单,因为框架内部使用 netty 作为web服务,所以你不需要使用 tomcat 或 jetty 这种web容器,只需要运行 main 方法执行即可。 API讲解 首先我们创建一个非常简单的demo程序 Blade blade = Blade.me(); blade.get("/", (req, res) -> res.text("Hello")); 这时候想直接启动服务只需要编写一行代码 blade.start(); 这样就可以启动,默认会监听在 tcp 的 9000 端口。 编码的方式修改端口可以使用 blade.listen(1234) 来监听。 细心的同学可能会发现在 start 方法中有很多参数,为什么有时候会传有时候不传呢? 我们把 API 中最长的那个方法贴出来分析一下大家就清楚了 start(Class<?> bootClass, String address, int port, String... args) 这里有4个参数,第一个指定启动类的Class,你会发现我写HelloWorld或者简单程序的时候没有传递这个东西,原因是我们希望在启动的时候扫描 bootClass 所在的包以及子包,这样对于开发者就可以不用配置扫描哪些包了(当然框架提供手动指定的API)。第二个参数即web服务绑定的IP地址,默认为本机 0.0.0.0 回环地址,如果不理解你可以认为是 127.0.0.1,第三个参数是端口,我们没有指定的时候默认为 9000。 最后一个参数如果使用方式是这样 blade.start(Application.class, args); 这里的 args 就是 main 方法中的字符串数组参数,当开发者在命令行中启动应用或者设置启动参数的时候,Blade 会读取到一些配置信息,当然如果你不用这个功能也可以不传递该参数。 上一篇:注册路由 下一篇:静态资源 系列目录:Blade 实战指南

跟我学Golang:(七)包 | 开发者秘籍_开发者提升

https://dev-cheats.com/golang/package.html

这是跟我学Golang系列教程的第七篇。 什么是包?为什么使用包? 到目前为止我们见到的 Go 程序都只有一个文件,文件中包含了一个main 函数 和几个其他函数。在实际中这种将所有代码都放在一个文件里的组织方式是不可行的。这样的组织方式使得代码变得无法重用和维护困难。包(package)用于解决这样的问题。 包用于组织Go源代码,以获得更好的重用性和可读性。 包提供了代码封装的机制从而使得Go应用程序易于维护。例如,假设我们正在开发一个图像处理应用,它提供了诸如图像裁剪,锐化,模糊和增色等功能。一种组织代码的方式是将所有实现同一功能的代码放在一个独立的包中。例如裁剪功能可以放在一个单独包中,而锐化功能可以放在另一个包中。这种做法的优点是:增色功能可能需要做一些锐化的处理,那么增色代码中可以简单地导入(我们即将讨论导入)锐化包,使用其中提供的功能即可。这种方式使得代码变得更容易重用。 我们将逐步创建一个计算矩形面积和对角线的应用程序。 通过构建该程序,我们将更好的理解包。 main函数与main包 每个可执行的Go程序都必须包含一个 main 函数。这个函数是执行程序的入口点。main 函数应该包含在 main 包中。 指定一个特定源文件属于一个包的语法为:package packagename,这条语句应该放在源文件的第一行。 下面让我们开始创建 main 函数和 main 包。在 [工作空间目录]/src 目录下新建一个子目录,命名为 geometry。在该目录下新建 geometry.go。 编写 geometry.go 代码如下: //geometry.go package main import "fmt" func main() { fmt.Println("Geometrical shape properties") } package main 这一行指定了该文件属于 main 包。import "packagename" 语句用来导入一个包,这里我们导入 fmt 包,该包导出了 Println 方法(译者注:该方法用于打印文本到标准输出)。然后是 main 函数,在这里仅打印 Geometrical shape properties。 执行 go install geometry 编译上面的程序。该命令在 geometry 目录下查找包含 main 函数的文件,在这里就是 geometry.go。找到后编译该文件并在 [工作空间目录]/bin 目录下生成二进制文件 geometry(在Windows下是 geometry.exe)。 现在的目录结构如下所示: src/ geometry/ geometry.go bin/ geometry 执行 [工作空间目录]/bin/geometry 运行该程序,其中 [工作空间目录] 需要换成自己的实际目录。这条命令运行在 bin 目录下的 geometry 二进制文件。你应该可以看到如下输出: Geometrical shape properties 创建自定义包 下面我们将创建一个 rectangle 包,将与矩形相关的功能(计算矩形的面积和对角线)都放在这个包里。 属于同一个包的源文件应该放在独立的文件夹中,按照Go的惯例,该文件夹的名字应该与包名相同。 因此让我们在 geometry 目录下创建一个 rectangle 子目录。所有放在该目录下的源文件都应该以 package rectangle 开头,用以表示这些源文件都属于 rectangle 包。 在 rectangle 目录下新建 rectangle.go ,编写如下代码: //rectprops.go package rectangle import "math" func Area(len, wid float64) float64 { area := len * wid return area } func Diagonal(len, wid float64) float64 { diagonal := math.Sqrt((len * len) + (wid * wid)) return diagonal } 在上面的代码中我们实现了两个函数 Area 和 Diagonal 分别用于计算矩形的面积和对角线。矩形的面积为长与宽的积。矩形的对角线为长与宽的平方和再开根号。这里调用 math 包中的 Sqrt 函数来计算平方根。 注意上面实现的两个函数的函数名 Area 和 Diagonal 都是以大写字母开头的。这是必要的,我们将很快解释为什么需要这样做。 导入自定义包 为了使用自定义包我们必须先导入它。用来导入自定义包的语法为:import path。我们必须指定 path 为相对于 [工作空间目录]/src 目录的相对路径。我们当前的目录结构如下所示: src/ geometry/ geometry.go rectangle/ rectangle.go 语句 import "geometry/rectangle" 表示我们要导入 rectangle 包。 在 geometry.go 中添加如下代码: //geometry.go package main import ( "fmt" "geometry/rectangle" //importing custom package ) func main() { var rectLen, rectWidth float64 = 6, 7 fmt.Println("Geometrical shape properties") /*Area function of rectangle package used */ fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth)) /*Diagonal function of rectangle package used / fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth)) } 上面的代码导入了 rectangle 包并且使用 Area 和 Diagonal 函数计算矩形的面积和对角线。在 Printf 中的 %.2f 格式化指示符表示仅保留浮点数的两位小数。程序输出如下: Geometrical shape properties area of rectangle 42.00 diagonal of the rectangle 9.22 导出名字 我们将 rectangle 包中的两个函数名称 Area 和 Diagonal 的首字母大写,这在 Go 中有特殊的意义。在 Go 中,任何以大写字母开头的变量名、函数名都是被导出的名字(exported name)。只有被导出的名字才能被其它包访问。在这里我们需要在 main 包中访问 Area 和 Diagonal 函数,因此将它们的首字母大写。 如果将 rectprops.go 中的 Area(len, wid float64) 改成 area(len, wid float64),并且将 geometry.go 中的 rectangle.Area(rectLen, rectWidth) 改成 rectangle.area(rectLen, rectWidth),那么运行程序时编译器将会报错:geometry.go:11: cannot refer to unexported name rectangle.area。因此,如果想访问包外的函数,必须将其首字母大写。 init 函数 每一个包都可以包含一个 init 函数。该函数不应该有任何参数和返回值,并且在我们的代码中不能显式调用它。init 函数形式如下: func init() { } init 函数可用于执行初始化任务,也可用于在执行开始之前验证程序的正确性。 一个包的初始化顺序如下: 包级别的变量首先被初始化 接着 init 函数被调用。一个包可以有多个 init 函数(在一个或多个文件中),它们的调用顺序为编译器解析它们的顺序。 如果一个包导入了另一个包,被导入的包先初始化。 尽管一个包可能被包含多次,但是它只被初始化一次。 下面让我们对我们的程序做一些修改来理解 init 函数。 首先在 rectprops.go 中添加一个 init 函数: //rectprops.go package rectangle import "math" import "fmt" / * init function added / func init() { fmt.Println("rectangle package initialized") } func Area(len, wid float64) float64 { area := len * wid return area } func Diagonal(len, wid float64) float64 { diagonal := math.Sqrt((len * len) + (wid * wid)) return diagonal } 我们添加了一个简单的 init 函数,它仅打印:rectangle package initialized。 现在我们来修改 main 包。我们知道矩形的 length 和 width 应该大于 0。我们将在 geometry.go 中添加 init 函数和包级别的变量来做此检查。 修改 geometry.go 如下: //geometry.go package main import ( "fmt" "geometry/rectangle" //importing custom package "log" ) / * 1. package variables / var rectLen, rectWidth float64 = 6, 7 / *2. init function to check if length and width are greater than zero */ func init() { println("main package initialized") if rectLen < 0 { log.Fatal("length is less than zero") } if rectWidth < 0 { log.Fatal("width is less than zero") } } func main() { fmt.Println("Geometrical shape properties") fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth)) fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth)) } 我们对 geometry.go 做了如下修改: rectLen 和 rectWidth 变量从 main 函数中移到了外面,成为了包级别的变量。 添加 init 函数。当 rectLen 或 rectWidth 小于 0 时,该函数利用 log.Fatal 打印一条日志并终止程序。 main 包的初始化顺序为: 首先初始化被导入的包。因此 rectangle 包先被初始化。 然后初始化包级别的变量: rectLen 和 rectWidth。 init 函数被调用。 最后 main 函数被调用。 运行该程序,输出如下: rectangle package initialized main package initialized Geometrical shape properties area of rectangle 42.00 diagonal of the rectangle 9.22 正如预期的那样,rectangle 包的 init 函数首先被调用,接着是包级别的变量 rectLen 和 rectWidth 被初始化,接着是 main 包的 init 函数被调用,该函数检测 rectLen 和 rectWidth 是否小于 0,如果小于 0,则终止程序。我们将会在单独的教程里介绍 if 语句。现在你可以假定 if rectLen < 0 将会检测 rectLen 是否小于 0,如果是,则终止程序。rectWidth 也是同样的处理。也就是说两个条件都为假程序才继续执行。最后,main 函数被调用。 让我们再次修改程序来学习 init 函数的使用。 将 geometry.go 中的 var rectLen, rectWidth float64 = 6, 7 这一行改为 var rectLen, rectWidth float64 = -6, 7。这里将 rectLen 改为负值。 现在运行程序,得到如下结果: rectangle package initialized main package initialized 2017/04/04 00:28:20 length is less than zero 像上面一样, rectangle 包首先被初始化,然后是 main 包中的包级别变量 rectLen 和 rectWidth 初始化。接着调用 main 包的 init 函数,因为 rectLen 是小于 0 的,因此程序打印 length is less than zero 后退出。 代码可以在 github 上下载。 使用空指示符 在 Go 中只导入包却不在代码中使用它是非法的。如果你这么做了,编译器会报错。这样做的原因是为了避免引入过多未使用的包而导致编译时间的显著增加。将 geometry.go 中的代码替换为如下代码: //geometry.go package main import ( "geometry/rectangle" //importing custom package ) func main() { } 上面的程序将会报错:geometry.go:6: imported and not used: "geometry/rectangle" 但是在开发过程中,导入包却不立即使用它是很常见的。可以用空指示符(_)来处理这种情况。 下面的代码可以避免抛出上面的错误: package main import ( "geometry/rectangle" ) var _ = rectangle.Area //error silencer func main() { } var _ = rectangle.Area 这一行屏蔽了错误。我们应该跟踪这些“错误消音器”(error silencer), 在开发结束时,我们应该去掉这些“错误消音器”,并且如果没有使用相应的包,这些包也应该被一并移除。因此,建议在 import 语句之后的包级别中写“错误消音器”。 有时我们导入一个包只是为了确保该包初始化的发生,而我们不需要使用包中的任何函数或变量。例如,我们也许需要确保 rectangle 包的 init 函数被调用而不打算在代码中的任何地方使用这个包。空指示符仍然可以处理这种情况,像下面的代码一样: package main import ( _ "geometry/rectangle" ) func main() { } 运行上面的程序,将会得到输出:rectangle package initialized。我们成功地初始化了这个包,即使在代码中的任何地方都没有使用它。 包的介绍到此结束。感谢阅读。 上一篇:跟我学Golang:(六)函数) 下一篇:跟我学Golang:(八)if else 语句 系列目录:跟我学习 Go 语言 原文出处:https://golangbot.com/packages

跟我学Golang:(五)常量 | 开发者秘籍_开发者提升

https://dev-cheats.com/golang/constants.html

这是跟我学Golang系列教程的第五篇。本篇介绍Golang中的常量。 定义常量 常量(constant)表示固定的值,比如:5,-89,"I love Go",67.89 等等。 考虑如下程序: var a int = 50 var b string = "I love Go" 上面的程序中, a 和 b 分别被赋值为常量 50 和 "I love Go"。关键字 const 用于指示常量,如 50 和 "I love Go"。在上面的代码中,尽管没有使用关键字 const 修饰 50 与 "I love Go",但它们在Go的内部表示为常量。(译者注:像 50 和 "I love Go" 这样的值称为字面值(literal)常量,它们的值即为它们本身,是无法被改变的。) 关键字 const 修饰的名字为常量,不能被重新赋予任何值。 因此下面的程序会报错:cannot assign to a。 package main func main() { const a = 55 //allowed a = 89 //reassignment not allowed } 常量的值必须在编译期间确定。因此不能将函数的返回值赋给常量,因为函数调用发生在运行期。 package main import ( "fmt" "math" ) func main() { fmt.Println("Hello, playground") var a = math.Sqrt(4)//allowed const b = math.Sqrt(4)//not allowed } 在上面的程序中,a 是一个变量因此可以被赋值为函数 math.Sqrt(4) 的调用结果。(我们将在单独的教程中更详细的讨论函数)。而 b 是一个常量,它的值必须在编译期间确定,但是函数 math.Sqrt(4) 的调用结果只能在运行时被计算出来,因此在编译 const b = math.Sqrt(4) 时将会报错:error main.go:11: const initializer math.Sqrt(4) is not a constant. 字符串常量 字符串常量最简单的常量,通过了解字符串常量可以更好的理解常量的概念。 在Go中任何用双引号(")括起来的值都是字符串常量,比如 "Hello World","Sam" 都是字符串常量。 字符串常量是什么类型呢?答案是 无类型(untyped)。 像 “Hello World” 这样的字符串没有任何类型。 const hello = "Hello World" 上面的代码将 "Hello World" 赋给一个名为 hello 的常量。那么现在常量 hello 是不是就有了类型?答案是:No。hello 仍然没有类型。 下面的代码中,变量 name 被赋值为一个无类型的常量 "Sam",它是如何工作的呢? package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") var name = "Sam" // 译者注:这里编译器需要推导出 name 的类型, // 那么它是如何从无类型的常量 "Sam" 中获取类型的呢? fmt.Printf("type %T value %v", name, name) } 答案是无类型常量有一个默认的类型,当且仅当代码中需要无类型常量提供类型时,它才会提供该默认类型。在语句 var name = "Sam" 中,name需要一个类型,因此它从常量 "Sam" 中获取其默认类型:string。 译者注:这里可以理解为常量是无类型的,但是在需要类型的场合,编译器会根据常量的值和上下文将常量转换为相应的类型。 有没有办法创建一个有类型(typed)的常量?答案是:Yes。下面的代码创建了一个有类型常量。 const typedhello string = "Hello World" 上面的代码中, typedhello 是一个字符串类型的常量。 Go是强类型语言。在赋值时混合使用类型是不允许的。让我们通过以下代码说明这是什么意思。 package main func main() { var defaultName = "Sam" //allowed type myString string var customName myString = "Sam" //allowed customName = defaultName //not allowed } 在上面的代码中,我们首先创建了一个变量 defaultName 并且赋值为常量 "Sam"。常量 "Sam" 的默认类型为 string,因此赋值之后,defaultName 的类型亦为 string。 下一行我们创建了一个新的类型 myString,它是 string 的别名。 译者注:可以通过 type NewType Type 的语法来创建一个新的类型。类似 C 语言的 typedef 。 接着我们创建了一个名为 customName 的 myString 类型的变量,并将常量 "Sam" 赋给它。因为常量 "Sam" 是无类型的所以可以将它赋值给任何字符串变量。因此这个赋值是合法的,customName 的类型是 myString。 现在我们有两个变量:string 类型的 defaultName 和 myString 类型的 customName。尽管我们知道 myString 是 string 的一个别名,但是Go的强类型机制不允许将一个类型的变量赋值给另一个类型的变量。因此, customName = defaultName 这个赋值是不允许的,编译器会报错:main.go:10: cannot use defaultName (type string) as type myString in assignment 布尔常量 布尔常量与字符串常量(在概念上)没有区别。布尔常量只包含两个值:true 和 false。字符串常量的规则也同样适用于布尔常量,这里不再赘述。下面的代码解释了布尔常量: package main func main() { const trueConst = true type myBool bool var defaultBool = trueConst //allowed var customBool myBool = trueConst //allowed defaultBool = customBool //not allowed } 上面的程序很好理解,这里就不过多解释了。 数值常量 数值常量(Numeric constants)包括整数,浮点数以及复数常量。数值常量有一些微妙之处。 让我们看一些例子使事情变得明朗。 package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") const a = 5 var intVar int = a var int32Var int32 = a var float64Var float64 = a var complex64Var complex64 = a fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var) } 上面的程序中,const a 是无类型的,值为 5。你也许想知道 a 的默认类型是什么?如果它有默认类型,那么它是怎么赋值给其他类型的变量的?答案在于使用 a 时的上下文。我们暂时放下这两个问题,先来看下面的程序: package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") var i = 5 var f = 5.6 var c = 5 + 6i fmt.Printf("i's type %T, f's type %T, c's type %T", i, f, c) } 在上面的程序中,所有变量的类型都是由数值常量决定的。在语法上看,5 在是一个整数,5.6 是一个浮点数, 5 + 6i 是一个复数。运行上面的程序,输出为:i's type int, f's type float64, c's type complex128 译者注:编译器可以根据字面值常量的表现形式来确定它的默认类型,比如 5.6 表现为浮点数,因此它的默认类型为 float64 ,而 “Sam” 表现为字符串,因此它的默认类型为 stirng。 现在应该很清楚下面的程序是如何工作的了: package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") const a = 5 var intVar int = a var int32Var int32 = a var float64Var float64 = a var complex64Var complex64 = a fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var) } 在这个程序中,a 的值是 5 并且 a 在语法上是泛化的(它既可以表示浮点数 5.0,也可以表示整数 5,甚至可以表示没有虚部的复数 5 + 0i),因此 a 可以赋值给任何与之类型兼容的变量。像 a 这种数值常量的默认类型可以想象成是通过上下文动态生成的。var intVar int = a 要求 a 是一个 int,那么 a 就变成一个 int 常量。var complex64Var complex64 = a 要求 a 是一个 complex64,那么 a 就变成一个 complex64 常量。这很容易理解:) 数值表达式 数值常量可以在表达式中自由的混合和匹配,仅当将它们赋值给变量或者在代码中明确需要类型的时候,才需要他们的类型。 package main import ( "fmt" ) func main() { var a = 5.9/8 fmt.Printf("a's type %T value %v",a, a) } 在上面的程序中,语法上 5.9 是一个浮点数,8 是一个整数。因为它们都是数值常量,因此 5.9/8 是合法的。相除的结果为 0.7375,是一个浮点数。因此变量 a 的类型为浮点型。上面的程序输出为:a's type float64 value 0.7375。 常量的介绍到此结束。 上一篇:跟我学Golang:(四)类型 下一篇:跟我学Golang:(六)函数 系列目录:跟我学习 Go 语言 原文出处:https://golangbot.com/hello-world

跟我学Golang:(八)if else 语句 | 开发者秘籍_开发者提升

https://dev-cheats.com/golang/if-statement.html

这是跟我学Golang系列教程的第八篇。 if 是一个条件语句。if 语句的语法为: if condition { } 如果 condition 为 true,那么就执行 { 和 } 之间的代码。 与其它语言(如C)不同,即使 {} 之间只有一条语句,{} 也是必需的。 if 语句后面可以接可选的 else if 和 else 语句: if condition { } else if condition { } else { } if 后面可以接任意数量的 else if 语句。condition 的求值由上到下依次进行,直到某个 if 或者 else if 中的 condition 为 true 时,执行相应的代码块。如果没有一个 conditon 为 true,则执行 else 中的代码块。 让我们写一个简单的程序来判断一个数是奇数还是偶数: package main import ( "fmt" ) func main() { num := 10 if num % 2 == 0 { //checks if number is even fmt.Println("the number is even") } else { fmt.Println("the number is odd") } } if num % 2 == 0 这条语句检测一个数除以 2 的余数是否为 0,如果是则输出:"the number is even",否则输出:"the number is odd"。上面的程序输出:the number is even。 if 语句还有如下的变体。这种形式的 if 语句先执行 statement,然后再判断 conditon。 if statement; condition { } 让我们用这种形式的 if 改写上面的程序: package main import ( "fmt" ) func main() { if num := 10; num % 2 == 0 { //checks if number is even fmt.Println(num,"is even") } else { fmt.Println(num,"is odd") } } 在上面的程序中, num 在 if 语句中初始化。需要注意的一点是,num 只能在 if 和 else 里面进行访问,即 num 的范围仅限于 if else 块中。如果我们试图在 if 或 else 之外访问 num,编译器将报错。 让我们用 else if 再写一个程序: package main import ( "fmt" ) func main() { num := 99 if num >= 0 && num <= 50 { fmt.Println("number is greater than 50") } else if num >= 51 && num <= 100 { fmt.Println("number is between 51 and 100") } else { fmt.Println("number is greater than 100") } } 上面的程序中 else if num >= 51 && num <= 100 为 true,因此程序的输出为:number is between 51 and 100。 if else 语句的介绍到此结束。感谢阅读。 上一篇:跟我学Golang:(七)包) 下一篇:跟我学Golang:(九)循环语句 系列目录:跟我学习 Go 语言 原文出处:https://golangbot.com/if-statement

Blade 实战指南:静态资源 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/static-resource.html

Blade 为开发者提供2种静态资源配置方式,默认我们将 classpath 下的 static 目录和 upload 目录作为静态资源配置的位置,同时也支持 webjars 的方式,下面我们一一给出例子。 举个栗子 🌰 来看看我的目录结构 我在 static 目录下存了一张图片,我们来启动服务访问 http://127.0.0.1:9000/static/1bd163bc88d4.png 是不是有点小激动,我们什么都不用配置,Blade已经帮我完成了静态资源的映射。 自定义资源目录 有位兄弟说了,我想试试自定义一个目录,static 这个名字太 low 了 23333。自定义静态资源目录的姿势有2种: 通过编码设置:blade.addStatics("/zhuangbi") 通过配置文件:mvc.statics=/zhuangbi 我们来试试: public static void main(String[] args) { Blade.me().addStatics("/zhuangbi").start(); } 实际上 Blade 内部提供了一个小功能,默认的关闭的,如果你希望看到静态资源目录下的列表可以开启这项技能,也是两种方式: 通过编码设置:blade.showFileList(true) 通过配置文件:mvc.statics.list=true 开启之后的样子 webjars是什么鬼? 使用过 SpringBoot 的同学可能用过这个东西,实际上我们引用静态资源的方式可以是一个 jar 包。 使用方法非常简单,你需要在 maven 的中加入一个依赖,比如: org.webjars bootstrap 3.3.7 这时候启动服务访问 http://127.0.0.1:9000/webjars/bootstrap/3.3.7/css/bootstrap.css 来,见证奇迹的时刻到了。如果你对 webjars 感兴趣,可以在 https://www.webjars.org/ 找到更多。 上一篇:启动服务 下一篇:完整的程序 系列目录:Blade 实战指南

Blade 实战指南:Hello World | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/hello-world.html

运行Hello World 我们就在默认生成的 App.java 文件中写上程序员入门必备的 Hello World。 /** * Hello world! */ public class App { public static void main(String[] args) { Blade.me() .get("/", (request, response) -> response.text("Hello World")) .start(App.class, args); } } 运行 main 函数,此时你会在控制台看到这样的输出信息 2017-06-21 00:02:26:630 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: jdk.version => 1.8.0_101 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: user.dir => /Users/biezhi/Documents/workspace-sts-3.8.3.RELEASE/first-blade-app 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: java.io.tmpdir => /var/folders/y7/fdpr6jzx1rs6x0jmty2h6lvw0000gn/T/ 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: user.timezone => Asia/Shanghai 2017-06-21 00:02:26:633 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: file.encoding => UTF-8 2017-06-21 00:02:26:636 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | Environment: classpath => /Users/biezhi/Documents/workspace-sts-3.8.3.RELEASE/first-blade-app/target/classes/ _, , , __, __, |) | /\ | \ | |) | , | | |/ | ~ ~~~ ~ ~ ~ ~~~ :: Blade :: (v2.0.5-BETA1) 2017-06-21 00:02:26:661 INFO - [ (:3」∠) ] c.b.m.r.RouteMatcher | Add route => GET / 2017-06-21 00:02:26:667 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Register bean: [com.blade.Environment@215fea12] 2017-06-21 00:02:26:866 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Blade initialize successfully, Time elapsed: 252 ms 2017-06-21 00:02:26:866 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Blade start with 0.0.0.0:9000 2017-06-21 00:02:26:867 INFO - [ (:3」∠) ] c.b.s.n.NettyServer | ⬢ Open your web browser and navigate to http://127.0.0.1:9000 ⚡ 我们打开浏览器访问 http://127.0.0.1:9000 惊喜的看到 Hello World 输出在网页上! 上一篇:创建一个Blade工程 下一篇:Mvc应用架构 系列目录:Blade 实战指南

Blade 实战指南:创建 Blade 工程 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/create-application.html

创建一个Blade工程 作者认为每一个编程语言都应该有一个合适的 包管理器,比如 nodejs 中的 npm,python的 pip,ruby的 gem 等等, 早期的Java开发者可能会使用 Ant 进行项目的构建,但在国内目前最流行还属 maven 了, 国外用 gradle 的人挺多,但我对这个家伙不是特别熟悉。 在开始一个 Blade 工程之前首先确保你已经安装了maven,如果还没有安装或了解, 可以看看 maven使用指南 必须环境 jdk8 maven idea/eclipse 搭建Blade工程的步骤 创建一个普通 maven 工程(需设置JDK编译版本为1.8) 加入 blade-mvc 依赖 在 Eclipse 创建 Blade 工程 选择创建 maven 骨架工程 这里选择创建一个最简单的 quickstart 工程 输入 GroupId 和 ArtifactId 以及包名 此时你看到的项目结构应该是如下: 实际上这样的项目结构是有问题的,可以看到默认的 JDK 编译版本是 1.5, 这时候我们使用一个 maven 插件将编译版本调整至 1.8,在 pom.xml 中加入 maven-compiler-plugin org.apache.maven.plugins maven-compiler-plugin 3.1 1.8 1.8 UTF-8 我在 eclipse 下加入后是这样的 在项目上右键刷新下 maven 配置 然后加入 blade-mvc 的依赖,具体版本可以在 github 查看或者在 maven 仓库搜索,尽量使用较新版本, 我当前使用的版本是 2.0.5-BETA1 com.bladejava blade-mvc 2.0.5-BETA1 ok,大功告成了,看起来上面很多图其实对于一个熟练J2EE开发的开发者操作起来也是分分钟的,作者尽可能讲的详细一些,避免大家在第一步的时候出现什么错误。 在 Idea 中创建 Blade 工程 输入 GroupId 和 ArtifactId 以及包名 和上面在 eclipse 下操作是一样的,加入编译插件保证1.8版本,然后加入 blade-mvc 依赖。 太棒了,项目创建成功了,去试试编写第一个Hello World程序。 上一篇:Blade简介 下一篇:运行Hello World 系列目录:Blade 实战指南

Blade 实战指南:注册路由 | 开发者秘籍_开发者提升

https://dev-cheats.com/blade-in-action/register-route.html

现代 Web 应用的 URL 十分优雅,易于人们辨识记忆。 在 Blade 中, 路由是一个 HTTP 方法配对一个 URL 匹配模型, 每一个路由可以对应一个处理方法。 如何管理呢?Blade 从以下三个方面对资源进行定义: 直观简短的资源地址:URI,比如:http://example.com/resources。 可传输的资源:Web 服务接受与返回的互联网媒体类型,比如:JSON,XML 等。 对资源的操作:Web 服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT或DELETE)。 在 Blade1x 的时候注册一个路由的方式非常多,但后来发现更多的API不代表就会有更多人使用,在 2.0 的版本中我们只保留了那些最核心的,使用最频繁的API,当然随着使用者的增多我们还会继续优化,目前我们保留了2种注册路由的方式: 通过Blade对象直接注册 编写控制器一次注册多个(像SpringMvc那样) 废话少说,带大家写几个路由感受一下 Blade blade = Blade.me(); blade.get("/hello", (request, response) -> response.html("

Fuck Blade!

")); blade.post("/save", (request, response) -> response.json(request.parameters())); 上面的写法看起来是很简洁的,也用到java8的语法,但是一般我们编写一个站点的时候会有很多的路由,都放在一个文件中不是很好管理,这时候Blade支持你以SpringMvc的编程习惯切换过来,我们可以编写一个控制器,在你的 Application 所在目录之下,我们最好将它放在 controller 包中,看到名字也就知道是控制器了。 @path public class IndexControoler{ @getroute("hello") public void hello(Request request, Response response){ System.out.println(request.query("name").orElse("默认值")); response.text(request.query("name").orElse("默认值")); } @getroute("index") public String index(){ return "index.html"; } } 前面我们注册了2个路由,分别讲一下,在路由中包含这么几个东西: 访问路径 请求方法 具体执行的方法体 所谓访问路径就是我们前面使用 Blade 对象进行路由配置的第一个参数,Blade 提供了四种请求方式:GET, POST,PUT,DELETE。 使用Blade对象注册的时候有2个参数,第一个是路由的访问路径,后面的参数是一个@FunctionalInterface,这个技术是在java8种出现的,实际上是一个接口(在其他语言中可能叫匿名函数),java8种规定了加@FunctionalInterface注解的接口只有一个方法,这样我们在使用的时候可以用 lambda 表达式,让代码看起来更加简洁。接口有2个参数,分别是 Request 和 Response 对象,具体的操作可以在核心概念章节中看到,比 ServletAPI 提供的更加方便和简单,例子中我们只输出了 html 和 json。 常用注解 @path : 标注一个类是控制器类,可用于类上 @route : 标注一个路由请求 @getroute : 标注一个 GET 请求 @PostRoute : 标注一个 POST 请求 @PutRoute : 标注一个 PUT 请求 @DeleteRoute : 标注一个 DELETE 请求 @JSON : 标注该方法返回值是一段 JSON,框架会自动将返回值解析为JSON输出 上一篇:初始化 下一篇:启动服务 系列目录:Blade 实战指南

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.