SpringBoot与文档excel,pdf集成案例分享

一、文档类型介绍

1、Excel文档

Excel一款电子表格软件。直观的界面、出色的计算功能和图表工具,在系统开发中,经常用来把数据转存到Excel文件,或者Excel数据导入系统中,这就涉及数据转换问题。

2、PDF文档

PDF是可移植文档格式,是一种电子文件格式,具有许多其他电子文档格式无法相比的优点。PDF文件格式可以将文字、字型、格式、颜色及独立于设备和分辨率的图形图像等封装在一个文件中。该格式文件还可以包含超文本链接、声音和动态影像等电子信息,支持特长文件,集成度和安全可靠性都较高。

二、Excel文件管理

1、POI依赖

Apache POI是Apache软件基金会的开源类库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。

github: https://github.com/apache/poi

<!-- Excel 依赖 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
</dependency>
<!-- 2007及更高版本 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>

2、文件读取

public static List<List<Object>> readExcel(String path) throws Exception {
    File file = new File(path) ;
    List<List<Object>> list = new LinkedList<>();
    XSSFWorkbook xwb = new XSSFWorkbook(new FileInputStream(file));
    // 读取 Sheet1 表格内容
    XSSFSheet sheet = xwb.getSheetAt(0);
    // 读取行数:不读取Excel表头
    for (int i = (sheet.getFirstRowNum()+1); i <= (sheet.getPhysicalNumberOfRows()-1); i++) {
        XSSFRow row = sheet.getRow(i);
        if (row == null) { continue; }
        List<Object> linked = new LinkedList<>();
        for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
            XSSFCell cell = row.getCell(j);
            if (cell == null) { continue; }
            Object value ;
            // 这里需根据实际业务情况处理
            switch (cell.getCellType()) {
                case XSSFCell.CELL_TYPE_NUMERIC:
                    //处理数值带{.0}问题
                    value = Double.valueOf(String.valueOf(cell)).longValue() ;
                    break;
                default:
                    value = cell.toString();
            }
            linked.add(value);
        }
        if (linked.size()!= 0) {
            list.add(linked);
        }
    }
    return list;
}

3、文件创建

public static void createExcel(String excelName, String[] headList,List<List<Object>> dataList)
        throws Exception {
    // 创建 Excel 工作簿
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet();
    // 创建表头
    XSSFRow row = sheet.createRow(0);
    for (int i = 0; i < headList.length; i++) {
        XSSFCell cell = row.createCell(i);
        cell.setCellType(XSSFCell.CELL_TYPE_STRING);
        cell.setCellValue(headList[i]);
    }
    //添加数据
    for (int line = 0; line < dataList.size(); line++) {
        XSSFRow rowData = sheet.createRow(line+1);
        List<Object> data = dataList.get(line);
        for (int j = 0; j < headList.length; j++) {
            XSSFCell cell = rowData.createCell(j);
            cell.setCellType(XSSFCell.CELL_TYPE_STRING);
            cell.setCellValue((data.get(j)).toString());
        }
    }
    FileOutputStream fos = new FileOutputStream(excelName);
    workbook.write(fos);
    fos.flush();
    fos.close();
}

4、文件导出

public static void exportExcel(String[] headList, List<List<Object>> dataList,
                               OutputStream outputStream) throws Exception {
    // 创建 Excel 工作簿
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet();
    // 创建表头
    XSSFRow row = sheet.createRow(0);
    for (int i = 0; i < headList.length; i++) {
        XSSFCell cell = row.createCell(i);
        cell.setCellType(XSSFCell.CELL_TYPE_STRING);
        cell.setCellValue(headList[i]);
    }
    //添加数据
    for (int line = 0; line < dataList.size(); line++) {
        XSSFRow rowData = sheet.createRow(line+1);
        List<Object> data = dataList.get(line);
        for (int j = 0; j < headList.length; j++) {
            XSSFCell cell = rowData.createCell(j);
            cell.setCellType(XSSFCell.CELL_TYPE_STRING);
            cell.setCellValue((data.get(j)).toString());
        }
    }
    workbook.write(outputStream);
    outputStream.flush();
    outputStream.close();
}

5、文件导出接口

@RestController
public class ExcelDownLoadWeb {
    @RequestMapping("/file/outExcel")
    public void outExcel (HttpServletResponse response) throws Exception {
        String exportName = "2023-05-BSDATA" ;
        response.setContentType("application/vnd.ms-excel");
        response.addHeader("Content-Disposition", "attachment;filename="+
                             URLEncoder.encode(exportName, "UTF-8") + ".xlsx");
        List<List<Object>> dataList = ExcelUtil.readExcel("F:\\file-type\\user-excel.xlsx") ;
        String[] headList = new String[]{"测站", "时间", "降雨量"} ;
        ExcelUtil.exportExcel(headList,dataList,response.getOutputStream()) ;
    }
}

三、PDF文件管理

1、IText依赖

iText是一种生成PDF报表的Java组件。通过在服务器端使用页面或API封装生成PDF报表,客户端可以通过超链接直接显示或下载到本地,在系统开发中通常用来生成比较正式的报告或者合同类的电子文档。

github: https://github.com/itext/itextpdf

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.11</version>
</dependency>
<dependency>
    <groupId>com.itextpdf.tool</groupId>
    <artifactId>xmlworker</artifactId>
    <version>5.5.11</version>
</dependency>

2、API二次封装

首先对于Itext提供的API做一下表格、段落、图片等基础样式的二次封装,可以更好的适配业务。

public class PdfFontUtil {
    private PdfFontUtil(){}

    /**
     * 段落样式获取
     */
    public static Paragraph getParagraph (String content, Font font,Integer alignment){
        Paragraph paragraph = new Paragraph(content,font) ;
        if (alignment != null && alignment >= 0){
            paragraph.setAlignment(alignment);
        }
        return paragraph ;
    }
    /**
     * 图片样式
     */
    public static Image getImage (String imgPath,float width,float height) throws Exception {
        Image image = Image.getInstance(imgPath);
        image.setAlignment(Image.MIDDLE);
        if (width > 0 && height > 0){
            image.scaleAbsolute(width, height);
        }
        return image ;
    }
    /**
     * 表格生成
     */
    public static PdfPTable getPdfPTable01 (int numColumns,float totalWidth) throws Exception {
        // 表格处理
        PdfPTable table = new PdfPTable(numColumns);
        // 设置表格宽度比例为%100
        table.setWidthPercentage(100);
        // 设置宽度:宽度平均
        table.setTotalWidth(totalWidth);
        // 锁住宽度
        table.setLockedWidth(true);
        // 设置表格上面空白宽度
        table.setSpacingBefore(10f);
        // 设置表格下面空白宽度
        table.setSpacingAfter(10f);
        // 设置表格默认为无边框
        table.getDefaultCell().setBorder(0);
        table.setPaddingTop(50);
        table.setSplitLate(false);
        return table ;
    }
    /**
     * 表格内容
     */
    public static PdfPCell getPdfPCell (Phrase phrase){
        return new PdfPCell (phrase) ;
    }
    /**
     * 表格内容带样式
     */
    public static void addTableCell (PdfPTable dataTable,Font font,List<String> cellList){
        for (String content:cellList) {
            dataTable.addCell(getParagraph(content,font,-1));
        }
    }
}

3、生成PDF文件

这里基于上面的工具类,画一个PDF页面作为参考。

public class PdfPagetTest {
    // 基础配置
    private static String PDF_SITE = "E:\\temp\\PDF页面2023-04-15.pdf" ;
    private static String FONT = "C:/Windows/Fonts/simhei.ttf";
    private static String PAGE_TITLE = "PDF" ;
    // 基础样式
    private static Font TITLE_FONT = FontFactory.getFont(FONT, BaseFont.IDENTITY_H,20, Font.BOLD);
    private static Font NODE_FONT = FontFactory.getFont(FONT, BaseFont.IDENTITY_H,15, Font.BOLD);
    private static Font BLOCK_FONT = FontFactory.getFont(FONT, BaseFont.IDENTITY_H,13, Font.BOLD, BaseColor.BLACK);
    private static Font INFO_FONT = FontFactory.getFont(FONT, BaseFont.IDENTITY_H,12, Font.NORMAL,BaseColor.BLACK);
    private static Font CONTENT_FONT = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

    private static void createPdfPage () throws Exception {
        // 创建文档
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(PDF_SITE));
        document.open();
        // 报告标题
        document.add(PdfFontUtil.getParagraph(PAGE_TITLE,TITLE_FONT,1)) ;
        document.add(PdfFontUtil.getParagraph("\n商户名称:XXX科技有限公司",INFO_FONT,-1)) ;
        document.add(PdfFontUtil.getParagraph("\n生成时间:2020-01-15\n\n",INFO_FONT,-1)) ;
        // 报告内容
        // 段落标题 + 报表图
        document.add(PdfFontUtil.getParagraph("城市数据分布统计",NODE_FONT,-1)) ;
        document.add(PdfFontUtil.getParagraph("\n· 可视化图表\n\n",BLOCK_FONT,-1)) ;
        // 设置图片宽高
        float documentWidth = document.getPageSize().getWidth() - document.leftMargin() - document.rightMargin();
        float documentHeight = documentWidth / 580 * 320;
        document.add(PdfFontUtil.getImage("F:\\file-type\\myChart.jpg",documentWidth-80,documentHeight-80)) ;
        // 数据表格
        document.add(PdfFontUtil.getParagraph("\n· 数据详情\n\n",BLOCK_FONT,-1)) ;
        PdfPTable dataTable = PdfFontUtil.getPdfPTable01(4,400) ;
        // 设置表格
        List<String> tableHeadList = tableHead () ;
        List<List<String>> tableDataList = getTableData () ;
        PdfFontUtil.addTableCell(dataTable,CONTENT_FONT,tableHeadList);
        for (List<String> tableData : tableDataList) {
            PdfFontUtil.addTableCell(dataTable,CONTENT_FONT,tableData);
        }
        document.add(dataTable);
        document.add(PdfFontUtil.getParagraph("\n· 报表描述\n\n",BLOCK_FONT,-1)) ;
        document.add(PdfFontUtil.getParagraph("数据报告可以监控每天的推广情况," +
                "可以针对不同的数据表现进行分析,以提升推广效果。",CONTENT_FONT,-1)) ;
        document.newPage() ;
        document.close();
        writer.close();
    }
    private static List<List<String>> getTableData (){
        List<List<String>> tableDataList = new ArrayList<>() ;
        for (int i = 0 ; i < 3 ; i++){
            List<String> tableData = new ArrayList<>() ;
            tableData.add("浙江"+i) ;
            tableData.add("杭州"+i) ;
            tableData.add("276"+i) ;
            tableData.add("33.3%") ;
            tableDataList.add(tableData) ;
        }
        return tableDataList ;
    }
    private static List<String> tableHead (){
        List<String> tableHeadList = new ArrayList<>() ;
        tableHeadList.add("省份") ;
        tableHeadList.add("城市") ;
        tableHeadList.add("数量") ;
        tableHeadList.add("百分比") ;
        return tableHeadList ;
    }
    public static void main(String[] args) throws Exception {
        createPdfPage () ;
    }
}

4、页面效果

四、网页转PDF

1、页面Jar包依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2、编写页面样式

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{font-family:SimSun;}
    </style>
</head>
<body>
项目信息:<br/>
名称:${name}<br/>
作者:${author}<br/><br/>
<img 
src="https://oscimg.oschina.net/oscnet/up-612b9330a67ba747846b0e0890e4906678b.png"/>
<br/>
</body>
</html>

3、核心配置类

public class PageConfig {
    private static final String DEST = "F:\\file-type\\HTML页面2020-01-15.pdf";
    private static final String HTML = "/pdf_page_one.html";
    private static final String FONT = "C:/Windows/Fonts/simsun.ttc";
    private static Configuration freemarkerCfg = null ;
    static {
        freemarkerCfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        //freemarker的模板目录
        try {
            String path = "TODO:模板路径{自定义}" ;
            freemarkerCfg.setDirectoryForTemplateLoading(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 创建文档
     */
    private static void createPdf(String content,String dest) throws Exception {
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        document.open();
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
        document.close();
    }
    /**
     * 页面渲染
     */
    private static String freeMarkerRender(Map<String, Object> data, String htmlTmp) throws Exception {
        Writer out = new StringWriter();
        Template template = freemarkerCfg.getTemplate(htmlTmp,"UTF-8");
        template.process(data, out);
        out.flush();
        out.close();
        return out.toString();
    }
    /**
     * 方法入口
     */
    public static void main(String[] args) throws Exception {
        Map<String,Object> data = new HashMap<> ();
        data.put("name","smile");
        data.put("author","知了") ;
        String content = PageConfig.freeMarkerRender(data,HTML);
        PageConfig.createPdf(content,DEST);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/48904.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

干翻Dubbo系列第四篇:Dubbo3第一个应用程序细节补充

前言 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽都顺利。 如…

Higress非K8S安装

Higress非K8S安装 文章目录 Higress非K8S安装环境安装安装higress进入到higress 的目录下修改下nacos的地址启动Higress登录higress管理页面 Higress 是基于阿里内部构建的下一代云原生网关&#xff0c;官网介绍&#xff1a;https://higress.io/zh-cn/docs/overview/what-is-hi…

HuggingGPT Solving AI Tasks with ChatGPT and its Friends in Hugging Face

总述 HuggingGPT 让LLM发挥向路由器一样的作用&#xff0c;让LLM来选择调用那个专业的模型来执行任务。HuggingGPT搭建LLM和专业AI模型的桥梁。Language is a generic interface for LLMs to connect AI models 四个阶段 Task Planning&#xff1a; 将复杂的任务分解。但是这里…

外文期刊影响因子去哪里查询,如何查询

期刊影响因子(Impact factor&#xff0c;IF)&#xff0c;是代表期刊影响大小的一项定量指标。也就是某刊平均每篇论文的被引用数&#xff0c;它实际上是某刊在某年被全部源刊物引证该刊前两年发表论文的次数&#xff0c;与该刊前两年所发表的全部源论文数之比。那么&#xff0c…

《嵌入式 - 工具》J-link读写MCU内部Flash

1 J-Link简介 J-Link是SEGGER公司为支持仿真ARM内核芯片推出的JTAG仿真器。配合IAR EWAR&#xff0c;ADS&#xff0c;KEIL&#xff0c;WINARM&#xff0c;RealView等集成开发环境支持所有ARM7/ARM9/ARM11,Cortex M0/M1/M3/M4, Cortex A5/A8/A9等内核芯片的仿真&#xff0c;是学…

redis 第二章

目录 1.持久化 2.主从复制 3.总结 1.持久化 通过 aof 和 rdb 将内存里的数据放到磁盘中 aof: rdb: 2.主从复制 将一台 redis 服务器的数据&#xff0c;复制到其他的 redis 服务器 3.总结 主从复制是高可用 redis 的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可…

线性代数(基础篇):第一章:行列式 、第二章:矩阵

文章目录 线性代数0&#xff1a;串联各章等价条件 第1章 行列式1.行列式的定义(1)行列式的本质定义(2)行列式的逆序数法定义(3)行列式的展开定理 (第三种定义) 2.行列式的性质3.行列式的公式4.基本行列式(1)主对角线行列式(2)副对角线行列式(3)拉普拉斯行列式(4)范德蒙德行列式…

深度学习入门(一):神经网络基础

一、深度学习概念 1、定义 通过训练多层网络结构对位置数据进行分类或回归&#xff0c;深度学习解决特征工程问题。 2、深度学习应用 图像处理语言识别自然语言处理 在移动端不太好&#xff0c;计算量太大了&#xff0c;速度可能会慢 eg.医学应用、自动上色 3、例子 使用…

关于Ubuntu 18.04 LTS环境下运行程序出现的问题

关于Ubuntu 18.04 LTS环境下运行程序出现的问题 1.运行程序时出现以下情况 2.检查版本 strings /lib/x86_64-linux-gnu/libc.so.6 |grep GLIBC_​ 发现Ubuntu18.04下的glibc版本最高为2.27,而现程序所使用的是glibc2.34,所以没办法运行, 3.解决办法 安装glibc2.34库, …

HCIA练习4

题目如下&#xff1a; 目录 第一步&#xff1a;IP的规划 第二步&#xff1a;缺省路由 第三步&#xff1a;开启telnet 第四步&#xff1a;编写ACL表 第五步&#xff1a;测试 思路分析&#xff1a; 华为默认允许所有&#xff0c;所以我们可以先写拒绝要求&#xff0c;再写允…

TD1850多用表校准系统参考标准

参考标准 分类 标准名称 国家标准 GB/T 13978-2008 数字多用表 GB/T 15637-2012 数字多用表校准仪通用规范 计量法规 JJF 1075-2015 钳形电流表校准规范 JJF 1284-2011 交直流电表校验仪校准规范 JJF 1587-2016 数字多用表校准规范 JJG 124-2005 电流表、电压表、功率表及…

脉冲信号测试应如何选择示波器带宽?

示波器模拟带宽的定义大家都比较熟悉&#xff0c;是针对于正弦波信号定义的。从频域上看&#xff0c;正弦波信号的频谱就是单根谱线&#xff0c;只要示波器的带宽不小于信号的频率&#xff0c;那么就可以有效观测到波形。若要追求更高的幅度测试精度&#xff0c;则可以按照5倍法…

pytest——断言后继续执行

前言 在编写测试用例的时候&#xff0c;一条用例可能会有多条断言结果&#xff0c;当然在自动化测试用例中也会遇到这种问题&#xff0c;我们普通的断言结果一旦失败后&#xff0c;就会出现报错&#xff0c;哪么如何进行多个断言呢&#xff1f;pytest-assume这个pytest的插件就…

Git使用详细教程

1. cmd面板的常用命令 clear&#xff1a;清屏cd 文件夹名称----进入文件夹cd … 进入上一级目录(两个点)dir 查看当前目录下的文件和文件夹(全拼:directory)Is 查看当前目录下的文件和文件夹touch 文件名----创建文件echo 内容 > 创建文件名----创建文件并写入内容rm 文件名…

ESP32 官方AT固件编译(从零开始环境搭建到编译完成全过程)

1、下载VMware免费版 https://download3.vmware.com/software/WKST-PLAYER-1702/VMware-player-full-17.0.2-21581411.exe 2、下载Ubuntu &#xff08;ubuntu-22.04.2-desktop-amd64.iso&#xff09;** https://releases.ubuntu.com/jammy/ubuntu-22.04.2-desktop-amd64.iso…

Solr原理剖析

一、简介 Solr是一个高性能、基于Lucene的全文检索服务器。Solr对Lucene进行了扩展&#xff0c;提供了比Lucene更为丰富的查询语言&#xff0c;并实现了强大的全文检索功能、高亮显示、动态集群&#xff0c;具有高度的可扩展性。同时从Solr 4.0版本开始&#xff0c;支持SolrCl…

vue element ui el-tree 通过子节点反向递归查找父节点

今天做了一个项目采用的是element tree组件&#xff0c;要求子父节点不强关联&#xff0c;但是当我点击子节点时&#xff0c;会反向的选择所有的父节点&#xff0c;如下图&#xff1a; 当我点击电话时&#xff0c;往上一层的“电话”和“我的”均为父级以上的节点&#xff0c;全…

服务器负载均衡算法有哪些

算法举例 服务器负载均衡算法是用于分配网络流量到多个服务器的策略&#xff0c;以实现负载均衡和提高系统性能。以下是一些常见的服务器负载均衡算法的详细说明&#xff1a; 轮询&#xff08;Round Robin&#xff09;算法&#xff1a; 轮询算法是最简单且常见的负载均衡算法之…

kubernetes 证书更新

参考&#xff1a; https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/https://kubernetes.io/zh-cn/docs/tasks/tls/certificate-rotation/ 查看证书 查看 kubelet是否支持证书自动轮换&#xff0c;默认轮换的证书位于目录 /var/lib/kubele…

Clion配置与使用记录

Clion与ROS2、docker 为了能够在Docker中使用ROS2环境&#xff0c;同时Clion能够在编辑代码时可以有代码提示以及函数、变量跳转等功能 Docker配置 参考&#xff1a;Docker SSH配置 启动Docker&#xff0c;需要将端口映射&#xff0c;添加如下参数&#xff1a; -p 8024:22&…