Convert Word (.docx) to PDF in Spring Boot with docx4j – A Complete Guide

This tutorial explains how to use the pure‑Java library docx4j in a Spring Boot application to automatically convert uploaded .docx files into high‑quality PDFs, covering Maven dependencies, a utility class, controller implementation, and platform‑specific font handling for Windows and Linux.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Convert Word (.docx) to PDF in Spring Boot with docx4j – A Complete Guide

Requirement Overview

In many projects users need to upload a Word .docx file and have the backend automatically generate a PDF for download, archiving, or online preview.

Solution Choice

Among various options—commercial Aspose, heavyweight LibreOffice, and lightweight docx4j—we choose a fully open‑source, pure‑Java solution based on docx4j.

Option Comparison

docx4j is pure Java, no Office or LibreOffice installation required.

Open‑source under Apache 2.0, free for commercial use.

Good conversion quality, preserving images, tables, headers, and footers.

Easy to integrate into Spring Boot.

Solution comparison diagram
Solution comparison diagram

Adding Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-core</artifactId>
        <version>11.4.8</version>
    </dependency>

    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
        <version>11.4.8</version>
    </dependency>

    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-export-fo</artifactId>
        <version>11.4.8</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
</dependencies>

Core Utility Class: DocxToPdfUtil

Create DocxToPdfUtil.java in the utils package:

package com.donglin.utils;

import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;

import java.io.File;
import java.io.FileOutputStream;

public class DocxToPdfUtil {
    /**
     * Convert a docx file to PDF.
     * @param docxPath input file path
     * @param pdfPath  output file path
     */
    public static void convert(String docxPath, String pdfPath) {
        try {
            // 1. Load the Word document
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(docxPath));
            // 2. Configure font mapper to avoid Chinese garbled text
            Mapper fontMapper = new IdentityPlusMapper();
            PhysicalFonts.discoverPhysicalFonts();
            PhysicalFont simsun = PhysicalFonts.get("SimSun");
            if (simsun != null) {
                fontMapper.put("SimSun", simsun);
                // Common Chinese font mappings
                fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
                fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
                fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft YaHei"));
                fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
                fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
                fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
                fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
                fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
                fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
                fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
                fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
                fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
                fontMapper.put("等线", PhysicalFonts.get("SimSun"));
                fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
                fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
                fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
                fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
                fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
                fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
                fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
                fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
                fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
                fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
                fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
                // Fix "SimSun (body) / SimSun (title)" garbled issue
                PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
                PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
                wordMLPackage.setFontMapper(fontMapper);
            }
            // 3. Create output stream and perform conversion
            try (FileOutputStream os = new FileOutputStream(pdfPath)) {
                Docx4J.toPDF(wordMLPackage, os);
            }
            System.out.println("✅ PDF generated successfully: " + pdfPath);
        } catch (Exception e) {
            System.err.println("❌ Conversion failed: " + e.getMessage());
        }
    }
}

Controller Example

Create an upload endpoint in the controller package:

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.OutputStream;

@RestController
@RequestMapping("/convert")
public class FileController {
    @GetMapping("/convertToPdf")
    public void convertToPdf(@RequestParam String filePath, HttpServletResponse response) throws Exception {
        // 1. Verify file existence
        File inputFile = new File(filePath);
        if (!inputFile.exists()) {
            throw new RuntimeException("File not found: " + filePath);
        }
        // 2. Define temporary PDF path
        String pdfPath = filePath.replace(".docx", ".pdf");
        // 3. Call conversion utility
        DocxToPdfUtil.convert(filePath, pdfPath);
        // 4. Set response headers and stream PDF back
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=" + new File(pdfPath).getName());
        try (FileInputStream fis = new FileInputStream(pdfPath);
             OutputStream os = response.getOutputStream()) {
            fis.transferTo(os);
            os.flush();
        }
        // Optional: delete temporary PDF file
        new File(pdfPath).delete();
    }
}

Send a request with Postman, e.g.

GET http://localhost:8080/convertToPdf?filePath=E:/ai/report.docx

, and the service will generate a PDF with the same name.

Windows Chinese Font Fix

Map common Chinese fonts to avoid garbled characters:

fontMapper.put("SimSun", simsun);
fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft YaHei"));
fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
fontMapper.put("等线", PhysicalFonts.get("SimSun"));
fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
wordMLPackage.setFontMapper(fontMapper);
Windows font mapping
Windows font mapping

Linux Font Installation

Install Windows fonts on Linux to ensure Chinese characters render correctly.

Create Font Directory

sudo mkdir -p /usr/share/fonts/win_font

Copy Windows Font Files

Copy the font files from C:\Windows\Fonts on a Windows 10 system to /usr/share/fonts/win_font on the Linux machine.

Load Font Files

cd /usr/share/fonts/win_font
sudo mkfontscale      # generate font scale file
sudo mkfontdir        # generate font directory index
sudo fc-cache -fv    # refresh font cache

Verify Installation

fc-list :lang=zh
Linux font verification
Linux font verification

Conclusion

Use the open‑source library docx4j; no Office or LibreOffice installation required.

Preserves common styles, images, and tables.

High performance and lightweight deployment.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootPDF conversiondocx to pdfdocx4j
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.