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入站通道适配器处理,因为没有响应主体发送回客户端。 以下各节将说明每个操作:

  1. 介绍
  2. 应用配置
  3. 进行操作
  4. 放置和发布操作
  5. 删除操作
  6. 结论

源代码可从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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言的位域

位域是什么&#xff1f;有些数据在存储时并不需要占用一个完整的字节&#xff0c;只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态&#xff0c;用 0 和 1 表示足以&#xff0c;也就是用一个二进位。正是基于这种考虑&#xff0c;C语言又提供了一种叫做位域的…

xp精简工具_办公人士需要精简Win10吗?

首先要说自己的系统需求1&#xff0c;笔记本是主要生产力工具&#xff0c;靠它做方案&#xff0c;联系网络社交&#xff1b;2&#xff0c;会偶尔&#xff08;一月2-3次&#xff09;用到PS&#xff0c;AI&#xff0c;PR等软件&#xff1b;3&#xff0c;文件多&#xff0c;版本多…

matlab 删除路径_MATLAB使用教程(一)—新手来看

前言&#xff1a;在这里&#xff0c;本人默认大家已经安装好了MATLAB软件&#xff0c;如果没有&#xff0c;请自行安装。注意事项&#xff1a;新手容易犯错&#xff0c;打开MATLAB之后&#xff0c;请按CTRLQ这个组合键&#xff0c;是不是发现你的MATLAB关闭了&#xff1f;对&am…

C语言开发单片机为啥都是全局变量形式?

01前言全局变量简直就是嵌入式系统的戈兰高地。冲突最激烈的双方是&#xff1a;1. 做控制的工程师&#xff1b;2. 做非嵌入式的软件工程师。02做控制的工程师特点他们普遍的理解就是“变量都写成全局该有多方便”。我之前面试过一个非常有名的做控制实验室里出来的PhD/Master&a…

ajax get请求_python测试开发django50.jquery发送Ajax请求(get)

前言有时候&#xff0c;我们希望点击页面上的某个按钮后&#xff0c;不刷新整个页面&#xff0c;给后台发送一个请求过去&#xff0c;请求到数据后填充到html上&#xff0c;这意味着可以在不重新加载整个网页的情况下&#xff0c;对网页的某部分进行更新。Ajax可以完美的实现。…

primefaces_PrimeFaces Mobile入门

primefaces介绍 如果您已经开发了利用PrimeFaces的应用程序&#xff0c;或者打算开发可在台式机和移动设备上使用的Web应用程序&#xff0c;请考虑将PrimeFaces Mobile用于您的移动实施。 这篇博客文章将介绍一些基础知识&#xff0c;以帮助您开始为现有的PrimeFaces应用程序开…

C语言指针这些使用技巧值得收藏!

指针用的好犹如神助&#xff0c;用不好会让你叫苦连连&#xff0c;但大多数人是用不好指针的&#xff0c;所以后来的很多语言都把指针封装&#xff0c;屏蔽。比如JAVA&#xff0c;java是没有指针的&#xff0c;但是很多地方都用到指针&#xff0c;不过不对用户开放&#xff0c;…

mysql数据库中的int类型_MySQL中int(M)和tinyint(M)数值类型中M值的意义

在一开始接触MySQL数据库时&#xff0c;对于int(M)及tinyint(M)两者数值类型后面的M值理解是最多能够插入数据库中的值不能大于M&#xff1b;后来工作后&#xff0c;也是一边学习一边使用&#xff0c;之后的理解是其中的M的意思是插入数据库中的值的字符长度不能大于M&#xff…

api怎么写_使用Node.js原生API写一个web服务器

Node.js是JavaScript基础上发展起来的语言&#xff0c;所以前端开发者应该天生就会一点。一般我们会用它来做CLI工具或者Web服务器&#xff0c;做Web服务器也有很多成熟的框架&#xff0c;比如Express和Koa。但是Express和Koa都是对Node.js原生API的封装&#xff0c;所以其实不…

C语言预处理命令分类和工作原理

C语言编程过程中&#xff0c;经常会用到如 #include、#define 等指令&#xff0c;这些标识开头的指令被称为预处理指令&#xff0c;预处理指令由预处理程序&#xff08;预处理器&#xff09;操作。相比其他编程语言&#xff0c;C/C 语言更依赖预处理器&#xff0c;故在阅读或开…

查看mysql用户权限_mysql 如何查看该数据库用户具有哪些权限?

展开全部背景在了解动态权限之前&#xff0c;我们先回顾下 MySQL 的权限列表。权限列表大体分为服务级别和表级别&#xff0c;列级别以32313133353236313431303231363533e59b9ee7ad9431333433633464及大而广的角色(也是MySQL 8.0 新增)存储程序等权限。我们看到有一个特殊的 SU…

注释嵌套注释_注释,无处不在的注释

注释嵌套注释十年前的2004年 &#xff0c; Java 1.5开始提供注释。 很难想象没有此功能的代码。 实际上&#xff0c;首先引入了注释&#xff0c;以减轻开发人员编写繁琐的样板代码的痛苦&#xff0c;并使代码更具可读性。 考虑一下J2EE 1.4&#xff08;没有可用的注释&#xff…

a标签跳到另一个页面指定选项卡_HTML常用标签

本篇文章主要是对a、img和table标签用法介绍&#xff1a;a标签&#xff1a;可称为锚元素&#xff0c;主要功能是创建通向其他网页、文件、同一页面的其他位置、电子邮件地址或其他任何url地址的超链接&#xff1b;1.img标签&#xff1a;发出get请求并显示返回的图片1.常用属性&…

c语言也能用模板方法模式?

模式动机在嵌入式的应用场景中&#xff0c;管理资源(例如文件、内存)是一件非常麻烦、非常容易出错的事情。因为在分配资源后&#xff0c;还必须释放资源。例如fopen()打开文件后&#xff0c;必须要使用fclose()来关闭文件&#xff0c;而使用malloc申请内存资源后&#xff0c;就…

游戏 服务器 微服务_整体服务器与微服务

游戏 服务器 微服务介绍 刚开始时&#xff0c;由于要求简单&#xff0c;所以应用程序既简单又小。 随着时间的要求和需求的增长&#xff0c;我们的应用程序变得越来越大&#xff0c;越来越复杂。 这就导致了将单片服务器开发和部署为一个单元。 在某种程度上&#xff0c;微服务…

数据与ELF数据节-计算机系统基础题目

实验内容&#xff1a;修改二进制可重定位目标文件“phase1.o”的数据&#xff08;.data&#xff09;节内容&#xff08;不允许修改其他节&#xff09;&#xff0c;使其与main.o模块如下链接后运行时输出目标字符串“123456789”。 实验步骤&#xff1a; 1. 使用objdump工具获得…

sqlserver拼接sql插入table_10个SQL技巧

介 绍为了理解这 10 个 SQL 技巧的价值&#xff0c;首先需要了解下 SQL 语言的上下文。为什么我要在 Java 会议上讨论 SQL 呢&#xff1f;(我可能是唯一一个在 Java 会议上讨论 SQL 的了)下面讲下为什么&#xff1a;从早期开始&#xff0c;编程语言设计者就有这种的愿望&#x…

【C语言笔记】指定初始化器

C99增加了一个新特性&#xff1a;指定初始化器(designated initializer)。利用该特性可以初始化指定的数组元素&#xff0c;也可以初始化指定的结构体变量。本文主要分享&#xff1a;使用指定初始化器初始化数组。例如&#xff0c;只初始化数组中的最后一个元素。对于传统的C初…

java锁性能对比_提高Java的锁性能

java锁性能对比Plumbr是唯一可以通过解释应用程序性能数据来自动检测Java性能问题根本原因的解决方案。 几个月前&#xff0c;我们在Plumbr中引入了锁定线程检测之后&#xff0c;我们开始收到类似于“嘿&#xff0c;太好了&#xff0c;现在我知道是什么导致了性能问题&#xf…

binlog日志_MySQL三大日志binlog、redo log和undo log

点击蓝色“JavaKeeper”关注我哟加个“星标”&#xff0c;一起成长&#xff0c;做牛逼闪闪的技术人Keeper导读&#xff1a;日志是mysql数据库的重要组成部分&#xff0c;记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制…