You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2020/02/13 03:39:48 UTC

[servicecomb-docs] branch master updated: [SCB-1666] improve documents for file uploading / downloading

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-docs.git


The following commit(s) were added to refs/heads/master by this push:
     new 8116e1b  [SCB-1666] improve documents for file uploading / downloading
8116e1b is described below

commit 8116e1b3f89239877b38831f571a7add422ff5b0
Author: liubao <bi...@qq.com>
AuthorDate: Thu Feb 13 11:34:01 2020 +0800

    [SCB-1666] improve documents for file uploading / downloading
---
 .../en_US/docs/config/general-config.md            |   1 +
 .../en_US/docs/start/first-sample.md               |   1 +
 .../zh_CN/docs/config/general-config.md            |   1 +
 .../docs/general-development/file-download.md      | 104 ++++++-----
 .../zh_CN/docs/general-development/file-upload.md  | 193 +++++++++++++++------
 .../docs/general-development/upload-download.md    |  12 ++
 .../zh_CN/docs/start/first-sample.md               |   1 +
 java-chassis-reference/zh_CN/mkdocs.yml            |   3 +-
 8 files changed, 217 insertions(+), 99 deletions(-)

diff --git a/java-chassis-reference/en_US/docs/config/general-config.md b/java-chassis-reference/en_US/docs/config/general-config.md
index 072ba1e..dc84d85 100644
--- a/java-chassis-reference/en_US/docs/config/general-config.md
+++ b/java-chassis-reference/en_US/docs/config/general-config.md
@@ -3,6 +3,7 @@
 ## Configuration source hierarchical relationship
 
 ServiceComb provides a hierarchical configuration mechanism. According to the priority, it is divided as below(the former is higher):
+
 * Configuration Center (dynamic configuration)
 * Java System Property (-D parameter)
 * Environmental variables
diff --git a/java-chassis-reference/en_US/docs/start/first-sample.md b/java-chassis-reference/en_US/docs/start/first-sample.md
index 9fb06e6..8e67809 100644
--- a/java-chassis-reference/en_US/docs/start/first-sample.md
+++ b/java-chassis-reference/en_US/docs/start/first-sample.md
@@ -1,6 +1,7 @@
 # Develop the first microservice
 
 Before you start, developers need to choose a familiar development method. There are currently 3 ways to choose:
+
 * Spring MVC
 * JaxRS
 * RPC
diff --git a/java-chassis-reference/zh_CN/docs/config/general-config.md b/java-chassis-reference/zh_CN/docs/config/general-config.md
index 33fcaf9..85d85cf 100644
--- a/java-chassis-reference/zh_CN/docs/config/general-config.md
+++ b/java-chassis-reference/zh_CN/docs/config/general-config.md
@@ -3,6 +3,7 @@
 ## 配置源层级
 
 ServiceComb提供了分层次的配置机制。按照优先级从高到低,分为:
+
 * 配置中心(动态配置)
 * Java System Property(-D参数)
 * 环境变量
diff --git a/java-chassis-reference/zh_CN/docs/general-development/file-download.md b/java-chassis-reference/zh_CN/docs/general-development/file-download.md
index 947ffb5..661b663 100644
--- a/java-chassis-reference/zh_CN/docs/general-development/file-download.md
+++ b/java-chassis-reference/zh_CN/docs/general-development/file-download.md
@@ -1,24 +1,37 @@
-文件下载,当前在vertx rest通道和servlet rest中可用。
+# 文件下载开发指导
 
-# 一、Producer
+## 服务提供者开发
 
-## 1.下载普通文件
+文件下载支持采用 Spring MVC 和 Jax RS 开发。 因为文件下载都是 GET 方法, 因此两者的使用差异很小, 这里的例子只提供
+Spring MVC 。 
+
+* File
+
+最简单的例子,接口的返回参数声明为 File 类型的参数, 即可定义一个下载接口。 
 
 ```
-return new File(......);
+@GetMapping(path = "/file")
+public File file(String name)
 ```
 
