官术网_书友最值得收藏!

2.1 第一個Java REST服務(wù)

本節(jié)講述基于Java SE環(huán)境的Jersey官方文檔中提供的示例simple-service(參考地址:https://jersey.java.net/documentation/latest/user-guide.html),并在此基礎(chǔ)上擴(kuò)展自定義的REST資源服務(wù)。

2.1.1 環(huán)境準(zhǔn)備

在動手之前,我們需要準(zhǔn)備開發(fā)REST服務(wù)的環(huán)境,包括JDK、Maven和IDE。

閱讀指南

2.1節(jié)示例所在目錄是jax-rs2-guide\sample\2\0simple-service。

源代碼地址為:https://github.com/feuyeux/jax-rs2-guide/tree/master/sample/2/0simple-service。

1.配置JDK

Jersey對JDK的版本要求是1.6及以上,讀者可根據(jù)項(xiàng)目情況,參考1.4節(jié)的Jersey 2依賴和GlassFish項(xiàng)目中的講述,選擇JDK 1.6以后的版本來開發(fā)基于Jersey的REST項(xiàng)目。本章示例使用的操作系統(tǒng)是Windows 7的64位版本,JDK版本是jdk-7u25-windows-x64.exe。下載并安裝好JDK,然后修改系統(tǒng)環(huán)境變量:添加JAVA_HOME參數(shù),并將其bin目錄追加到path中。示例如下。

JAVA_HOME=D:\Program Files\Java\jdk1.7.0_25
Path=%JAVA_HOME%\bin;……

設(shè)置完畢后,Windows操作系統(tǒng)需要重啟控制臺使Java生效;在Linux下,需要使用命令source path2profile啟用Java。

2.配置Maven

Maven是Apache的項(xiàng)目,是當(dāng)今流行的項(xiàng)目構(gòu)建工具。讀者可以通過其官網(wǎng)(http://maven.apache.org)了解更多信息。需要注意的是,Maven版本中的3.x相比2.x有性能上的優(yōu)勢,推薦使用Maven 3.x。Maven 3.0.x和Maven 3.1.x的區(qū)別在于其內(nèi)部實(shí)現(xiàn),作為用戶使用而言,筆者沒有推薦傾向。對于工具版本的選擇,并不推薦使用最新版,除非新版本更加穩(wěn)定可靠。比如3.0.5這個版本是Maven 3.0.x的修復(fù)和維護(hù)版本,這意味著該版本較之前面的版本更趨穩(wěn)定。作為演示,本例選擇的是最新版本maven-3.1.0。下載并解壓Maven,然后在系統(tǒng)環(huán)境變量中定義M2_HOME并指向Maven解壓后的路徑,在Path中添加M2_HOME下的bin目錄,或定義M2變量為M2_HOME下的bin目錄,然后將其添加到Path中,如下所示。

M2_HOME=D:\-aquarius\apache-maven-3.1.0
MAVEN_OPTS=-Xms128m-Xmx512m
Path=%M2_HOME%\bin;……

MAVEN_OPTS用于定義Maven運(yùn)行時JVM虛擬機(jī)參數(shù),通常至少需要定義JVM堆的最大值-Xmx以支持構(gòu)建較大的項(xiàng)目。Maven的版本測試命令是mvn-v,其測試結(jié)果如下所示。

mvn-v
Apache Maven 3.1.0(893ca28a1da9d5f51ac03827af98bb730128f9f2; 2013-06-28 10:15:32+0800)
Maven home: D:\-aquarius\apache-maven-3.1.0
Java version: 1.7.0_25, vendor: Oracle Corporation
Java home: D:\Program Files\Java\jdk1.7.0_25\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"
3.使用IDE

也許讀者希望就某種IDE講述示例,由于本書的全部示例都是基于Maven的Java項(xiàng)目,當(dāng)今的主流IDE對集成Maven的支持都非常好,因此本書在講述技術(shù)細(xì)節(jié)時,將不特別針對某種IDE的使用有傾向性的推薦和描述。

本書盡可能確保所提供的全部示例的源代碼在以下IDE中編譯、運(yùn)行和測試無誤。Eclipse Indigo(3.7.2)IDE中的服務(wù)器還是要自行配置,否則純屬環(huán)境配置問題,而非示例代碼問題。下面是常見的IDE列表。

□Eclipse Juno(4.3)。

□IntelliJ IDEA 12.1.6+。

□NetBeans IDE 7.3.1。

讀者可以根據(jù)個人使用偏好選擇IDE。Jersey的開發(fā)和Web開發(fā)相比,形式上基本一致,所以不必更換IDE來運(yùn)行本書示例。

2.1.2 創(chuàng)建服務(wù)

準(zhǔn)備好環(huán)境,我們就可以動手操作了。我們從Maven原型開始創(chuàng)建,然后測試并分析該示例。

1.從Maven原型創(chuàng)建項(xiàng)目

Jersey官方文檔中提供的例子simple-service是一個Maven原型項(xiàng)目,我們從這里開始。所謂“原型項(xiàng)目”即指通過Maven命令即可從Maven中央倉庫取回一個已經(jīng)具備基本功能、依賴包完好、編譯和運(yùn)行測試無誤的示例項(xiàng)目。mvn archetype:generate字面解讀為:以指定的原型為模板,生成或者創(chuàng)建新的Maven項(xiàng)目。在控制臺執(zhí)行如下命令來生成我們想要的simple-service項(xiàng)目,項(xiàng)目的目標(biāo)存儲路徑由讀者自行選擇。

mvn archetype:generate-DarchetypeArtifactId=jersey-quickstart-grizzly2-DarchetypeGroupId=org.glassfish.jersey.archetypes-DinteractiveMode=false-DgroupId=com.example-DartifactId=simple-service-Dpackage=com.example-DarchetypeVersion=2.9

控制臺命令成功執(zhí)行后,會在當(dāng)前目錄下創(chuàng)建simple-service目錄。該目錄包含了最簡REST示例,即simple-service項(xiàng)目的全部源代碼。

閱讀指南

如果讀者在確保本地配置無誤的情況下,執(zhí)行上述命令失敗,說明該官方例子項(xiàng)目已經(jīng)失效或者由于非技術(shù)原因?qū)е碌臒o法訪問,讀者可以直接使用本書提供的源代碼。Maven管理的項(xiàng)目版本清晰,一般活躍的項(xiàng)目的失效的可能性比較低。

2.測試項(xiàng)目可用性

simple-service項(xiàng)目在本地創(chuàng)建成功后,首先要確定該項(xiàng)目在本機(jī)的可用性。進(jìn)入simple-service項(xiàng)目的根目錄,然后執(zhí)行Maven的測試命令,若simple-service項(xiàng)目在環(huán)境中已經(jīng)可用,則控制臺將輸出如下信息。

simple-service>mvn clean test
[INFO]------------------------------------------------------------------------
[INFO] Building simple-service 1.0-SNAPSHOT
[INFO]------------------------------------------------------------------------
……
-------------------------------------------------------
TESTS
-------------------------------------------------------
……
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO]------------------------------------------------------------------------
[INFO] Total time: 4.791s
[INFO] Finished at: Sat Jul 27 12:10:43 CST 2013
[INFO] Final Memory: 13M/224M

該項(xiàng)目默認(rèn)使用JDK 1.6編譯,如果用戶的JDK版本不同,在執(zhí)行測試之前,首先要修改Maven的配置文件pom.xml,設(shè)置編譯插件的JDK版本參數(shù)。pom.xml文件位于項(xiàng)目根目錄下。使用讀者熟悉的編輯器打開pom文件,下面以文本編輯器為例:

notepad D:\simple-service\pom.xml

搜索關(guān)鍵字maven-compiler-plugin,定位<source>和<target>兩行。以JDK 1.7為例,修改為<source>1.7</source>和<target>1.7</target>,保存并退出。最后執(zhí)行Maven命令“mvn clean test”進(jìn)行測試。

3.項(xiàng)目分析

項(xiàng)目測試通過意味著本地環(huán)境沒有問題了,接下來可以開始學(xué)習(xí)simple-service項(xiàng)目了,為下一步擴(kuò)展項(xiàng)目做好準(zhǔn)備。

在simple-service項(xiàng)目的根目錄執(zhí)行“tree/f”命令,可以縱覽simple-service的文件結(jié)構(gòu),如圖2-1所示。

圖2-1 simple-service項(xiàng)目源代碼組織結(jié)構(gòu)

在圖2-1所示的目錄結(jié)構(gòu)中,對開發(fā)者有價值的內(nèi)容包括源代碼Main.java、MyResource.java和測試代碼MyResourceTest.java。

