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("width:"+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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM