Java中的HTTP客户端API:第3部分
#初学者 #java #http

概述

本文的目的是展示如何使用HTTP客户端API从休息端点上传/下载文件内容。

让我们回顾一下呼叫Web资源的步骤,因为此过程相同以上传/下载文件数据。

  • httpclient对象是在需要的情况下进一步配置的(超时,身份验证器,http版本,lastredirects ...)

  • HTTP请求是通过URL创建的。可选,可以设置其他功能。例如,HTTP方法,HTTP标头,超时和HTTP版本。

  • 然后,不是直接创建httpresponse,而是由于使用httpclient发送httprequest而返回的。完成后,状态代码和身体如果可以从中检查任何内容。

现在,让我们继续下载文件用例。

下载文件内容

我们将按照上述步骤执行此操作。但是首先,让我们看一下后端。终点是将文件的内容发送回字节数组

@RestController
@RequestMapping("api/v1/documents")
public class DocumentController {
// ommited code here

    @GetMapping(value = "/{documentId}")
    ResponseEntity<Resource> downloadDocument(@PathVariable Long 
                                              documentId) {
        Optional<Document> document = documentRepo.findById(documentId);

        if (document.isEmpty())
            return ResponseEntity.notFound().build();

        return ResponseEntity
            .ok() 
            .contentType(MediaType.parseMediaType(
                document.get().getType()))
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; 
                filename=\"" + document.get().getName() + "\"")
            .body(new ByteArrayResource( 
                 document.get().getContents()));
    }

API提供BodyHandlers类(HTTPRESPONSE INTRAT静态类)来管理常见响应类型,例如字符串或文件。以下是此类可用的一些有用方法的列表:

  1. of bytearray:身体写入字节数组。
  2. offile:尸体被写入文件,而httpresponse.body..body()返回对其路径的引用。
  3. OffileDownload:正文完全写入文件,httpresponse.body()返回文件的路径对象。
  4. ofstring:使用内容类型响应标头中指定的字符集写入并解码。
  5. ofInputStream:返回一个输入流,可以从中读取身体。
  6. oflines:返回流。尸体可能尚未收到。
  7. of Publisher:返回出版商,可以从中获得身体响应字节,并在收到时获得。发布者可以而且必须仅订阅一次。

当端点返回字节数组时,bytearray方法似乎是一个很好的匹配。文件名是从内容分配标题中提取的。下面显示的代码段:

// Byte Array
HttpResponse<byte[]> response = client
    .send(request, HttpResponse.BodyHandlers.ofByteArray()); 
