在Java中开发的最大优势之一是可用于执行任何必要任务的库和框架数量。这是由于一个非常活跃和敬业的社区在创造的语言中已有将近30年。
但是,缺点之一是,我们对不同的实现,配置,使用方式和良好实践感到不知所措。这也适用于重置API(或任何其他类型的HTTP申请),因为有许多库可供选择:httpurlConnection,httpclient,httpclient,restlate和Spring webclient,以及Spring Cloud Cloud OpenFeign。< /p>本文的目的是为每个库中的每个库中的两个实现示例 - get请求和帖子 - 为将来的查询创建“备忘单”。
中
boralâð21171171171171171
pron© - 条件
首先是第一件事。
以下所有示例咨询了https://jsonplaceholder.typicode.com/users中可用的相同API。阿里恩(Alion),我强烈建议那些正在学习休息并创建第一个请求的人。有终点徒劳无功à。
所选端点以以下格式返回常规列表:
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
... vários outros usuários
我们想咨询API并将返回的JSON转换为对象。为此,我们将添加以下库中的pom.xml:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
如果您使用的是gradle,则动词少量:
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
}
接下来,我们将创建一个record(对于使用JDK 14+的人,如果您使用以前的版本,则必须像我们的祖先一样创建POJO):
// User.java
public record User(
Integer id,
String name,
String username,
String email,
Address address,
String phone,
String website,
Company company)
{
public record Address(
String street,
String suite,
String city,
String zipcode,
Geo geo)
{
public record Geo(String lat, String lng) {}
}
public record Company(String name, String catchPhrase, String bs) {}
}
最后,为了使我们的生活更轻松,让我们创建一个功利级别,其中包含一些妈妈将对象转换为对象格式,反之亦然,以及其他功能:
// ExampleUtils.java
public class ExampleUtils {
private ExampleUtils() {}
public static final String USER_API = "https://jsonplaceholder.typicode.com/users";
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static List<User> toList(InputStream inputStream) {
try {
return OBJECT_MAPPER.readValue(inputStream, new TypeReference<>() {});
}
catch (IOException exc) {
throw new UncheckedIOException(exc);
}
}
public static User toObject(InputStream inputStream) {
try {
return OBJECT_MAPPER.readValue(inputStream, User.class);
}
catch (IOException exc) {
throw new UncheckedIOException(exc);
}
}
public static String toJson(User user) {
try {
return OBJECT_MAPPER.writeValueAsString(user);
}
catch (JsonProcessingException exc) {
throw new UncheckedIOException(exc);
}
}
public static User buildUser() {
User.Address address = new User.Address(
"Rua http 200",
"apto POST",
"São Paulo",
"00200-404",
new User.Address.Geo("-257422", "25566987"));
User.Company company = new User.Company(
"My Great Company",
"We develop software!",
"sofware, development, java");
return new User(null,
"Archimedes Fagundes Junior",
"archimedes.junior",
"archimedes.junior@dev.com",
address,
"11 95523-9999",
"https://my.company.com",
company);
}
}
想知道!不用进一步的卷发,让我们转到我们的第一个实现:类HttpurlConnection 。
老式的httpurlconnection
要探索的第一个实现是HttpURLConnection
。自JDK 1.1以来,此实现是最古老的,并且存在。以下是一个座右铭的示例,该座右铭显示使用整个GET和辅助类别的常规列表:public void listUsers() {
System.out.println("\nListing users using the old school HttpURLConnection:");
try {
URL url = new URL(ExampleUtils.USER_API);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
int responseCode = httpURLConnection.getResponseCode();
System.out.println("HTTP status: " + responseCode);
System.out.println("Users returned in request: ");
List<User> users = ExampleUtils.toList(httpURLConnection.getInputStream());
users.forEach(System.out::println);
System.out.println("Headers:");
httpURLConnection.getHeaderFields().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
catch (MalformedURLException e) {
throw new RuntimeException("You've entered an invalid URL here: " + ExampleUtils.USER_API);
}
catch (IOException e) {
throw new RuntimeException("Error processing request", e);
}
}
观察包含List<User> users = ExampleUtils.toList(httpURLConnection.getInputStream())
拉伸的线。在这里获得了一个InputStream
并将其传递给我们的助理母亲。无法将JSON直接作为字符串。让我们继续使用Inputstream方法来其他示例
现在,让我们尝试使用母亲©每篇文章创建一个用户并显示返回:
public void createNewUser() {
System.out.println("\nCreating a new user using the old school HttpURLConnection:");
User user = ExampleUtils.buildUser();
try {
URL url = new URL(ExampleUtils.USER_API);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", "application/json");
String userJson = ExampleUtils.toJson(user);
httpURLConnection.setDoOutput(true);
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
outputStream.write(userJson.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
int responseCode = httpURLConnection.getResponseCode();
System.out.println("HTTP status: " + responseCode);
User createdUser = ExampleUtils.toObject(httpURLConnection.getInputStream());
System.out.println("Created new user: " + createdUser);
System.out.println("Headers:");
httpURLConnection.getHeaderFields().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
catch (MalformedURLException e) {
throw new RuntimeException("You've entered an invalid URL here: " + ExampleUtils.USER_API);
}
catch (IOException e) {
throw new RuntimeException("Error processing request", e);
}
}
要观察到两个有趣的点:
- 我们在请求中使用
httpURLConnection.setRequestProperty("Content-Type", "application/json");
添加了一个新的头 - 要在请求正文中发送一些值,我们必须首先使用Koud4启用止损,获取对Koud5对象的引用并在其中写入值。累人。
Java 11 httpclient
JDK 11于2018年9月推出,带来了一个新的简单和狂热的客户端。让我们看一下如何列出端点常规:
public void listUsers() {
System.out.println("\nListing users using Java 11 HttpClient:");
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(ExampleUtils.USER_API)).GET().build();
try {
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
int statusCode = response.statusCode();
System.out.println("HTTP status: " + statusCode);
System.out.println("Users returned in request: ");
List<User> users = ExampleUtils.toList(response.body());
users.forEach(System.out::println);
System.out.println("Headers:");
response.headers().map().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
该示例是将API作为InputStream
的返回,以便我们可以继续使用我们的妈妈,但是如果我们想将JSON作为字符串,我们可以做:
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response json: " + response.body());
现在让我们看看如何创建新用户:
public void createNewUser() {
System.out.println("\nCreating a new user using Java 11 HttpClient:");
User user = ExampleUtils.buildUser();
HttpRequest.BodyPublisher userPublisher = HttpRequest.BodyPublishers.ofString(ExampleUtils.toJson(user));
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest
.newBuilder(URI.create(ExampleUtils.USER_API))
.POST(userPublisher)
.setHeader("Content-Type", "application/json")
.build();
try {
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
int statusCode = response.statusCode();
System.out.println("HTTP status: " + statusCode);
User createdUser = ExampleUtils.toObject(response.body());
System.out.println("Created new user: " + createdUser);
System.out.println("Headers:");
response.headers().map().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
比您的班级更清晰,更流利
在上面的示例中,我们做了一个soma soration,也就是说,我们的应用程序将停止等待API的返回。如果我们想使用旧类HttpURLConnection
进行呼叫,我们将需要创建一个新线程并在其中执行我们的方式。幸运的是,新的HttpClient
类使您无需额外的努力就可以执行异步呼叫。以下摘录有一个新用户的新用途的示例:
public void createNewUserAsync() {
System.out.println("\nCreating a new user asynchronously using Java 11 HttpClient:");
User user = ExampleUtils.buildUser();
HttpRequest.BodyPublisher userPublisher = HttpRequest.BodyPublishers.ofString(ExampleUtils.toJson(user));
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest
.newBuilder(URI.create(ExampleUtils.USER_API))
.POST(userPublisher)
.setHeader("Content-Type", "application/json")
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
System.out.println("Http status: " + response.statusCode());
System.out.println("Headers:");
response.headers().map().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
return response;
})
.thenApply(HttpResponse::body)
.thenApply(ExampleUtils::toObject)
.thenAccept(createdUser -> System.out.println("New user created asynchronously: " + createdUser))
.join();
}
好的。我们看到了Java API中可用的实现。现在,让我们看一下两个库,一个众所周知,有些不是那么多。让我们从最著名的开始。
春季残留模板
使用Spring Boot Web创建的项目已经在工具箱中具有可用于使用的RestTemplate
类。让我们看看如何与她获取用户列表:
public void listUsers() {
System.out.println("\nListing users using Spring RestTemplate:");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<User[]> response = restTemplate.getForEntity(URI.create(ExampleUtils.USER_API), User[].class);
HttpStatusCode statusCode = response.getStatusCode();
System.out.println("HTTP status: " + statusCode.value());
System.out.println("Is status code 2xx successful? " + statusCode.is2xxSuccessful());
System.out.println("Users returned in request: ");
User[] users = Objects.requireNonNull(response.getBody());
Arrays.stream(users).forEach(System.out::println);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
以及如何在我们的API中创建新用户:
public void createNewUser() {
System.out.println("\nCreating a new user using Spring RestTemplate:");
User user = ExampleUtils.buildUser();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<User> response = restTemplate.postForEntity(URI.create(ExampleUtils.USER_API), user, User.class);
HttpStatusCode statusCode = response.getStatusCode();
System.out.println("HTTP status: " + statusCode.value());
System.out.println("Is status code 2xx successful? " + statusCode.is2xxSuccessful());
User createdUser = response.getBody();
System.out.println("Created new user: " + createdUser);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
请注意,这次我们需要使用助手将InputStream
或字符串转换为用户对象。 RESTTEMPLATE已经照顾了这部分。
在上面的示例中,我们使用母亲©All Koud11和Koud12与API互动。我们还可以使用最QueNo exchange
。让我们看看如何与这个母亲创建新的常规:
public void createNewUserUsingExchangeMethod() {
System.out.println("\nCreating a new user using Spring RestTemplate's exchange method:");
RestTemplate restTemplate = new RestTemplate();
RequestEntity<User> request = RequestEntity
.post(URI.create(ExampleUtils.USER_API))
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, "Bearer XYZ1234abc")
.body(ExampleUtils.buildUser());
ResponseEntity<User> response = restTemplate.exchange(request, User.class);
HttpStatusCode statusCode = response.getStatusCode();
System.out.println("HTTP status: " + statusCode.value());
System.out.println("Is status code 2xx successful? " + statusCode.is2xxSuccessful());
User createdUser = response.getBody();
System.out.println("Created new user with exchange method: " + createdUser);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
春季网络电视机
仍然在春季启动世界内,但是对于那些使用 spring webflux 库来使用反应性代码的人,我们有 webclient 类。现在,我们的代码越来越少。
让我们使用WebClient列出用途:
public void listUsers() {
System.out.println("\nListing users using Spring WebFlux:");
WebClient webClient = WebClient.create(ExampleUtils.USER_API);
ResponseEntity<List<User>> response = webClient.get().retrieve().toEntityList(User.class).block();
Objects.requireNonNull(response);
HttpStatusCode statusCode = response.getStatusCode();
System.out.println("HTTP status: " + statusCode.value());
System.out.println("Is status code 2xx successful? " + statusCode.is2xxSuccessful());
System.out.println("Users returned in request: ");
List<User> users = Objects.requireNonNull(response.getBody());
users.forEach(System.out::println);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
设定的线条不佳。现在变得非常好ð。
让我们看看如何创建新用户:
public void createNewUser() {
System.out.println("\nCreating a new user using Spring WebClient:");
User user = ExampleUtils.buildUser();
WebClient webClient = WebClient.create(ExampleUtils.USER_API);
ResponseEntity<User> response = webClient.post()
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(Mono.just(user), User.class)
.retrieve()
.toEntity(User.class)
.block();
Objects.requireNonNull(response);
HttpStatusCode statusCode = response.getStatusCode();
System.out.println("HTTP status: " + statusCode.value());
System.out.println("Is status code 2xx successful? " + statusCode.is2xxSuccessful());
User createdUser = response.getBody();
System.out.println("Created new user: " + createdUser);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
WebClient是一个反应性库,可与数据流相机,例如Flux
和Koud15。对于我们的简单示例,我们使用整个Koud16来使客户在返回实体之前等待收到请求的所有请求。但是,如果您想加深春季Webflux并了解什么是通量和单声道,我建议您查看https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux中处置的官方文档。
春天云开放式
现在,让我们上楼梯上的一些步骤,并使用一个称为 openFeign 的库,该库与 spring cloud 的职责集成在一起。。
这个概念非常简单:您创建一个接口,添加一些注释,然后我们有一个功能性的HTTP客户端。春天照顾无聊的部分。
在使用假装Cliver之前,我们需要限定它。为此,我们在应用程序的主要类中添加了注释:
@SpringBootApplication
@EnableFeignClients
public class HttpClientFeignApplication {
public static void main(String[] args) {
SpringApplication.run(HttpClientFeignApplication.class, args);
}
}
请注意,@EnableFeignClients
我在上面。
现在,让我们创建我们的响应界面以与通常的API通信:
// UserClient.java
@FeignClient(name="userClient", url = ExampleUtils.USER_API)
public interface UserClient {
@GetMapping
List<User> simpleListUsers();
@GetMapping
ResponseEntity<List<User>> listUsers();
@PostMapping
ResponseEntity<User> createNewUser(User user);
}
正是这样,仅此而已!在这里,我们创建了三个妈妈©全部:
- 母亲©All
simpleListUsers()
仅返回我们的常规列表,好像是母亲的呼唤©whinewhere。 - 母亲©所有
listUsers()
返回我们一个ResponseEntity
对象,以便我们可以检查标题,请求状态等。 - 母亲©所有
createNewUser()
创建新用户。
让我们看看如何使用它们中的每个。
而不是忘记将客户注入班级的依赖:
@Component
public class HttpClientFeign {
private final UserClient userClient;
public HttpClientFeign(UserClient userClient) {
this.userClient = userClient;
}
// ... other methods listed below
返回一个简单的常规列表:
public void simpleListUsers() {
System.out.println("\nListing users using OpenFeign client:");
List<User> users = userClient.simpleListUsers();
System.out.println("Users returned in request: ");
users.forEach(System.out::println);
}
返回请求列表和信息列表:
public void listUsers() {
System.out.println("\nListing users using OpenFeign client:");
ResponseEntity<List<User>> response = userClient.listUsers();
int statusCode = response.getStatusCode().value();
System.out.println("HTTP status: " + statusCode);
System.out.println("Users returned in request: ");
List<User> users = Objects.requireNonNull(response.getBody());
users.forEach(System.out::println);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
最后,创建一个新用户:
public void createNewUser() {
System.out.println("\nCreating a new user using OpenFeign client:");
User user = ExampleUtils.buildUser();
ResponseEntity<User> response = userClient.createNewUser(user);
int statusCode = response.getStatusCode().value();
System.out.println("HTTP status: " + statusCode);
User createdUser = response.getBody();
System.out.println("Created new user: " + createdUser);
System.out.println("Headers:");
response.getHeaders().forEach((header, value) -> System.out.println(header + " = " + String.join(", ", value)));
}
简单且极其实用!
包括£o
本文没有声称是结论性的,而是我在项目上使用的库的快速咨询指南。这些库中还有更多资源可以探索。我还提到了其他有趣的库,例如Micronaut或Apache Commons的HTTP客户端,但我将留下一些链接到感兴趣的人。
如上所述,所有这些示例,包括它们的其他配置和类,都在我的Github中。
在©aximað
反思
- https://www.digitalocean.com/community/tutorials/java-httpurlconnection-example-java-http-request-get-post
- https://www.baeldung.com/java-9-http-client
- https://www.baeldung.com/rest-template
- https://reflectoring.io/spring-webclient/
- https://www.baeldung.com/spring-cloud-openfeign
- https://guides.micronaut.io/latest/micronaut-http-client-maven-java.html
- https://www.vogella.com/tutorials/ApacheHttpClient/article.html