zoukankan      html  css  js  c++  java
  • spring boot:用itextpdf处理pdf表格文件(spring boot 2.3.2)

    一,什么是itextpdf?

    1,itextpdf的用途

    itextpdf是用来生成PDF文档的一个java类库,

    通过iText可以生成PDF文档,

    还可以把XML/Html文件转化为PDF文件

    2,官方网站:

    https://itextpdf.com/en

    3,itextpdf使用中的几个问题:

    使用中文字体

    插入表格

    插入图片时设置图片宽度

    浏览器直接显示pdf

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,演示项目的相关信息

    1,代码地址:

    https://github.com/liuhongdi/exportpdf

    2,功能说明:

         直接显示pdf

         把数据保存成pdf文件

         pdf文件下载

    3,项目结构:如图:

    三,配置文件说明

    1,pom.xml

            <!--pdf begin-->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.13.1</version>
            </dependency>
    
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itext-asian</artifactId>
                <version>5.2.0</version>
            </dependency>
            <!--pdf   end-->
    
            <!--mybatis begin-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.3</version>
            </dependency>
            <!--mybatis end-->
    
            <!--mysql begin-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!--mysql end-->

    说明:要引入itextpdf

    2,把自己要使用的字体文件,复制到

        resources/font目录下供访问

    3,数据表建表sql

    CREATE TABLE `goods` (
     `goodsId` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
     `goodsName` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'name',
     `subject` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',
     `price` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
     `stock` int(11) NOT NULL DEFAULT '0' COMMENT 'stock',
     PRIMARY KEY (`goodsId`)
    ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表'

    四,java代码说明

    1,AbstractITextPdfView.java

    /**
    新建一个pdfview,主要是为了避免AbstractPdfView中使用的pdf库太旧的问题
     AbstractPdfView只支持到 com.lowagie.itext的2.1.7版本,
     版本太旧,文档也缺少
     修改后可以支持itextpdf库的类,
     新增AbstractITextPdfView后此问题完美解决
     by liuhongdi
    */
    public abstract class AbstractITextPdfView extends AbstractView {
        public AbstractITextPdfView() {
            setContentType("application/pdf");
        }
    
        @Override
        protected boolean generatesDownloadContent() {
            return true;
        }
    
        @Override
        protected final void renderMergedOutputModel(Map<String, Object> model,
                                                     HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            // 获得流
            ByteArrayOutputStream baos = createTemporaryOutputStream();
            Document document = newDocument();
            PdfWriter writer = newWriter(document, baos);
            prepareWriter(model, writer, request);
            buildPdfMetadata(model, document, request);
            buildPdfDocument(model, document, writer, request, response);
            writeToResponse(response, baos);
        }
    
        protected Document newDocument() {
            return new Document(PageSize.A4);
        }
    
        protected PdfWriter newWriter(Document document, OutputStream os)
                throws DocumentException {
            return PdfWriter.getInstance(document, os);
        }
    
        protected void prepareWriter(Map<String, Object> model, PdfWriter writer,
                                     HttpServletRequest request) throws DocumentException {
    
            writer.setViewerPreferences(getViewerPreferences());
        }
    
        protected int getViewerPreferences() {
            return PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage;
        }
    
        protected void buildPdfMetadata(Map<String, Object> model,
                                        Document document, HttpServletRequest request) {
        }
    
        protected abstract void buildPdfDocument(Map<String, Object> model,
                                                 Document document, PdfWriter writer, HttpServletRequest request,
                                                 HttpServletResponse response) throws Exception;
    }

    说明:如果在浏览器的页面上直接显示pdf,而不是下载文件后再打开,

             则需要使用AbstractPdfView,但spring boot默认支持的itext库代码太旧,

            注释中已做了说明,所以我们另外自己定义一个

    2, ViewPdfUtil.java

    public class ViewPdfUtil extends AbstractITextPdfView {
    
        //文件名
        private String fileName;
        public String getFileName() {
            return this.fileName;
        }
        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    
        //指定一个类型,方便知道调用哪个类处理
        private String pdfType;
        public String getPdfType() {
            return this.pdfType;
        }
        public void setPdfType(String pdfType) {
            this.pdfType = pdfType;
        }
    
        //生成pdf的document并显示出来
        @Override
        protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition","filename=" + URLEncoder.encode(this.fileName, "UTF-8"));
            List<Goods> products = (List<Goods>) model.get("sheet");
            if (this.pdfType.equals("goods")) {
                PdfTableService pdfTableService = new PdfTableServiceImpl();
                //不保存成文件,直接显示,所以不指定保存路径
                pdfTableService.createPDF(document, products,"");
            }
        }
    }

    说明:主要是实现buildPdfDocument方法,供ModelAndView调用时直接显示到浏览器页面

    3,PdfTableServiceImpl.java

    @Service
    public class PdfTableServiceImpl implements PdfTableService {
    
        //创建pdf文件,
        // savePath是保存路径,如果是空字串,则直接输出到document
        //document:pdf内容
        //goods:写入到pdf表格中的数据
        @Override
        public void createPDF(Document document, List<Goods> goods,String savePath)  {
            try {
                if (!savePath.equals("")) {
                    PdfWriter.getInstance(document, new FileOutputStream(savePath));
                }
                document.addTitle("商品库存统计表");
                document.addAuthor("老刘");
                document.addSubject("2020年商品库存统计");
                document.addKeywords("商品库存");
                document.open();
                Paragraph para = getParagraphText("整个白酒行业从2012年开始,都迅速下滑,销量和利润都是大跌。2014年和2015年,茅台的股价涨得不错,但也没有超过同期的白马股太多,加上利润增速一直没有恢复塑化剂之前的状态,我就一直没有再买入");
                document.add(para);
                String imagePath = "/data/springboot2/logo.jpg";      // 图片的绝对路径
                Image image = Image.getInstance(imagePath);       // 取得图片对象
                //计算得到目标宽高
                File gifFile = new File(imagePath);
                int origWidth = 0;
                int origHeight = 0;
                try {
                    BufferedImage imageBuffer = ImageIO.read(gifFile);
                    if (imageBuffer != null) {//如果image=null 表示上传的不是图片格式
                        origWidth = imageBuffer.getWidth();
                        origHeight = imageBuffer.getHeight();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                System.out.println(""+document.getPageSize().getWidth());
                System.out.println("margin:"+document.leftMargin());
                //得到新的高度和新的宽度
                float newwidth = document.getPageSize().getWidth()-document.leftMargin()-document.rightMargin();
                float newHeight = (newwidth*origHeight) / origWidth;
    
                image.scaleAbsolute(newwidth, newHeight);
    
                document.add(image);
    
                PdfPTable table = createTable(goods);
                document.add(table);
    
            } catch ( IOException e) {
                e.printStackTrace();
            } catch (DocumentException e) {
                e.printStackTrace();
            } finally {
                if (document.isOpen()) {
                    document.close();
                }
            }
        }
    
        //从text得到可以添加到document的Paragraph
        public static Paragraph getParagraphText(String text)  {
    
            try {
                Font font = new Font(BaseFont.createFont(new ClassPathResource("/font/FZLTHK.TTF").getPath(),BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
                font.setColor(BaseColor.GRAY);
    
                Paragraph para = new Paragraph(text,font);
                return para;
            } catch ( IOException | DocumentException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        //创建PdfTable
        public static PdfPTable createTable(List<Goods> products) throws IOException, DocumentException {
            PdfPTable table = new PdfPTable(4);//生成一个4列的表格
    
            int widths[] = { 10,40,40,10 };//指定各列的宽度百分比
            table.setWidthPercentage(100);
            table.setSpacingBefore(10);
            table.setWidths(widths);
    
            PdfPCell cell;
            int size = 20;
    
            Font font = new Font(BaseFont.createFont(new ClassPathResource("/font/FZLTHK.TTF").getPath(),BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
            font.setColor(BaseColor.BLACK);
    
            Font font_head = new Font(BaseFont.createFont(new ClassPathResource("/font/FZLTHK.TTF").getPath(),BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
            font_head.setColor(BaseColor.BLUE);
    
            Font font_title = new Font(BaseFont.createFont(new ClassPathResource("/font/FZLTHK.TTF").getPath(),BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
            font_title.setColor(BaseColor.GREEN);
            font_title.setSize(36);
    
            cell = new PdfPCell(new Phrase("商品库存信息表",font_title));
            cell.setColspan(4);//设置所占列数
            cell.setFixedHeight(50);//设置高度
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);//设置水平居中
            table.addCell(cell);
    
            cell = new PdfPCell(new Phrase("ID",font_head));//商品编号
            cell.setFixedHeight(size);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("商品名称",font_head));//商品名称
            cell.setFixedHeight(size);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("描述",font_head));//描述
            cell.setFixedHeight(size);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("价格",font_head));//商品价格
            cell.setFixedHeight(size);
            table.addCell(cell);
    
            for(int i = 0;i<products.size();i++) {
                cell = new PdfPCell(new Phrase(String.valueOf(products.get(i).getGoodsId()),font));//商品编号
                cell.setFixedHeight(size);
                table.addCell(cell);
                cell = new PdfPCell(new Phrase(products.get(i).getGoodsName(),font));//商品名称
                cell.setFixedHeight(size);
                table.addCell(cell);
                cell = new PdfPCell(new Phrase(products.get(i).getSubject(),font));//描述
                cell.setFixedHeight(size);
                table.addCell(cell);
                cell = new PdfPCell(new Phrase(products.get(i).getPrice()+"",font));//商品价格
                cell.setFixedHeight(size);
                table.addCell(cell);
            }
            return table;
        }
    
    }

    用途:把数据添加到pdf的 document,注意对中文字体的引用

             另外注意插入图片时得到默认宽度的计算,需要减掉两侧的margin

    4,HomeController.java

    @RestController
    @RequestMapping("/home")
    public class HomeController {
    
        @Resource
        private GoodsMapper goodsMapper;
    
        @Resource
        PdfTableService pdfTableService;
    
        //把数据保存到pdf文件
        @GetMapping("/savepdf")
        public String savepdf() {
            List<Goods> goodsList = goodsMapper.selectAllGoods();
            String savePath = "/data/springboot2/goodslist.pdf";
            pdfTableService.createPDF(new Document(PageSize.A4), goodsList,savePath);
            return "pdf saveed";
        }
    
        //从浏览器直接显示pdf
        @GetMapping("/viewpdf")
        public ModelAndView viewpdf() {
            List<Goods> goodsList = goodsMapper.selectAllGoods();
            Map<String, Object> model = new HashMap<>();
            model.put("sheet", goodsList);
            ViewPdfUtil viewPdf = new ViewPdfUtil();
            viewPdf.setFileName("测试.pdf");
            viewPdf.setPdfType("goods");
            return new ModelAndView(viewPdf, model);
        }
    
        //下载pdf文件
        @GetMapping("/downpdf")
        public void downpdf() {
              String filepath = "/data/springboot2/goodslist.pdf";
              PdfUtil.downPdfFile(filepath);
         }
    }

    三个功能:直接显示,保存成文件,下载

    五,效果测试

    1,直接显示:

    访问:

    http://127.0.0.1:8080/home/viewpdf

    如图:

    2,直接保存成pdf文件:

    访问:

    http://127.0.0.1:8080/home/savepdf

    效果如图:

    3,下载pdf文件:

    访问:

    http://127.0.0.1:8080/home/downpdf

    六,查看spring boot的版本:

      .   ____          _            __ _ _
     /\ / ___'_ __ _ _(_)_ __  __ _    
    ( ( )\___ | '_ | '_| | '_ / _` |    
     \/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.3.2.RELEASE)
  • 相关阅读:
    eclipse禁用svg文件Validation
    在centos上安装jenkins
    5.volatile的应用
    4.资源限制
    linux git保存用户名密码(避免每次push输用户名密码)
    mysql 从库落后主库太多优化
    mfs使用指引
    Asura监控---AsuraMonitor,阿修罗监控开源
    docker overlay网络实现
    ELK+kafka日志收集
  • 原文地址:https://www.cnblogs.com/architectforest/p/13398442.html
Copyright © 2011-2022 走看看