使用入站适配器公开HTTP Restful API。 第1部分(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

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

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

相关文章

使用jOOQ和JavaFX将SQL数据转换为图表

最近&#xff0c;我们已经展示了Java 8和函数式编程将如何为使用jOOQ和Java 8 lambda和Streams进行SQL数据的函数数据转换为Java开发人员带来新的视角。 今天&#xff0c;我们将这一步骤更进一步&#xff0c;将数据转换为JavaFX XYChart.Series以根据数据生成美观的条形图。 设…

node.js学习笔记(1)

一&#xff0e; 安装以及环境配置 安装路径 http://nodejs.cn/download/ 多种环境选择 环境变量的配置 Step1 先检查环境变量中的系统变量里面的path,查看是否加入了node.js 例如我的node.js安装路径是C:\Program Files\nodejs 那么&#xff0c;这个path里面就应该加…

主要版本发布后Java开发人员应使用的15种工具

新部署的生存工具包&#xff1a;适用于Java开发人员的工具&#xff0c;这些工具经常将代码部署到生产中&#xff01; Takipi会检测生产中的所有错误&#xff0c;并像发生错误时一样显示变量值 立即部署并获得免费的T恤 适用于新部署的终极生存套件 与在僵尸末日场景下玩弄&…

Java EE 7批处理和魔兽世界–第2部分

今天&#xff0c;我将把第二部分带到我以前关于Java EE 7批处理和《魔兽世界–第1部分》的帖子中。 在本文中&#xff0c;我们将了解如何从第1部分中获得的数据中汇总和提取指标。 概括 批处理目的是下载魔兽世界拍卖行的数据&#xff0c;处理拍卖并提取指标。 这些指标将建立…

js导航条 二级滑动 模仿块级作用域

for(var i 1;i<7;i){    //因为首级标题有6个&#xff0c;对每个首级标题添加mouseover和mouseout事件。    //这里用到块级作用域(function(k){document.getElementById("p_"k).addEventListener(mouseover,function(event){document.getElementById(p_…

struts+swfupload实现批量图片上传(上):swfupload

custom_settings : {progressTarget : "fsUploadProgress",cancelButtonId : "btnCancel",uploadButtonId : "btnUpload",myFileListTarget : "idFileList" },custom_settings调用方法 this.customSettings.cancelButtonId 缩略图js …

40行中的持久性KeyValue Server和一个可悲的事实

再次出现。. 回顾 Peters关于Unsafe用法的书面概述 &#xff0c;我将简要介绍一下Java中的低级技术如何通过启用更高级别的抽象或允许Java性能级别来节省开发工作可能很多人都不知道。 我的主要观点是表明&#xff0c;将对象转换为字节&#xff0c;反之亦然是一个重要的基础&a…

TreeMap源码分析——深入分析(基于JDK1.6)

TreeMap有Values、EntrySet、KeySet、PrivateEntryIterator、EntryIterator、ValueIterator、KeyIterator、DescendingKeyIterator、NavigableSubMap、AscendingSubMap、DescendingSubMap、SubMap、Entry共十三个内部类。Entry是在TreeMap中用于表示树的节点的内部类&#xff0…

Python2.6 Cx_Oracle Linux下编译安装

分类&#xff1a; python Oracle 2012-06-07 00:04 239人阅读 评论(0) 收藏 举报(一) Python 2.6 安装 1.下载Python2.6.X 版本的源码包&#xff0c;这里采用平台编译安装。 Python-2.6.4.tar.bz2 2.解压缩 ,使用J参数解压bigz2类型的压缩文件 tar -jxvf Python-2.6.4.tar.bz2…

Apache TomEE(和Tomcat)的自签名证书

可能在大多数Java EE项目中&#xff0c;您将拥有具有SSL支持&#xff08; https &#xff09;的部分或整个系统&#xff0c;因此浏览器和服务器可以通过安全连接进行通信。 这意味着在处理数据之前&#xff0c;已发送的数据已加密&#xff0c;传输并最终解密。 问题在于&…

WEB效能测试和负载测试部分截图

效能测试&#xff1a; 负载测试&#xff1a; 转载于:https://www.cnblogs.com/DOOM-scse/archive/2013/01/07/2849110.html

Java8 Lambdas:解释性能缺陷的排序

与Peter Lawrey合作撰写 。 几天前&#xff0c;我对使用新的Java8声明式的排序性能提出了严重的问题。 在这里查看博客文章。 在那篇文章中&#xff0c;我仅指出了问题所在&#xff0c;但在这篇文章中&#xff0c;我将更深入地了解和解释问题的原因。 这将通过使用声明式样式重…

Asp.net MVC3.0 基于不同的角色显示不同的菜单

前面提到过用Asp.net MVC3.0正在做一个问答系统性质的论坛。前期把菜单全部显示以方便测试模块功能。现在正在完善&#xff0c;加上角色模块&#xff0c;然后不同的角色登陆系统会看到不同的菜单栏&#xff0c;还有就是游客&#xff08;未登录用户&#xff09;看到的菜单栏。网…

LoadRunner如何监控Linux下的系统资源

前一段时间在研究LoadRunner过程中&#xff0c;在进行压力场景测试中通过LoadRunner来实时监控windows的系统资源&#xff0c;在前几节中我已经总结了相关过程&#xff0c;近段时间发现群里有朋友问如何监控Linux下的系统资源&#xff0c;所以我也就此问题搭建了一些的Linux环境…

页面跳转多种方法(加传参)

onclick"javascript:location.href/HelpCenter/HelpCenter/" <a href"/HelpCenter/HelpCenter">帮助中心</a>点击页面返回上一页&#xff1a; onclick"javascript:window.history.go(-1); *********************************************…

JCG学院开设了Java设计模式课程!

自从我们推出JCG学院以来&#xff0c;已经有一段时间了。JCG学院是一个基于付费内容的高级订阅网站&#xff0c;提供有关最新技术的课程&#xff0c;涵盖从RedSQL数据库&#xff08;如Redis和CouchDB&#xff09;到使用Android进行移动开发的最新知识。 当然&#xff0c;与Jav…

用友异常清理工具

此类工具网上很多&#xff0c;但&#xff0c;网上的病毒千千万万&#xff0c;还是自己开发使用较为放心。而且具体执行了什么也一清二楚&#xff0c;可以放心。 此工具适用大部份版本&#xff0c;从U821至U871&#xff0c;包括U6系列。 转载于:https://www.cnblogs.com/wuxi15/…

JVM因“ OutOfMemory”错误而关闭-我该怎么办?

看起来似乎很神奇&#xff0c;但是在有关JVM设置的搜索请求结果中经常显示这种“从深度”的呼喊。 您可能会遇到“我记得该选项&#xff0c;但如何启用它”的问题&#xff0c;而有时&#xff08;主要是半年一次&#xff09;管理服务器或调整虚拟设备&#xff0c;而又除主要任务…

JBoss Data Virtualization 6.1 Beta现在可用

JBoss 数据虚拟化 &#xff08;JDV&#xff09;是一种数据集成解决方案&#xff0c;位于多个数据源的前面&#xff0c;并允许将它们视为一个源。 做到这一点&#xff0c;它提供了数据抽象&#xff0c;联合&#xff0c;集成&#xff0c;转换和交付功能&#xff0c;可将来自一个或…

点击显示底框颜色,默认显示第一个。

页面初始化显示第一个底框颜色&#xff0c;点击另一个第一个底框颜色消失&#xff0c;被点击的底框颜色显示&#xff0c;以此循环。 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional…