HeavenTang

导航

java导出pdf

wps直接编辑pdf文件,不用java里面用word模板

点击查看代码

    @Override
    public void downloadTransferZipV2(KsxxDto dto, HttpServletResponse response, HttpServletRequest request) {
        String nd = dto.getNd();
        if (StringUtils.isBlank(nd)) {
            throw new CloudException("请设置招生年度");
        }
        // 查询需要导出的考生
        dto.setYear(nd);
        List<Ksxx> ksxxList = ksxxMapper.queryLqKsxx(dto);
//        // 查询调档函相关数据
//        SjzdExample example = new SjzdExample();
//        example.createCriteria().andCFlbmEqualTo("ddhxx").andCSfscEqualTo(CodeConstants.SF_F);
//        List<Sjzd> ddhList = sjzdMapper.selectByExample(example);
//        Map<String, Sjzd> ddhMap = new HashMap<>();
//        if (ddhList != null && !ddhList.isEmpty()) {
//            ddhMap = ddhList.stream().collect(Collectors.toMap(Sjzd::getcBm, Function.identity(), (key1, key2) -> key2));
//        }

//        String schoolName = getSchoolName();
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            for (Ksxx ksxx : ksxxList) {
                ByteArrayOutputStream os = new ByteArrayOutputStream();

                QrCodeVo vo = new QrCodeVo();
                vo.setKsbh(ksxx.getKsbh());
                vo.setXm(ksxx.getXm());
                vo.setBmh(ksxx.getBmh());
                vo.setZjhm(ksxx.getZjhm());
                vo.setLx(ksxx.getLx());
                vo.setYxdm(StringUtils.equals(ksxx.getLx(), CodeConstants.RYLX_TJ) ? ksxx.getTjYxsdm() : ksxx.getBkyxsm());
                vo.setZydm(StringUtils.equals(ksxx.getLx(), CodeConstants.RYLX_TJ) ? ksxx.getTjZydm() : ksxx.getBkzydm());
                vo.setXxfs(StringUtils.equals(ksxx.getLx(), CodeConstants.RYLX_TJ) ? ksxx.getTjXxfs() : ksxx.getBkxxfs());
                vo.setXh(ksxx.getXh());
                vo.setDaxh(ksxx.getDaxh());
                String codeInfo = JSON.toJSONString(vo);
                codeInfo = AESUtil.aesEncrypt(codeInfo, CodeConstants.AES_TOKEN);

                String qrCodeBase64 = pdfUtils.getQrCodeBase64(codeInfo);
                Map<String, Object> dataModel = new HashMap<>();
                dataModel.put("nd", nd);
//                dataModel.put("xxmc", getSchoolName());
                dataModel.put("dwxx", UsualUtil.strIsEmpty(ksxx.getDaszdw()) ? "" : ksxx.getDaszdw() + ":");
                dataModel.put("xm", ksxx.getXm());
//                dataModel.put("rq1", "2025年7月5日");
//                dataModel.put("rq2", "2025年5月20日");
//                dataModel.put("yjdz", "浙江省杭州市钱塘区学源街998号浙江传媒学院行政楼202");
//                dataModel.put("yzbm", "310018");
//                dataModel.put("lxdh", "洪老师 0571-86832041");
                dataModel.put("qrImage", qrCodeBase64);
                dataModel.put("yxmc", StringUtils.equals(ksxx.getLx(),CodeConstants.KSXXLX_YZY) ? ksxx.getBkyxsmc() : ksxx.getTjYxsmc());
                dataModel.put("zymc", StringUtils.equals(ksxx.getLx(),CodeConstants.KSXXLX_YZY) ? ksxx.getBkzymc() : ksxx.getTjZymc());
                dataModel.put("yjfxmc", StringUtils.equals(ksxx.getLx(),CodeConstants.KSXXLX_YZY) ? ksxx.getYjfxmc() : ksxx.getTjYjfxmc());
                String fileTemplate = pdfUtils.getPdfTempPath("ddh25050601.pdf");
                pdfUtils.fillTemplate(dataModel, fileTemplate, os);
                InputStream pdfImputStream = new ByteArrayInputStream(os.toByteArray());
                zos.putNextEntry(new ZipEntry(ksxx.getXh() + "_" + ksxx.getXm() + ".pdf"));
                byte[] buffer = new byte[ONE_THOUSAND_AND_TWENTY_FOUR];
                writeStram(zos, buffer, pdfImputStream);
                if (os != null) {
                    os.close();
                }
            }
            zos.closeEntry();
            zos.flush();
        } catch (Exception e) {
            log.error("生成二维码错误!", e);
            e.printStackTrace();
        }
    }

点击查看代码
package com.yw.server.utils.tools;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.google.zxing.client.j2se.MatrixToImageConfig.BLACK;
import static com.google.zxing.client.j2se.MatrixToImageConfig.WHITE;

@Slf4j
@Component
public class MyPdfUtils {

    @Value("${win.fonts.song}")
    private String songFonts;

    /**
     * 利用模板生成pdf
     *
     * @param o            写入的数据
     * @param templatePath pdf模板路径
     * @param fileName     文件名
     * @param response     响应体
     */
    public void fillTemplate(Map<String, Object> o, String templatePath, String fileName, HttpServletResponse response) throws Exception {
        if (UsualUtil.strIsNotEmpty(fileName)) {
            forwardToBrowser("application/x-msdownload", fileName, response);
        }
        fillTemplate(o, templatePath, response.getOutputStream());
    }

    public void fillTemplate(Map<String, Object> o, String templatePath , OutputStream os) throws Exception {
        PdfReader reader;
        ByteArrayOutputStream bos;
        PdfStamper stamper;
        try {
            String fonts = System.getProperty("user.dir") + File.separator + "fonts" + File.separator;
            // 特别注意一下,linux路径只能使用/  window \ / 都可以
            File file = new File(fonts);
            if (!file.exists()) {
                //TODO 这里可以再次进行字体文件上传的校验,当发现没有上传成功后的补救
            }
            String path1 = fonts + songFonts + ",0";
            // 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
            BaseFont bf = BaseFont.createFont(path1, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

//            // 此处的字体,服务要是在linux上,中文会出现导出填不上的情况,所以,此处字体必填
//            BaseFont bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);

            Font FontChinese = new Font(bf, 5, Font.NORMAL);
            // 读取pdf模板
            reader = new PdfReader(templatePath);
            // FileInputStream is = new FileInputStream(fileTemplate);
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);
            AcroFields form = stamper.getAcroFields();

            java.util.Iterator<String> it = form.getFields().keySet().iterator();
            form.addSubstitutionFont(bf);
            while (it.hasNext()) {
                String name = it.next();
                System.out.println(name);
                String value = o.get(name) != null ? o.get(name).toString() : null;
                log.info("名字:{},标签:{}", value, name);
                if ("qrImage".equals(name)) {
//                    byte[] image = o.get(name) != null ? (byte[]) o.get(name) : null;
//                    if (image == null) {
//                        insertImage(form, "qrImage", stamper, getImagesPath("lydx.png"));
//                        continue;
//                    }
                    if (value == null) {
                        continue;
                    }
                    insertImageV2(form, "qrImage", stamper, value);
                } else {
                    form.setField(name, value);
                }
            }
            // 如果为false那么生成的PDF文件还能编辑,一定要设为true
            stamper.setFormFlattening(true);
            stamper.close();
            log.info("插入成功");
            Document doc = new Document();
            Font font = new Font(bf, 32);
            PdfCopy copy = new PdfCopy(doc, os);
            doc.open();
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
            copy.addPage(importPage);
            doc.close();
        } catch (IOException | DocumentException e) {
            log.error("利用模板导出PDF失败:{}", e);
        }
    }

    public String getPdfTempPath(String fileName) throws URISyntaxException {
        return Objects.requireNonNull(MyPdfUtils.class.getClassLoader().getResource("templates" + File.separator + "pdfTemp" + File.separator + fileName)).toURI().toString();
    }

    public String getImagesPath(String fileName) throws URISyntaxException {
        return Objects.requireNonNull(MyPdfUtils.class.getClassLoader().getResource("templates" + File.separator + "images" + File.separator + fileName)).toURI().toString();
    }


