restful xml_使用入站适配器公开HTTP Restful API。 第1部分(XML)
restful xml
1.簡介
這篇文章的目的是使用Spring Integration HTTP入站適配器實現HTTP Restful API。 本教程分為兩個部分:
- XML配置示例(同一篇文章)。
- Java DSL示例。 這將在本教程的下一部分中進行說明,展示如何使用Spring Integration Java DSL配置應用程序,并提供Java 7和Java 8的示例。
在查看代碼之前,讓我們看一下下圖,該圖顯示了應用程序公開的不同服務:
GET操作由HTTP入站網關處理,而其余操作(PUT,POST和DELETE)由HTTP入站通道適配器處理,因為沒有響應主體發送回客戶端。 以下各節將說明每個操作:
源代碼可從Github獲得 。
2.應用程序配置
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>以下各節將說明http-inbound-config.xml文件。
下面是pom.xml文件的詳細信息。 重要的是要注意杰克遜庫。 由于我們將使用JSON表示資源,因此這些庫必須存在于類路徑中。 否則,框架將不會注冊所需的轉換器。
<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.進行操作
該流程的配置如下所示:
http-inbound-config.xml
網關接收到以下路徑的請求:/ persons / {personId}。 請求到達后,將創建一條消息并將其發送到httpGetChannel通道。 然后,網關將等待服務激活器 (personEndpoint)返回響應:
現在,需要解釋一些要點:
- 支持的方法 :此屬性指示網關支持哪些方法(僅GET請求)。
- payload-expression :我們在這里所做的是從URI模板中的personId變量獲取值并將其放入消息的有效負載中。 例如,請求路徑“ / persons / 3”將成為一條值為“ 3”的消息作為其有效負載。
- request-mapping :我們可以包含此元素以指定幾個屬性,并過濾哪些請求將映射到網關。 在示例中,此網關僅處理包含Content-Type標頭(consumes屬性)和Accept標頭(produces屬性)的值“ application / json”的請求。
將請求映射到此網關后,便會構建一條消息并將其發送到服務激活器。 在示例中,我們定義了一個簡單的bean,它將從服務中獲取所需的信息:
@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 }根據從服務收到的響應,我們將返回被請求的人員或指示未找到人員的狀態代碼。
現在,我們將測試一切是否按預期進行。 首先,我們定義將響應轉換為的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 }然后我們執行測試。 在buildHeaders方法中,我們指定了Accept和Content-Type標頭。 請記住,我們在這些標頭中使用'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標頭中未指定正確的值將導致415不支持的媒體類型錯誤,因為網關不支持此媒體類型。
另一方面,在Accept標頭中指定不正確的值將導致406 Not Acceptable錯誤,因為網關返回的內容類型不同于預期。
4.放置和發布操作
對于PUT和POST操作,我們使用相同的HTTP入站通道適配器,并利用了為它定義多個路徑和方法的可能性。 一旦請求到達,路由器將負責將消息傳遞到正確的端點。
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"/>此通道適配器包括兩個新屬性:
- status-code-expression :默認情況下,通道適配器確認已收到請求,并返回200狀態碼。 如果要覆蓋此行為,可以在此屬性中指定其他狀態代碼。 在這里,我們指定這些操作將返回204 No Content狀態代碼。
- request-payload-type :此屬性指定將請求主體轉換為哪個類。 如果我們沒有定義它,它將無法轉換為服務激活器期望的類(ServerPerson)。
收到請求后,適配器會將其發送到路由器期望它的routeRequest通道。 該路由器將檢查消息頭,并根據“ http_requestMethod”頭的值將其傳遞到適當的端點。
PUT和POST操作都由同一個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());} }返回類型為空,因為沒有期望的響應; 入站適配器將處理狀態碼的返回。
PutOperationsTest驗證是否返回了正確的狀態代碼以及資源是否已更新:
@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驗證是否已添加新資源:
@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的最后一個操作是刪除操作。 這次我們為此使用一個單通道適配器:
<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"/>通道適配器使我們可以定義返回狀態代碼,并且我們正在使用有效負載表達式屬性將請求的personId映射到消息正文。 該配置與先前操作中的配置略有不同,但是這里沒有任何未解釋的內容。
服務激活者,我們的人員端點,將請求人員服務刪除此資源。
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());}} }六,結論
這篇文章是對我們的應用程序的介紹,目的是從已知的角度(xml配置)了解它的結構。 在本教程的下一部分中,我們將使用Java DSL來實現相同的應用程序。 該應用程序將配置為可以在Java 8上運行,但是當使用lambda時,我還將展示如何在Java 7上完成它。
我正在Google Plus和Twitter上發布我的新帖子。 如果您要更新新內容,請關注我。
翻譯自: https://www.javacodegeeks.com/2014/12/exposing-http-restful-api-with-inbound-adapters-part-1-xml.html
restful xml
總結
以上是生活随笔為你收集整理的restful xml_使用入站适配器公开HTTP Restful API。 第1部分(XML)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring依赖注入_Spring的依赖
- 下一篇: 华为电脑客服苏州地址(华为苏州客服地址电