首先,定位該項(xiàng)目中的有用信息以去除項(xiàng)目中的噪聲。什么是噪聲呢?無論使用哪一種IDE做開發(fā),其自身都會產(chǎn)生具有該IDE方言的項(xiàng)目文件。除非特殊情況,我們不必理會這些項(xiàng)目文件,如果是團(tuán)隊(duì)開發(fā),在提交到版本控制庫的時候,應(yīng)該對其過濾(使用GIT做SCM時,過濾文件位于項(xiàng)目根目錄,名稱為.gitignore)。target目錄是Maven的生成目錄,類似構(gòu)建工具Ant、Gradle的build或者bin目錄,我們也可以忽略。

小白講堂

Eclipse產(chǎn)生的項(xiàng)目文件包括.settings目錄,以及.classpath和.project文件。

IntelliJ產(chǎn)生的項(xiàng)目文件包括.idea目錄,以及項(xiàng)目同名的.iml文件。

NetBeans產(chǎn)生的項(xiàng)目文件包括nb-configuration.xml文件。

(1)資源類分析

套用Web開發(fā)中典型的三層邏輯,資源類位于邏輯分層的最高層——API層,其下為Service層和數(shù)據(jù)訪問層,如圖2-2所示。在三層邏輯中,API層用于對外公布接口,對于REST應(yīng)用,API層的資源類用于對外公布REST服務(wù)接口。其下的兩層,REST應(yīng)用的開發(fā)和標(biāo)準(zhǔn)Web開發(fā)的區(qū)別不是很大。

圖2-2 邏輯分層

本例中的API層資源類是MyResource,代碼示例如下。

package com.example;
...
//關(guān)注點(diǎn)1:資源路徑
@Path("myresource")
public class MyResource {
// 關(guān)注點(diǎn)2:資源方法
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String getIt() {
      return "Got it!";
  }
}

在這段代碼中,資源類MyResource使用了JAX-RS標(biāo)準(zhǔn)中定義的@Path注解來聲明名為myresource的資源路徑,見關(guān)注點(diǎn)1。該類只有一個處理HTTP協(xié)議的GET方法的getIt()方法,沒有輸入?yún)?shù),輸出是一個String類型,傳輸格式是字符串類型(MediaType.TEXT_PLAIN),返回字符串值是“Got it!”,見關(guān)注點(diǎn)2。

在沒有測試、運(yùn)行這個例子之前,我們可以推測通過REST訪問getIt()方法的資源路徑如下,接下來的講述將驗(yàn)證該資源路徑。資源路徑即是對外公布的REST服務(wù)接口。

HTTP服務(wù)器路徑/REST服務(wù)名稱/myresource/

(2)入口類分析

因?yàn)檫@是一個Java SE的應(yīng)用,所以需要一個入口類來啟動服務(wù)器并加載項(xiàng)目資源。對于Java EE的應(yīng)用則無須定義這樣的入口類,因?yàn)镴ava EE容器本身扮演著入口類的角色。Main類是simple-service項(xiàng)目的主類,即入口類,代碼示例如下。

