restful xml_使用入站适配器公开HTTP Restful API。 第1部分(XML)
restful xml
1.簡介
這篇文章的目的是使用Spring Integration HTTP入站適配器實(shí)現(xiàn)HTTP Restful API。 本教程分為兩個(gè)部分:
- XML配置示例(同一篇文章)。
- Java DSL示例。 這將在本教程的下一部分中進(jìn)行說明,展示如何使用Spring Integration Java DSL配置應(yīng)用程序,并提供Java 7和Java 8的示例。
在查看代碼之前,讓我們看一下下圖,該圖顯示了應(yīng)用程序公開的不同服務(wù):
GET操作由HTTP入站網(wǎng)關(guān)處理,而其余操作(PUT,POST和DELETE)由HTTP入站通道適配器處理,因?yàn)闆]有響應(yīng)主體發(fā)送回客戶端。 以下各節(jié)將說明每個(gè)操作:
源代碼可從Github獲得 。
2.應(yīng)用程序配置
web.xml文件包含分派器Servlet的定義:
<servlet><servlet-name>springServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:xpadro/spring/integration/configuration/http-inbound-config.xml</param-value></init-param> </servlet> <servlet-mapping><servlet-name>springServlet</servlet-name><url-pattern>/spring/*</url-pattern> </servlet-mapping>以下各節(jié)將說明http-inbound-config.xml文件。
下面是pom.xml文件的詳細(xì)信息。 重要的是要注意杰克遜庫。 由于我們將使用JSON表示資源,因此這些庫必須存在于類路徑中。 否則,框架將不會(huì)注冊所需的轉(zhuǎn)換器。
<properties><spring-version>4.1.3.RELEASE</spring-version><spring-integration-version>4.1.0.RELEASE</spring-integration-version><slf4j-version>1.7.5</slf4j-version><junit-version>4.9</junit-version><jackson-version>2.3.0</jackson-version> </properties><dependencies><!-- Spring Framework - Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring-version}</version></dependency><!-- Spring Framework - Integration --><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-core</artifactId><version>${spring-integration-version}</version></dependency><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-http</artifactId><version>${spring-integration-version}</version></dependency><!-- JSON --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${jackson-version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson-version}</version></dependency><!-- Testing --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit-version}</version><scope>test</scope></dependency><!-- Logging --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j-version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j-version}</version></dependency> </dependencies>3.進(jìn)行操作
該流程的配置如下所示:
http-inbound-config.xml
網(wǎng)關(guān)接收到以下路徑的請求:/ persons / {personId}。 請求到達(dá)后,將創(chuàng)建一條消息并將其發(fā)送到httpGetChannel通道。 然后,網(wǎng)關(guān)將等待服務(wù)激活器 (personEndpoint)返回響應(yīng):
現(xiàn)在,需要解釋一些要點(diǎn):
- 支持的方法 :此屬性指示網(wǎng)關(guān)支持哪些方法(僅GET請求)。
- payload-expression :我們在這里所做的是從URI模板中的personId變量獲取值并將其放入消息的有效負(fù)載中。 例如,請求路徑“ / persons / 3”將成為一條值為“ 3”的消息作為其有效負(fù)載。
- request-mapping :我們可以包含此元素以指定幾個(gè)屬性,并過濾哪些請求將映射到網(wǎng)關(guān)。 在示例中,此網(wǎng)關(guān)僅處理包含Content-Type標(biāo)頭(consumes屬性)和Accept標(biāo)頭(produces屬性)的值“ application / json”的請求。
將請求映射到此網(wǎng)關(guān)后,便會(huì)構(gòu)建一條消息并將其發(fā)送到服務(wù)激活器。 在示例中,我們定義了一個(gè)簡單的bean,它將從服務(wù)中獲取所需的信息:
@Component public class PersonEndpoint {private static final String STATUSCODE_HEADER = "http_statusCode";@Autowiredprivate PersonService service;public Message<?> get(Message<String> msg) {long id = Long.valueOf(msg.getPayload());ServerPerson person = service.getPerson(id);if (person == null) {return MessageBuilder.fromMessage(msg).copyHeadersIfAbsent(msg.getHeaders()).setHeader(STATUSCODE_HEADER, HttpStatus.NOT_FOUND).build(); }return MessageBuilder.withPayload(person).copyHeadersIfAbsent(msg.getHeaders()).setHeader(STATUSCODE_HEADER, HttpStatus.OK).build();}//Other operations }根據(jù)從服務(wù)收到的響應(yīng),我們將返回被請求的人員或指示未找到人員的狀態(tài)代碼。
現(xiàn)在,我們將測試一切是否按預(yù)期進(jìn)行。 首先,我們定義將響應(yīng)轉(zhuǎn)換為的ClientPerson類:
@JsonIgnoreProperties(ignoreUnknown = true) public class ClientPerson implements Serializable {private static final long serialVersionUID = 1L;@JsonProperty("id")private int myId;private String name;public ClientPerson() {}public ClientPerson(int id, String name) {this.myId = id;this.name = name;}//Getters and setters }然后我們執(zhí)行測試。 在buildHeaders方法中,我們指定了Accept和Content-Type標(biāo)頭。 請記住,我們在這些標(biāo)頭中使用'application / json'值限制了請求。
@RunWith(BlockJUnit4ClassRunner.class) public class GetOperationsTest {private static final String URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";private final RestTemplate restTemplate = new RestTemplate();private HttpHeaders buildHeaders() {HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));headers.setContentType(MediaType.APPLICATION_JSON); return headers;}@Testpublic void getResource_responseIsConvertedToPerson() {HttpEntity<Integer> entity = new HttpEntity<>(buildHeaders());ResponseEntity<ClientPerson> response = restTemplate.exchange(URL, HttpMethod.GET, entity, ClientPerson.class, 1);assertEquals("John" , response.getBody().getName());assertEquals(HttpStatus.OK, response.getStatusCode());}@Testpublic void getResource_responseIsReceivedAsJson() {HttpEntity<Integer> entity = new HttpEntity<>(buildHeaders());ResponseEntity<String> response = restTemplate.exchange(URL, HttpMethod.GET, entity, String.class, 1);assertEquals("{\"id\":1,\"name\":\"John\",\"age\":25}", response.getBody());assertEquals(HttpStatus.OK, response.getStatusCode());}@Test(expected=HttpClientErrorException.class)public void getResource_sendXml_415errorReturned() {HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));headers.setContentType(MediaType.APPLICATION_XML);HttpEntity<Integer> entity = new HttpEntity<>(headers);restTemplate.exchange(URL, HttpMethod.GET, entity, ClientPerson.class, 1);}@Test(expected=HttpClientErrorException.class)public void getResource_expectXml_receiveJson_406errorReturned() {HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));headers.setContentType(MediaType.APPLICATION_JSON);HttpEntity<Integer> entity = new HttpEntity<>(headers);restTemplate.exchange(URL, HttpMethod.GET, entity, ClientPerson.class, 1);}@Test(expected=HttpClientErrorException.class)public void getResource_resourceNotFound_404errorReturned() {HttpEntity<Integer> entity = new HttpEntity<>(buildHeaders());restTemplate.exchange(URL, HttpMethod.GET, entity, ClientPerson.class, 8);} }在Content-Type標(biāo)頭中未指定正確的值將導(dǎo)致415不支持的媒體類型錯(cuò)誤,因?yàn)榫W(wǎng)關(guān)不支持此媒體類型。
另一方面,在Accept標(biāo)頭中指定不正確的值將導(dǎo)致406 Not Acceptable錯(cuò)誤,因?yàn)榫W(wǎng)關(guān)返回的內(nèi)容類型不同于預(yù)期。
4.放置和發(fā)布操作
對(duì)于PUT和POST操作,我們使用相同的HTTP入站通道適配器,并利用了為它定義多個(gè)路徑和方法的可能性。 一旦請求到達(dá),路由器將負(fù)責(zé)將消息傳遞到正確的端點(diǎn)。
http-inbound-config.xml
<int-http:inbound-channel-adapter channel="routeRequest" status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"supported-methods="POST, PUT" path="/persons, /persons/{personId}"request-payload-type="xpadro.spring.integration.server.model.ServerPerson"><int-http:request-mapping consumes="application/json"/> </int-http:inbound-channel-adapter><int:router input-channel="routeRequest" expression="headers.http_requestMethod"><int:mapping value="PUT" channel="httpPutChannel"/><int:mapping value="POST" channel="httpPostChannel"/> </int:router><int:service-activator ref="personEndpoint" method="put" input-channel="httpPutChannel"/> <int:service-activator ref="personEndpoint" method="post" input-channel="httpPostChannel"/>此通道適配器包括兩個(gè)新屬性:
- status-code-expression :默認(rèn)情況下,通道適配器確認(rèn)已收到請求,并返回200狀態(tài)碼。 如果要覆蓋此行為,可以在此屬性中指定其他狀態(tài)代碼。 在這里,我們指定這些操作將返回204 No Content狀態(tài)代碼。
- request-payload-type :此屬性指定將請求主體轉(zhuǎn)換為哪個(gè)類。 如果我們沒有定義它,它將無法轉(zhuǎn)換為服務(wù)激活器期望的類(ServerPerson)。
收到請求后,適配器會(huì)將其發(fā)送到路由器期望它的routeRequest通道。 該路由器將檢查消息頭,并根據(jù)“ http_requestMethod”頭的值將其傳遞到適當(dāng)?shù)亩它c(diǎn)。
PUT和POST操作都由同一個(gè)bean處理:
@Component public class PersonEndpoint {@Autowiredprivate PersonService service;//Get operationpublic void put(Message<ServerPerson> msg) {service.updatePerson(msg.getPayload());}public void post(Message<ServerPerson> msg) {service.insertPerson(msg.getPayload());} }返回類型為空,因?yàn)闆]有期望的響應(yīng); 入站適配器將處理狀態(tài)碼的返回。
PutOperationsTest驗(yàn)證是否返回了正確的狀態(tài)代碼以及資源是否已更新:
@RunWith(BlockJUnit4ClassRunner.class) public class PutOperationsTest {private static final String URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";private final RestTemplate restTemplate = new RestTemplate();//build headers method@Testpublic void updateResource_noContentStatusCodeReturned() {HttpEntity<Integer> getEntity = new HttpEntity<>(buildHeaders());ResponseEntity<ClientPerson> response = restTemplate.exchange(URL, HttpMethod.GET, getEntity, ClientPerson.class, 4);ClientPerson person = response.getBody();person.setName("Sandra");HttpEntity<ClientPerson> putEntity = new HttpEntity<ClientPerson>(person, buildHeaders());response = restTemplate.exchange(URL, HttpMethod.PUT, putEntity, ClientPerson.class, 4);assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());response = restTemplate.exchange(URL, HttpMethod.GET, getEntity, ClientPerson.class, 4);person = response.getBody();assertEquals("Sandra", person.getName());} }PostOperationsTest驗(yàn)證是否已添加新資源:
@RunWith(BlockJUnit4ClassRunner.class) public class PostOperationsTest {private static final String POST_URL = "http://localhost:8081/int-http-xml/spring/persons";private static final String GET_URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";private final RestTemplate restTemplate = new RestTemplate();//build headers method@Testpublic void addResource_noContentStatusCodeReturned() {ClientPerson person = new ClientPerson(9, "Jana");HttpEntity<ClientPerson> entity = new HttpEntity<ClientPerson>(person, buildHeaders());ResponseEntity<ClientPerson> response = restTemplate.exchange(POST_URL, HttpMethod.POST, entity, ClientPerson.class);assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());HttpEntity<Integer> getEntity = new HttpEntity<>(buildHeaders());response = restTemplate.exchange(GET_URL, HttpMethod.GET, getEntity, ClientPerson.class, 9);person = response.getBody();assertEquals("Jana", person.getName());} }5.刪除操作
我們的RESTful API的最后一個(gè)操作是刪除操作。 這次我們?yōu)榇耸褂靡粋€(gè)單通道適配器:
<int-http:inbound-channel-adapter channel="httpDeleteChannel" status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"supported-methods="DELETE" path="/persons/{personId}" payload-expression="#pathVariables.personId"><int-http:request-mapping consumes="application/json"/> </int-http:inbound-channel-adapter><int:service-activator ref="personEndpoint" method="delete" input-channel="httpDeleteChannel"/>通道適配器使我們可以定義返回狀態(tài)代碼,并且我們正在使用有效負(fù)載表達(dá)式屬性將請求的personId映射到消息正文。 該配置與先前操作中的配置略有不同,但是這里沒有任何未解釋的內(nèi)容。
服務(wù)激活者,我們的人員端點(diǎn),將請求人員服務(wù)刪除此資源。
public void delete(Message<String> msg) {long id = Long.valueOf(msg.getPayload());service.deletePerson(id); }最后,所需的測試:
@RunWith(BlockJUnit4ClassRunner.class) public class DeleteOperationsTest {private static final String URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";private final RestTemplate restTemplate = new RestTemplate();//build headers method@Testpublic void deleteResource_noContentStatusCodeReturned() {HttpEntity<Integer> entity = new HttpEntity<>(buildHeaders());ResponseEntity<ClientPerson> response = restTemplate.exchange(URL, HttpMethod.DELETE, entity, ClientPerson.class, 3);assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());try {response = restTemplate.exchange(URL, HttpMethod.GET, entity, ClientPerson.class, 3);Assert.fail("404 error expected");} catch (HttpClientErrorException e) {assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode());}} }六,結(jié)論
這篇文章是對(duì)我們的應(yīng)用程序的介紹,目的是從已知的角度(xml配置)了解它的結(jié)構(gòu)。 在本教程的下一部分中,我們將使用Java DSL來實(shí)現(xiàn)相同的應(yīng)用程序。 該應(yīng)用程序?qū)⑴渲脼榭梢栽贘ava 8上運(yùn)行,但是當(dāng)使用lambda時(shí),我還將展示如何在Java 7上完成它。
我正在Google Plus和Twitter上發(fā)布我的新帖子。 如果您要更新新內(nèi)容,請關(guān)注我。
翻譯自: https://www.javacodegeeks.com/2014/12/exposing-http-restful-api-with-inbound-adapters-part-1-xml.html
restful xml
總結(jié)
以上是生活随笔為你收集整理的restful xml_使用入站适配器公开HTTP Restful API。 第1部分(XML)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring依赖注入_Spring的依赖
- 下一篇: asp.net ajax控件工具集 Au