簡體   English   中英

使用Axios將Vue前端的pdf文件上傳/下載到Spring Backend

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM