java 利用poi根据excel模板导出数据(一)

前言

作为B端开发,导出数据是不可以避免的,但是有时候需求很变态,表头复杂的一笔,各种合并单元格,如下图:

 

 这些虽说用代码可以实现,但是很繁琐,而且代码并不能通用,遇到更复杂的更难受。为了追求更简单,高效率,我们需要换个方法-------利用模板导出数据!

?????能用模板?????

sure!

本文所用的excel样式,如果列更多、更复杂,直接套用就行  (下方图片中的数字是列名),行序号为1的是表格标题名称,行序号为2的是适应导出时把条件也导出来的情况,别怀疑,就是有这种需求!!

 

正文开始

1.需要用到的包

 poi

  <!-- json4excel,poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.3</version>
        </dependency>

nutz(工具包,非必须,公司框架,本文与之相关的就只有一个NutMap==Map<String,Object>,不用这个请手动替换)

   <!-- https://mvnrepository.com/artifact/org.nutz/nutz -->
        <dependency>
            <groupId>org.nutz</groupId>
            <artifactId>nutz</artifactId>
            <version>1.r.68.v20200427</version>
        </dependency>

2.直接上代码

  入口

    public static void doExportLongArrearsData() {
        // 要导出的数据
        NutMap nutMap = NutMap.NEW();
        nutMap.addv("comm","1111");
        nutMap.addv("a","1111");
        nutMap.addv("b","2222");
        nutMap.addv("c","11333311");
        nutMap.addv("d","1114441");
        nutMap.addv("e","555");
        nutMap.addv("f","6666");
        nutMap.addv("g","7777");
        nutMap.addv("h","88888");
        List<NutMap> list = Lists.newArrayList();
        list.add(nutMap);
        // 导出列  列数
        int colNum = 9;
        int[] colWidth = new int[colNum];
        for (int i = 0; i < colNum; i++) {
            colWidth[i] = 23;
        }
        // 从XX行开始为数据内容  excel 第一行为0
        int startRow = 5;
        //  2003版本的Excel (xls) ---- HSSFWorkbook
        //    2007版本以及更高版本 (xlsx)---- XSSFWorkbook
        XSSFWorkbook workbook = null;
        try {
            // 此处linux和windows通用   /files/cq.xlsx 在resource目录下  视情况而定
 
        /**
             *   特殊说明: this.getClass().getResourceAsStream 
             *   如果fileUrl路径前不加 / 那么会读取类文件夹下的文件。加了才会读取resource下面的文件
             *   exp: this.getClass().getResourceAsStream("/files/cq.xlsx") ==>读取resource下面的文件
             *   this.getClass().getResourceAsStream("files/cq.xlsx") ==>读取当前类下的文件
             *   源码:
             *     private String resolveName(String name) {
             *         if (name == null) {
             *             return name;
             *         }
             *         if (!name.startsWith("/")) {
             *             Class<?> c = this;
             *             while (c.isArray()) {
             *                 c = c.getComponentType();
             *             }
             *             String baseName = c.getName();
             *             int index = baseName.lastIndexOf('.');
             *             if (index != -1) {
             *                 name = baseName.substring(0, index).replace('.', '/')
             *                     +"/"+name;
             *             }
             *         } else {
             *             name = name.substring(1);
             *         }
             *         return name;
             *     }
             */
            //  InputStream inputStream = this.getClass().getResourceAsStream("/files/cq.xlsx");
            FileInputStream inputStream = new FileInputStream( new File("C:\\Users\\usaer\\Desktop\\buss.xlsx"));
            workbook = new XSSFWorkbook(inputStream);
 
            // 获取sheet
            XSSFSheet sheetAt = workbook.getSheetAt(0);
 
            // 动态列  修改表头名 、修改模板数据等操作
            // 自定义参数
            int k = 1;
            updateCellLoad(workbook,sheetAt,k);
 
            // 填充数据
            fillBodyData( sheetAt,startRow,list,colWidth);
 
            // 设置单元格宽度 (不设置的话,就是模板的宽度)
            if (null != colWidth) {
                for (int i = 0; i < colWidth.length; i++) {
                    sheetAt.setColumnWidth(i, colWidth[i] * 256 + 184);
                }
            }
 
            // 输出流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            // excel工作空间写入流
            workbook.write(byteArrayOutputStream);
            InputStream wrap = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            // 写到本地
            writeToLocal("C:\\Users\\usaer\\Desktop\\buss_"+k+".xlsx",wrap);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            // 关闭流
            if (null != workbook)
                try {
                    workbook.close();
                }
                catch (IOException e) {
 
                }
        }
    }

