I'm encountering an issue while attempting to convert a document to PDF using the JodConverter library in a Spring WebFlux application. Does anyone have any suggestions?
"timestamp": "2023-07-14T19:40:59.407+00:00", "status": 415, "error": "Unsupported Media Type", "trace": "org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/msword' is not supported\n\tat
Project:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.document.converter</groupId>
<artifactId>document-converter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>document-converter</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-local</artifactId>
<version>4.4.6</version>
</dependency>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-spring-boot-starter</artifactId>
<version>4.4.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Central Maven repository</id>
<name>Central Maven repository https</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- ... -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Controller
package com.document.converter.controller;
import com.document.converter.service.ConverterService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
@RestController
public class ConverterController {
private final ConverterService converterService;
private final String PDF_FORMAT = "pdf";
public ConverterController(ConverterService converterService) {
this.converterService = converterService;
}
@PostMapping(path = "/converter/v1/pdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<ResponseEntity<byte[]>> convert(@RequestPart("file") Mono<MultipartFile> filePart) {
return filePart
.publishOn(Schedulers.boundedElastic())
.flatMap(converterService::convertToPdf)
.map(convertedFile -> {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=output.pdf");
return ResponseEntity.ok()
.headers(headers)
.body(convertedFile);
});
}
}
service
package com.document.converter.service;
import org.jodconverter.core.DocumentConverter;
import org.jodconverter.core.document.DefaultDocumentFormatRegistry;
import org.jodconverter.core.document.DocumentFormat;
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.core.office.OfficeManager;
import org.jodconverter.local.LocalConverter;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@Service
public class ConverterService {
private final OfficeManager officeManager;
public ConverterService(OfficeManager officeManager) {
this.officeManager = officeManager;
}
public Mono<byte[]> convertToPdf(MultipartFile inputFile) {
return Mono.fromCallable(() -> {
final DocumentFormat conversionTargetFormat =
DefaultDocumentFormatRegistry.getFormatByExtension("pdf");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final DocumentConverter converter = LocalConverter.builder()
.officeManager(officeManager)
.build();
try (InputStream inputStream = inputFile.getInputStream()) {
converter
.convert(inputStream)
.to(outputStream)
.as(conversionTargetFormat)
.execute();
} catch (IOException | OfficeException e) {
throw new RuntimeException("Failed to convert the file.", e);
}
return outputStream.toByteArray();
}).subscribeOn(Schedulers.boundedElastic());
}
}
main class
package com.document.converter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(ServerProperties.class)
public class DocumentConverterApplication {
public static void main(String[] args) {
SpringApplication.run(DocumentConverterApplication.class, args);
}
}
application.yml
server.port: 8083
jodconverter:
local:
enabled: true
port-numbers: 2002
kill-existing-process: true
process-timeout: 250000
process-retry-interval: 1000
max-tasks-per-process: 200
task-execution-timeout: 250000
task-queue-timeout: 90000
format-options:
html:
store:
TEXT:
FilterOptions: EmbedImages
i am testing it as below using postman ,
Url http://localhost:8083/converter/v1/pdf
Method : POST
Content-Type:multipart/form-data
Detailed
any suggestions ?