使用若依导出,客户提出要导出图片,原导出不支持,只能用原生的写,返回前端格式要和若依的保持一致,在网上找了一些,结合一下,在若依里面这样使用:图片导出位置在序号后面第一列。
依赖包和版本号:poi--3.17版本
<poi.version>3.17</poi.version>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>${poi.version}</version>
</dependency>
package com.ruoyi.common.utils;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
* @Auther: lwy
* @Date: 2020/12/14
* @Description:
public class ExportExcelUtils {
private String title; // 导出表格的表名
private String[] rowName;// 导出表格的列名
private List<Object[]> dataList = new ArrayList<Object[]>(); // 对象数组的List集合
private HttpServletResponse response;
// 传入要导入的数据
public ExportExcelUtils(String title, String[] rowName, List<Object[]> dataList, HttpServletResponse response)
this.title = title;
this.rowName = rowName;
this.dataList = dataList;
this.response = response;
// 导出数据
public AjaxResult exportData(){
String fileName=null;
HSSFWorkbook workbook = new HSSFWorkbook(); // 创建一个excel对象
HSSFSheet sheet = workbook.createSheet(title); // 创建表格
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// 产生表格标题行
HSSFRow rowm = sheet.createRow(0); // 行
HSSFCell cellTiltle = rowm.createCell(0); // 单元格
// sheet样式定义
HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook); // 头样式
HSSFCellStyle style = this.getStyle(workbook); // 单元格样式
* 参数说明
* 从0开始 第一行 第一列 都是从角标0开始
* 行 列 行列 (0,0,0,5) 合并第一行 第一列 到第一行 第六列
* 起始行,起始列,结束行,结束列
* new Region() 这个方法使过时的
// 合并第一行的所有列
sheet.addMergedRegion(new CellRangeAddress(0, (short) 0, 0, (short) (rowName.length - 1)));
cellTiltle.setCellStyle(columnTopStyle);
cellTiltle.setCellValue(title);
int columnNum = rowName.length; // 表格列的长度
HSSFRow rowRowName = sheet.createRow(1); // 在第二行创建行
HSSFCellStyle cells = workbook.createCellStyle();
cells.setBottomBorderColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
rowRowName.setRowStyle(cells);
// 循环 将列名放进去
for (int i = 0; i < columnNum; i++){
HSSFCell cellRowName = rowRowName.createCell((int) i);
cellRowName.setCellType(CellType.STRING);// 单元格类型
HSSFRichTextString text = new HSSFRichTextString(rowName[i]); // 得到列的值
cellRowName.setCellValue(text); // 设置列的值
cellRowName.setCellStyle(columnTopStyle); // 样式
// 将查询到的数据设置到对应的单元格中
for (int i = 0; i < dataList.size(); i++){
Object[] obj = dataList.get(i);//遍历每个对象
HSSFRow row = sheet.createRow(i + 2);//创建所需的行数
row.setHeightInPoints(40);
for (int j = 0; j < obj.length; j++){
HSSFCell cell = null; //设置单元格的数据类型
if (j == 0) {
// 第一列设置为序号
cell = row.createCell(j, CellType.NUMERIC);
cell.setCellValue(i + 1);
}else{
cell = row.createCell(j, CellType.STRING);
if (!"".equals(obj[j]) && obj[j] != null){
if ((obj[j].toString()).contains("http") ){
cell.setCellValue(" ");
drawPictureInfoExcel(workbook, patriarch, obj[j].toString(), i + 2);//i+2代表当前的行
}else{
cell.setCellValue(obj[j].toString());
//设置单元格的值
}else{
cell.setCellValue(" ");
cell.setCellStyle(style); // 样式
// 让列宽随着导出的列长自动适应
sheet.setColumnWidth(0, 8 * 256); //调整第一列宽度
sheet.setColumnWidth(1, 15 * 256);
sheet.setColumnWidth(2, 10 * 256);
sheet.setColumnWidth(3, 15 * 256);
sheet.setColumnWidth(4, 10 * 256);
sheet.setColumnWidth(5, 25 * 256);
sheet.setColumnWidth(6, 18 * 256);
sheet.setColumnWidth(7, 20 * 256);
sheet.setColumnWidth(8, 15 * 256);
sheet.setColumnWidth(9, 18 * 256);
sheet.setColumnWidth(10, 20 * 256);
sheet.setColumnWidth(11, 18 * 256);
sheet.setColumnWidth(12, 28 * 256);
sheet.setColumnWidth(13, 20 * 256);
sheet.setColumnWidth(14, 20 * 256);
sheet.setColumnWidth(15, 20 * 256);
sheet.setColumnWidth(16, 20 * 256);
sheet.setColumnWidth(17, 15 * 256);
sheet.setColumnWidth(18, 15 * 256);
sheet.setColumnWidth(19, 15 * 256);
sheet.setColumnWidth(20, 18 * 256);
sheet.setColumnWidth(21, 20 * 256);
sheet.setColumnWidth(22, 15 * 256);
sheet.setColumnWidth(23, 15 * 256);
sheet.setColumnWidth(24, 10 * 256);
sheet.setColumnWidth(25, 10 * 256);
sheet.setColumnWidth(26, 10 * 256);
sheet.setColumnWidth(27, 21 * 256);
sheet.setColumnWidth(28, 20 * 256);
sheet.setColumnWidth(29, 20 * 256);
sheet.setColumnWidth(30, 20 * 256);
sheet.setColumnWidth(31, 20 * 256);
sheet.setColumnWidth(32, 20 * 256);
sheet.setColumnWidth(33, 15 * 256);
sheet.setColumnWidth(34, 25 * 256);
sheet.setColumnWidth(35, 20 * 256);
sheet.setColumnWidth(36, 12 * 256);
// sheet.setColumnWidth(37, 20 * 256);
if (workbook != null){
// excel 表文件名
fileName = title + String.valueOf(System.currentTimeMillis()).substring(4, 13) + "..xlsx";
String fileName11 = URLEncoder.encode(fileName, "UTF-8");
String fileName12 = java.net.URLDecoder.decode(fileName11, "UTF-8");
String headStr = "attachment; filename=\"" + fileName12 + "\"";
response.setContentType("APPLICATION/OCTET-STREAM");
// response.setHeader("Content-Disposition", headStr);
response.setHeader("Content-Disposition",
"attachment;filename=" + new String(fileName12.getBytes("gb2312"), "ISO8859-1"));
// OutputStream out = response.getOutputStream();
// workbook.write(out);
OutputStream out = new FileOutputStream(getAbsoluteFile(fileName));
workbook.write(out);
out.flush();
out.close();
}catch (IOException e){
e.printStackTrace();
return AjaxResult.success(fileName);
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error();
// return fileName;
private void drawPictureInfoExcel(HSSFWorkbook wb, HSSFPatriarch patriarch, String pictureUrl, int rowIndex)
//rowIndex代表当前行
if (pictureUrl != null)
URL url = new URL(pictureUrl);//获取人员照片的地址
//打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求方式为"GET"
conn.setRequestMethod("GET");
//超时响应时间为5秒
conn.setConnectTimeout(5 * 1000);
//通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
//得到图片的二进制数据,以二进制封装得到数据,具有通用性
byte[] data = readInputStream(inStream);
//anchor主要用于设置图片的属性
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, rowIndex, (short) 1,
rowIndex);
//Sets the anchor type (图片在单元格的位置)
//0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
anchor.setAnchorType(ClientAnchor.AnchorType.byId(1));
patriarch.createPicture(anchor, wb.addPicture(data, HSSFWorkbook.PICTURE_TYPE_JPEG));
catch (IOException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
private static byte[] readInputStream(InputStream inStream) throws Exception
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
//创建一个Buffer字符串
byte[] buffer = new byte[1024];
//每次读取的字符串长度,如果为-1,代表全部读取完毕
int len = 0;
//使用一个输入流从buffer里把数据读取出来
while ((len = inStream.read(buffer)) != -1)
//用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len);
//关闭输入流
inStream.close();
//把outStream里的数据写入内存
return outStream.toByteArray();
public HSSFCellStyle getStyle(HSSFWorkbook workbook)
// 设置字体
HSSFFont font = workbook.createFont();
//设置字体大小
font.setFontHeightInPoints((short) 9);
//字体加粗
//font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//设置字体名字
font.setFontName("Courier New");
//设置样式;
HSSFCellStyle style = workbook.createCellStyle();
//设置底边框;
style.setBorderBottom(BorderStyle.THIN);
//设置底边框颜色;
style.setBottomBorderColor(HSSFColor.BLACK.index);
//设置左边框;
style.setBorderLeft(BorderStyle.THIN);
//设置左边框颜色;
style.setLeftBorderColor(HSSFColor.BLACK.index);
//设置右边框;
style.setBorderRight(BorderStyle.THIN);
//设置右边框颜色;
style.setRightBorderColor(HSSFColor.BLACK.index);
//设置顶边框;
style.setBorderTop(BorderStyle.THIN);
//设置顶边框颜色;
style.setTopBorderColor(HSSFColor.BLACK.index);
//在样式用应用设置的字体;
style.setFont(font);
//设置自动换行;
style.setWrapText(false);
//设置水平对齐的样式为居中对齐;
style.setAlignment(HorizontalAlignment.CENTER);
//设置垂直对齐的样式为居中对齐;
style.setVerticalAlignment(VerticalAlignment.CENTER);
return style;
public HSSFCellStyle getColumnTopStyle(HSSFWorkbook workbook)
// 设置字体
HSSFFont font = workbook.createFont();
//设置字体大小
font.setFontHeightInPoints((short) 10);
//字体加粗
// font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
font.setBold(true);
//设置字体名字
font.setFontName("Courier New");
//设置样式;
HSSFCellStyle style = workbook.createCellStyle();
//设置底边框;
style.setBorderBottom(BorderStyle.THIN);
//设置底边框颜色;
style.setBottomBorderColor(HSSFColor.BLACK.index);
//设置左边框;
style.setBorderLeft(BorderStyle.THIN);
//设置左边框颜色;
style.setLeftBorderColor(HSSFColor.BLACK.index);
//设置右边框;
style.setBorderRight(BorderStyle.THIN);
//设置右边框颜色;
style.setRightBorderColor(HSSFColor.BLACK.index);
//设置顶边框;
style.setBorderTop(BorderStyle.THIN);
//设置顶边框颜色;
style.setTopBorderColor(HSSFColor.BLACK.index);
//在样式用应用设置的字体;
style.setFont(font);
//设置自动换行;
style.setWrapText(false);
//设置水平对齐的样式为居中对齐;
style.setAlignment(HorizontalAlignment.CENTER);
//设置垂直对齐的样式为居中对齐;
style.setVerticalAlignment(VerticalAlignment.CENTER);
return style;
public String getAbsoluteFile(String filename)
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
desc.getParentFile().mkdirs();
return downloadPath;
controller:
@GetMapping("/export")
public AjaxResult export(VO vo, HttpServletRequest request, HttpServletResponse response){
Object data = null;
//查询导出列表
List list = xxxxervice.selectExportList(vo);
String title = "导出数据";
String[] rowsName = new String[] { "序号", "图片","编号", "姓名"};
List<Object[]> dataList = new ArrayList<Object[]>();
ExportExcelUtils ex = new ExportExcelUtils(title,rowsName,dataList,response);
if (list.size() != 0){
Object[] objs = null;
//获取当前运行服务器的IP和端口号,也可以直接写死在里面
String host = serverPortConfig.getUrl();
for (int i = 0; i < list.size(); i++){
objs = new Object[rowsName.length];
objs[0] = i;
String picUrl= list.get(i).getPicUrl();
if(StringUtils.isNotBlank(picUrl)){
picUrl= host + (list.get(i).getPicUrl());
objs[1] = picUrl;
objs[2] = list.get(i).getBh();
objs[3] = list.get(i).getXm();
dataList.add(objs);
ex = new ExportExcelUtils(title, rowsName, dataList,response);
return ex.exportData();
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error();
若依前端vue:具体请参考若以官网吧。地址:https://doc.ruoyi.vip/ruoyi-vue/document/htsc.html#%E5%AF%BC%E5%87%BA%E5%AE%9E%E7%8E%B0%E6%B5%81%E7%A8%8B
1、前端调用方法(参考如下)
// 查询参数 queryParams
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined
// 导出接口exportUser
import { exportUser } from "@/api/system/user";
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有用户数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportConfig(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
2、添加导出按钮事件
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
其实还可以再优化封装,时间有些来不及,先这样吧,不足之处请补充
补充ServerPortConfig工具类:
package com.ruoyi.common.utils;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
* 获取项目的IP和端口
* @Owner:lwy
* @Time: 2020/12/15
@Component
public class ServerPortConfig implements ApplicationListener<WebServerInitializedEvent> {
public int getServerPort() {
return serverPort;
private int serverPort;
public String getUrl() {
InetAddress address = null;
try {
address = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
return "http://"+address.getHostAddress()+":"+this.serverPort;
public String getHost() {
InetAddress address = null;
try {
address = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
return address.getHostAddress();
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
serverPort = event.getWebServer().getPort();
图片百宝箱6.2用于在Excel中批量插入图片、批量导出图片,批量生成二维码和条形码等,支持Excel 2007、2010、2013、2016、2019和2021,也支持WPS。具体功能如下:
1.批量导入图片:在工作表中创建指定路径下的所有图片的目录,支持四种图片格式,可对子文件夹中的文件一并创建目录。创建目录时可将图片存放在单元格也还可以放在批注中。
2.按名称导入对应图片(支持子目录):选中已经有图片名称的所有单元格,然后批量导入对应的图片到右方单元格中。导入时支持子文件夹,也就是说图片分散在多个文件夹中时,程序会自动找出对应的图片。
3.导入图片到多行多列:在工作表中批量导入图片,且显示为多行多列,具体列数可以自定义,图片的高度也可以自定义。
4.导入图片到合并区域:批量导入图片和图片名称到工作表中,存放图片名称的单元格允许是合并单元格。
5.导入图片并按页面排版:批量导入图片到工作表中,并按页面大小排版,从而使打印工作表时每页刚好打印指定数量的图片。
6.插入网络图片:批量插入网络中的图片到工作表中,可以自定义图片显示尺寸 。如果按住Shift键再单击菜单,那么导入图片的同时还会用指列的值对图片自动命名。
7.导出所有图片:将工作表中所有图片另存为图片文件,可以自定义保存图片的路径。
8.删除所有图片:删除工作表中的所有图片,不删除自选图形、图表和各种控件。
9.对齐图片:将当前表或者所有工作表的图片调整为所有单元格的大小。调整后的图片可以让它随着单元格的大小变化而变化,即修改单元格大小时图片也跟随变化尺寸,也可以让它参与排序和筛选。
10.解除工作表密码:一键解除工作表密码,不管工作表的密码有多复杂。
11.图片预览:只要提前指定图片路径,那么选单元格时,在右方预览窗格中会产生图片预览。本方法不插入图片到工作表中,因此不会影响工作簿的体积和打开速度。
12.批量生成二维码:根据选区的值批量生成二维码,存放在单元格右方。每行数据生成一个对应的二维码。
13.批量生成条形码:根据选区的值批量生成条形码,存放在单元格右方。每个单元格数值生成一个对应的条形码。支持Code128、Code39、Jan13和Jan8。
/ @ApiImplicitParam(name = "isUpdateSupport", value = "支持更新,0是不支持,1是支持", paramType = "query", dataType = "String"),@ApiImplicitParam(name = "Type", value = "身份,0是学生,1是教职工", paramType = "query", dataType = "String"),", fileName));
我通过以下代码将一个图像添加到工作表中:// Create the drawing patriarch. This is the top level container for all shapes.Drawing drawing = sheet.createDrawingPatriarch();//add a picture shape//ClientAnchor anchor = this....
HSSFWorkbook(03版Excel,最多只有65536行,导入导出速度快)
XSSFWorkbook(07版Excel,支持百万数据的导入导出,导入导出速度慢)
SXSSFWorkbook(07版Excel升级版,会在过程中生成中间文件,导入导出速度快)
工作表对象Sheet
行对象Row
单元格对象Cell
最基础的demo
需要的ma
81. 隐藏单元格中的所有值(微软OFFICE技巧大赛获奖作品) 46
82. 恢复隐藏列 47
83. 快速隐藏/显示选中单元格所在行和列(微软OFFICE技巧大赛获奖作品) 47
84. 彻底隐藏单元格 48
85. 用下拉列表快速输入数据 48
86. 快速输入自定义短语 49
87. 设置单元格背景色 50
88. 快速在多个单元格中输入相同公式 50
89. 同时在多个单元格中输入相同内容 50
90. 快速输入日期和时间 51
91. 将复制的单元格安全地插入到现有单元格之间 51
92. 在EXCEL中不丢掉列标题的显示 52
93. 查看与日期等效的序列数的值 52
94. 快速复制单元格内容 53
95. 使用自定义序列排序(微软OFFICE技巧大赛获奖作品) 53
96. 快速格式化EXCEL单元格 53
97. 固定显示某列 54
98. 在EXCEL中快速编辑单元格 54
99. 使用自动填充快速复制公式和格式 55
100. 为单元格添加批注 56
101. 数据自动输入 56
102. 在EXCEL中快速计算一个人的年龄 57
103. 快速修改单元格次序 57
104. 将网页上的数据引入到EXCEL表格中 58
一、 图形和图表编辑技巧 58
105. 在网上发布EXCEL生成的图形 58
106. 创建图表连接符 59
107. 将EXCEL单元格转换成图片形式插入到WORD中 60
108. 将WORD内容以图片形式插入到EXCEL表格中 61
109. 将WORD中的内容作为图片链接插入EXCEL表格中 61
110. 在独立的窗口中处理内嵌式图表 62
111. 在图表中显示隐藏数据 62
112. 在图表中增加文本框 63
113. 建立文本与图表文本框的链接 63
114. 给图表增加新数据系列 64
115. 快速修改图表元素的格式 65
116. 创建复合图表 65
117. 对度量不同的数据系列使用不同坐标轴 66
118. 将自己满意的图表设置为自定义图表类型 66
119. 复制自定义图表类型 67
120. 旋转三维图表 67
121. 拖动图表数据点改变工作表中的数值 68
122. 把图片合并进你的图表 68
123. 用图形美化工作表 70
124. 让文本框与工作表网格线合二为一 71
125. 快速创建默认图表 71
126. 快速创建内嵌式图表 71
127. 改变默认图表类型 72
128. 快速转换内嵌式图表与新工作表图表 72
129. 利用图表工具栏快速设置图表 73
130. 快速选取图表元素 74
131. 通过一次按键创建一个EXCEL图表 75
132. 绘制平直直线 75
一、 函数和公式编辑技巧 75
133. 巧用IF函数清除EXCEL工作表中的0 75
134. 批量求和 76
135. 对相邻单元格的数据求和 77
136. 对不相邻单元格的数据求和 78
137. 利用公式来设置加权平均 79
138. 自动求和 79
139. 用记事本编辑公式 80
140. 防止编辑栏显示公式 80
141. 解决SUM函数参数中的数量限制 81
142. 在绝对与相对单元引用之间切换 81
143. 快速查看所有工作表公式 82
144. 实现条件显示 82
一、 数据分析和管理技巧 83
145. 管理加载宏 83
146. 在工作表之间使用超级连接 84
147. 快速链接网上的数据 85
148. 跨表操作数据 86
149. 查看EXCEL中相距较远的两列数据 86
150. 如何消除缩位后的计算误差(微软OFFICE技巧大赛获奖作品) 87
151. 利用选择性粘贴命令完成一些特殊的计算 87
152. WEB查询 88
153. 在EXCEL中进行快速计算 89
154. 自动筛选前10个 89
155. 同时进行多个单元格的运算(微软OFFICE技巧大赛获奖作品) 90
156. 让EXCEL出现错误数据提示 91
157. 用“超级连接”快速跳转到其它文件 92
一、 设置技巧 92
158. 定制菜单命令 92
159. 设置菜单分隔线 93
160. 备份自定义工具栏 93
161. 共享自定义工具栏 94
162. 使用单文档界面快速切换工作簿 94
163. 自定义工具栏按钮 95
由于项目需要同时导入excel文档和jpg图片,因此尝试了一些方法来完成任务。
图片数据是以base64格式存入的,显示和转移都比较方便。
一开始考虑的是将图片插入excel中,这样的好处是一一对应,不会出错,但是搜索了关于图片的插入,还是比较复杂的,对用户来说不太现实。
最后我将excel和图片分开导入,使用图片名来对应字段,效果还可以,下面附上代码。下面是数据的导入:
点击文件进行上传
只能上传xls/xlsx文件
使用的是element-ui,使用的是vue解析excel方法,需要安装xslx,可参考https://blog.cs