修改列的方法 (填充数据之前之后都可以修改内容,包括但不限于修改列、修改行、样式等)

 
    public static void updateCellLoad( XSSFWorkbook workbook,Sheet sheet,int k) {
        try {
            //设置行 指定行 
            Row titlerow=sheet.getRow(2);
            //根据索引获取对应的列   如果合并单元格 有可能第一列就找不到  根据需求修改参数值
            Cell cell=titlerow.getCell(0, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
            //设置列的类型是字符串
            cell.setCellType(CellType.STRING);
            cell.setCellValue(k==1?"1":"0");
            String titleValue=cell.getStringCellValue();
            System.out.println(titleValue);
 
 
            // 设置行 指定行修改数据和样式 有可能第一行就找不到  根据需求修改参数值
            CellStyle style1 = workbook.createCellStyle();
            // 自动换行
            style1.setWrapText(true);
            Row row1 = sheet.createRow(1);
            // 行高度
            row1.setHeight(Short.parseShort("1000"));
            Cell row1Cell = row1.createCell(0, CellType.STRING);
            row1Cell.setCellStyle(style1);
            StringBuilder sb = new StringBuilder();
            sb.append("条件1:").append("ABC").append("\r\n");
            sb.append("条件2:").append("DEF").append("\r\n");
            sb.append("条件3:").append("GHI").append("\r\n");
            row1Cell.setCellValue(sb.toString());
 
        } catch (EncryptedDocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }

填充数据的方法

private static void fillBodyData(Sheet sheet, int startRow, List<NutMap> bodyList, int[] colWidth) {
 
        // 碰到 时间、金额等需要转换的  在setCellValue 里面操作
        for (int rowNum = 0; rowNum < bodyList.size(); rowNum++) {
            NutMap map = bodyList.get(rowNum);
            Row row = sheet.createRow(rowNum + startRow);
            int colNum = 0;
            // comm
            Cell accountNumberCell = row.createCell(colNum++, CellType.STRING);
            String accountNumber = map.getString("comm");
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(accountNumber));
            accountNumberCell.setCellValue(accountNumber);
            // a
            Cell accountNameCell = row.createCell(colNum++, CellType.STRING);
            String accountName = map.getString("a");
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(accountName));
            accountNameCell.setCellValue(accountName);
            // b
            Cell mobileCell = row.createCell(colNum++, CellType.STRING);
            String mobile = map.getString("b");
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(mobile));
            mobileCell.setCellValue(mobile);
 
            // c
            Cell addressCell = row.createCell(colNum++, CellType.STRING);
            String address = map.getString("c");
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(address));
            addressCell.setCellValue(address);
 
            // d
            Cell meterNoCell = row.createCell(colNum++, CellType.STRING);
            String meterNo = map.getString("d");
            meterNoCell.setCellValue(meterNo);
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(meterNo));
 
            // e
            Cell uncollectedNumberCell = row.createCell(colNum++, CellType.STRING);
            String uncollectedNumber = map.getString("e");
            uncollectedNumberCell.setCellValue(uncollectedNumber);
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(uncollectedNumber));
 
            // f
            Cell uncollectedDosageCell = row.createCell(colNum++, CellType.STRING);
            String uncollectedDosage = map.getString("f");
            uncollectedDosageCell.setCellValue(uncollectedDosage);
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(uncollectedDosage));
 
            // g
            Cell uncollectedDosageCell1 = row.createCell(colNum++, CellType.STRING);
            String uncollectedDosage1 = map.getString("g");
            uncollectedDosageCell1.setCellValue(uncollectedDosage1);
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(uncollectedDosage1));
 
            // h
            Cell uncollectedDosageCell2 = row.createCell(colNum++, CellType.STRING);
            String uncollectedDosage2 = map.getString("h");
            uncollectedDosageCell2.setCellValue(uncollectedDosage2);
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(uncollectedDosage2));
        }
    }

写到本地

 private static void writeToLocal(String destination, InputStream input)
            throws IOException {
        int index = 0;
        byte[] bytes = new byte[1024];
        FileOutputStream downloadFile = new FileOutputStream(destination);
        while ((index = input.read(bytes)) > 0) {
            downloadFile.write(bytes, 0, index);
        }
        downloadFile.close();
        input.close();
    }

代码就这些,纯测试,有些命名很随意,到时候用的时候自己改

效果图

注意: 

本文读取文件是从本地读取的,部署后,需要把模板文件放在resource下,利用代码中

 // 此处linux和windows通用   /files/cq.xlsx 在resource目录下  视情况而定
           //  InputStream inputStream = this.getClass().getResourceAsStream("/files/cq.xlsx");

来读取(本人框架非spring,spring自行解决),总之,获取到模板文件就是成功!!

