[英]Upload/Download pdf file from Vue front-end to Spring Backend using Axios
在后端使用spring-boot 2.0.4,在前端使用vue 2.5.16 / axios 0.18.0,我希望將PDF文件上傳到后端數據庫,並從前端檢索它們。
最初,我從這個示例的春季部分受到啟發: https : //grokonez.com/frontend/angular/angular-6/angular-6-client-upload-files-download-files-to-mysql-with-springboot- restapis
這是Axios部分的要點: https : //gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
我的代碼如下:
使用axios在Vue中上傳文件(將this.file變量使用“ input type =“ file”“表單輸入正確設置為我的文件,AxiosService()僅用於設置正確的baseUrl並包括帶有令牌的Authorization標頭):
createRecord() { let formData = new FormData(); formData.append("file", this.file); AxiosService() .post("/commands/material/", formData, { headers: { "Content-Type": "multipart/form-data" } }) .then(response => { console.log("File uploaded"); }) .catch(error => { console.log(error); });
處理上傳的春季部分如下所示。 在我的實體中,內容字段定義為帶@Lob注釋的byte []。
@BasePathAwareController @RequestMapping("/commands/material") public class MaterialCommandHandler { @Autowired MaterialRepository MaterialRepository; @RequestMapping(method=POST, path = "/") public ResponseEntity create(@RequestParam("file") MultipartFile file){ MaterialEntity material = new MaterialEntity(); material.setName(file.getOriginalFilename()); material.setMimetype(file.getContentType()); try { material.setContent(file.getBytes()); } catch (IOException e) { e.printStackTrace(); } try { MaterialRepository.save(material); } catch (Exception e) { if (e instanceof DataIntegrityViolationException) { throw new InvalidCommandException("Data is invalid for creation."); } throw(e); } return ResponseEntity.status(HttpStatus.CREATED).body(material.getId()); }
使用此代碼,可以在數據庫中正確創建條目,mysql中的content字段為longblob類型。
定義為返回文件內容的方法:
@RequestMapping(method = GET, path = "/download/{fileId}") public ResponseEntity<byte[]> getFile(@PathVariable Long fileId) { Optional<MaterialEntity> fileOptional = materialRepository.findById(fileId); if(fileOptional.isPresent()){ FrancaisMaterialEntity file = fileOptional.get(); HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachement; filename=\\"" + file.getName() + "\\""); return ResponseEntity.ok() .headers(headers) .body(file.getContent()); } return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); }
最后,使用axios從前端發送的GET方法:
downloadFile() { AxiosService() .get(`/commands/material/download/${this.material.id}`, { responseType: "blob", }) .then(response => { console.log(response); const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement("a"); link.href = url; link.setAttribute("download", "CalculRanking.pdf"); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); }) .catch(error => { console.log(error); this.errorMessage = error.response.data.message; }); }
嘗試下載文件時,導航器中的彈出窗口正確顯示,但不幸的是,下載的.pdf文件似乎已損壞,因為Chrome指出:“錯誤無法加載PDF文檔”,我也無法在“預覽”中打開它。
我認為問題出在過程中的某個時刻,內容解釋有誤。 我做了很多研究,但沒有嘗試過的解決方案使它起作用(我嘗試過的一些事情:在值中添加值為“ application / pdf”的“ Accept”標頭,並在get請求中設置“ responseType:arrayBuffer”)我決定在這里問這個問題。 在此先感謝您的幫助。
您可以通過以下方法更改getFile
方法:
@GetMapping("/download/{fileId}")
@CrossOrigin
@ResponseBody
public ResponseEntity<InputStreamResource> getFile(@PathVariable(required = true, value = "fileId") Long fileId,
HttpServletRequest request) throws IOException {
Optional<MaterialEntity> fileOptional = materialRepository.findById(fileId);
if (ensemblesRegles.isPresent()) {
String fileName = "example.xlsx";
MediaType mediaType = MediaType.parseMediaType("application/vnd.ms-excel");
File file = new File(fileName); //the fileUtils is org.apache.commons.io.FileUtils;
FileUtils.writeByteArrayToFile(file, fileOptional.get()); // Hope that your get return a byte[] array
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
// Content-Disposition
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
// Content-Type
.contentType(mediaType)
// Contet-Length
.contentLength(file.length()) //
.body(resource);
}
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
為什么不看一下Spring Content 。 這旨在完全按照您的意圖進行操作,並將一個或多個內容對象與Spring數據實體相關聯。
要將其添加到現有的Spring Boot項目中,請執行以下操作:
的pom.xml
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-jpa-boot-starter</artifactId>
<version>0.4.0</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest-boot-starter</artifactId>
<version>0.4.0</version>
</dependency>
MaterialEntity.java
@Entity
public class MaterialEntity {
@Id
@GeneratedValue
private long id;
...other existing fields...
@ContentId
private String contentId;
@ContentLength
private long contentLength = 0L;
@MimeType
private String mimeType = "text/plain";
...
}
MaterialEntityContentStore.java
@StoreRestResource(path="materialEntityContents")
public interface MaterialEntityContentStore extends ContentStore<MaterialEntity, String> {
}
這是獲取REST端點所需要做的所有工作,這些端點將允許您存儲和檢索與每個MaterialEntity關聯的內容。 實際工作方式與Spring Data非常相似。 當您的應用程序啟動時,Spring Content將看到spring-content-jpa-boot-starter
依賴關系,並且知道您要將內容存儲在數據庫中。 然后,它將在數據庫中創建一個架構來這樣做,並注入MaterialEntityContentStore
接口的JPA實現。 它還將看到spring-content-rest-boot-starter
並將注入與內容存儲接口對話的REST端點。 意味着您不必自己執行任何此操作。
因此,例如:
curl -X POST /materialEntityContents/{materialEntityId} -F "file=@/path/to/image.jpg"
會將圖像存儲在數據庫中,並將其與ID為materialEntityId
的材料實體相關聯。
curl /materialEntityContents/{materialEntity}
會再次獲取它,依此類推...實際上也支持完整的CRUD和視頻流。
Specificially,有一個(非SpringBoot)MySQL的例子在這里 。
您還可以通過將spring-content-jpa-boot-starter
依賴項交換為適當的Spring Content Storage模塊,來決定將內容存儲在文件系統等其他位置,或在S3中。 每種存儲類型的示例在此處 。
不幸的是,在前端方面沒有任何vuejs示例,但是這里確實有一個angularjs 1.x示例。 這可能對前端有所幫助,因為它們是相似的技術(以我對兩者的有限經驗!)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.