当前位置: 首页 > web >正文

利用Java自定义格式,循环导出数据、图片到excel

利用Java自定义格式,循环导出数据、图片到excel

  • 1、自定义格式循环导出数据
    • 1.1.设置格式
      • 1.1.1、居中样式
      • 1.1.2、应用样式到合并区域
      • 1.1.3、合并单元格
      • 1.1.4、设置列宽
    • 1.2、写入数据
      • 1.2.1、创建标签头部
      • 1.2.2、写入标签内容
  • 2、自定义格式循环导出图片
    • 2.1、设置格式并插入图片
  • 3、格式和数据写入统一封装
  • 4、测试方法和效果
    • 4.1、测试方法
    • 4.2、运行效果

1、自定义格式循环导出数据

我有一个需求,需要做一个标签,格式固定,但是数据从数据库中获取,手动一个一个写不现实,所以我考虑写个方法,自定义格式,循环的将数据导出到excel。
说明:

因为我要做的一个标签,占据excel 5行4列,所以在下面的代码中,会提到 4 5或者这两数的倍数关系,请注意这个情况

1.1.设置格式

1.1.1、居中样式

// 创建居中样式private static CellStyle createCenterStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();// 水平居中style.setAlignment(HorizontalAlignment.CENTER);// 垂直居中style.setVerticalAlignment(VerticalAlignment.CENTER);// 设置边框style.setBorderTop(BorderStyle.THIN);style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);//字体Font font = workbook.createFont();font.setFontName("微软雅黑"); // 设置字体类型font.setFontHeightInPoints((short) 8); // 设置字体大小style.setFont(font);return style;}

1.1.2、应用样式到合并区域

    /*** 应用样式到合并区域* @param sheet 工作表* @param region 合并区域* @param style 样式*/private static void applyStyleToMergedRegion(Sheet sheet, CellRangeAddress region, CellStyle style) {for (int row = region.getFirstRow(); row <= region.getLastRow(); row++) {Row sheetRow = sheet.getRow(row) != null ? sheet.getRow(row) : sheet.createRow(row);for (int col = region.getFirstColumn(); col <= region.getLastColumn(); col++) {Cell cell = sheetRow.getCell(col) != null ?sheetRow.getCell(col) : sheetRow.createCell(col);cell.setCellStyle(style);}}}

1.1.3、合并单元格

	/*** 合并单元格并居中* @param sheet 工作表* @param centerStyle 样式* @param columnsNum 列数* @param lineNum 行数*/private static void mergeAndCenterCells(Sheet sheet, CellStyle centerStyle,int columnsNum, int lineNum) {for (int i = 0; i < lineNum; i=i+5) {for (int j = 0; j < columnsNum; j=j+4) {//标签头部的合并区域  同一行 4列CellRangeAddress titleMerge = new CellRangeAddress(i, i, j, j+3);//图片合并区域 标签头部第2行到第5行 第1列到第2列CellRangeAddress photoMerge = new CellRangeAddress(i+1, i+4, j, j+1);//数据合并区域CellRangeAddress queMerge = new CellRangeAddress(i+3, i+3, j+2, j+3);CellRangeAddress timeMerge = new CellRangeAddress(i+4, i+4, j+2, j+3);//写入工作表sheet.addMergedRegion(titleMerge);sheet.addMergedRegion(photoMerge);sheet.addMergedRegion(queMerge);sheet.addMergedRegion(timeMerge);// 应用居中样式到合并区域applyStyleToMergedRegion(sheet, titleMerge, centerStyle);applyStyleToMergedRegion(sheet, photoMerge, centerStyle);applyStyleToMergedRegion(sheet, queMerge, centerStyle);applyStyleToMergedRegion(sheet, timeMerge, centerStyle);}}}

1.1.4、设置列宽

循环设置标签列宽,以适应图片和数据,大小 1 * 256 为1个字符。

 	/*** 设置列的宽度 以适应图片和数据* @param columnsNum 列数* @param sheet 工作表*/private static void setColumnWidth(int columnsNum,Sheet sheet){//循环设置标签的列宽for (int i=0;i<columnsNum;i=i+4){sheet.setColumnWidth(i, 4 * 256); // 设置第一列宽度为4个字符sheet.setColumnWidth(i+1, 4 * 256); // 设置第二列宽度为4个字符sheet.setColumnWidth(i+2, 12 * 256); // 设置第三列宽度为12个字符sheet.setColumnWidth(i+3, 12 * 256); // 设置第四列宽度为12个字符}}

1.2、写入数据

1.2.1、创建标签头部

	/*** 创建标签头部* @param sheet 工作表* @param style 居中样式* @param mainTitleStr 头部数据* @param columnsNum 列数* @param lineNum 行数*/private static void createHeader(Sheet sheet, CellStyle style,String mainTitleStr,int columnsNum, int lineNum) {for (int i = 0; i < lineNum; i=i+5) {// 隔5行设置一次Row headerRow = sheet.createRow(i);// 主标题(将被合并)for (int j = 0; j < columnsNum; j=j+4) {//隔4列设置一次Cell mainTitle = headerRow.createCell(j);mainTitle.setCellValue(mainTitleStr);mainTitle.setCellStyle(style);}}}

1.2.2、写入标签内容

标签固定的内容可以在这里先写好,其他有变动的可以从其他渠道获取后再去拼接。

    /*** 设置内容格式及数据 固定不变的可以在这里写好 其他从数据库取到的再去拼接* @param sheet 工作表* @param style 样式* @param List 从数据库或其他途径取到的数据* @param columnsNum 列数* @param lineNum 行数*/private static void createContent(Sheet sheet, CellStyle style,List<Map<Object,Object>> List,int columnsNum, int lineNum) {int lineTemp=0;// 临时的 行数int columnsTemp=0;// 临时的 列数for (Map<Object,Object> map:List) {//搞成二位数据 直接固定格式 后续方便固定格式 写入excel表格Object[][] data = {{"型号:"+map.get("name"), "夹具类型:"+ map.get("type")},{"精度:符合标准", "编号:"+map.get("num")},{"确认人:xxx □    xxx □   "},{"点检有效期:"+ DateUtil.year(new Date())+"       - "+ DateUtil.year(new Date())+"         "},};//遍历二维数组for (int i = 0; i < data.length; i++) {int temp=lineTemp+i + 1;//要生成指定行 行数  +1 是因为数据在标签头部下面写入//这么做的目的是 为了避免重新生成一行,导致之前的数据被删除Row row=sheet.getRow(temp);//获得之前生成的行if (row==null){//如果之前未生成行 那将需要去生成row = sheet.createRow(temp);}int cellTemp=columnsTemp+2;//指定哪一列 +2是因为前面两列是设置图片for (int j = 0; j < data[i].length; j++) {Cell value = row.createCell(cellTemp);row.createCell(cellTemp).setCellValue(data[i][j].toString());//写入内容value.setCellStyle(style);//设置格式cellTemp+=1;//下一列}}//为了不超过设置的行数 和列数 做出如下判断if (columnsTemp<columnsNum && (columnsTemp+4)!=columnsNum){columnsTemp=columnsTemp+4;}else {columnsTemp=0;if (lineTemp<lineNum && (lineTemp+5)!=lineNum){lineTemp=lineTemp+5;}else{lineTemp=0;}}}}

2、自定义格式循环导出图片

在每个标签中,我都要插入一个二维码,位置都是固定的,所以就自定义图片的位置,并且循环插入不同的二维码。

2.1、设置格式并插入图片

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;/*** 图片保存到excel的类*/
public class ImageForExcel {/*** 设置图片保存到excel的位置* @param workbook excel* @param sheet 工作表* @param photoPath 插入图片的路径 一个list集合* @param columnsNum 列数* @param lineNum 行数*/public static void setPhoto(Workbook workbook, Sheet sheet, List<String> photoPath, int columnsNum, int lineNum){int index=0;for (int i = 0; i < lineNum; i=i+5) {for (int j = 0; j < columnsNum; j=j+4) {// 读取图片文件try (InputStream is = new FileInputStream(photoPath.get(index))) {// 将图片转换为字节数组byte[] bytes = IOUtils.toByteArray(is);// 添加图片到工作簿int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);// 创建绘图工具CreationHelper helper = workbook.getCreationHelper();Drawing<?> drawing = sheet.createDrawingPatriarch();// 创建锚点,设置图片位置ClientAnchor anchor = helper.createClientAnchor();anchor.setCol1(j); // 图片起始列(0-based)anchor.setRow1(i+1); // 图片起始行(0-based)anchor.setCol2(j+2); // 图片结束列(0-based)anchor.setRow2(i+5); // 图片结束行(0-based)// 创建图片并设置锚点Picture pict = drawing.createPicture(anchor, pictureIdx);index=index+1;// 可选:调整单元格大小以适应图片
//            sheet.setColumnWidth(1, 4 * 256); // 调整列宽
//            sheet.setColumnWidth(0, 4 * 256); // 调整列宽/*Row row = sheet.createRow(3);row.setHeightInPoints(100); // 调整行高*/} catch (IOException e) {e.printStackTrace();}}}}
}

3、格式和数据写入统一封装

将格式设计和写入数据的方法同意封装成一个方法,方便调用。

/*** 统一封装的方法* @param mainTitleStr 标签头部* @param exportPath 导出的路径 二维码图片获取的路径* @param columnsNum 标签的总列数* @param lineNum 标签的总行数* @param data 变动的数据* @return* @throws Exception*/public static String exportTitle(String mainTitleStr, String exportPath,int columnsNum, int lineNum, List<Map<Object,Object>> data) throws Exception {String excelPath=exportPath+"标签WZ.xlsx";Workbook workbook = new XSSFWorkbook();Sheet sheet = workbook.createSheet("标签");//工作表名// 1、设置列宽(单位是1/256个字符宽度)setColumnWidth(columnsNum,sheet);// 设置行高(单位是点,1点=1/20像素)
//        Row row = sheet.createRow(0);
//        row.setHeightInPoints(30); // 设置行高为30点// 2. 创建居中样式CellStyle centerStyle = createCenterStyle(workbook);// 3. 设置表头数据createHeader(sheet, centerStyle,mainTitleStr,columnsNum,lineNum);// 4. 设置内容数据createContent(sheet, centerStyle,data,columnsNum,lineNum);// 5. 设置合并区域并应用居中样式mergeAndCenterCells(sheet, centerStyle,columnsNum,lineNum);//将图片插入excelList<String> photoPath=new ArrayList<>();for (Map<Object,Object> map:data) {photoPath.add(exportPath+map.get("mold").toString()+".png");}ImageForExcel.setPhoto(workbook,sheet,photoPath,columnsNum,lineNum);// 7. 保存文件try (FileOutputStream out = new FileOutputStream(excelPath)) {workbook.write(out);}return excelPath;}

4、测试方法和效果

文字数据是我自己编的,如果大家要从数据库或者其他来源获取,改动data即可。
二维码图片是我利用二维码生成方法生成的,如果大家有兴趣,可以看看我上一篇的博客。点击这里: 二维码生成方法

4.1、测试方法

这个是有循环生成多个标签的功能。
所以列数 行数 需要根据自己的需求。
如不需要循环,只需将行列数设置为一个标签所需要占据的数即可。
目前我的测试方法是,一个标签占据5行4列,下面设定是有4个标签。
如果对代码中 4 5 或者 4 5 倍数 ,又或者其他数据有疑问的话,可以看看这里

import com.codermy.myspringsecurityplus.utils.qrUtils.TitleForExcel;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class BiaoQian {public static void main(String[] args) throws Exception {//1、表头String mainTitleStr="夹具确认表 DOC-190-AA0004-01D";//2、excel存放的位置String exportPath="D:/java/codeSpace/testFile/";/*这个是有生成多个的功能 所以列数 行数 需要根据自己的需求如不需要循环,只需将行列数设置为一个标签所需要占据的数即可目前我的数据是,一个标签占据5行4列,下面设定是循环写入4个标签如果对代码中 4 5  或者 4 5 倍数 ,又或者其他数据有疑问的话,可以看看这里*///3、列数int columnsNum=8;//4、行数int lineNum=10;//5、数据   可以从数据库中得到 然后再按照我们需要的数据做处理// 下面是我自己模拟的一些数据List<Map<Object,Object>> data=new ArrayList<>();String name="C40888";String type="WZ";//这个 (i < 5) ,需要对应上面的行列数 有四个标签for (int i = 1; i < 5; i++) {Map<Object,Object> map=new HashMap<>();map.put("name",name);map.put("type",type);map.put("num",i);map.put("mold",name+"-"+type+"-"+i);data.add(map);}String result=TitleForExcel.exportTitle(mainTitleStr,exportPath,columnsNum,lineNum,data);System.out.println(result);}}

4.2、运行效果

由于图片有二维码,会被和谐,所以我在二维码上搞了贴纸,实际导出效果没有贴纸
在这里插入图片描述


以上就是本篇文章的全部内容,部分代码是利用AI生成,然后再去修改成我想要的效果,如果有侵权的地方,还请联系本人。
本文有很多可以修改优化的地方,如果各位同学有好的见解可以评论留言讨论。
如果代码有异常,或者有其他疑惑、可以评论区留言。

http://www.xdnf.cn/news/15624.html

相关文章:

  • 【论文阅读 | CVPR 2023 |CDDFuse:基于相关性驱动的双分支特征分解的多模态图像融合】
  • lua(xlua)基础知识点记录
  • 【前端】在Vue3中绘制多系列柱状图与曲线图
  • 量子比特耦合与系统集成:量子计算硬件的核心突破
  • 入门华为数通,HCIA/HCIP/HCIE该怎么选?
  • 2025年自动化工程、物联网与计算机应用国际会议(AEITCA 2025)
  • Java基础:分支/循环/数组
  • PLC-BMS电力载波通信技术深度解析:智能电网与储能系统的融合创新
  • 【WRFDA数据第一期】WRFDA Free Input 数据网页
  • Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
  • 【后端】.NET Core API框架搭建(6) --配置使用MongoDB
  • 微软AutoGen:多智能体协作的工业级解决方案
  • PyCharm高效入门
  • NodeJS Express 静态文件、中间件、路由案例
  • 手撕Spring底层系列之:IOC、AOP
  • java操作Excel两种方式EasyExcel 和POI
  • 跟着Carl学算法--回溯【2】
  • React Hooks 数据请求库——SWR使用详解
  • Spring AI 系列之十四 - RAG-ETL之一
  • Vue3+Ts实现父子组件间传值的两种方式
  • Unity Android Logcat插件 输出日志中文乱码解决
  • 小白成长之路-Elasticsearch 7.0 配置
  • BNN 技术详解:当神经网络只剩下 +1 和 -1
  • 基于redis的分布式锁 lua脚本解决原子性
  • 免杀学习篇(1)—— 工具使用
  • 网页源码保护助手 海洋网页在线加密:HTML 源码防复制篡改,密文安全如铜墙铁壁
  • 基于华为欧拉系统安装FileGator文件管理器
  • 【Android】日志的使用
  • 深度学习中的激活函数:从原理到 PyTorch 实战
  • python 基于 httpx 的流式请求