JAVA导出复杂PDF表格(带水印),使用response下载

 1.pom添加

<!-- pdf start -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.9</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <!-- pdf end -->

2.PDF样例图 

3.PDF CLASS

一共包含三个CLASS

PDFDemo.java(Demo可直接使用)、PDFExport.java(导出封装)、PDFPageEvent.java(导出水印)

 PDFDemo.java

package com.dhproject.utils.pdf;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class PDFDemo {
    public static void main(HttpServletResponse response) {
        demoDownload(response,"这个是水印");
    }
    /**
     * 流式下载
     * @param response
     * @param aligned
     */
    public static void demoDownload(HttpServletResponse response,String aligned){
        try {
            //设置请求返回类型
            response.setHeader("Content-Disposition", "attachment; filename=pdffile.pdf");
            OutputStream outputStream = response.getOutputStream();
            InputStream inputStream = PDFExport.getTpl().getInputStream();

            PdfReader reader = new PdfReader(inputStream);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PdfStamper ps = new PdfStamper(reader, bos);

            //设置字体
            final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<>();
            fontList.add(font);

            //提取表单
            AcroFields s = ps.getAcroFields();
            s.setSubstitutionFonts(fontList);

            s.setFieldProperty("type", "textfont", font, null);
            s.setFieldProperty("createTime", "textfont", font, null);
            s.setFieldProperty("title", "textfont", font, null);
            s.setField("type", "日报");
            s.setField("createTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            s.setField("title", "这是title,模板画的位置框");
            ps.setFormFlattening(true);
            ps.close();

            //*******************填充编辑好后的pdf**************
            reader = new PdfReader(bos.toByteArray());
            Rectangle pageSize = reader.getPageSize(1);
            Document document = new Document(pageSize);
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);
            writer.setPageEvent(new PDFPageEvent(aligned));
            // 打开文档
            document.open();
            PdfContentByte cbUnder = writer.getDirectContentUnder();
            PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);
            cbUnder.addTemplate(pageTemplate, 0, 0);

            //这里进行数据填充
            demoData(writer, document);

            document.close();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param writer
     * @param document
     */
    public static void demoData(PdfWriter writer, Document document) throws IOException, DocumentException {
        //新创建一个7列的表格
        PdfPTable table = PDFExport.getTable(writer,new float[]{25,30,30,30,30,30,30});
        //表头信息

        //有7列数据将行全部合并  并且隐藏边框
        PDFExport.setRowData(table,1,7,"XXXX表",13);

        //有12行数据将第一列全部合并
        PDFExport.setRowData(table,12,1,"合并列明");

        PDFExport.setRowData(table,1,2,"XXXX表");
        PDFExport.setRowData(table,1,4,"-");

        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");

        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1, "-");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,4,"-");
        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,4,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,1,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,4,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,4,"-");

        PDFExport.setRowData(table,4,1,"时   间");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,2,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,8,1,"时   间");

        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"时   间");

        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1, "-");

        PDFExport.setRowData(table,1,1,"时   间");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");
        PDFExport.setRowData(table,1,1,"-");

        PDFExport.setRowData(table,1,3,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,3,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,3,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,3,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        PDFExport.setRowData(table,1,3,"时   间");
        PDFExport.setRowData(table,1,3,"-");

        document.add(table);
    }
}

PDFExport.java(导出封装)

package com.dhproject.utils.pdf;

import com.dhproject.common.config.ProjectConfig;
import com.dhproject.common.utils.DateUtils;
import com.dhproject.common.utils.StringUtils;
import com.dhproject.common.utils.file.FileUploadUtils;
import com.dhproject.common.utils.uuid.Seq;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.springframework.core.io.ClassPathResource;
import java.io.*;

/**
 * 模板第一页不占满,生成表格
 */
public class PDFExport {
    /**
     * 获取上传根目录
     * @return
     */
    public static final String getBaseDir(){
        return ProjectConfig.getDownloadPath();
    }

    /**
     * 获取模板
     * @return
     */
    public static final ClassPathResource getTpl(){
        return new ClassPathResource("static/public/pdf/tpl.pdf");
    }

    /**
     * 编码文件名
     * @return
     */
    public static final String extractFilename()
    {
        return StringUtils.format("pdf/{}/{}.{}", DateUtils.datePath(), Seq.getId(Seq.uploadSeqType),"pdf");
    }