如果想要设置单元格的样式比如字体垂直、水平居中等可以在  fillBodyData 中添加如下代码

 // 单元格样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        // 设置单元格的水平对齐类型
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 设置单元格的垂直对齐类型
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

 然后再循环体内每个cell设置style ,例如:

 Cell accountNumberCell = row.createCell(colNum++, CellType.STRING);
            String accountNumber = map.getString("comm");
            colWidth[colNum - 1] = Math.max(colWidth[colNum - 1], Strings.charLength(accountNumber));
            accountNumberCell.setCellValue(accountNumber);
// 设置style
            accountNumberCell.setCellStyle(cellStyle);

 附加,如果springboot项目,获取项目目录下的模板,和直接输出到客户端,可参考:

@GetMapping("/exportTest4")
    //@ResponseBody
    public void exportTest4(HttpServletResponse response) {
//设置信息头,告诉浏览器内容为excel类型
        response.setHeader("content-Type", "application/vnd.ms-excel");
        //设置下载名称
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("展商模板.xlsx", StandardCharsets.UTF_8.name()));

//获取项目resources/excel目录下的excel模板文件
String REPORT_MONTH = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "/excel/test2.xlsx";
        String path = REPORT_MONTH;
        try{
            System.out.println("path1=="+path);
            path = path.substring(1,path.length());
            path = java.net.URLDecoder.decode(path,"utf-8");
            System.out.println("path2=="+path);
        }catch (Exception e){
            e.printStackTrace();
        }

        String filename = "D://核酸检测信息.xls";
        try {
            // 输出到硬盘,所以要用到IO流,输出到fileName指定的路径上
            FileOutputStream fos = new FileOutputStream(filename);
            wb.write(fos);//写出
            wb.close();//关闭
            System.out.println("导出成功");
        } catch (Exception e) {
            //异常信息
            e.printStackTrace();
        }
}

如果是若依系统,也可以使用若依的通用下载方式下载:

直接返回文件名称,然后再页面通过ajax再次请求

return success(filename);

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

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

相关文章

Python编程面试题及答案(20例)

以下是一些常见的Python编程面试题以及它们的答案&#xff1a; 1.解释Python中的 GIL&#xff08;全局解释器锁&#xff09;是什么&#xff0c;它对多线程编程有什么影响&#xff1f; 答案&#xff1a;GIL是Python解释器中的一个机制&#xff0c;它确保在任何给定时间只有一个…

Lecture 5 Part of Speech Tagging

目录 POS application: Information Extraction 词性应用&#xff1a;信息提取 POS Open Class 开放类词性Problem of word classes: Ambiguity 词类问题&#xff1a;模糊性Tagsets 标记集Penn Treebank Tags:Derived Tags: 衍生标签Tagged Text Example 标记文本示例Reasons f…

160个CrackMe之001

吾爱中的逆向练习题 运行程序 有两个方式 一个是账号登入 一个是序列号输入 账号输入 方法一 爆破 我们先进行账号输入 这个是最简单的逆向 所以我们可以使用 字符串查找看看 先试用ollydbg打开 右键 ->查找 ->所有参考文本字符串 这里我们能发现有两个报错 我们还…

通过python封装1688图片搜索商品数据接口,拍立淘API接口

1688图片搜索API封装接口是一个可以帮助用户快速使用1688图片搜索API的接口封装库。该接口封装库可以帮助用户快速引入1688图片搜索API&#xff0c;并提供各种参数配置和封装的API调用方法&#xff0c;以方便用户快速实现自己的图片搜索需求。 该接口封装库将1688图片搜索API的…

九耶丨阁瑞钛伦特-springmvc(三)

SpringMVC作为一种流行的Java Web框架&#xff0c;是基于Spring之上的。它提供了强大的MVC&#xff08;Model-View-Controller&#xff09;架构&#xff0c;能够快速地实现Java Web开发&#xff0c;高效地与数据交互。如何使用SpringMVC成为开发人员的首要问题。要了解SpringMV…

设计模式之~外观模式

定义&#xff1a; 为子系统中的一组接口提供一个一致的界面&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 结构图&#xff1a; 区分中介模式&#xff1a; 门面模式对外提供一个接口 中介模式对内提供一个接口 优点&#xff1a; 松耦…

Linux进程概念引入

文章目录 冯诺依曼体系操作系统概念设计目的定位系统调用和库函数的概念 进程概念描述进程PCBtask_struct内容分类 组织进程查看进程通过系统调用获取进程标识符通过系统调用创建进程 冯诺依曼体系 目前我们的计算机基本都是遵守冯诺依曼体系的&#xff0c;在冯诺依曼体系中&am…

C++ 内存分区模型

C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的 全局区&#xff1a;存放全局变量和静态变量以及常量 栈区&#xff1a;由编译器自动分配释放 , 存放函数的参数值 , 局部变量等 堆区&…

第11届蓝桥杯Scratch国赛真题集锦

编程题 第 1题 问答题 3D打印小猫 题目说明 背景信息:3D打印技术,它与普通打印工作原理基本相同,打印机内装有液体或粉未等“打印材料”,与电脑连接后,通过电脑控制把“打印材料”一层层叠加起来,最终把计算机上的蓝图变成实物。 编程实现:通过滑杆控制小猫造型变化,按下…

YUM在线升级功能

文章目录 YUM在线升级功能利用YUM进行查询、安装、升级与删除功能查询功能使用案例 安装/升级功能删除功能 YUM的配置文件修改软件源产生的问题与解决之道使用案例 YUM的软件群组功能使用案例 全系统自动升级 管理的抉择&#xff1a;RPM还是Tarball基础服务案例&#xff1a;以A…

学生成绩管理系统

基于springboot vue实现的学生成绩管理系统 主要模块&#xff1a; 1&#xff09;学生模块&#xff1a;我的成绩、成绩统计、申述管理、修改密码 2&#xff09;教师模块&#xff1a;任务管理、对学生班级任务安排、班级学生的成绩查看、申述管理 3&#xff09;管理员模块&…

应用运维的三个项目

应用运维 目录概述需求&#xff1a; 设计思路实现思路分析1.开发和运维2.比重3.历史项目4.工作内容5.历程 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,…

南山城市更新--向南村(一期,二期)项目详情

向南村&#xff08;一期&#xff09;城市更新单元项目简介 项目于2010年被列入《深圳城市更新单元规划制定计划第一批计划》中&#xff0c;申报主体为向南实业股份有限公司&#xff0c;后与恒大合作开发。 项目位于南山区桂庙路南侧&#xff0c;毗邻前海、衔接后海&am…

javaWeb ssh小提琴管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh小提琴管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S 模式开发。开发环境为TOMCAT7.0,…

TypeScript实现贪吃蛇游戏

TS实现贪吃蛇游戏 文章目录 TS实现贪吃蛇游戏[toc]1.项目效果2.项目梳理3.项目准备4.主体页面结构5.CSS样式6.TS逻辑6.1 食物逻辑6.2 蛇逻辑6.3 记分板逻辑6.4 游戏控制器逻辑6.5 程序入口ts 1.项目效果 项目体验 2.项目梳理 这个小游戏主要包括积分面板&#xff0c;食物&…

【Spring】— 映射文件

目录 映射文件select元素insert元素update元素和delete元素sql元素resultMap元素 映射文件 映射文件是MyBatis框架中十分重要的文件。在映射文件中&#xff0c;<mapper>元素是映射文件的根元素&#xff0c;其他元素都是它的子元素。映射文件中的主要元素如下所示。 <…

【owt】WebrtcNode, subscribe-sdp offer 流程(1)

sdp offer 流程 1. AmqpClient - New message received sdp offer 的消息 2023-04-26T21:54:19.790 - DEBUG: AmqpClient - RpcServer New message received {method: onTransportSignaling,args: [b149e44bb10d4e91bd162a8c6806ae7b,{sdp: v0\r\n o- 7177131362423164715 …

生活-考驾照2

昨日已通过科目一&#xff0c;接下来&#xff0c;向着科目二出发&#xff01;&#xff01;&#xff01; 考试注意事项 就考前一周死命刷题&#xff0c;至少一天有三次93以上的记录&#xff0c;我也就最后一天达到90&#xff0c;之前一直马路杀手刷题&#xff0c;我就在网页版…

WRF模式应用:天气预报、模拟分析观测气温、降水、风场、水汽和湿度、土地利用变化、土壤及近地层能量水分通量、土壤、水体、植被等相关气象变量

查看原文>>>高精度气象模拟软件WRF(Weather Research Forecasting)技术及案例应用 气候是多个领域&#xff08;生态、水资源、风资源及碳中和等问题&#xff09;的主要驱动因素&#xff0c;合理认知气候变化有利于解释生态环境变化机理及过程&#xff0c;而了解现在、…

Alibaba Arthas学习与使用

Alibaba Arthas学习与使用 目录 下载安装卸载退出快捷键重点部分: 命令 dashboardthreadjvmsyspropsysenvvmoptiongetstaticognlscsmjadmcredefinedumpclassloadermonitorwatchtracestackttoptionsprofiler 下载安装 # 下载 curl -O https://alibaba.github.io/arthas/art…