Выгрузка / загрузка pdf-файла из внешнего интерфейса Vue в Spring Backend с помощью Axios - PullRequest
0 голосов
/ 30 ноября 2018

Используя spring-boot 2.0.4 в моем бэк-энде и vue 2.5.16 / axios 0.18.0 в моем фронт-энде, я ищу, чтобы загрузить PDF-файлы в мою базу данных и извлечь их из моегоfront-end.

Изначально я вдохновлялся этим примером для пружинной части: 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

Мой кодвыглядит следующим образом:

  • Загрузка файла в Vue с помощью axios (переменная this.file правильно установлена ​​для моего файла с помощью ввода формы "input type =" file "", AxiosService ()просто используется для установки правильного baseUrl и включения заголовка авторизации с токеном):

    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.

    @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 имеет тип 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);
    }
    
  • Наконец метод GET, отправленный из внешнего интерфейса с помощью axios:

    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-документ ", и я не могу открыть его в Preview, а также.

Я думаю, что проблемы возникают из-за неправильной интерпретации содержимого в какой-то момент в процессе.Я провел много исследований, но ни одно из решений, которые я пробовал, не сработало (некоторые вещи, которые я пробовал: добавление заголовка «Accept» со значением «application / pdf» и установка «responseType: arrayBuffer» в запросе get), такЯ решил задать этот вопрос здесь.Заранее спасибо за помощь.

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

Почему бы вам не взглянуть на 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 и будет знать, что вы хотите хранить контент в своей базе данных.Затем он создаст схему в БД для этого, а также внедрит реализацию JPA интерфейса MaterialEntityContentStore.Он также увидит spring-content-rest-boot-starter и введет конечные точки REST, которые взаимодействуют с интерфейсом хранилища контента.Это означает, что вам не нужно ничего делать самостоятельно.

Так, например:

curl -X POST /materialEntityContents/{materialEntityId} -F "file=@/path/to/image.jpg"

сохранит изображение в базе данных и свяжет его с материальным объектом с идентификатором materialEntityId.

curl /materialEntityContents/{materialEntity}

будет извлекать его снова и так далее ... фактически поддерживает полную CRUD и потоковую передачу видео.

В частности, есть (не SpringBoot) пример MySQL здесь .

Вы также можете решить хранить содержимое в другом месте, например, в файловой системе или на S3, поменяв зависимость spring-content-jpa-boot-starter для соответствующего модуля Spring Content Storage.Примеры для каждого типа хранилища: здесь .

Во внешнем виде, к сожалению, нет примеров vuejs, но у нас есть пример angularjs 1.x здесь ,Это может помочь с интерфейсом, так как они являются похожими технологиями (в моем ограниченном опыте с обоими!).

0 голосов
/ 30 ноября 2018

Не могли бы вы изменить свой метод 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...