    /**
     * 获取URL
     * @param fileName
     * @return
     */
    public static final String getPathFileName(String fileName) throws IOException {
        return FileUploadUtils.getPathFileName(getBaseDir(), fileName);
    }

    /**
     * 获取下载绝对路径
     * @param fileName
     * @return
     */
    public static final java.io.File getAbsoluteFile(String fileName)
    {
        java.io.File desc = new java.io.File(getBaseDir() + java.io.File.separator + fileName);

        if (!desc.exists())
        {
            if (!desc.getParentFile().exists())
            {
                desc.getParentFile().mkdirs();
            }
            try {
                desc.createNewFile();

            } catch (IOException e) {

                e.printStackTrace();
            }
        }
        return desc;
    }
    /**
     * 单行数据写入
     * //隐藏上边框
     * // cell.disableBorderSide(1);
     * //隐藏下边框
     * // cell.disableBorderSide(2);
     * //隐藏上、下边框
     * //cell.disableBorderSide(3);
     * //隐藏左边框
     * //cell.disableBorderSide(4);
     * //隐藏左、上边框
     * //cell.disableBorderSide(5);
     * //隐藏左、下边框
     * //cell.disableBorderSide(6);
     * //隐藏左、上、下边框
     * //cell.disableBorderSide(7);
     * //隐藏右边框
     * //cell.disableBorderSide(8);
     * //隐藏右、上边框
     * // cell.disableBorderSide(9);
     * //隐藏右、下边框
     * //cell.disableBorderSide(10);
     * //隐藏右、上、下边框
     * //cell.disableBorderSide(11);
     * //隐藏左、右边框
     * //cell.disableBorderSide(12);//左右没了
     * //隐藏上、左、右边框
     * //cell.disableBorderSide(13);//只剩下
     * //隐藏下、左、右边框
     * //cell.disableBorderSide(14);//只剩上
     * //隐藏全部
     * //cell.disableBorderSide(15);//全没了
     * @param table
     * @param setRowspan
     * @param setColspan
     * @param text
     * @param disableBorderSide
     * @throws IOException
     * @throws DocumentException
     */
    public static void setRowData(PdfPTable table,int setRowspan,int setColspan,String text,int disableBorderSide) throws IOException, DocumentException {
        //定义数据的字体
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        Font textFont = new Font(baseFont, 10, Font.NORMAL);
        PdfPCell heandCell = new PdfPCell();
        heandCell.setRowspan(setRowspan);
        heandCell.setColspan(setColspan);
        heandCell.setMinimumHeight(30);
        heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
        heandCell.setPhrase(new Phrase(text, textFont));
        if(disableBorderSide>0){
            heandCell.disableBorderSide(disableBorderSide);//隐藏边框
        }
        table.addCell(heandCell);
    }

    /**
     * 单行数据写入
     * @param table
     * @param setRowspan
     * @param setColspan
     * @param text
     * @throws IOException
     * @throws DocumentException
     */
    public static void setRowData(PdfPTable table,int setRowspan,int setColspan,String text) throws IOException, DocumentException {
        setRowData(table,setRowspan,setColspan,text,-1);
    }

    /**
     * 生成表格
     * @param writer
     * @param colls
     * @return
     */
    public static PdfPTable getTable(PdfWriter writer,float[] colls){
        PdfPTable table = new PdfPTable(colls);
        table.setTotalWidth(520);
        table.setPaddingTop(0);
        table.setLockedWidth(true);
        table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
        table.writeSelectedRows(0, -1, 500, 800, writer.getDirectContentUnder());
        return table;
    }
}


PDFPageEvent.java(导出水印) 

package com.dhproject.utils.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import java.io.IOException;

public class PDFPageEvent  extends PdfPageEventHelper {
    //页眉
    public String header = "";

    //文档字体大小,页脚页眉最好和文本大小一致
    public int presentFontSize = 10;

    //文档页面大小,最好前面传入,否则默认为A4纸张
    public Rectangle pageSize = PageSize.A4;

    // 模板
    public PdfTemplate total;

    // 基础字体对象
    public BaseFont bf = null;

    // 利用基础字体生成的字体对象,一般用于生成中文文字
    public Font fontDetail = null;

    //水印文字
    public String aligned = "";

    /**
     *Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.
     */
    public PDFPageEvent() {

    }

    /**
     * Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.
     * @param aligned
     */
    public PDFPageEvent(String aligned) {
        this.aligned = aligned;
    }

    /**
     *
     * Creates a new instance of PdfReportM1HeaderFooter 构造方法.
     * @param yeMei
     * @param presentFontSize 数据体字体大小
     * @param pageSize 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
     */
    public PDFPageEvent(String yeMei, int presentFontSize, Rectangle pageSize) {
        this.header = yeMei;
        this.presentFontSize = presentFontSize;
       this.pageSize = pageSize;
    }

    /**
     * Creates a new instance of PdfReportM1HeaderFooter 构造方法.
     * @param presentFontSize 数据体字体大小
     * @param pageSize 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
     */
    public PDFPageEvent( int presentFontSize, Rectangle pageSize) {
        this.presentFontSize = presentFontSize;
        this.pageSize = pageSize;
    }

    /**
     * TODO 文档打开时创建模板
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter,com.itextpdf.text.Document)
     * @param writer
     * @param document
     */
    public void onOpenDocument(PdfWriter writer, Document document) {
        total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
    }

    /**
     * TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,com.itextpdf.text.Document)
     * @param writer
     * @param document
     */
    public void onEndPage(PdfWriter writer, Document document) {
        this.addPage(writer, document);
        //加水印
        this.addWatermark(writer);
    }

    /**
     * 加分页
     * @param writer
     * @param document
     */
    public void addPage(PdfWriter writer, Document document){
        //设置分页页眉页脚字体
        try {
            if (bf == null) {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
            }
            if (fontDetail == null) {
                fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 1.写入页眉
        // ColumnText.showTextAligned(writer.getDirectContent(),Element.ALIGN_LEFT, new Phrase(header, fontDetail),document.left(), document.top() + 20, 0);
        // 2.写入前半部分的 第 X页/共
        int pageS = writer.getPageNumber();
        String foot1 = "第 " + pageS + " 页 /共";
        //String foot1 = pageS  +"/";
        Phrase footer = new Phrase(foot1, fontDetail);
        // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
        float len = bf.getWidthPoint(foot1, presentFontSize);
        // 4.拿到当前的PdfContentByte
        PdfContentByte cb = writer.getDirectContent();
        // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
        // 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了
        // ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。
        ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F , document.bottom() - 20, 0);
        // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
        // len , y 轴和之前的保持一致,底边界-20
        cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F , document.bottom() - 20); // 调节模版显示的位置
    }

    /**
     * 加水印
     * @param writer
     */
    public void addWatermark(PdfWriter writer) {
        // 水印图片
        /*
        Image image;
        try {
            image = Image.getInstance("./web/images/001.jpg");
            PdfContentByte content = writer.getDirectContentUnder();
            content.beginText();
            // 开始写入水印
            for(int k=0;k<5;k++){
                for (int j = 0; j <4; j++) {
                    image.setAbsolutePosition(150*j,170*k);
                    content.addImage(image);
                }
            }
            content.endText();
        } catch (IOException | DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        */
        BaseFont font = null;
        try {
            font = BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        PdfGState gs = new PdfGState();
        //添加透明度
        gs.setFillOpacity(0.4f);
        PdfContentByte content = writer.getDirectContentUnder();
        content.beginText();
        //水印颜色
        content.setColorFill(new BaseColor(100, 100, 100));
        content.setGState(gs);
        //水印字体样式和大小
        content.setFontAndSize(font, 26);
        //插入水印  循环每页插入的条数
        for (int j = 0; j < 1; j++) {
            content.showTextAligned(Element.ALIGN_CENTER, aligned, 300, 600 * (j + 1), 30);
        }
        content.endText();
    }

    /**
     * TODO 关闭文档时,替换模板,完成整个页眉页脚组件
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter,com.itextpdf.text.Document)
     * @param writer
     * @param document
     */
    public void onCloseDocument(PdfWriter writer, Document document) {
        // 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
        total.beginText();
        total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
        String foot2 = " " + (writer.getPageNumber()) + " 页"; //页脚内容拼接  如  第1页/共2页
        //String foot2 = String.valueOf(writer.getPageNumber()); //页脚内容拼接  如  1/2
        total.showText(foot2);// 模版显示的内容
        total.endText();
        total.closePath();
    }
}

猜你喜欢

转载自blog.csdn.net/zlxls/article/details/128251809