String headerContentDisposition = 
    (String)response.headers().firstValue("content- 
    disposition").get();
String fileName = 
    "C:/workspace/files/"+getFileName(headerContentDisposition);

// Save to file
Files.write(Paths.get(fileName),
    response.body(), StandardOpenOption.CREATE_NEW);

执行程序后,将文件成功下载到指定的位置。

Directory: C:\workspace\files

Mode            LastWriteTime         Length Name                                                                                                                                 
----            -------------         ------ ----                                                                                                                                 
-a----          4/1/2023   7:28 PM    388374 LinuxCommands.jpg   

可以使用其他bodyhandler下载文件,如以下行所证明的

HttpResponse<Path> response = client.send(request,                
    HttpResponse.BodyHandlers.ofFile( 
    Path.of("C:/workspace/files/DownloadedFile.jpg")));

另一个选项是使用ofinputstream方法。

HttpResponse<InputStream> response = client
   .send(request,             
         HttpResponse.BodyHandlers.ofInputStream());
String headerContentDisposition = 
   (String)response.headers().firstValue("content- 
   disposition").get();
String fileName = "C:/workspace/files/"+ 
   getFileName(headerContentDisposition);

Files.copy(response.body(), Paths.get(fileName), 
   StandardCopyOption.REPLACE_EXISTING);

您可以看到,完成工作有很多选择: - )。

上传文件内容

在此用户情况下,已经设置了两个不同的端点来上传文件。因此,我们将看到不同的方式将身体发挥作用。
请求主体是通过提供给其中一个帖子或PUT方法的Bodypublisher提供的。班级BodyPublisher提供了许多常见出版商的实现。这是BodyPublishers中可用的一些方法的列表

  1. ofString:返回一个Bodypublisher,其主体是给定的字符串,使用UTF_8字符​​转换。
  2. ofinputstream:从输入流读取其数据的身体发布者。
  3. of bytearray:返回一个请求正文出版商,其主体是给定字节阵列的。
  4. offile:从文件内容中获取数据的请求主体发布者。
  5. of bytearrays:从字节阵列中获取数据的请求主体发布者。

现在我们可以继续进行第一个上传示例。其余端点将文件内容视为字符串。文件类型和名称出现在标题中。

@PostMapping()
ResponseEntity<Void> uploadDocument(@RequestBody String data, 
                     @RequestHeader("Content-Type") String type,
                     @RequestHeader("fileName") String fileName) {
    Document document = new Document();
    document.setName(fileName);
    document.setCreationDate(LocalDate.now());
    document.setType(type);
    document.setContents(data.getBytes());

    documentRepo.save(document);

    return ResponseEntity.created(URI.create( 
        "http://localhost:8080/api/v1/documents/"+document.getId() 
        )).build();
    } 

您可以看到BodyPublishers.offile方法将路径作为参数。发送请求时,正文将包含文件的内容。

Path file = Paths.get("C:/workspace/files/trees.jpg");
var request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/documents"))
    .header("Content-Type", "image/jpg")
    .header("fileName", file.getFileName().toString())
    .header("Authorization", 
         getBasicAuthenticationHeader("admin1234","password5678"))
    .POST(HttpRequest.BodyPublishers.ofFile(file))
    .build();

HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Headers %s \n", 
    response.headers().firstValue("location"));

输出

Status 201 
Headers Optional[http://localhost:8080/api/v1/documents/3] 

文件已保存到数据库,并发现其在位置标题中返回。
在第二个示例中,控制器将主体作为字节数组。

@RestController
@RequestMapping("api/v2/documents")
public class DocumentControllerV2 {

    @PostMapping()
    ResponseEntity<Void> uploadDocument(@RequestBody byte[] data
            ,@RequestHeader("Content-Type") String type
            ,@RequestHeader("fileName") String fileName) {
    // omitted code
    }
}

在这种情况下,Bytearray的方法是完美的匹配。所需的只是将文件的内容转换为字节数组。为此,FileInputStream将完成工作。

String fileName = "C:/workspace/files/java_tutorial.pdf";
var request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:8080/api/v2/documents"))
    .header("Content-Type", "image/png")
    .header("filename", 
        fileName.substring(fileName.lastIndexOf("/")))
    .POST(HttpRequest.BodyPublishers.ofByteArray(new 
        FileInputStream(fileName).readAllBytes()))
    .build();

var response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Headers %s \n", 
    response.headers().firstValue("location"));

输出

Status 201 
Headers Optional[http://localhost:8080/api/v1/documents/4] 

finnaly,要验证新文件存储在数据库中,列表文件端点被调用。

[
  {
    "name": "PlainText.txt",
    "creationDate": "2023-03-15",
    "size": 26,
    "type": "text/plain"
  },
  {
    "name": "LinuxCommands.jpg",
    "creationDate": "2023-02-07",
    "size": 388374,
    "type": "image/jpeg"
  },
  {
    "name": "trees.jpg",
    "creationDate": "2023-04-02",
    "size": 21011905,
    "type": "image/jpg"
  },
  {
    "name": "/java_tutorial.pdf",
    "creationDate": "2023-04-02",
    "size": 1012786,
    "type": "image/png"
  }

概括

就是这样。使用Java的Core API下载和上传文件非常简单。我们必须选择合适的身体出版商或身体处理程序来发送文件内容并分别接收文件内容。

这是这个迷你系列的最后一篇文章,我们在其中研究了Java HTTP客户端API。以前的作品可以在以下链接中找到:

  1. API简介加上最常见的用例。

  2. 发送安全凭据进行身份验证

希望您喜欢阅读! Nore Java与将来的相关文章。

GitHub

上检查代码