    public static byte[] getByteByUrl(String fileUrl) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        InputStream inputStream = null;
        byte[] result = null;
        try {
            URL imageUrl = new URL(fileUrl);
            HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            inputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            result = outStream.toByteArray();
            return result;
        } catch (Exception ignored) {
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                outStream.close();
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    public void insertImage(AcroFields form, String name, PdfStamper pdfStamper, byte[] url) throws DocumentException, IOException {
        /**
         * 添加图片
         */
        int page = form.getFieldPositions(name).get(0).page;
        Rectangle signReact = form.getFieldPositions(name).get(0).position;
        float x = signReact.getLeft();
        float y = signReact.getBottom();
        Image image = Image.getInstance(url);
        PdfContentByte under = pdfStamper.getOverContent(page);
        image.scaleToFit(signReact.getWidth(), signReact.getHeight());
        image.setAbsolutePosition(x, y);
        under.addImage(image);
    }

    public void insertImage(AcroFields form, String name, PdfStamper pdfStamper, String url) throws DocumentException, IOException {
        /**
         * 添加图片
         */
        int page = form.getFieldPositions(name).get(0).page;
        Rectangle signReact = form.getFieldPositions(name).get(0).position;
        float x = signReact.getLeft();
        float y = signReact.getBottom();
        Image image = Image.getInstance(url);
        PdfContentByte under = pdfStamper.getOverContent(page);
        image.scaleToFit(signReact.getWidth(), signReact.getHeight());
        image.setAbsolutePosition(x, y);
        under.addImage(image);
    }

//    public void insertImageV2(AcroFields form, String name, PdfStamper pdfStamper, String qrCodeBase64)
//            throws DocumentException, IOException {
//        // 获取字段的位置信息
//        int page = form.getFieldPositions(name).get(0).page;
//        Rectangle signRect = form.getFieldPositions(name).get(0).position;
//        float x = signRect.getLeft();
//        float y = signRect.getBottom();
//        // 解析Base64图片数据
//        String base64Data = qrCodeBase64;
//        if (base64Data.startsWith("data:image/")) {
//            // 去掉Base64前缀(如 data:image/png;base64,iVBORw0KG...)
//            base64Data = base64Data.split(",")[1];
//        }
//        byte[] imageBytes = Base64.getDecoder().decode(base64Data);
//        Image image = Image.getInstance(imageBytes);
//        // 调整图片大小和位置
//        image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//        image.setAbsolutePosition(x, y);
//
//        // 插入图片
//        PdfContentByte under = pdfStamper.getOverContent(page);
//        under.addImage(image);
//    }


    public void insertImageV2(AcroFields form, String name, PdfStamper pdfStamper, String qrCodeBase64)
            throws DocumentException, IOException {
        // 获取字段的位置信息
        int page = form.getFieldPositions(name).get(0).page;
        Rectangle signRect = form.getFieldPositions(name).get(0).position;
        float x = signRect.getLeft();
        float y = signRect.getBottom();

        // 解析Base64图片数据
        String base64Data = qrCodeBase64.startsWith("data:image/") ? qrCodeBase64.split(",")[1] : qrCodeBase64;
        byte[] imageBytes = Base64.getDecoder().decode(base64Data);

        // 调试:临时保存图片到本地以验证Base64解码是否正确
//        File tempFile = new File("debug_qrcode.png");
//        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
//            fos.write(imageBytes);
//        }

        // 加载图片
        Image image = Image.getInstance(imageBytes);

        // 打印图片原始尺寸用于调试
        System.out.println("Original width: " + image.getWidth() + ", height: " + image.getHeight());

        // 调整图片大小和位置
        image.scaleToFit(signRect.getWidth(), signRect.getHeight());
        image.setAbsolutePosition(x, y);

        // 插入图片
        PdfContentByte canvas = pdfStamper.getOverContent(page); // 确保使用的是getOverContent
        canvas.addImage(image);

        // 可选:为了确保图片显示正常,可以尝试直接设置图片大小而非scaleToFit
//         image.scaleAbsolute(signRect.getWidth(), signRect.getHeight());
    }

    public void forwardToBrowser(String contentType, String fileName, HttpServletResponse response) {
        response.setContentType(contentType);
        // 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    }

    public String addSuffix(Object t, String suffix) {
        if (Objects.isNull(t)) {
            return null;
        }
        return t + suffix;
    }

    public String getQrCodeBase64(String qrData) throws IOException, WriterException {
        // 生成二维码
        BufferedImage qrImage = generateQRCodeImage(qrData);
        // 将二维码图像转换为Base64字符串
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(qrImage, "png", baos);
        String qrImageBase64 = "data:image/png;base64," + javax.xml.bind.DatatypeConverter.printBase64Binary(baos.toByteArray());
//        return Base64Util.encode(baos.toByteArray());
        return qrImageBase64;
    }

    private BufferedImage generateQRCodeImage(String text) throws WriterException {
        QRCodeWriter barcodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = barcodeWriter.encode(text, BarcodeFormat.QR_CODE, 200, 200, getMinimalHints());
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }

    /**
     * 使用尽可能少的配置来生成二维码,可能不包括安静区
     */
    private Map<EncodeHintType, Object> getMinimalHints() {
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        // 设置边缘为0,尝试去除留白
        hints.put(EncodeHintType.MARGIN, 0);
        // 可选:设置错误校正等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
        return hints;
    }

}

image
image

posted on 2026-04-14 12:12  HeavenTang  阅读(8)  评论(0)    收藏  举报