之前文章說到了如何通過将檔案轉成圖檔或者pdf來實作線上預覽,一般來說線上預覽圖檔或者pdf都是存儲在圖檔伺服器上的,在通過接口調用把檔案傳回給前端,但是把檔案傳回給前端效果一般是有兩種:線上預覽和下載下傳。那這兩種效果分别又該怎麼實作呢?我們今天就來說這兩種效果的實作。
其實接口實作線上預覽和下載下傳很簡單,隻需要通過設定content-type和Content-Disposition這兩個http的響應标頭就可以實作:
Content-Disposition是HTTP協定中的一個頭部字段,用于訓示如何顯示附加的檔案。它是MIME協定的擴充,最初在MIME标準中定義。Content-Disposition頭部字段可以控制使用者請求所得的内容存為一個檔案的時候提供一個預設的檔案名,檔案直接在浏覽器上顯示或者在通路時彈出檔案下載下傳對話框。
在正常的 HTTP 應答中,Content-Disposition 響應标頭訓示回複的内容該以何種形式展示,是以内聯的形式(即網頁或者頁面的一部分),還是以附件的形式下載下傳并儲存到本地。
在 multipart/form-data 類型的應答消息體中,Content-Disposition 通用标頭可以被用在 multipart 消息體的子部分中,用來給出其對應字段的相關資訊。各個子部分由在 Content-Type中定義的邊界(boundary)分隔。用在消息體自身則無實際意義。
作為消息主體的标頭
在 HTTP 場景中,第一個參數有以下兩種
- inline:表示回複中的消息體會以頁面的一部分或者整個頁面的形式展示
- attchment:以附件形式被下載下傳到本地;大多數浏覽器會呈現一個“儲存為”的對話框,将 filename 的值預填為下載下傳後的檔案名,假如它存在的話
第二個參數 filename 代表被傳輸的檔案名稱(可選)
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
備注: 在同源 URL情況下,Chrome 和 Firefox 82 以及更高的版本會優先使用 HTML 的 元素的 download 屬性而不是 Content-Disposition: inline 參數來處理下載下傳。而 Firefox 的早期版本則優先使用标頭資訊并内聯顯示内容。
作為多部分主體的标頭
當使用 multipart/form-data 格式送出表單資料(HTTP 表單及 POST 請求)時,每個子部分(例如每個表單字段和任何與字段資料相關的檔案)都需要提供一個 Content-Disposition 标頭,以提供相關資訊。标頭的第一個參數始終為 form-data,并且還必須包含一個 name 參數來辨別相關字段。,以及可選的第三個參數 filename 。
Content-Disposition: form-data; name="fieldName"
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"
下面将通過代碼示範通過設定content-type響應标頭來實作圖檔、pdf的線上預覽和下載下傳,為傳回的代碼基本一樣是以封裝了一個公共方法,後面代碼将通過調用這個公共方法來示範:
所用到的工具類代碼:
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class HttpUtil {
public static ResponseEntity<?> getResponseEntity(byte[] fileContent, String contentDispositionType, String originalFileName){
ResponseEntity.BodyBuilder responseEntity = ResponseEntity.ok();
HttpHeaders httpHeaders = new HttpHeaders();
Tika tika = new Tika();
String mediaType = tika.detect(fileContent);
httpHeaders.setContentType(MediaType.parseMediaType(mediaType));
httpHeaders.setContentDisposition(ContentDisposition.builder(contentDispositionType)
.filename(URLEncoder.encode(originalFileName)).build());
httpHeaders.setCacheControl(CacheControl.noCache());
//httpHeaders.setCacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES));
return responseEntity.headers(httpHeaders).body(fileContent);
}
}
1、圖檔預覽:
@GetMapping(value = "/image/review")
public ResponseEntity<?> imageReview() throws IOException {
File file = new File("D:\\picture\\美女\\aa37a7be4196c07f43a3f776801d1b46.jpg");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
return HttpUtil.getResponseEntity(buf, "inline", "aa37a7be4196c07f43a3f776801d1b46.jpg");
}
}
實作效果:
2、圖檔下載下傳:
@GetMapping(value = "/image/down")
public ResponseEntity<?> imageDown() throws IOException {
File file = new File("D:\\picture\\美女\\aa37a7be4196c07f43a3f776801d1b46.jpg");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
return HttpUtil.getResponseEntity(buf, "attachment", "aa37a7be4196c07f43a3f776801d1b46.jpg");
}
}
實作效果:
3、pdf預覽:
@GetMapping(value = "/pdf/review")
public ResponseEntity<?> pdfReview() throws IOException {
File file = new File("D:\\書籍\\電子書\\其它\\自然哲學的數學原理.pdf");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
return HttpUtil.*getResponseEntity(buf, "inline", file.getName());
}
}
實作效果:
4、pdf下載下傳:
@GetMapping(value = "/pdf/down")
public ResponseEntity<?> pdfDown() throws IOException {
File file = new File("D:\\書籍\\電子書\\其它\\自然哲學的數學原理.pdf");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
return HttpUtil.getResponseEntity(buf, "" +
""
, file.getName());
}
}
實作效果: