mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-02-03 23:40:14 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
1b68ea54a6
@ -1,50 +1,48 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Yufei-Yan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12555-1.html)
|
||||
[#]: subject: (An example of very lightweight RESTful web services in Java)
|
||||
[#]: via: (https://opensource.com/article/20/7/restful-services-java)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
|
||||
|
||||
An example of very lightweight RESTful web services in Java
|
||||
|
||||
一个用 Java 实现的超轻量级 RESTful web 服务示例
|
||||
一个用 Java 实现的超轻量级 RESTful Web 服务示例
|
||||
======
|
||||
|
||||
通过完整的代码例子管理一套图书,来探索轻量级的 RESTful 服务。
|
||||
> 通过管理一套图书的完整代码示例,来探索轻量级的 RESTful 服务。
|
||||
|
||||
![Coding on a computer][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/202008/27/071808tt9zlno3b6lmbgl8.jpg)
|
||||
|
||||
Web 服务,以这样或那样的形式,已经存在了近二十年。比如,[XML-RPC 服务][2]出现在 90 年代后期,紧接着是 SOAP 分支编写的服务。在 XML-RPC 和 SOAP 这两个开拓者之后出现后不久,REST 架构风格的服务在大约 20 年前也出现了。[REST][4]风格(后来的 Restful)服务现在主导了流行的网站,比如 eBay、Facebook 和 Twitter。尽管分布式计算的 web 服务有很多替代品(如 web sockets,微服务和远程过程调用的新框架),基于 Restful 的网页服务依然具有吸引力,原因如下:
|
||||
Web 服务,以这样或那样的形式,已经存在了近二十年。比如,[XML-RPC 服务][2]出现在 90 年代后期,紧接着是用 SOAP 分支编写的服务。在 XML-RPC 和 SOAP 这两个开拓者之后出现后不久,REST 架构风格的服务在大约 20 年前也出现了。[REST][4] 风格(以下简称 Restful)服务现在主导了流行的网站,比如 eBay、Facebook 和 Twitter。尽管分布式计算的 Web 服务有很多替代品(如 Web 套接字、微服务和远程过程调用的新框架),但基于 Restful 的 Web 服务依然具有吸引力,原因如下:
|
||||
|
||||
* Restful 服务是在现有的基础设施和协议的基础上构建的,特别是 web 服务器和 HTTP/HTTPS 协议。对于那些对数据和底层功能比用 HTML 如何展示内容更感兴趣的客户来说,拥有基于 HTML 网站的公司可以很容易的添加 web 服务。比如,亚马逊就率先通过网站和 web 服务(基于 SOAP 或 Restful)提供相同的信息和功能。
|
||||
* Restful 服务将 HTTP 当作 API,因此避免了复杂的软件分层,这种分层是基于 SOAP web 服务的明显特征。比如,Restful API 支持通过 HTTP 命令(POST-GET-PUT-DELETE)进行标准的 CRUD(增加-读取-更新-删除)操作;通过 HTTP 状态码可以知道请求是否成功或者为什么失败。
|
||||
* Restful web 服务可以根据需要变得简单或复杂。Restful 是一种风格,事实上是一种非常灵活的风格,而不是一套关于如何设计和构造服务的配方。(伴随而来的缺点是,可能很难确定哪些服务不能算作 Restful 服务。)
|
||||
* 作为使用者或者客户端,Restful web 服务与语言和平台无关。客户端发送 HTTP(S) 请求并且接受当前流行的数据交换的对应文本(比如,JSON)。.
|
||||
* 几乎每一种通用编程语言都至少有足够(而且通常都很强大)的对 HTTP/HTTPS 的支持,也就是说 web 服务的客户端可以用这些语言来编写。
|
||||
* Restful 服务建立在现有的基础设施和协议上,特别是 Web 服务器和 HTTP/HTTPS 协议。一个拥有基于 HTML 的网站的组织可以很容易地为客户添加 Web 服务,这些客户对数据和底层功能更感兴趣,而不是对 HTML 的表现形式感兴趣。比如,亚马逊就率先通过网站和 Web 服务(基于 SOAP 或 Restful)提供相同的信息和功能。
|
||||
* Restful 服务将 HTTP 当作 API,因此避免了复杂的软件分层,这种分层是基于 SOAP 的 Web 服务的明显特征。比如,Restful API 支持通过 HTTP 命令(POST-GET-PUT-DELETE)进行标准的 CRUD(增加-读取-更新-删除)操作;通过 HTTP 状态码可以知道请求是否成功或者为什么失败。
|
||||
* Restful Web 服务可以根据需要变得简单或复杂。Restful 是一种风格,实际上是一种非常灵活的风格,而不是一套关于如何设计和构造服务的规定。(伴随而来的缺点是,可能很难确定哪些服务不能算作 Restful 服务。)
|
||||
* 作为使用者或者客户端,Restful Web 服务与语言和平台无关。客户端发送 HTTP(S) 请求,并以适合现代数据交换的格式(如 JSON)接收文本响应。
|
||||
* 几乎每一种通用编程语言都至少对 HTTP/HTTPS 有足够的(通常是强大的)支持,这意味着 Web 服务的客户端可以用这些语言来编写。
|
||||
|
||||
这篇文章将通过一段完整的 Java 代码来展现轻量级的 Restful 服务。
|
||||
这篇文章将通过一段完整的 Java 代码示例来探讨轻量级的 Restful 服务。
|
||||
|
||||
### 基于 Restful 的”小说“ web 服务
|
||||
### 基于 Restful 的“小说” Web 服务
|
||||
|
||||
基于 Restful 的”小说“ web 服务包含三个程序员定义的类:
|
||||
基于 Restful 的“小说” web 服务包含三个程序员定义的类:
|
||||
|
||||
* `Novel` 类代表了只有三个属性的小说:机器生成的 ID,作者和标题。属性可以根据实际情况进行扩展,但我还是想让这个例子看上去更简单一些。
|
||||
* `Novels` 类包含了用于各种任务的使用工具:将一个 `Novel` 或者这样的一个列表的明文编码成 XML 或者 JSON;支持在小说的容器上进行 CRUD 操作;可以从存储在文件中的数据对容器进行初始化。`Novels` 类在 `Novel` 实例和 servlet 之间进行调解。
|
||||
* `NovelsServlet` 类是从 `HttpServlet` 中继承的,`HttpServlet` 是健壮且灵活的一段代码,自 90 年代末的早期企业级 Java 就已经存在了。对于客户端的 CRUD 请求,servlet 可以当作 HTTP 的端点。 servlet 代码主要用于处理客户端的请求和生成合适的响应,而将复杂的细节留给 `Novels` 类中的工具类进行处理。
|
||||
* `Novel` 类代表一个小说,只有三个属性:机器生成的 ID、作者和标题。属性可以根据实际情况进行扩展,但我还是想让这个例子看上去更简单一些。
|
||||
* `Novels` 类包含了用于各种任务的工具类:将一个 `Novel` 或者它们的列表的纯文本编码转换成 XML 或者 JSON;支持在小说集合上进行 CRUD 操作;以及从存储在文件中的数据初始化集合。`Novels` 类在 `Novel` 实例和 servlet 之间起中介作用。
|
||||
* `NovelsServlet` 类是从 `HttpServlet` 中继承的,`HttpServlet` 是一段健壮且灵活的代码,自 90 年代末的早期企业级 Java 就已经存在了。对于客户端的 CRUD 请求,servlet 可以当作 HTTP 的端点。 servlet 代码主要用于处理客户端的请求和生成相应的响应,而将复杂的细节留给 `Novels` 类中的工具类进行处理。
|
||||
|
||||
一些 Java 框架,比如 Jersey(JAX-RS)和 Restlet,就是为 Restful 服务设计的。尽管如此,`HttpServlet` 本身为完成这些服务提供了轻量、灵活、强大且充分测试过的 API。我会通过下面的“小说”例子来说明。
|
||||
|
||||
### 部署“小说”web 服务
|
||||
### 部署“小说” Web 服务
|
||||
|
||||
当然,部署“小说”web服务需要一个 web 服务器。我的选择是 [Tomcat][5],但是如果服务托管在 Jetty 或者甚至是 Java 应用服务器上,那么这个服务应该至少可以工作(著名的最后一句话!)。[在我的网站上][6]有总结了如何安装 Tomcat 的 README 文件和代码。还有一个附带文档的 Apache Ant 脚本,可以用来构建“小说”服务(或者任何其他服务或网站)并且将它部署在 Tomcat 或相同的服务。
|
||||
当然,部署“小说” Web 服务需要一个 Web 服务器。我的选择是 [Tomcat][5],但是如果该服务托管在 Jetty 或者甚至是 Java 应用服务器上,那么这个服务应该至少可以工作(著名的最后一句话!)。[在我的网站上][6]有总结了如何安装 Tomcat 的 README 文件和代码。还有一个附带文档的 Apache Ant 脚本,可以用来构建“小说”服务(或者任何其他服务或网站),并且将它部署在 Tomcat 或相同的服务。
|
||||
|
||||
Tomcat 可以从它的[官网][7]上下载。当你在本地安装后,将 `TOMCAT_HOME` 设置为安装目录。有两个子目录值得关注:
|
||||
|
||||
* `TOMCAT_HOME/bin` 目录包含类 Unix 系统(`startup.sh` 和 `shutdown.sh`)和 Windows(`startup.bat` 和 `shutdown.bat`) 的启动和停止脚本。Tomcat 作为 Java 应用程序运行。web 服务器的 servlet 容器叫做 Catalina。(在 Jetty 中,web 服务器和容器的名字一样。)当 Tomcat 启动后,在浏览器中输入 `http://localhost:8080/` 可以查看详细文档,包括示例。
|
||||
* `TOMCAT_HOME/webapps` 目录是已部署的 web 网站和服务的默认目录。部署网站或 web 服务的直接方法是复制以 `.war`结尾的 JAR 文件(也就是 WAR 文件)到 `TOMCAT_HOME/webapps` 或它的子目录下。然后 Tomcat 会将 WAR 文件解压到它自己的目录下。比如,Tomcat 会将 `novels.war` 文件解压到一个叫做 `novels` 的子目录下,并且保留 `novels.war` 文件。网站或 web 服务可以通过删除 WAR 文件进行移除,也可以用一个新版 WAR 文件来覆盖已有文件进行更新。顺便说一下,调试网站或服务的第一步就是检查 Tomcat 已经正确解压 WAR 文件;如果没有的话,网站或服务就无法发布,因为代码或配置中有致命错误。
|
||||
* 因为 Tomcat 默认会监听 8080 端口上的 HTTP 请求,所以本机上的 URL 请求以 `http://localhost:8080/` 开始
|
||||
* `TOMCAT_HOME/bin` 目录包含了类 Unix 系统(`startup.sh` 和 `shutdown.sh`)和 Windows(`startup.bat` 和 `shutdown.bat`) 的启动和停止脚本。Tomcat 作为 Java 应用程序运行。Web 服务器的 servlet 容器叫做 Catalina。(在 Jetty 中,Web 服务器和容器的名字一样。)当 Tomcat 启动后,在浏览器中输入 `http://localhost:8080/` 可以查看详细文档,包括示例。
|
||||
* `TOMCAT_HOME/webapps` 目录是已部署的 Web 网站和服务的默认目录。部署网站或 Web 服务的直接方法是复制以 `.war` 结尾的 JAR 文件(也就是 WAR 文件)到 `TOMCAT_HOME/webapps` 或它的子目录下。然后 Tomcat 会将 WAR 文件解压到它自己的目录下。比如,Tomcat 会将 `novels.war` 文件解压到一个叫做 `novels` 的子目录下,并且保留 `novels.war` 文件。一个网站或 Web 服务可以通过删除 WAR 文件进行移除,也可以用一个新版 WAR 文件来覆盖已有文件进行更新。顺便说一下,调试网站或服务的第一步就是检查 Tomcat 已经正确解压 WAR 文件;如果没有的话,网站或服务就无法发布,因为代码或配置中有致命错误。
|
||||
* 因为 Tomcat 默认会监听 8080 端口上的 HTTP 请求,所以本机上的 URL 请求以 `http://localhost:8080/` 开始。
|
||||
|
||||
通过添加不带 `.war` 后缀的 WAR 文件名来访问由程序员部署的 WAR 文件:
|
||||
|
||||
@ -60,25 +58,25 @@ http://locahost:8080/myapps/novels/
|
||||
|
||||
我会在靠近文章结尾处的测试部分提供这部分的更多细节。
|
||||
|
||||
如前所述,我的主页上有一个包含 Ant 脚本的 ZIP 文件,这个文件可以编译并且部署网站或者服务。(这个 ZIP 文件中也包含一个 `novels.war` 的副本。)对于“小说”这个例子,命令的示例(以 `%` 作为命令行提示符)如下:
|
||||
如前所述,我的主页上有一个包含 Ant 脚本的 ZIP 文件,这个文件可以编译并且部署网站或者服务。(这个 ZIP 文件中也包含一个 `novels.war` 的副本。)对于“小说”这个例子,命令的示例(`%` 是命令行提示符)如下:
|
||||
|
||||
```
|
||||
% ant -Dwar.name=novels deploy
|
||||
```
|
||||
|
||||
这个命令首先会编译 Java 源代码,并且创建一个可部署的 `novels.war` 文件,然后将这个文件保存在当前目录中,再复制到 `TOMCAT_HOME/webapps` 目录中。如果一切顺利,`GET`请求(使用浏览器或者命令行工具,比如 `curl`)可以用来做地一个测试:
|
||||
这个命令首先会编译 Java 源代码,并且创建一个可部署的 `novels.war` 文件,然后将这个文件保存在当前目录中,再复制到 `TOMCAT_HOME/webapps` 目录中。如果一切顺利,`GET` 请求(使用浏览器或者命令行工具,比如 `curl`)可以用来做一个测试:
|
||||
|
||||
```
|
||||
% curl http://localhost:8080/novels/
|
||||
```
|
||||
|
||||
默认情况下,Tomcat 设置为 _<ruby>热部署<rt>hot deploys</rt></ruby>_:web 服务器不需要关闭就可以进行部署,更新或者移除一个 web 应用。
|
||||
默认情况下,Tomcat 设置为 <ruby>热部署<rt>hot deploys</rt></ruby>:Web 服务器不需要关闭就可以进行部署、更新或者移除一个 web 应用。
|
||||
|
||||
### “小说”服务的代码
|
||||
|
||||
让我们回到“小说”这个例子,不过是在代码层面。考虑下面的 `Novel` 类:
|
||||
|
||||
#### 例1:Novel 类
|
||||
#### 例 1:Novel 类
|
||||
|
||||
```java
|
||||
package novels;
|
||||
@ -104,11 +102,11 @@ public class Novel implements Serializable, Comparable<Novel> {
|
||||
}
|
||||
```
|
||||
|
||||
这个类实现了 `Comparable` 接口中的 `compareTo` 方法,因为 `Novel` 实例是存储在一个线程安全的无序 `ConcurrentHashMap` 中。在响应查看集合的请求时,”小说“服务对来自 map 的集合进行排序(一个 `ArrayList`);`compareTo`的实现通过 `Novel` 的 ID 将它按升序排序。
|
||||
这个类实现了 `Comparable` 接口中的 `compareTo` 方法,因为 `Novel` 实例是存储在一个线程安全的无序 `ConcurrentHashMap` 中。在响应查看集合的请求时,“小说”服务会对从映射中提取的集合(一个 `ArrayList`)进行排序;`compareTo` 的实现通过 `Novel` 的 ID 将它按升序排序。
|
||||
|
||||
`Novels`类中包含多个实用工具:
|
||||
`Novels` 类中包含多个实用工具函数:
|
||||
|
||||
#### 例2:Novels 实用工具类:
|
||||
#### 例 2:Novels 实用工具类
|
||||
|
||||
```java
|
||||
package novels;
|
||||
@ -205,17 +203,17 @@ public class Novels {
|
||||
}
|
||||
```
|
||||
|
||||
`populate` 是最复杂的方法,这个方法从一个包含在 WAR 文件中的文本文件读取。这个文本文件包括了”小说“的最初集合。要打开此文件,`populate` 方法需要 `ServletContext`,这是一个 Java 映射类型,包含了关于嵌入在 servlet 容器中的 servlet 的所有关键信息。这个文本文件有包含了像下面这样的记录:
|
||||
最复杂的方法是 `populate`,这个方法从一个包含在 WAR 文件中的文本文件读取。这个文本文件包括了“小说”的初始集合。要打开此文件,`populate` 方法需要 `ServletContext`,这是一个 Java 映射类型,包含了关于嵌入在 servlet 容器中的 servlet 的所有关键信息。这个文本文件有包含了像下面这样的记录:
|
||||
|
||||
```
|
||||
Jane Austen!Persuasion
|
||||
```
|
||||
|
||||
这一行被解析为两部分(作者和标题),由感叹号(`!`)分隔。然后这个方法创建一个 `Novel` 实例,设置作者和标题属性,并且将”小说“加到容器中,保存在内存中。
|
||||
这一行被解析为两部分(作者和标题),由感叹号(`!`)分隔。然后这个方法创建一个 `Novel` 实例,设置作者和标题属性,并且将“小说”加到容器中,保存在内存中。
|
||||
|
||||
`Novels` 类也有一些实用工具,可以将”小说“容器编码为 XML 或 JSON,取决与发出请求的人所要求的格式。默认是 XML 格式,但是也可以请求 JSON 格式。一个轻量级的 XML 转 JSON 包提供了 JSON。下面是关于编码的更多细节。
|
||||
`Novels` 类也有一些实用工具函数,可以将“小说”容器编码为 XML 或 JSON,取决于发出请求的人所要求的格式。默认是 XML 格式,但是也可以请求 JSON 格式。一个轻量级的 XML 转 JSON 包提供了 JSON。下面是关于编码的更多细节。
|
||||
|
||||
#### 例3:NovelsServlet 类
|
||||
#### 例 3:NovelsServlet 类
|
||||
|
||||
```java
|
||||
package novels;
|
||||
@ -418,12 +416,12 @@ public class NovelsServlet extends HttpServlet {
|
||||
NovelsServlet extends HttpServlet extends GenericServlet implements Servlet
|
||||
```
|
||||
|
||||
从名字可以很清楚的看出来,`HttpServlet` 是为实现 HTTP(S) 上的 servlet 设计的。这个类提供了与标准 HTTP 请求动词同名的方法(官方说法,<ruby>_方法_<rt>methods</rt></ruby>):
|
||||
从名字可以很清楚的看出来,`HttpServlet` 是为实现 HTTP(S) 上的 servlet 设计的。这个类提供了以标准 HTTP 请求动词(官方说法,<ruby>方法<rt>methods</rt></ruby>)命名的空方法:
|
||||
|
||||
* `doPost` (Post = Create)
|
||||
* `doGet` (Get = Read)
|
||||
* `doPut` (Put = Update)
|
||||
* `doDelete` (Delete = Delete)
|
||||
* `doPost` (Post = 创建)
|
||||
* `doGet` (Get = 读取)
|
||||
* `doPut` (Put = 更新)
|
||||
* `doDelete` (Delete = 删除)
|
||||
|
||||
其他一些 HTTP 动词也会涉及到。`HttpServlet` 的子类,比如 `NovelsServlet`,会重载相关的 `do` 方法,并且保留其他方法为<ruby>空<rt>no-ops</rt></ruby>。`NovelsServlet` 重载了七个 `do` 方法。
|
||||
|
||||
@ -436,7 +434,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) {
|
||||
`request` 参数是一个 HTTP 请求信息的映射,而 `response` 提供了一个返回给请求者的输出流。像 `doPost` 的方法,结构如下:
|
||||
|
||||
* 读取 `request` 信息,采取任何适当的措施生成一个响应。如果该信息丢失或者损坏了,就会生成一个错误。
|
||||
* 使用提取的请求信息来执行适当的 CRUD 操作(在本例中,创建一个 `Novel`),然后使用 `response` 输出流为请求者编码一个适当的相应。在 `doPost` 例子中,响应就是确认已经成功生成一个新”小说“并且添加到容器中。当响应被发送后,输出流就关闭了,同时也将连接关闭了。
|
||||
* 使用提取的请求信息来执行适当的 CRUD 操作(在本例中,创建一个 `Novel`),然后使用 `response` 输出流为请求者编码一个适当的响应。在 `doPost` 例子中,响应就是已经成功生成一个新“小说”并且添加到容器中的一个确认。当响应被发送后,输出流就关闭了,同时也将连接关闭了。
|
||||
|
||||
### 关于方法重载的更多内容
|
||||
|
||||
@ -452,7 +450,7 @@ Accept-type: text/plain ## ditto
|
||||
|
||||
第一行由 HTTP 动词(在本例中是 `GET`)和以名词(在本例中是 `novels`)命名目标资源的 URI 开始。报头中包含键-值对,用冒号分隔左面的键和右面的值。报头中的键 `Host`(大小写敏感)是必须的;主机名 `localhost` 是当前机器上的本地符号地址,`8080` 端口是 Tomcat web 服务器上等待 HTTP 请求的默认端口。(默认情况下,Tomcat 在 8443 端口上监听 HTTP 请求。)报头元素可以以任意顺序出现。在这个例子中,`Accept-type` 报头的值是 MIME 类型 `text/plain`。
|
||||
|
||||
一些请求(特别是 `POST` 和 `PUT`)会有报文,而其他请求(特别是 `GET` 和 `DELETE`)没有。如果有报文(可能为空),两个换行符将报头和报文分隔开;HTTP 报文包含一系列键-值对。对于无报文的请求,比如说查询字符串,报头元素就可以用来发送信息。下面是一个用 ID 2 对 `/novels` 资源的 `GET` 请求:
|
||||
一些请求(特别是 `POST` 和 `PUT`)会有报文,而其他请求(特别是 `GET` 和 `DELETE`)没有。如果有报文(可能为空),以两个换行符将报头和报文分隔开;HTTP 报文包含一系列键-值对。对于无报文的请求,比如说查询字符串,报头元素就可以用来发送信息。下面是一个用 ID 2 对 `/novels` 资源的 `GET` 请求:
|
||||
|
||||
```
|
||||
GET /novels?id=2
|
||||
@ -460,7 +458,7 @@ GET /novels?id=2
|
||||
|
||||
通常来说,查询字符串以问号开始,并且包含一个键-值对,尽管这个键-值可能值为空。
|
||||
|
||||
带有 `getParameter` 和 `getParameterMap` 等方法的 `HttpServlet` 很好地回避了有报文和没有报文的 HTTP 请求之前的差异。在”小说“例子中,`getParameter` 方法用来从 `GET`、`POST` 和 `DELETE` 方法中提取所需的信息。(处理 `PUT` 请求需要更底层的代码,因为 Tomcat 没有提供可以解析 `PUT` 请求的参数映射。)下面展示了一段在 `NovelsServlet` 中被重载的 `doPost` 方法:
|
||||
带有 `getParameter` 和 `getParameterMap` 等方法的 `HttpServlet` 很好地回避了有报文和没有报文的 HTTP 请求之前的差异。在“小说”例子中,`getParameter` 方法用来从 `GET`、`POST` 和 `DELETE` 方法中提取所需的信息。(处理 `PUT` 请求需要更底层的代码,因为 Tomcat 没有提供可以解析 `PUT` 请求的参数映射。)下面展示了一段在 `NovelsServlet` 中被重载的 `doPost` 方法:
|
||||
|
||||
```java
|
||||
@Override
|
||||
@ -479,13 +477,13 @@ public void doDelete(HttpServletRequest request, HttpServletResponse response) {
|
||||
...
|
||||
```
|
||||
|
||||
`doGet` 方法需要区分 `GET` 请求的两种方式:一种是”获得所有“,而另一种是”获得某一个“。如果 `GET` 请求 URL 中包含一个键是一个 ID 的查询字符串,那么这个请求就被解析为”获得某一个“:
|
||||
`doGet` 方法需要区分 `GET` 请求的两种方式:一种是“获得所有”,而另一种是“获得某一个”。如果 `GET` 请求 URL 中包含一个键是一个 ID 的查询字符串,那么这个请求就被解析为“获得某一个”:
|
||||
|
||||
```
|
||||
http://localhost:8080/novels?id=2 ## GET specified
|
||||
```
|
||||
|
||||
如果没有查询字符串,`GET` 请求就会被解析为”获得所有“:
|
||||
如果没有查询字符串,`GET` 请求就会被解析为“获得所有”:
|
||||
|
||||
```
|
||||
http://localhost:8080/novels ## GET all
|
||||
@ -493,9 +491,9 @@ http://localhost:8080/novels ## GET all
|
||||
|
||||
### 一些值得注意的细节
|
||||
|
||||
“小说”服务的设计反映了像 Tomcat 这样基于 Java 的 web 服务器是如何工作的。在启动时,Tomcat 构建一个线程池,从中提取请求处理程序,这种方法称为 <ruby>_“每个请求一个线程”_<rt>one thread per request</rt></ruby> 模型。现在版本的 Tomcat 使用非阻塞 I/O 来提高个性能。
|
||||
“小说”服务的设计反映了像 Tomcat 这样基于 Java 的 web 服务器是如何工作的。在启动时,Tomcat 构建一个线程池,从中提取请求处理程序,这种方法称为 “<ruby>每个请求一个线程<rt>one thread per request</rt></ruby>” 模型。现在版本的 Tomcat 使用非阻塞 I/O 来提高个性能。
|
||||
|
||||
“小说”服务是作为 `NovelsServlet` 类的一个单独实例来执行的,该实例也就维护了一个“小说”集合。相应的,也就会出现竞态条件,比如出现两个请求同时被处理:
|
||||
“小说”服务是作为 `NovelsServlet` 类的单个实例来执行的,该实例也就维护了一个“小说”集合。相应的,也就会出现竞态条件,比如出现两个请求同时被处理:
|
||||
|
||||
* 一个请求向集合中添加一个新“小说”。
|
||||
* 另一个请求获得集合中的所有“小说”。
|
||||
@ -509,8 +507,7 @@ public class Novels {
|
||||
...
|
||||
```
|
||||
|
||||
默认情况下,对客户端请求的响应被编码为 XML。为了简单,“小说”程序使用了以前的 `XMLEncoder` 类;另一个包含更丰富功能的选项是使用 JAX-B 库。代码很简单:
|
||||
|
||||
默认情况下,对客户端请求的响应被编码为 XML。为了简单,“小说”程序使用了以前的 `XMLEncoder` 类;另一个包含更丰富功能的方式是使用 JAX-B 库。代码很简单:
|
||||
|
||||
```java
|
||||
public String toXml(Object obj) { // default encoding
|
||||
@ -527,9 +524,9 @@ public String toXml(Object obj) { // default encoding
|
||||
}
|
||||
```
|
||||
|
||||
`Object` 参数要么是一个有序的”小说“ `ArraList`(用以响应<ruby>”获得所有“<rt>get all</rt></ruby>请求),要么是一个 `Novel` 实例(用以响应<ruby>“获得一个”<rt>get one</rt></ruby>请求),又或者是一个 `String`(确认消息)。
|
||||
`Object` 参数要么是一个有序的“小说” `ArraList`(用以响应“<ruby>获得所有<rt>get all</rt></ruby>”请求),要么是一个 `Novel` 实例(用以响应“<ruby>获得一个<rt>get one</rt></ruby>”请求),又或者是一个 `String`(确认消息)。
|
||||
|
||||
如果 HTTP 请求报头指定 JSON 作为所需要的类型,那么 XML 就被转化成 JSON。下面是对 `NovelsServlet` 中的 `doGet` 方法进行检查:
|
||||
如果 HTTP 请求报头指定 JSON 作为所需要的类型,那么 XML 就被转化成 JSON。下面是 `NovelsServlet` 中的 `doGet` 方法中的检查:
|
||||
|
||||
```java
|
||||
String accept = request.getHeader("accept"); // "accept" is case insensitive
|
||||
@ -549,14 +546,14 @@ public String toJson(String xml) { // option for requester
|
||||
}
|
||||
```
|
||||
|
||||
`NovelsServlet`会对各种类型进行错误检查。比如,`POST` 请求应该包含作者和新”小说“的标题。如果有一个丢了,`doPost`方法会抛出一个异常:
|
||||
`NovelsServlet`会对各种类型进行错误检查。比如,`POST` 请求应该包含新“小说”的作者和标题。如果有一个丢了,`doPost` 方法会抛出一个异常:
|
||||
|
||||
```java
|
||||
if (author == null || title == null)
|
||||
throw new RuntimeException(Integer.toString(HttpServletResponse.SC_BAD_REQUEST));
|
||||
```
|
||||
|
||||
`SC_BAD_REQUEST` 中的 `SC` 代表的是 <ruby>_状态码_<rt>status code</rt></ruby>,`BAD_REQUEST` 的标准 HTTP 数值是 400。如果请求中的 HTTP 动词是 `TRACE`,一个不同的状态码会返回:
|
||||
`SC_BAD_REQUEST` 中的 `SC` 代表的是 <ruby>状态码<rt>status code</rt></ruby>,`BAD_REQUEST` 的标准 HTTP 数值是 400。如果请求中的 HTTP 动词是 `TRACE`,会返回一个不同的状态码:
|
||||
|
||||
```java
|
||||
public void doTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
@ -564,9 +561,9 @@ public void doTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
}
|
||||
```
|
||||
|
||||
### 测试”小说“服务
|
||||
### 测试“小说”服务
|
||||
|
||||
用浏览器测试 web 服务会很不顺手。在 CRUD 动词中,现代浏览器只能生成 `POST`(Create)和 `GET`(Read)请求。甚至从浏览器发送一个 `POST` 请求都有点不好办,因为报文需要包含键-值对;这样的测试通常通过 HTML 表单完成。命令行工具,比如说 [curl][21],是一个更好的选择,因为这个部分展示的一些 `curl` 命令,已经包含在我网站的 ZIP 文件中了。
|
||||
用浏览器测试 web 服务会很不顺手。在 CRUD 动词中,现代浏览器只能生成 `POST`(创建)和 `GET`(读取)请求。甚至从浏览器发送一个 `POST` 请求都有点不好办,因为报文需要包含键-值对;这样的测试通常通过 HTML 表单完成。命令行工具,比如说 [curl][21],是一个更好的选择,这个部分展示的一些 `curl` 命令,已经包含在我网站的 ZIP 文件中了。
|
||||
|
||||
下面是一些测试样例,没有展示相应的输出结果:
|
||||
|
||||
@ -576,9 +573,9 @@ public void doTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
% curl --header "Accept: application/json" localhost:8080/novels/
|
||||
```
|
||||
|
||||
第一条命令请求所有”小说“,默认是 XML 编码。第二条命令请求 ID 为 1 的”小说“,XML 编码。最后一条命令通过 `application/json` 添加了 `Accept` 报头元素,作为所需要的 MIME 类型。<ruby>”获得一个“<rt>get one</rt></ruby>命令也可以用这个报头。这些请求用了 JSON 而不是 XML 编码作为响应。
|
||||
第一条命令请求所有“小说”,默认是 XML 编码。第二条命令请求 ID 为 1 的“小说”,XML 编码。最后一条命令通过 `application/json` 添加了 `Accept` 报头元素,作为所需要的 MIME 类型。“<ruby>获得一个<rt>get one</rt></ruby>”命令也可以用这个报头。这些请求用了 JSON 而不是 XML 编码作为响应。
|
||||
|
||||
下两条命令在集合中创建了一个新”小说“,并且确认添加了进去:
|
||||
下面两条命令在集合中创建了一个新“小说”,并且确认添加了进去:
|
||||
|
||||
```
|
||||
% curl --request POST --data "author=Tolstoy&title=War and Peace" localhost:8080/novels/
|
||||
@ -601,11 +598,11 @@ public void doTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
% curl localhost:8080/novels/
|
||||
```
|
||||
|
||||
这个请求是删除 ID 为 2 的”小说“。第二个命令会显示剩余的”小说“。
|
||||
这个请求是删除 ID 为 2 的“小说”。第二个命令会显示剩余的“小说”。
|
||||
|
||||
### web.xml 配置文件
|
||||
|
||||
尽管官方规定他是可选的,`web.xml` 配置文件是一个生产级别网站或服务的重要组成部分。这个配置文件可以配置独立于代码的路由、安全性,或者网站或服务的其他功能。”小说“服务的配置通过为该服务的请求分配一个 URL 模式来配置路由:
|
||||
尽管官方规定它是可选的,`web.xml` 配置文件是一个生产级别网站或服务的重要组成部分。这个配置文件可以配置独立于代码的路由、安全性,或者网站或服务的其他功能。“小说”服务的配置通过为该服务的请求分配一个 URL 模式来配置路由:
|
||||
|
||||
```xml
|
||||
<xml version = "1.0" encoding = "UTF-8">
|
||||
@ -629,21 +626,21 @@ public void doTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
http://localhost:8080/novels/
|
||||
```
|
||||
|
||||
端口号后斜杠后的 URI,是所请求资源的 _路径_,在这个例子中,就是”小说“服务。因此,`novels` 出现在了第一个单斜杠后。
|
||||
端口号后斜杠后的 URI,是所请求资源的“路径”,在这个例子中,就是“小说”服务。因此,`novels` 出现在了第一个单斜杠后。
|
||||
|
||||
在 `web.xml` 文件中,`url-patter` 被指定为 `/*`,代表 _以 /novels 为起始的任意路径_。假设 Tomcat 遇到了一个不存在的 URL,像这样:
|
||||
在 `web.xml` 文件中,`url-patter` 被指定为 `/*`,代表 “以 `/novels` 为起始的任意路径”。假设 Tomcat 遇到了一个不存在的 URL,像这样:
|
||||
|
||||
```
|
||||
http://localhost:8080/novels/foobar/
|
||||
```
|
||||
|
||||
`web.xml` 配置也会指定这个请求被分配到”小说“ servlet 中,因为 `/*` 模式也包含 `/foobar`。因此,这个不存在的 URL 也会得到像上面合法路径的相同结果。
|
||||
`web.xml` 配置也会指定这个请求被分配到“小说” servlet 中,因为 `/*` 模式也包含 `/foobar`。因此,这个不存在的 URL 也会得到像上面合法路径的相同结果。
|
||||
|
||||
生产级别的配置文件可能会包含安全相关的信息,包括<ruby>连接级<rt>wire-level</rt></ruby>和<ruby>用户角色<rt>users-roles</rt></ruby>。即使在这种情况下,配置文件的大小也只会是这个例子中的两到三倍大。
|
||||
生产级别的配置文件可能会包含安全相关的信息,包括<ruby>连接级别<rt>wire-level</rt></ruby>和<ruby>用户角色<rt>users-roles</rt></ruby>。即使在这种情况下,配置文件的大小也只会是这个例子中的两到三倍大。
|
||||
|
||||
### 总结
|
||||
|
||||
`HttpServlet` 是 Java web 技术的核心。像”小说“这样的网站或 web 服务继承了这个类,并且根据需求重载了相应的 `do` 动词方法。像 Jersay(JAX-RS)或 Restlet 这样的 Restful 框架通过提供定制的 servlet 完成了基本相同的功能,针对对框架中的 web 应用程序的请求,这个 servlet 扮演者着 HTTP(S)<ruby>终端<rt>endpoint</rt></ruby>的角色。
|
||||
`HttpServlet` 是 Java web 技术的核心。像“小说”这样的网站或 web 服务继承了这个类,并且根据需求重载了相应的 `do` 动词方法。像 Jersay(JAX-RS)或 Restlet 这样的 Restful 框架通过提供定制的 servlet 完成了基本相同的功能,针对框架中的 web 应用程序的请求,这个 servlet 扮演着 HTTP(S) <ruby>终端<rt>endpoint</rt></ruby>的角色。
|
||||
|
||||
当然,基于 servlet 的应用程序可以访问 web 应用程序中所需要的任何 Java 库。如果应用程序遵循<ruby>关注点分离<rt>separation-of-concerns</rt></ruby>原则,那么 servlet 代码仍然相当简单:代码会检查请求,如果存在缺陷,就会发出适当的错误;否则,代码会调用所需要的功能(比如,查询数据库,以特定格式为响应编码),然后向请求这发送响应。`HttpServletRequest` 和 `HttpServletReponse` 类型使得读取请求和编写响应变得简单。
|
||||
|
||||
@ -656,7 +653,7 @@ via: https://opensource.com/article/20/7/restful-services-java
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Yufei-Yan](https://github.com/Yufei-Yan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,61 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Being open to open values)
|
||||
[#]: via: (https://opensource.com/open-organization/20/8/being-open-to-open-values)
|
||||
[#]: author: (Heidi Hess von Ludewig https://opensource.com/users/heidi-hess-von-ludewig)
|
||||
|
||||
Being open to open values
|
||||
======
|
||||
Managing openly can feel intimidating. One manager explains why it's
|
||||
worth the risks.
|
||||
![Open Lego CAD][1]
|
||||
|
||||
In this installment of our "[Managing with Open Values][2]" series, I chat with Braxton, Director of Pricing for a nationwide U.S. insurance company and people manager.
|
||||
|
||||
In June 2018, Braxton reached out to Red Hatters in the Open Organization community. He wanted to learn more about how both he _and_ his team could work differently, using open values. We were happy to help. So I helped organize a workshop on [open organization principles][3] for Braxton and his team—and kept in touch afterward, so I could learn about his adventure in becoming more open.
|
||||
|
||||
We recently caught up with Braxton and sat down with him to hear how things were going. Tracy Guiliani, [industrial/organizational psychologist and expert in associate engagement][4], joined me, as did [Bryan Behrenshausen][5]. Our conversation was wide-ranging, exploring what it was like to learn firsthand about open source values, how to use them to transform an organization, and how they helped Braxton and his team perform better and increase engagement.
|
||||
|
||||
Working with Braxton has been an exceptionally meaningful experience. It has allowed us to witness—directly—how someone transformed Open Organization community-driven workshop material into dynamic change with benefits for him, his team, and his organization. Open Organization Ambassadors are _always_ seeking to help people gain insights and knowledge on open values that empower them to understand culture change and [transformation within their own organization][6].
|
||||
|
||||
He and his team were performing their unique version of the open values in ways that worked for them, and in ways that allowed the benefits the team realized to outweigh the time and energy commitment of proposed changes.
|
||||
|
||||
Braxton's embrace—both of his _own interpretation_ of open organization principles and his strategies for making an organization more open—inspires us.
|
||||
|
||||
Braxton acknowledges that his goals in being more open didn't include "making another Red Hat." Instead, he and his team were performing their unique version of the open values in ways that worked for them, and in ways that allowed the benefits the team realized to outweigh the time and energy commitment of proposed changes.
|
||||
|
||||
In the first part of our interview, you'll also hear Braxton describe:
|
||||
|
||||
1. What "open management" means to him, after learning about the five open organization values of transparency, collaboration, adaptability, community and inclusivity
|
||||
2. Some of his open management practices
|
||||
3. How he champions open culture on his team and how he encourages open source values among late adopters, and the benefits he's experienced
|
||||
4. What people most misunderstand about open source values when they try to transform their own organizations
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Listen to the interview with Braxton
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/open-organization/20/8/being-open-to-open-values
|
||||
|
||||
作者:[Heidi Hess von Ludewig][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/heidi-hess-von-ludewig
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/open-lego.tiff_.png?itok=mQglOhW_ (Open Lego CAD)
|
||||
[2]: https://opensource.com/open-organization/managing-with-open-values
|
||||
[3]: https://github.com/open-organization/open-org-definition
|
||||
[4]: https://opensource.com/open-organization/20/5/commitment-engagement-org-psychology
|
||||
[5]: https://opensource.com/users/bbehrens
|
||||
[6]: https://opensource.com/open-organization/18/4/rethinking-ownership-across-organization
|
55
translated/talk/20200821 Being open to open values.md
Normal file
55
translated/talk/20200821 Being open to open values.md
Normal file
@ -0,0 +1,55 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Being open to open values)
|
||||
[#]: via: (https://opensource.com/open-organization/20/8/being-open-to-open-values)
|
||||
[#]: author: (Heidi Hess von Ludewig https://opensource.com/users/heidi-hess-von-ludewig)
|
||||
|
||||
对开放的价值观持开放态度
|
||||
======
|
||||
开放管理可能会让人感到恐惧。一位经理人解释了它为什么值得冒险。
|
||||
![Open Lego CAD][1]
|
||||
|
||||
在本期的“[用开放的价值观管理][2]”系列中,我和美国一家全国性保险公司的定价总监、人事经理 Braxton 聊了聊。
|
||||
|
||||
2018 年 6 月,Braxton 联系到了开放组织社区的红帽人员。他想了解更多关于他_和_他的团队如何使用开放的价值观,以不同的方式工作。我们很乐意提供帮助。于是我帮助 Braxton 和他的团队组织了一个关于[开放组织原则][3]的研讨会,并在之后还保持着联系,这样我就可以了解他在变得更加开放的过程中的风险。
|
||||
|
||||
最近我们采访了 Braxton,并和他一起坐下来听了事情的进展。[产业/组织心理学家和员工参与度专家][4] Tracy Guiliani 和 [Bryan Behrenshausen][5] 一起加入了我。我们的谈话范围很广,探讨了了解开源价值观后的感受,如何利用它们来改变组织,以及它们如何帮助 Braxton 和他的团队更好地工作和提高参与度。
|
||||
|
||||
与 Braxton 合作是一次异常有意义的经历。它让我们直接见证了一个人如何将开放组织社区驱动的研讨会材料融入动态变化,并使他、他的团队和他的组织受益。开放组织大使_一直_在寻求帮助人们获得关于开放价值的见解和知识,使他们能够理解文化变革和[自己组织内的转型][6]。
|
||||
|
||||
他和他的团队正在以对他们有效的方式执行他们独特的开放价值观,并且让团队实现的利益超过了提议变革在时间和精力上的投入。
|
||||
|
||||
Braxton 对开放组织原则的_解释_和使组织更加开放的策略的接受,让我们深受启发。
|
||||
|
||||
Braxton 承认,他的更开放的目标并不包括“制造另一个红帽”。相反,他和他的团队是在以对他们有效的方式,以及让团队实现的利益超过提议的变革所带来的时间和精力投入,来执行他们独特的开放价值观。
|
||||
|
||||
In the first part of our interview, you'll also hear Braxton describe:
|
||||
在我们采访的第一部分,你还会听到 Braxton 描述。
|
||||
|
||||
1. 在了解了透明性、协作性、适应性、社区性和包容性这五种开放式组织价值观之后,“开放式管理”对他意味着什么?
|
||||
2. 他的一些开放管理做法
|
||||
3. 他如何在他的团队中倡导开放文化,如何在后来者中鼓励开源价值观,以及他所体验到的好处。
|
||||
4. 当人们试图改造自己的组织时,对开源价值观最大的误解是什么?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/open-organization/20/8/being-open-to-open-values
|
||||
|
||||
作者:[Heidi Hess von Ludewig][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/heidi-hess-von-ludewig
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/open-lego.tiff_.png?itok=mQglOhW_ (Open Lego CAD)
|
||||
[2]: https://opensource.com/open-organization/managing-with-open-values
|
||||
[3]: https://github.com/open-organization/open-org-definition
|
||||
[4]: https://opensource.com/open-organization/20/5/commitment-engagement-org-psychology
|
||||
[5]: https://opensource.com/users/bbehrens
|
||||
[6]: https://opensource.com/open-organization/18/4/rethinking-ownership-across-organization
|
Loading…
Reference in New Issue
Block a user