使用Java 11 Http Client API发送HTTP GET / POST / PUT /


Java 11中添加的功能之一是标准化的Http Client API。本文介绍如何使用Java 11 Http Client API发送HTTP GET / POST / PUT / DELETE请求。

这个新的API支持HTTP / 1.1以及HTTP2。HTTP协议的较新版本旨在提高客户端发送请求和从服务器接收响应的整体性能。这是通过引入一些更改(例如流多路复用,标头压缩和推送承诺)来实现的。

在JDK 11中,引入了一个新模块,如下所示:

module java.net.http {
exports java.net.http;
}

该软件包包含:

HttpClient 用于发送请求和接收响应。提供同步和异步请求机制。 HttpClient实例是不可变的,一旦创建,您就可以发送相同的多个请求。 要发送请求,首先需要创建HttpClient。 例子:

HttpClient client = HttpClient.newBuilder().version(Version.HTTP_2).build();

如果服务器不支持HTTP / 2,则使用HTTP / 1.1处理请求 您可以将executor()用于异步任务。 HttpRequest 创建HttpRequest实例并设置URI,request方法可以选择指定正文和标头。 HttpRequest实例是不可变的,可以发送多次。 客户端支持所有HTTP方法。可用于发出不同请求的方法是GET(),POST(),PUT(),DELETE(),method()。 例子:

HttpRequest request = HttpRequest.newBuilder(URI.create(http://localhost:8080/addDetails”))
.header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(inputJson)).build();

HttpRequest.BodyPublisher / HttpRequest.BodyPublishers BodyPublisher用于发送带有请求正文的请求。 BodyPublishers负责从字符串或文件发布正文内容。 在上面的示例中,使用BodyPublishers.ofString()创建了BodyPublisher并将其作为参数传递给POST()方法。 HttpResponse 客户端发送HttpRequest之后,将立即接收HttpResponse,其中包括标头和消息正文(如果有)。 例子:

CompletableFuture<HttpResponse<String>> response = client.sendAsync(request,HttpResponse.BodyHandlers.ofString());

sendAsync()用于异步(非阻塞)发送HttpRequest并返回CompletableFuture。 HttpResponse.BodyHandler / HttpResponse.BodyHandlers

  • HttpResponse.BodyHandler确定如何处理响应正文。一旦响应状态代码和标头可用,但在接收到响应主体字节之前,将调用BodyHandler。BodyHandler负责创建BodySubscriber。
  • HttpResponse.BodyHandlers提供了用于创建Body Handler的工厂方法。将响应字节累积在内存中,直到被完全接收为止,之后将其转换为高级Java类型,例如String。 HttpResponse.BodySubscriber HttpResponse.BodySubscriber是一个无反应流订阅者,它以无阻塞背压接收数据流。 考虑您已经使用Spring Boot创建了RESTful Web服务。您可以使用Java 11 Http Client API异步发送请求并接收响应。无需向您的项目添加任何外部库。

所需软件:

  1. Eclipse
  2. JDK 11
  3. MySQL 8.0

使用带有以下项目结构的Spring Boot 2.1.x创建RESTful Web服务应用程序。

1586523673272.png

1.您可以在此处引用POM.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.13.RELEASE</version>
        <relativePath></relativePath> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.productservice</groupId>
    <artifactId>ProductService</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ProductService</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
       </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>

            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.在application.properties文件中提及以下内容。

spring.datasource.url= jdbc:mysql://localhost:3307/springrestdemos
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto = create
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

3.在com.example.productservice.business.bean包中创建ProductBean类。

public class ProductBean {
    private int id;
    private String name;    
    private String description;
    private Double price;
    // getters and setters
    // toString()
}
  1. Create ProductController class in com.example.productservice.controller package.
package com.example.productservice.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.productservice.business.bean.ProductBean;
import com.example.productservice.service.ProductServiceImpl;
@RestController
public class ProductController {
    @Autowired
    private ProductServiceImpl productServiceImpl;

    @GetMapping(value = "product/controller/getDetails", produces = MediaType.APPLICATION_JSON_VALUE )
    public ResponseEntity<List<ProductBean>> getProductDetails() {
        List<ProductBean> listProduct = new ArrayList<ProductBean>(productServiceImpl.getAllProduct());
        return new ResponseEntity<List<ProductBean>>(listProduct,HttpStatus.OK);
    }

    @GetMapping(value="product/controller/getDetailsById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<ProductBean> getProductDetailByEmployeeId(@PathVariable("id") int myId) {
        ProductBean product = productServiceImpl.getProductDetailsById(myId);
        if (product != null) {

            return new ResponseEntity<ProductBean>(product, HttpStatus.OK);
        } else {
            return new ResponseEntity<ProductBean>(HttpStatus.NOT_FOUND);
        }
    }

    @PostMapping(value="product/controller/addProduct", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_HTML_VALUE)
    public ResponseEntity<String> addProduct(@RequestBody ProductBean product) {
        int count=productServiceImpl.addProduct(product);
        return new ResponseEntity<String>("Product added successfully with id:" + count,HttpStatus.CREATED);
    }

    @PutMapping(value = "product/controller/updateProduct",consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<ProductBean> updateProduct(@RequestBody  ProductBean product) {
        if (productServiceImpl.getProductDetailsById(product.getId()) == null) {
            ProductBean product2 = null;
            return new ResponseEntity<ProductBean>(product2,HttpStatus.INTERNAL_SERVER_ERROR);
        }
        ProductBean updated = productServiceImpl.updateProduct(product);
        return new ResponseEntity<ProductBean>(updated, HttpStatus.OK);
    }

    @DeleteMapping(value = "product/controller/deleteProduct/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<ProductBean> deleteProduct(@PathVariable("id") int myId) {
        ProductBean product2=productServiceImpl.getProductDetailsById(myId);
        if (productServiceImpl.getProductDetailsById(myId) == null) {
            return new ResponseEntity<ProductBean>(product2,HttpStatus.INTERNAL_SERVER_ERROR);
        }
        productServiceImpl.removeProduct(myId);
        return new ResponseEntity<ProductBean>(product2, HttpStatus.OK);
    }
}
  1. Create ProductService Inteface in com.example.productservice.service package.
package com.example.productservice.service;
import java.util.Collection;
import com.example.productservice.business.bean.ProductBean;
public interface ProductService {
    Collection<ProductBean> getAllProduct();
    ProductBean getProductDetailsById(int id);
    Integer addProduct(ProductBean product);
    ProductBean updateProduct(ProductBean product);
    void removeProduct(int id);
}
  1. Create ProductServiceImpl class in com.example.productservice.service package.
package com.example.productservice.service;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.productservice.business.bean.ProductBean;
import com.example.productservice.dao.ProductDAOWrapper;
@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductDAOWrapper productDAOWrapper;
    public Collection<ProductBean> getAllProduct(){
        return productDAOWrapper.findAll();         
    }
    public ProductBean getProductDetailsById(int id){
        return productDAOWrapper.findOne(id);
    }
    public Integer addProduct(ProductBean product){
        return productDAOWrapper.saveProduct(product);
    }
    public ProductBean updateProduct (ProductBean product){
        return productDAOWrapper.updateProduct(product);
    }
    public void removeProduct (int id){
        productDAOWrapper.delete(id);
    }
}
  1. Create ProductDAO interface in com.example.productservice.dao package.
package com.example.productservice.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.productservice.entity.ProductEntity;
public interface ProductDAO extends JpaRepository<ProductEntity, Integer>
{
}
  1. Create ProductDAOWrapper class in com.example.productservice.dao package.
package com.example.productservice.dao;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.productservice.business.bean.ProductBean;
import com.example.productservice.entity.ProductEntity;
@Repository
public class ProductDAOWrapper {
    @Autowired
    private ProductDAO dao;


    public List<ProductBean>findAll(){
        List<ProductBean> list = new ArrayList<ProductBean>(); 
        Iterable<ProductEntity> listEn= dao.findAll();
        listEn.forEach(x->{
            ProductBean product = new ProductBean();
            BeanUtils.copyProperties(x, product);
            list.add(product);
        });
        return list;
    }


    public ProductBean findOne(Integer id){ 
            ProductEntity x= dao.findById(id).get();
            ProductBean product =null;
            if(x!=null){
                product = new ProductBean();        
                BeanUtils.copyProperties(x, product);
                }
            System.out.println(x);
        return product;
    }

    public Integer saveProduct(ProductBean product){
        ProductEntity productEntityBean = new ProductEntity();
        BeanUtils.copyProperties(product, productEntityBean);
        ProductEntity en=  dao.save(productEntityBean);
        return en.getId();  

    }


    public ProductBean updateProduct(ProductBean product){
        ProductEntity productEntityBean = new ProductEntity();
        BeanUtils.copyProperties(product, productEntityBean);
        ProductEntity en=  dao.save(productEntityBean);
        ProductBean product2 = new ProductBean();
        BeanUtils.copyProperties(en,product2);
        return product2;    
    }


    public void delete(int id){
        dao.deleteById(id);
    }
}

9.在com.example.productservice.entity包中创建ProductEntity类。

package com.example.productservice.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="product")
public class ProductEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;    
    private String description;
    private Double price;
    // getters and setters
}

使用clean install spring-boot:在maven目标中运行来运行应用程序。

打开浏览器,然后按以下方式访问网址:

http:// localhost:8080 / emp / controller / getDetails

使用JDK 11创建Java应用程序以使用创建的ProductService应用程序:

1.在模块路径中添加Jackson-annotations-2.7.3,Jackson-core-2.7.3,Jackson-databind-2.7.3 jar文件。

2.使HttpClientAsyncDemo模块打开。

open module HttpClientAsyncDemo {
    requires java.net.http;
    requires jackson.databind;
    requires jackson.core;
}

3.在com.httpclientdemo.utility包中创建JSONUtils类。用于将JSON转换为Object,反之亦然。

