本文将介绍一个快速的附带项目-一个自动从各种Q&A StackExchange网站上发布热门问题的机器人,例如StackOverflow , ServerFault , SuperUser等。我们将为StackExchange API构建一个简单的客户端,然后进行设置使用Spring Social与Twitter API的交互-这第一部分将仅关注StackExchange Client。 此实现的最初目的不是要成为整个StackExchange API的完整客户端-这不在本项目的范围之内。 客户端存在的唯一原因是,我无法对与正式API的2.x版本兼容的对象进行罚款。
1. Maven依赖
要使用StackExchange REST API,我们将需要很少的依赖项-本质上只是一个HTTP客户端-Apache HttpClient可以很好地满足此目的:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.3</version>
</dependency
还可以使用Spring RestTemplate与HTTP API进行交互,但这会在项目中引入很多其他与Spring相关的依赖项,这些依赖项不是严格必需的,因此HttpClient将使事情变得轻而易举。
2.问题客户
该客户端的目的是使用StackExchange 发布的/ questions REST服务,而不是为整个StackExchange API提供通用客户端–因此,出于本文的目的,我们仅着眼于此。 使用HTTPClient的实际HTTP通信相对简单:
public String questions(int min, String questionsUri) {
HttpGet request = null;
try {
request = new HttpGet(questionsUri);
HttpResponse httpResponse = client.execute(request);
InputStream entityContentStream = httpResponse.getEntity().getContent();
return IOUtils.toString(entityContentStream, Charset.forName('utf-8'));
} catch (IOException ex) {
throw new IllegalStateException(ex);
} finally {
if (request != null) {
request.releaseConnection();
}
}
}
这种简单的交互非常适合获取API发布的原始JSON问题–下一步将处理该JSON。 这里有一个相关的细节-也就是questionsUri方法参数 -有多个StackExchange API可以发布问题(如官方文档所建议的那样),并且此方法必须足够灵活才能使用所有问题。 例如,它可以使用最简单的API(通过将questionUri设置为https://api.stackexchange.com/2.1/questions?site=stackoverflow来返回问题),也可以使用基于https://api.stackexchange.com/的标记取而代之的是2.1 / tags / {tags} / faq?site = stackoverflow API,具体取决于客户端的需求。
对StackExchange API的请求已完全配置有查询参数,即使是对于更复杂的高级搜索查询,也没有发送正文。 为了构造questionsUri ,我们将构建一个基本的流畅的RequestBuilder类,该类将使用 HttpClient库中的URIBuilder 。 这将确保正确编码URI,并通常确保最终结果有效:
public class RequestBuilder {
private Map<String, Object> parameters = new HashMap<>();
public RequestBuilder add(String paramName, Object paramValue) {
this.parameters.put(paramName, paramValue);
return this;
}
public String build() {
URIBuilder uriBuilder = new URIBuilder();
for (Entry<String, Object> param : this.parameters.entrySet()) {
uriBuilder.addParameter(param.getKey(), param.getValue().toString());
}
return uriBuilder.toString();
}
}
现在,为StackExchange API构造一个有效的URI:
String params = new RequestBuilder().
add('order', 'desc').add('sort', 'votes').add('min', min).add('site', site).build();
return 'https://api.stackexchange.com/2.1/questions' + params;
3.测试客户端
客户端将输出原始JSON,但是要进行测试,我们需要一个JSON处理库,特别是Jackson 2 :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.1.3</version>
<scope>test</scope>
</dependency>
我们将看到的测试将与实际的StackExchange API交互:
@Test
public void whenRequestIsPerformed_thenSuccess()
throws ClientProtocolException, IOException {
HttpResponse response = questionsApi.questionsAsResponse(50, Site.serverfault);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}
@Test
public void whenRequestIsPerformed_thenOutputIsJson()
throws ClientProtocolException, IOException {
HttpResponse response = questionsApi.questionsAsResponse(50, Site.serverfault);
String contentType = httpResponse.getHeaders(HttpHeaders.CONTENT_TYPE)[0].getValue();
assertThat(contentType, containsString('application/json'));
}
@Test
public void whenParsingOutputFromQuestionsApi_thenOutputContainsSomeQuestions()
throws ClientProtocolException, IOException {
String questionsAsJson = questionsApi.questions(50, Site.serverfault);
JsonNode rootNode = new ObjectMapper().readTree(questionsAsJson);
ArrayNode questionsArray = (ArrayNode) rootNode.get('items');
assertThat(questionsArray.size(), greaterThan(20));
}
第一次测试已验证API提供的响应确实为200 OK,因此检索问题的GET请求实际上是成功的。 在确保基本条件之后,我们继续使用Content-Type HTTP标头指定的表示形式,该表示形式必须为JSON。 接下来,我们实际上解析JSON并验证输出中是否确实存在问题-解析逻辑本身是低级且简单的,足以满足测试目的。 请注意,这些请求计入API指定的速率限制 -出于这个原因,实时测试不包含在标准Maven版本中:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<excludes>
<exclude>**/*LiveTest.java</exclude>
</excludes>
</configuration>
</plugin>
4.下一步
当前的Client仅专注于StackExchange API发布的许多可用类型中的一种资源。 这是因为它的最初目的是有限的–仅需要使用户能够使用StackExchange产品组合中各个站点的问题 。 因此,可以改进客户端,使其超出此初始用例的范围,以能够使用其他类型的API 。 实现也非常原始 -使用Questions REST服务后,它只是将JSON输出作为字符串返回-而不是从该输出中输出任何类型的Questions模型。 因此,下一步可能是将JSON解组到适当的域DTO中,然后将其返回而不是原始JSON。
5.结论
本文的目的是演示如何开始与StackExchange API或实际上是基于HTTP的API建立集成。 它涵盖了如何针对实时API编写集成测试,以及如何确保端到端交互确实有效。
本文的第二部分将展示如何使用Spring Social库与Twitter API进行交互,以及如何使用我们在此处构建的StackExchange Client在新的Twitter帐户上发布问题。
我已经建立了一些Twitter帐户,现在每天在Twitter上发布各种学科的2个热门问题:
- SpringAtSO –每天来自StackOverflow的两个最佳Spring问题
- JavaTopSO –每天来自StackOverflow的两个最佳Java问题
- AskUbuntuBest –每天来自AskUbuntu的两个最佳问题
- BestBash –每天来自所有StackExchange网站的两个最佳Bash问题
- ServerFaultBest –每天来自ServerFault的两个最佳问题
该StackExchange Client的完整实现在github上 。
参考: 使用Spring Social 推销StackExchange –第一部分,来自JCG合作伙伴 Eugen Paraschiv,来自baeldung博客。
翻译自: https://www.javacodegeeks.com/2013/02/tweeting-stackexchange-with-spring-social-part-1.html