使用Java动态数据生成PDF报告:简化您的报告导出流程

在当今的数据驱动世界中,能够快速且有效地将数据转化为可视化的报告是一项宝贵的技能。无论是商业分析、项目管理还是学术研究,PDF报告都是分享和存档信息的理想格式。在这篇博客中,我们将探讨如何使用Java编程语言结合iText库来动态生成包含动态数据的PDF报告。


为什么选择Java和iText?

Java作为一种广泛使用的编程语言,以其强大的功能和跨平台兼容性而闻名。iText是一个流行的Java库,专门用于处理PDF文档的创建和操作。通过结合这两者,我们可以轻松构建复杂、定制化的PDF报告,这些报告可以根据实时数据进行更新。

准备工作

在开始之前,请确保你的开发环境中已安装以下工具:

  • JDK(Java Development Kit)
  • 一个IDE(如IntelliJ IDEA或Eclipse)
  • Maven或Gradle(用于依赖管理)

还需要添加iText库作为项目的依赖项。对于Maven项目,可以在pom.xml文件中添加如下依赖:

1、引入Maven

        
	    dependency>
			org.freemarker
			freemarker
			2.3.30
		
		
		
			com.itextpdf
			itext7-core
			7.1.16
			pom
		
		
		
			com.itextpdf
			html2pdf
			3.0.1
		

2、创建templates文件存放模版:位置 src/main/resources/templates/invoice.html

下面是一个简单的例子,演示了如何从HTML模板生成PDF报告,并自动填充动态数据。




    ${user[0].name}-测评报告
    




测试演示demo
测评报告

姓名:${user[0].name} 性别:${user[0].sex} 年龄:${user[0].age}岁

<#list listScore as score>
姓名 年龄 性别
${score.name!} ${score.age!'-'} ${score.sex!'-'}
测评结果:
测试很好已完成
结果提示*:
没啥大事,多喝水就行

*本报告结果仅供临床参考,不作为诊断依据,需经专科医师明确诊断。

  测评者:长伞大师 报告时间:20220418

3、创建项目fonts文件存放字体:将本地字体C:\Windows\Fonts\宋体 复制到src/main/resources/fonts/STSONG.TTF

使用Java动态数据生成PDF报告:简化您的报告导出流程_第1张图片

4、上代码HTML转PDF生成


import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.layout.font.FontProvider;
import com.mdnov.ciipweb.examinfo.controller.SysExamController;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@Service
public class PdfGeneratorService {

    /**
     * 解析 FreeMarker 模板并生成 PDF
     */
    public byte[] generatePdf(String templateName, Map data) throws IOException, TemplateException {
        // 解析 HTML
        String htmlContent = parseTemplate(templateName, data);
        return itexConvertHtmlToPdf(htmlContent);
    }

    /**
     * 解析 FreeMarker 模板,返回 HTML 字符串
     */
    private String parseTemplate(String templateName, Map data) throws IOException, TemplateException {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
        cfg.setClassForTemplateLoading(SysExamController.class, "/templates");
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        Template template = cfg.getTemplate(templateName);
        try (StringWriter stringWriter = new StringWriter()) {
            template.process(data, stringWriter);
            return stringWriter.toString();
        }
    }

    /**
     * 将 HTML 转换为 PDF
     */
    public byte[] itexConvertHtmlToPdf(String html) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 创建PdfWriter实例
            PdfWriter writer = new PdfWriter(outputStream);
            // 创建PdfDocument实例并设置页面大小
            PdfDocument pdfDocument = new PdfDocument(writer);
            pdfDocument.setDefaultPageSize(PageSize.A4);

            // 加载支持中文的字体, 例如SIMSUNB.TTF
            URL fontUrl = getClass().getResource("/fonts/STSONG.TTF");
            if (fontUrl == null) {
                throw new IOException("字体文件未找到: /fonts/STSONG.TTF");
            }

            // 使用字体URL创建PdfFont
            PdfFont font = PdfFontFactory.createFont(fontUrl.toExternalForm(), "Identity-H", true);

            // 设置ConverterProperties并指定字体
            ConverterProperties converterProperties = new ConverterProperties();
            FontProvider fontProvider = new FontProvider();
            fontProvider.addFont(fontUrl.toExternalForm(), "Identity-H");
            converterProperties.setFontProvider(fontProvider);

            // 使用HtmlConverter将HTML转换为PDF,并应用字体
            HtmlConverter.convertToPdf(new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)), pdfDocument, converterProperties);

            // 关闭PdfDocument对象
            pdfDocument.close();

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace(); // 更好的错误处理方式
            throw e; // 或者根据需要处理异常
        }
    }

}

5、开放接口调用

 (1) 将service注入到要调用的业务文件中

    
    private final PdfGeneratorService pdfGeneratorService;


	@Autowired
	public SysExamController(PdfGeneratorService pdfGeneratorService) {
		this.pdfGeneratorService = pdfGeneratorService;
	}

(2)开始写对应接口逻辑:下面是模拟的参数,具体参数根据业务随便查询数据库也行

   /**
	 * html生成PDF
	 * @description TODO
	 * @author 大博士.J
	 * @date 2023/4/18 15:01
	 */
	@RequestMapping(value="/exportPdf")
	public ResponseEntity exportHtmlPdf(String examId) throws IOException, TemplateException {
		List>  listScore = new ArrayList<>();
		Map data = new HashMap<>();
		data.put("name","张三");
		data.put("age","15");
		data.put("sex","女");
		listScore.add(data);
		data.put("name","李四");
		data.put("age","13");
		data.put("sex","男");
		listScore.add(data);
 		Map dataModel = new HashMap<>();
		dataModel.put("user", listScore);
		dataModel.put("listScore", listScore);
		// 生成 PDF 字节流
		byte[] pdfBytes = pdfGeneratorService.generatePdf("ExportAssessReport.html", dataModel);

		// 动态设置文件名
		String fileName = listScore.get(0).get("name") + "-测评报告.pdf";

		// 设置 HTTP 头,返回 PDF 文件
		HttpHeaders headers = new HttpHeaders();
		// 对于不支持filename*的老浏览器提供一个基本的filename
        // Content-Disposition:attachment直接下载 inline 预览
		headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()).replace("+", "%20"));
		// 使用filename*提供UTF-8编码的文件名
		headers.add(HttpHeaders.CONTENT_DISPOSITION + ";**filename**", "filename*=utf-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()).replace("+", "%20"));
		headers.setContentType(MediaType.APPLICATION_PDF);

		// 返回带有自定义文件名的PDF文件
		ByteArrayInputStream bis = new ByteArrayInputStream(pdfBytes);
		InputStreamResource resource = new InputStreamResource(bis);

		return new ResponseEntity<>(resource, headers, HttpStatus.OK);
	}

6、我简单的写了一个按钮调用

 


//导出PDF
function exportPdf(examId){
	var url = "${pageContext.request.contextPath}/sysmanage/sysexam/exportHtmlPdf?examId=" + examId ;
		window.open(url);
}

7、测试成功:样式虽然难看,但你在HTML模版中可以自己写一下css这样生成的pdf更好看

使用Java动态数据生成PDF报告:简化您的报告导出流程_第2张图片

总结

通过上述步骤,你可以轻松地使用Java和iText库来动态生成包含实时数据的PDF报告。这种方法不仅提高了工作效率,还增强了报告的专业性和可读性。希望这篇博客能帮助你在自己的项目中实现类似的功能。如果你有任何问题或需要进一步的帮助,请随时留言讨论!

 

你可能感兴趣的:(java,html,pdf)