-## 2.下载临时文件
+* Part
 
-本场景下,需要根据请求参数动态创建临时文件,下载完成后,需要将临时文件删除
+如果需要根据请求参数动态创建临时文件,下载完成后,将临时文件删除,可以采用 Part 类型的参数。
 
 ```
-return new FilePart(file).setDeleteAfterFinished(true);
+@GetMapping(path = "/file")
+public Part file(String content) throws IOException {
+File file = createTempFile(content);
+return new FilePart(null, file)
+    .setDeleteAfterFinished(true)
+    .setSubmittedFileName("test.txt");
+}
 ```
 
-## 3.下载org.springframework.core.io.Resource
+* Resource
 
-因为resource不一定表示文件下载,所以需要通过swagger annotation(@ApiResponse)标识这是一个文件下载场景
+可以将接口声明为 org.springframework.core.io.Resource。 由于resource不一定表示文件下载,所以需要通过
+@ApiResponse 标识这是一个文件下载场景
 
 以ByteArrayResource为例说明:
 
@@ -28,7 +41,6 @@ return new FilePart(file).setDeleteAfterFinished(true);
   @ApiResponse(code = 200, response = File.class, message = "")
 })
 public Resource resource() {
-  ……
   return new ByteArrayResource(bytes) {
     @Override
     public String getFilename() {
@@ -38,7 +50,8 @@ public Resource resource() {
 }
 ```
 
-上例中,因为ByteArrayResource没有文件名的概念,所以需要实现Resource的getFilename方法,也可以通过ResponseEntity进行包装:
+上例中,因为ByteArrayResource没有文件名的概念,所以需要实现Resource的getFilename方法,也可以通过ResponseEntity
+进行包装:
 
 ```
 @GetMapping(path = "/resource")
@@ -46,7 +59,6 @@ public Resource resource() {
   @ApiResponse(code = 200, response = File.class, message = "")
 })
 public ResponseEntity<Resource> resource() {
-  ……
   return ResponseEntity
       .ok()
       .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
@@ -55,11 +67,10 @@ public ResponseEntity<Resource> resource() {
 }
 ```
 
-## 4.下载InputStream
+* InputStream
 
-因为InputStream不一定表示文件下载,所以需要通过swagger annotation(@ApiResponse)标识这是一个文件下载场景
+一样的, 使用 InputStream 需要 @ApiResponse 标识这是一个文件下载场景
 
-有的场景下,资源并不保存在本地
 ```
 return ResponseEntity
     .ok()
@@ -68,9 +79,9 @@ return ResponseEntity
     .body(stream);
 ```
 
-在下载完成后,ServiceComb会自动关闭stream,开发人员不必再关注
+在下载完成后,ServiceComb会自动关闭stream,开发人员不必再关注。
 
-## 5.文件类型判定
+* 文件类型判定
 
 只要没有通过ResponseEntity直接设置HttpHeaders.CONTENT\_TYPE,ServiceComb都会尝试通过File、Part、Resource中的文件名后缀进行自动判定。
 
@@ -78,7 +89,7 @@ ServiceComb使用java的mime type机制进行文件类型判定,如果业务
 
 如果这不满足要求,假设文件后缀为xyz,期望文件类型为application/file-xyz,以下方式任选一种均可解决:
 
-### 1)通过Java的mime type机制扩展
+   1. 通过Java的mime type机制扩展
 
 在META-INF目录下,创建mime.types文件,其内容为:
 
@@ -86,22 +97,38 @@ ServiceComb使用java的mime type机制进行文件类型判定,如果业务
 application/file-xyz xyz
 ```
 
-### 2)在业务代码中通过Part指定
+    2. 在业务代码中通过Part指定
 
 ```
-return new FilePart(null, file).contentType("application/file-xyz");
+@GetMapping(path = "/tempFilePart")
+public Part tempFilePart(String content) throws IOException {
+File file = createTempFile(content);
+
+return new FilePart(null, file)
+    .setDeleteAfterFinished(true)
+    .contentType("application/file-xyz")
+    .setSubmittedFileName("tempFilePart.txt");
+}
+
 ```
 
-### 3)在业务代码中通过ResponseEntity指定
+    3. 在业务代码中通过ResponseEntity指定
 
 ```
-return ResponseEntity
-    .ok()
-    .header(HttpHeaders.CONTENT_TYPE, "application/file-xyz")
-    .body(……);
+@GetMapping(path = "/tempFileEntity")
+public ResponseEntity<Part> tempFileEntity(String content) throws IOException {
+    File file = createTempFile(content);
+    
+    return ResponseEntity
+        .ok()
+        .header(HttpHeaders.CONTENT_TYPE, "application/file-xyz")
+        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt")
+        .body(new FilePart(null, file)
+            .setDeleteAfterFinished(true));
+}
 ```
 
-## 6.文件名
+* 指定文件名
 
 只要没有通过ResponseEntity直接设置HttpHeaders.CONTENT\_DISPOSITION,ServiceComb都会尝试通过File、Part、Resource中的文件名生成HttpHeaders.CONTENT\_DISPOSITION,假设文件名为file.txt,则生成的数据如下:
 
@@ -113,11 +140,12 @@ Content-Disposition: attachment;filename=file.txt;filename*=utf-8’’file.txt
 
 如果业务代码中直接设置Content-Disposition,需要自行处理多浏览器支持的问题。
 
-# 二、Consumer
+文件下载的更多用法可以通过下载 java-chassis 源码, 查看 DownloadSchema 里面的例子。
 
-消费端统一使用org.apache.servicecomb.foundation.vertx.http.ReadStreamPart处理文件下载。
+## 服务消费者开发
 
-## 1.透明RPC
+消费者统一使用 org.apache.servicecomb.foundation.vertx.http.ReadStreamPart 处理文件下载。
+可以使用透明 RPC 方式, 
 
 ```
 public interface ……{
@@ -126,16 +154,12 @@ public interface ……{
 }
 ```
 
-## 2.RestTemplate
-
-以get为例:
+或者 RestTemplate
 
 ```
 ReadStreamPart part = restTemplate.getForObject(url, ReadStreamPart.class);
 ```
 
-## 3.从ReadStreamPart读取数据
-
 ReadStreamPart提供了一系列方法,将数据流保存为本地数据:
 
 ```
@@ -145,13 +169,9 @@ org.apache.servicecomb.foundation.vertx.http.ReadStreamPart.saveToFile(String)
 org.apache.servicecomb.foundation.vertx.http.ReadStreamPart.saveToFile(File, OpenOptions)
 ```
 
-注意:
+***注意:***
 
 * 在得到ReadStreamPart实例时,并没有完成文件内容的下载,调用save系列方法才开始真正从网络上读取文件数据。
-
-* 如果使用saveAsBytes、saveAsString,数据是直接保存在内存中的,如果下载的文件很大,会内存撑爆的风险。
-
-* save系列方法,返回的都是CompletableFuture对象:
-
-  * 如果要阻塞等待下载完成,通过future.get\(\)即可
-  * 如果通过future.whenComplete进行异步回调处理,要注意回调是发生在网络线程中的,此时需要遵守reactive的线程规则。
+* 如果使用saveAsBytes、saveAsString,数据是直接保存在内存中的,如果下载的文件很大,会导致内存溢出。
+* save系列方法,返回的都是CompletableFuture对象, 如果要阻塞等待下载完成,通过future.get\(\)即可;
+ 如果通过future.whenComplete进行异步回调处理,要注意回调是发生在网络线程中的,此时需要遵守reactive的线程规则。
diff --git a/java-chassis-reference/zh_CN/docs/general-development/file-upload.md b/java-chassis-reference/zh_CN/docs/general-development/file-upload.md
index 8a83cf9..f404542 100644
--- a/java-chassis-reference/zh_CN/docs/general-development/file-upload.md
+++ b/java-chassis-reference/zh_CN/docs/general-development/file-upload.md
@@ -1,82 +1,103 @@
-文件上传,当前支持在vertx rest通道和servlet rest中使用。
+# 文件上传开发指导
 
-文件上传使用标准的http form格式,可与浏览器的上传直接对接。
+## 服务提供者开发
+服务提供者可以采用Spring MVC 或者 Jax RS定义上传接口。
 
-## Producer:
-支持jaxrs和springmvc开发模式
+* 采用Spring MVC
 
-jaxrs开发模式:
-* 支持servlet定义的javax.servlet.http.Part类型
-
-* 可以直接使用@FormParam传递文件类型及普通参数
-
-springmvc开发模式:
-
-* 支持servlet定义的javax.servlet.http.Part类型,也支持org.springframework.web.multipart.MultipartFile类型
+```java
+@PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, 
+  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+public String fileUpload(@RequestPart(name = "file") MultipartFile file)
 
-* 两种数据类型功能是一致的,MultipartFile的底层也是Part
+@PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, 
+  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+public String fileUpload(@RequestPart(name = "file") Part file)
+```
 
-* 两种数据类型可以混合使用,比如第一个参数是Part,第二个参数是MultipartFile
+文件上传需要通过 @RequestPart 声明参数,参数类型支持 servlet 定义的 javax.servlet.http.Part 类型,也支持
+org.springframework.web.multipart.MultipartFile 类型,两种数据类型功能是一致的,MultipartFile 的底
+层也是Part。  两种数据类型可以混合使用,比如第一个参数是Part,第二个参数是MultipartFile。 除了通过
+定义多个参数的方式上传多个文件,也可以通过List或者数组的方式声明上传多个文件。
 
-* 可以直接使用@RequestPart传递文件类型及普通参数
+```java
+@PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, 
+  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+public String fileUpload(@RequestPart(name = "files")  List<MultipartFile> files)
 
-注意:
+@PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, 
+  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+public String fileUpload(@RequestPart(name = "files") MultipartFile[] files)
+```
 
-* 先配置文件上传临时目录,默认为null不支持文件上传,文件上传请求Content-Type必须为multipart/form-data
+可以通过@RequestAttribute获取其他额外信息。
 
-* 同名参数只支持一个文件
+```java
+@PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, 
+  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+public String fileUpload(@RequestPart(name = "files")  List<MultipartFile> files,
+     @RequestAttribute("message") String message)
+```
 
-* 支持一次传输多个不同参数名的文件
+Spring MVC方式定义上传接口还有其他很多方式,可以下载java-chassis源码,并查看UploadSpringmvcSchema里面的示例。
 
-* 通过MultipartFile或Part打开流后,记得关闭,否则上传的临时文件会无法删除,最终导致上传临时目录被撑爆
 
-Springmvc模式下的代码样例:
+* 采用Jax RS
 
 ```java
-@PostMapping(path = "/upload", consumes = MediaType.MULTIPART_FORM_DATA)
-public String fileUpload(@RequestPart(name = "file1") MultipartFile file1, @RequestPart(name = "file2") Part file2, @RequestPart String param1) {
-  ……
-}
+@Path("/fileUpload")
+@POST
+@Produces(MediaType.TEXT_PLAIN)
+public String fileUpload(@FormParam(name = "file") Part file)
 ```
 
-### 配置说明:
+文件上传需要通过 @FormParam 声明参数,参数类型支持servlet定义的javax.servlet.http.Part类型。除了通过
+定义多个参数的方式上传多个文件,也可以通过List或者数组的方式声明上传多个文件。
 
-| 配置项 | 默认值 | 取值范围 | 含义 |
-| :--- | :--- | :--- | :--- |
-| servicecomb.uploads.directory | null |  | 上传的临时文件保存在哪个目录,**默认值null表示不支持文件上传** |
-| servicecomb.uploads.maxSize | -1 |  | http body的最大允许大小,单位byte,默认值-1表示无限制 |
-
-## Consumer:
-
-支持以下数据类型:
-
-* java.io.File
+```java
+@Path("/fileUpload")
+@POST
+@Produces(MediaType.TEXT_PLAIN)
+public String fileUpload(@FormParam(name = "files") List<Part> files)
+
+@Path("/fileUpload")
+@POST
+@Produces(MediaType.TEXT_PLAIN)
+public String fileUpload(@FormParam(name = "files") Part[] files)
+```
 
-* javax.servlet.http.Part
+可以通过@FormParam获取其他额外信息。
 
-* java.io.InputStream
+```java
+@Path("/fileUpload")
+@POST
+@Produces(MediaType.TEXT_PLAIN)
+public String fileUpload(@FormParam(name = "files") List<Part> files,
+    @FormParam("message") String message)
+```
 
-* org.springframework.core.io.Resource
+Jax RS 方式定义上传接口还有其他很多方式,可以下载java-chassis源码,并查看 UploadJaxrsSchema 里面的示例。
 
-使用InputStream时,因为是流的方式,此时没有客户端文件名的概念,所以producer获取客户端文件名会得到null
+* 业务开发注意事项
+   
+   通过MultipartFile或Part打开流后,记得关闭,否则上传的临时文件会无法删除,导致资源泄露和磁盘空间耗尽。
 
-如果既要使用内存数据,又想让producer可以获取客户端文件名,可以使用resource类型,继承org.springframework.core.io.ByteArrayResource,且override getFilename即可。
+## 开发服务消费者
 
-### 透明RPC代码样例:
+可以使用透明 RPC 
 
 ```java
-interface UploadIntf {
-  String upload(File file);
-}
-```
+ interface UploadIntf {
+   String upload(File file);
+ }
 
-获得接口引用后,直接调用即可:
+ @RpcReference(microserviceName = "name", schemaId = "schema")
+ UploadIntf uploadIntf;
 
-```java
-String result = uploadIntf.upload(file);
+ String result = uploadIntf.upload(file);
 ```
 
-### RestTemplate代码样例:
+或者 RestTemplate 进行文件上传。 
 
 ```java
 Map<String, Object> map = new HashMap<>();
@@ -84,10 +105,72 @@ map.put("file", new FileSystemResource("a file path!"));
 map.put("param1", "test");
 HttpHeaders headers = new HttpHeaders();
 headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA);
-HttpEntity<Map<String, Object>> entry = new HttpEntity<>(map, headers);
+HttpEntity<Map<String, Object>> entity = new HttpEntity<>(map, headers);
+
+String reseult = template.postForObject(url, entity, String.class);
+```
+
+服务消费者不区分服务提供者是 Spring MVC 或者 Jax RS。 在使用透明 RPC 或者 RestTemplate 的时候, 可以使用如下类型
+与服务提供者的文件对应: 
+
+* java.io.File
+* javax.servlet.http.Part
+* java.io.InputStream
+* org.springframework.core.io.Resource
+
+使用InputStream时,因为是流的方式,此时没有客户端文件名的概念,服务提供者获取到的文件名为null。 
+如果既要使用内存数据,又想让producer可以获取客户端文件名,可以使用resource类型,继承
+org.springframework.core.io.ByteArrayResource,且需要实现 getFilename 方法。
+
+一样的,服务消费者还有其他灵活的使用方式,可以下载 java-chassis 代码查看调用示例。
+
+## 使用浏览器上传文件
 
-String reseult = template.postForObject(
-    url,
-    entry,
-    String.class);
+浏览器通过Form的方式上传文件,下面是一个简单的HTML 和 JS 示例
+
+```html
+<form id="upload_form" method="POST">
+    <p>
+        File Name: <input type="file" name="fileName"/>
+    </p>
+    <p>
+        <input type="button" value="Upload" onclick="uploadAction()">
+    </p>
+</form>
+```
+
+事件处理:
+
+```
+function uploadAction() {
+     var formData = new FormData(document.getElementById("upload_form"));
+
+     $.ajax({
+        type: 'POST',
+        url: "/api/file-service/upload",
+        data: formData,
+        processData:false,
+        contentType:false,
+        success: function (data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Upload Successfully, file id=" + data;
+            error.hidden=false;
+        },
+        error: function(data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Upload failed";
+            error.hidden=false;
+        },
+        async: true
+    });
 ```
+
+## 配置参数说明
+
+| 配置项 | 默认值 | 取值范围 | 含义 |
+| :--- | :--- | :--- | :--- |
+| servicecomb.uploads.directory | null |  | 上传的临时文件保存在哪个目录,**默认值null表示不支持文件上传** |
+| servicecomb.uploads.maxSize | -1 |  | http body的最大允许大小,单位byte,默认值-1表示无限制 |
+
diff --git a/java-chassis-reference/zh_CN/docs/general-development/upload-download.md b/java-chassis-reference/zh_CN/docs/general-development/upload-download.md
new file mode 100644
index 0000000..16a3422
--- /dev/null
+++ b/java-chassis-reference/zh_CN/docs/general-development/upload-download.md
@@ -0,0 +1,12 @@
+通过浏览器上传下载文件,是非常普遍的应用场景。java-chassis基于REST提供了上传下载功能:
+
+* 在定义服务提供者的时候,只允许采用Spring MVC 或者 Jax RS模式。 开发服务消费者不受限制,可以使用透明RPC或者RestTemplate。
+* 在定义通信模型的时候,只允许使用REST over Vert.x 或者 REST over Servlet,不能够使用HIGHWAY协议。
+* 上传下载文件功能默认是关闭的。需要配置servicecomb.uploads.directory启用,如果通过边缘服务(Edge Service)转发请求,边缘服务也需要这个配置项。
+* 通过HTTP FORM的方式上传文件(一般采用POST);通过GET下载文件。
+
+本章节包含如下内容:
+
+* [文件上传开发指导](file-upload.md)
+* [文件下载开发指导](file-download.md)
+
diff --git a/java-chassis-reference/zh_CN/docs/start/first-sample.md b/java-chassis-reference/zh_CN/docs/start/first-sample.md
index bdd0d37..a348091 100644
--- a/java-chassis-reference/zh_CN/docs/start/first-sample.md
+++ b/java-chassis-reference/zh_CN/docs/start/first-sample.md
@@ -1,6 +1,7 @@
 # 开发第一个微服务
 
 开始之前,开发者需要选择熟悉的开发方式,目前有3种方式可供选择:
+
 * Spring MVC
 * JaxRS
 * POJO
diff --git a/java-chassis-reference/zh_CN/mkdocs.yml b/java-chassis-reference/zh_CN/mkdocs.yml
index c5c1324..fc09ef5 100644
--- a/java-chassis-reference/zh_CN/mkdocs.yml
+++ b/java-chassis-reference/zh_CN/mkdocs.yml
@@ -47,8 +47,7 @@ nav:
     - 自定义调用链打点: general-development/customized-tracing.md
     - 本地开发和测试: general-development/local-develop-test.md
     - Http Filter: general-development/http-filter.md
-    - 文件上传: general-development/file-upload.md
-    - 文件下载: general-development/file-download.md
+    - 文件上传下载: general-development/upload-download.md
     - Reactive: general-development/reactive.md
     - DNS自定义配置: general-development/dnsconfig.md
     - 代理设置: general-development/dai-li-she-zhi.md