java集成itextpdf实现通过pdf模板填充数据生成pdf

文章目录

  • 一、制作pdf模板
    • 1.1、使用excel制作一个表格
    • 1.2、转成pdf
    • 1.3、设置表单域
    • 1.4、最终模版效果
  • 二、引入POM依赖
  • 三、代码实现
    • 3.1、工具类
    • 3.2、实体对象
    • 3.3、Controller

一、制作pdf模板

1.1、使用excel制作一个表格

1.2、转成pdf

我采用的是pdfelement 官网地址需要付费或者自行破解,也可以使用其他pdf编辑器。

1.3、设置表单域

1.4、最终模版效果

二、引入POM依赖

<!--pdf处理-->
 <dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itextpdf</artifactId>
     <version>5.5.13</version>
 </dependency>
 <dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itext-asian</artifactId>
     <version>5.2.0</version>
 </dependency>

三、代码实现

将制作好的pdf模板放入项目resources/pdf目录下,如图

3.1、工具类

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.ResourceUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * pdf相关工具类
 * 注意事项:
 * 1、时间类型需要转成字符串
 * 2、只支持对象嵌对象,两层结构;对象嵌对象再嵌对象,第三层对象无法解析,如果遇到这种情况需要写成递归或解析第三次。
 *
 * @author zero
 */
@Slf4j
public class PdfUtil {

    private static boolean isPrimitiveOrWrapper(Class<?> clazz) {
        return clazz.isPrimitive() || clazz.getName().startsWith("java.lang");
    }

    private static Map<String, String> turnMap(Object object) {
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(object);
        Map<String, String> map = new HashMap<>(stringObjectMap.size() * 2);
        // 打印输出属性名称和属性值
        for (Map.Entry<String, Object> entry : stringObjectMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (ObjectUtil.isNotEmpty(value)) {
                //基本类型和封装类型
                if (isPrimitiveOrWrapper(value.getClass())) {
                    map.put(key, String.valueOf(value));
                } else {
                    //其他类型
                    if (value instanceof List) {
                        List<Object> list = (List) value;
                        for (int i = 0; i < list.size(); i++) {
                            Object o = list.get(i);
                            Map<String, Object> stringObjectMap1 = BeanUtil.beanToMap(o);
                            for (Map.Entry<String, Object> entry1 : stringObjectMap1.entrySet()) {
                                String key1 = entry1.getKey();
                                Object value1 = entry1.getValue();
                                map.put(StrUtil.format("{}.{}{}", key, key1, i), String.valueOf(value1));
                            }
                        }
                    } else {
                        Map<String, Object> stringObjectMap1 = BeanUtil.beanToMap(value);
                        for (Map.Entry<String, Object> entry1 : stringObjectMap1.entrySet()) {
                            String key1 = entry1.getKey();
                            Object value1 = entry1.getValue();
                            map.put(StrUtil.format("{}.{}", key, key1), String.valueOf(value1));
                        }
                    }
                }
            }
        }
        return map;
    }

    public static void generatePdf(HttpServletRequest request,
                                   HttpServletResponse response,
                                   String templateName, Object object,
                                   boolean download) {
        try (OutputStream responseOutputStream = response.getOutputStream();
             ByteArrayOutputStream fileOut = new ByteArrayOutputStream()) {
             //模板在项目中的位置
            Resource resource = new PathMatchingResourcePatternResolver()
                    .getResource(ResourceUtils.CLASSPATH_URL_PREFIX + "pdf/" + templateName);
            PdfReader reader = new PdfReader(resource.getInputStream());
            PdfStamper ps = new PdfStamper(reader, fileOut);
//            BaseFont bf = BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA_BOLD, BaseFont.WINANSI, BaseFont.EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<>();
            fontList.add(bf);
            //取出报表模板中的所有字段
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);
            PdfUtil.fillData(fields, PdfUtil.turnMap(object));
            //必须要调用这个,否则文档不会生成的  如果为false那么生成的PDF文件还能编辑,一定要设为true
            ps.setFormFlattening(true);
            ps.close();
            if (download) {
                writerFile(request, response, templateName, false);
            }
            fileOut.writeTo(responseOutputStream);
        } catch (Exception e) {
            log.error("pdf生成异常:", e);
            throw new RuntimeException("操作异常请联系管理员!");
        }
    }

    /**
     * 填充数据
     *
     * @param fields
     * @param data
     * @throws IOException
     * @throws DocumentException
     */
    private static void fillData(AcroFields fields, Map<String, String> data) throws IOException, DocumentException {
        Map<String, AcroFields.Item> formFields = fields.getFields();
        for (String key : data.keySet()) {
            if (formFields.containsKey(key)) {
                String value = data.get(key);
                // 为字段赋值,注意字段名称是区分大小写的
                fields.setField(key, value);
            }
        }
    }

    /**
     * 写出文件
     *
     * @param request
     * @param response
     * @param fileName
     * @param deleteOnExit 是否需要删除本地文件
     */
    private static void writerFile(HttpServletRequest request,
                                   HttpServletResponse response,
                                   String fileName,
                                   boolean deleteOnExit) throws IOException {
        File file = new File("/" + fileName);
        file.createNewFile();
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setContentType("application/pdf");
        try (FileInputStream fis = new FileInputStream(file);) {
            //这里主要防止下载的PDF文件名乱码
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();

            if (deleteOnExit) {
                file.deleteOnExit();
            }
        } catch (Exception e) {
            log.error("pdf生成异常1:", e);
            throw new RuntimeException("操作异常1请联系管理员!");
        }
    }
}

3.2、实体对象


import lombok.Data;

import java.util.List;

/**
 * @author zero
 */
@Data
public class TestDto {
    private String name;
    private String birthday;
    private Other other;
    private List<Other> otherList;

    @Data
    public static class Other {
        private String career;
        private String company;
    }

}

3.3、Controller

import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 测试 控制层
 *
 * @author zero
 */
@RestController
@RequestMapping("test")
@Api(tags = "测试")
public class TestController {

    @GetMapping("/pdf")
    public void pdf(HttpServletRequest request, HttpServletResponse response) {
        TestDto testDto = new TestDto();
        testDto.setName("张三");
        testDto.setBirthday("2020-12-12");
        TestDto.Other other = new TestDto.Other();
        other.setCareer("码农");
        other.setCompany("字节不跳动");
        testDto.setOther(other);
        List<TestDto.Other> list = new ArrayList<>();
        for (int i = 0; i <= 2; i++) {
            TestDto.Other other1 = new TestDto.Other();
            other1.setCareer("码农" + i);
            other1.setCompany("字节不跳动" + i);
            list.add(other1);
        }
        testDto.setOtherList(list);
        PdfUtil.generatePdf(request, response, "test.pdf", testDto, false);
    }
   }

浏览器访问ip:port/test/pdf,其中ip为你的ip地址,port为你的端口,访问结果如下:

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2023年12月28日 下午3:20
下一篇 2023年12月28日

相关推荐

此站出售,如需请站内私信或者邮箱!