package com.httpclientdemo.utility;
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONUtils {
    //convert JSON into List of Objects
    static public <T> List<T> convertFromJsonToList(String json, TypeReference<List<T>> var) throws JsonParseException, JsonMappingException, IOException
    {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(json, var);
    }

    //Generic Type Safe Method – convert JSON into Object
    static public <T> T covertFromJsonToObject(String json, Class<T> var) throws IOException{
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(json, var);//Convert Json into object of Specific Type
    }
    //convert Object into JSON
    public static String covertFromObjectToJson(Object obj) throws JsonProcessingException{
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(obj);
    }

}

4.在com.httpclientdemo.business.bean包中创建与ProductService应用程序相同的ProductBean类。

5.在com.httpclientdemo.uiclient包中创建一个主要的Java类HttpClientAsyncDemo类。

package com.httpclientdemo.uiclient;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.httpclientdemo.business.bean.ProductBean;
import com.httpclientdemo.utility.JSONUtils;

public class HttpClientAsyncDemo {
private static final HttpClient client = HttpClient.newBuilder().version(Version.HTTP_2).build();
private static final String serviceURL = "http://localhost:8080/product/controller/";
public static void main(String[] args) throws InterruptedException, ExecutionException, IOException{

    //getAllProducts();
    //getProductDetailsById();
    addProduct();
    //updateProduct();
    //deleteProduct();

}
//sending request to retrieve all the products available.
public static void getAllProducts() throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException
{
    HttpRequest req = HttpRequest.newBuilder(URI.create(serviceURL+"getDetails"))
            .GET().build();
    CompletableFuture<HttpResponse<String>> response = client.sendAsync(req, BodyHandlers.ofString());
    response.thenAccept(res -> System.out.println(res));
    List<ProductBean> products = JSONUtils.convertFromJsonToList(response.get().body(), new TypeReference<List<ProductBean>>() {});
    products.forEach(System.out::println);
    response.join();
}
//sending request retrieve the product based on the productId
public static void getProductDetailsById() throws InterruptedException, ExecutionException, IOException
{
    HttpRequest req = HttpRequest.newBuilder(URI.create(serviceURL+"getDetailsById/1"))
            .GET().build();
    CompletableFuture<HttpResponse<String>> response = client.sendAsync(req, BodyHandlers.ofString());
    response.thenAccept(res -> System.out.println(res));
    if(response.get().statusCode() == 500)
        System.out.println("Product Not Avaialble");
    else
    {
        ProductBean bean = JSONUtils.covertFromJsonToObject(response.get().body(), ProductBean.class);
        System.out.println(bean);
    }
    response.join();
}
//send request to add the product details.
public static void addProduct() throws InterruptedException, ExecutionException, JsonProcessingException
{
    ProductBean bean = new ProductBean();
    bean.setName("handwash");
    bean.setDescription("Herbal");
    bean.setPrice(143.10);

    String inputJson = JSONUtils.covertFromObjectToJson(bean);


    HttpRequest request = HttpRequest.newBuilder(URI.create(serviceURL+"addProduct"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(inputJson)).build();
    CompletableFuture<HttpResponse<String>> response = client.sendAsync(request,HttpResponse.BodyHandlers.ofString());
    System.out.println(response.get().body());
}
//send request to update the product details.
public static void updateProduct() throws InterruptedException, ExecutionException, IOException
{
    ProductBean bean = new ProductBean();
    bean.setId(1);
    bean.setName("Hand Wash");
    bean.setDescription("Herbal Prodcuct by XYZ company");
    bean.setPrice(198.10);

    String inputJson=JSONUtils.covertFromObjectToJson(bean);
    HttpRequest request = HttpRequest.newBuilder(URI.create(serviceURL+"updateProduct"))
            .header("Content-Type", "application/json")
            .PUT(HttpRequest.BodyPublishers.ofString(inputJson)).build();
    CompletableFuture<HttpResponse<String>> response = client.sendAsync(request,HttpResponse.BodyHandlers.ofString());
    if(response.get().statusCode() == 500)
        System.out.println("Product Not Avaialble to update");
    else {
        bean = JSONUtils.covertFromJsonToObject(response.get().body(), ProductBean.class);
        System.out.println(bean);
    }
    response.join();
}
//send request to delete the product by its productId
public static void deleteProduct() throws ExecutionException, InterruptedException, IOException
{
    HttpRequest request = HttpRequest.newBuilder(URI.create(serviceURL+"deleteProduct/1"))
            .DELETE().build();
    CompletableFuture<HttpResponse<String>> response = client.sendAsync(request,HttpResponse.BodyHandlers.ofString());
    if(response.get().statusCode() == 500)
        System.out.println("Product Not Available to delete");
    else {
        ProductBean bean = JSONUtils.covertFromJsonToObject(response.get().body(), ProductBean.class);
        System.out.println(bean);
    }
    response.join();
}
}

运行应用程序。您可以观察数据库表中添加的产品详细信息。

在主要方法中取消对getProductDetailsById()的注释,注释其他方法并运行应用程序,您可以观察控制台中显示的产品详细信息。

同样,您可以注释和取消注释主类中提供的功能,并观察结果。

结论 使用Java 11中的HttpClient客户端,我们可以在HTTP / 1.1和HTTP 2的支持下同步/异步发送不同类型的请求。无需向您的项目添加任何外部http客户端库。


原文链接:http://codingdict.com