package com.example;
...
public class Main {
// 關(guān)注點(diǎn)1:服務(wù)器路徑
    public static final String BASE_URI = "http://localhost:8080/myapp/";
    public static HttpServer startServer() {
// 關(guān)注點(diǎn)2:加載資源
        final ResourceConfig rc = new ResourceConfig().packages("com.example");
// 關(guān)注點(diǎn)3:Grizzly HTTP 服務(wù)器
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }
    public static void main(String[] args) throws IOException {
        final HttpServer server = startServer();
        System.out.println(String.format("Jersey app started with WADL available at "
               + "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
        System.in.read();
        server.shutdownNow();
    }
}

Main類定義了HTTP服務(wù)器的路徑(BASE_URI),即http://localhost:8080/myapp/,見關(guān)注點(diǎn)1。在其構(gòu)造中映射了源代碼中資源所在的包名new ResourceConfig().packages(“com.example”),這意味著,服務(wù)器啟動時會自動掃描該包下的所有類,根據(jù)該包中所含類的REST資源路徑的注解,在內(nèi)存中做好映射,見關(guān)注點(diǎn)2。這樣一來,客戶端請求指定路徑后,服務(wù)器就可以根據(jù)映射,分派請求給相應(yīng)的資源類實(shí)例的相應(yīng)方法了。這就是Jersey中的IoC機(jī)制。這個例子不是運(yùn)行在Servlet容器中的,相反,它是一個Java SE應(yīng)用。該服務(wù)自帶了HTTP服務(wù)器的實(shí)現(xiàn),本例使用的服務(wù)器是Grizzly,見關(guān)注點(diǎn)3。

宅人坑事

在1.4節(jié)中,我們對Grizzly有過介紹,這里額外要說的是,Grizzly是Jersey提供的集成測試中默認(rèn)的內(nèi)嵌測試服務(wù)器,有了Grizzly,我們就可以在不啟動額外Servlet容器服務(wù)器的情況下,測試REST服務(wù)。這點(diǎn)對于Maven老用戶來說,一定會聯(lián)想到在運(yùn)行Servlet容器測試時使用Jetty插件的情形。略有不同的是,Jetty的角色之于Maven是一個聲明式的(配置參數(shù))、無須編碼的插件,而Grizzly是編碼式的。

(3)測試類分析

最后我們來看看真正用于單元測試的測試類MyResourceTest。它只有一個測試方法testGetIt()用來測試MyResource類公布的資源路徑myresource。其代碼示例如下。

package com.example;
...
public class MyResourceTest {
// 關(guān)注點(diǎn)1:全局字段
    private HttpServer server;
    private WebTarget target;
// 關(guān)注點(diǎn)2:準(zhǔn)備測試環(huán)境
    @Before
    public void setUp() throws Exception {
        server = Main.startServer();
        Client c = ClientBuilder.newClient();
        target = c.target(Main.BASE_URI);
    }
// 關(guān)注點(diǎn)3:釋放測試環(huán)境
    @After
    public void tearDown() throws Exception {
        server.shutdownNow();
    }
// 關(guān)注點(diǎn)4:測試GET 方法
    @Test
    public void testGetIt() {
        String responseMsg = target.path("myresource").request().get(String.class);
        assertEquals("Got it!", responseMsg);
    }
}

MyResourceTest定義了兩個全局字段,分別是Grizzly服務(wù)器類HttpServer和JAX-RS 2.0的客戶端資源定位類WebTarget,見關(guān)注點(diǎn)1。

注解為@Before的setUp()方法是JUnit測試前要執(zhí)行的方法,為測試準(zhǔn)備環(huán)境。首先啟動Grizzly服務(wù)器,然后實(shí)例化一個Client,最后將服務(wù)器的資源地址作為參數(shù),傳給客戶端示例,獲取到客戶端資源定位類實(shí)例target,見關(guān)注點(diǎn)2。

testGetIt()方法用于測試GET方法,使用資源定位類WebTarget實(shí)例target向myresource資源發(fā)出get請求,將返回值作為相等斷言的輸入?yún)?shù),和“Got it!”進(jìn)行比對,見關(guān)注點(diǎn)4。

注解為@After的方法tearDown()在測試結(jié)束后執(zhí)行,以釋放測試環(huán)境中的資源,如停止服務(wù)器實(shí)例、釋放資源等,見關(guān)注點(diǎn)3。這里需要注意的是,釋放資源過程無須處理客戶端實(shí)例,該實(shí)例的連接已經(jīng)在獲取響應(yīng)實(shí)體時斷開,詳見后文的講述。

到此,我們已經(jīng)掌握了simple-service項(xiàng)目。在入門學(xué)習(xí)中,模仿是以后做到收放自如的第一步。接下來,我們重用Main作為環(huán)境支撐,模仿MyResource寫一個自定義的資源類,并進(jìn)行擴(kuò)展性的嘗試:引入實(shí)體類、邏輯分層類,支持更多的傳輸類型。還記得本章開始時關(guān)于設(shè)計一個更新設(shè)備的API的疑問嗎?繼續(xù)輕松的學(xué)習(xí)之旅吧。

2.1.3 擴(kuò)展服務(wù)

在Maven原型示例的基礎(chǔ)上進(jìn)行模仿來擴(kuò)展該項(xiàng)目的REST服務(wù)接口是本節(jié)的第二個任務(wù),通過這一過程實(shí)現(xiàn)對Jersey使用的初步認(rèn)識。下面我們要完成的任務(wù)是實(shí)現(xiàn)一個更新設(shè)備的API,這將包括開發(fā)設(shè)備實(shí)體類、資源類和邏輯分層類,然后對其進(jìn)行測試,以檢驗(yàn)我們的成果。

1.增加設(shè)備實(shí)體類

資源類和邏輯分層類在圖2-2中已經(jīng)展示,實(shí)體類是資源自身的信息,用于序列化和持久化資源。設(shè)備的實(shí)體類用于傳輸和持久化設(shè)備資源,設(shè)備的實(shí)體類命名為Device,該類是一個最基本的POJO類,包含兩個屬性,分別是設(shè)備的IP和設(shè)備的狀態(tài)。其代碼示例如下。

// 關(guān)注點(diǎn)1:JAXB 根元素
@XmlRootElement(name = "device")
public class Device {
  private String deviceIp;
  private int deviceStatus;
  public Device() {
  }
  public Device(String deviceIp) {
          super();
          this.deviceIp = deviceIp;
  }
// 關(guān)注點(diǎn)2:JAXB 屬性 @XmlAttribute
  public String getIp() {
          return deviceIp;
  }
  public void setIp(String deviceIp) {
          this.deviceIp = deviceIp;
  }
  @XmlAttribute
  public int getStatus() {
          return deviceStatus;
  }
  public void setStatus(int deviceStatus) {
          this.deviceStatus = deviceStatus;
  }
}

該類標(biāo)注了JAXB標(biāo)準(zhǔn)定義的@XmlRootElement和@XmlAttribute注解,以便將Device類和XML格式的設(shè)備數(shù)據(jù)相互轉(zhuǎn)換并在服務(wù)器和客戶端之間傳輸,見關(guān)注點(diǎn)1和關(guān)注點(diǎn)2。

小白講堂

Jersey內(nèi)部使用JAXB處理Java類(POJO)和XML格式的信息、JSON格式的信息映射,JAXB通過POJO中定義的XML注解(比如@XmlRootElement代表根節(jié)點(diǎn),@XmlAttribute代表一個節(jié)點(diǎn)的屬性等)將其與XML格式的信息對應(yīng)起來。

2.增加設(shè)備資源類

創(chuàng)建了設(shè)備實(shí)體類后,我們需要一個資源類來公布設(shè)備的REST API。源代碼中已經(jīng)提供了資源類MyResource,為實(shí)現(xiàn)設(shè)備管理,我們模仿該類,創(chuàng)建設(shè)備資源類DeviceResource,代碼示例如下。

@Path("device")
public class DeviceResource {
// 關(guān)注點(diǎn)1:注入Dao實(shí)例
    private final DeviceDao deviceDao;
    public DeviceResource() {
        deviceDao = new DeviceDao();
    }
// 關(guān)注點(diǎn)2:GET方法
    @GET
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Device get(@QueryParam("ip") final String deviceIp) {
    Device result = null;
        if(deviceIp != null) {
            result = deviceDao.getDevice(deviceIp);
        }
        return result;
    }
// 關(guān)注點(diǎn)3:PUT方法
    @PUT
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Device put(final Device device) {
        Device result = null;
        if(device != null) {
            result = deviceDao.updateDevice(device);
        }
        return result;
    }
}

在這段代碼中,關(guān)注點(diǎn)2中的GET方法和2.1.2節(jié)定義的GET方法作用相同,用于獲取設(shè)備信息,輸入?yún)?shù)deviceIp是以設(shè)備IP作為查詢條件,輸出是設(shè)備實(shí)體類的實(shí)例,其表述格式可以是JSON或者XML。關(guān)注點(diǎn)3是DeviceResource類處理HTTP協(xié)議的PUT方法。put()方法定義了兩個注解,@PUT是標(biāo)識處理PUT請求,@Produces是標(biāo)識返回實(shí)體的類型,本例中同時支持JSON格式和XML格式。細(xì)心的讀者會質(zhì)疑持久層Dao類DeviceDao的實(shí)例化是在資源類中完成的,見關(guān)注點(diǎn)1,可能會發(fā)現(xiàn)這不符合三層設(shè)計,也不符合IoC。我們會在后續(xù)示例中逐漸做到更加嚴(yán)謹(jǐn),這只是第一個入門例子,放輕松。

3.增加設(shè)備邏輯類

本例演示了簡單的分層結(jié)構(gòu),數(shù)據(jù)的持久化由DeviceDao類完成,該類簡單地模擬了設(shè)備持久化。其示例代碼如下。

public class DeviceDao {
    ConcurrentHashMap<String, Device> fakeDB = new ConcurrentHashMap<>();
    public DeviceDao() {
    // 關(guān)注點(diǎn)1:測試數(shù)據(jù),初始化了兩個設(shè)備實(shí)例
        fakeDB.put("10.11.58.163", new Device("10.11.58.163"));
        fakeDB.put("10.11.58.184", new Device("10.11.58.184"));
    }
    public Device getDevice(String ip) {
        return fakeDB.get(ip);
    }
    public Device updateDevice(Device device) {
        String ip = device.getIp();
        fakeDB.put(ip, device);
        return fakeDB.get(ip);
    }
}

在這段代碼中,DeviceDao類簡單地使用HashMap實(shí)現(xiàn)了內(nèi)存級別的持久化。為了單元測試的需要,本例使用了硬編碼的測試數(shù)據(jù),持久層加載時,為測試環(huán)境初始化了兩個設(shè)備實(shí)例,見關(guān)注點(diǎn)1。這部分代碼在實(shí)際項(xiàng)目的單元測試中,不要使用硬編碼,可以使用內(nèi)存數(shù)據(jù)庫比如H2、Derby等替換;在集成環(huán)境中,應(yīng)使用真實(shí)的數(shù)據(jù)庫進(jìn)行替換。

2.1.4 測試和運(yùn)行服務(wù)

到此,完成了simple-service擴(kuò)展的代碼開發(fā)部分,接下來為代碼編寫單元測試類,以檢驗(yàn)擴(kuò)展的REST接口是否正常工作。

DeviceResourceTest類模仿測試類MyResourceTest,分別測試了上述的GET和PUT請求處理方法,示例代碼如下。

