- Java RESTful Web Service實(shí)戰(zhàn)
- 韓陸
- 5490字
- 2018-12-31 14:06:54
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ù)。
- 高手是如何做產(chǎn)品設(shè)計的(全2冊)
- Java程序設(shè)計實(shí)戰(zhàn)教程
- Java系統(tǒng)分析與架構(gòu)設(shè)計
- Vue.js入門與商城開發(fā)實(shí)戰(zhàn)
- 我的第一本算法書
- Learning Raspbian
- 常用工具軟件立體化教程(微課版)
- Android驅(qū)動開發(fā)權(quán)威指南
- OpenCV 3計算機(jī)視覺:Python語言實(shí)現(xiàn)(原書第2版)
- 邊玩邊學(xué)Scratch3.0少兒趣味編程
- Learning D
- Flink入門與實(shí)戰(zhàn)
- 樹莓派開發(fā)從零開始學(xué):超好玩的智能小硬件制作書
- JavaScript全棧開發(fā)
- Learning RSLogix 5000 Programming