public class DeviceResourceTest {
    private HttpServer server;
    private WebTarget target;
    @Before
    public void setUp() throws Exception {
        server = Main.startServer();
        final Client c = ClientBuilder.newClient();
        target = c.target(Main.BASE_URI);
    }
    @After
    public void tearDown() throws Exception {
        server.shutdownNow();
    }
    // 關(guān)注點(diǎn)1:測試GET方法
    @Test
    public void testGetDevice() {
        final String testIp = "10.11.58.184";
        // 關(guān)注點(diǎn)2:帶參數(shù)的GET 請求
        final Device device = target.path("device")
       .queryParam("ip", testIp).request().get(Device.class);
        // 關(guān)注點(diǎn)3:設(shè)備IP的斷言
        Assert.assertEquals(testIp ,device.getIp());
    }
        // 關(guān)注點(diǎn)4:測試PUT方法
    @Test
    public void testUpdateDevice() {
        final String testIp = "10.11.58.163";
        final Device device = new Device(testIp);
        device.setStatus(1);
        Entity<Device> entity = Entity.entity(device, MediaType.APPLICATION_XML_TYPE);
        final Device result = target.path("device").request().put(entity, Device.class);
        // 關(guān)注點(diǎn)5:設(shè)備狀態(tài)的斷言
        Assert.assertEquals(1, result.getStatus());
    }
}

GET測試方法testGetDevice()測試資源路徑為device的get請求,見關(guān)注點(diǎn)1。在關(guān)注點(diǎn)2,target傳遞了一個字符串參數(shù)ip,其值為“10.11.58.184”。斷言驗(yàn)證返回的設(shè)備IP是否與預(yù)期相同,見關(guān)注點(diǎn)3。PUT測試方法testUpdateDevice()創(chuàng)建了一個Device實(shí)例,并以put方法將其提交到device資源路徑,見關(guān)注點(diǎn)4。斷言驗(yàn)證返回設(shè)備狀態(tài)是否與預(yù)期一致,見關(guān)注點(diǎn)5。

完成測試類后,打開控制臺,在項(xiàng)目的存儲目錄再次運(yùn)行“mvn clean test”命令,如果測試通過,即斷言驗(yàn)證成功,說明擴(kuò)展實(shí)現(xiàn)已經(jīng)成功結(jié)束。

宅人坑事

關(guān)于單元測試,想和諸君分享一點(diǎn)體會。單元測試是對實(shí)現(xiàn)方法所設(shè)置的第一道檢驗(yàn)屏障,是持續(xù)集成中至關(guān)重要的環(huán)節(jié),是質(zhì)量保證體系中測試覆蓋率的基礎(chǔ)。成為優(yōu)秀開發(fā)者就要遵守良好的習(xí)慣,單元測試不可忽視,甚至應(yīng)該遵循測試先行、測試驅(qū)動開發(fā)這些軟件工程中優(yōu)秀的方法論。

如果開發(fā)者寫不好單元測試或者忽略其重要性,將這一步驟交由工具來生成,以便完成集成測試的流程和代碼覆蓋率的KPI,那么,筆者所持的觀點(diǎn)是,這是一種倒退性實(shí)踐,極力反對這種方式。

最后,我們運(yùn)行Main類,通過瀏覽器來體驗(yàn)一下第一個REST服務(wù)。在瀏覽器地址欄中輸入http://localhost:8080/myapp/device?ip=10.11.58.184,預(yù)期得到的輸出為:<device"10.11.58.184"status="0"/>。同時,這個測試也驗(yàn)證了前文中推測的資源地址URL規(guī)則:

HTTP服務(wù)器路徑/REST服務(wù)名稱/myresource/

到此,我們已經(jīng)快速掌握了一個非常簡單的Jersey 2的Java SE應(yīng)用。接下來,我們介紹更加常用的基于Servlet容器的REST Web服務(wù)。

主站蜘蛛池模板: 玛沁县| 广平县| 万全县| 中江县| 板桥市| 喀喇沁旗| 巫山县| 铜鼓县| 合肥市| 平阴县| 泸西县| 沂南县| 来安县| 上虞市| 巴楚县| 宕昌县| 平利县| 潜江市| 扎鲁特旗| 岚皋县| 广水市| SHOW| 宣威市| 霍林郭勒市| 金平| 武陟县| 镶黄旗| 从化市| 营口市| 墨脱县| 岫岩| 家居| 苏尼特左旗| 合川市| 崇文区| 潜江市| 涟源市| 芷江| 如皋市| 绵竹市| 阿克|