2024-03-22 09:37:32 +08:00
|
|
|
|
package com.zcloud.util;
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFRow;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
2024-03-25 09:36:21 +08:00
|
|
|
|
import org.apache.poi.poifs.filesystem.Entry;
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
import java.awt.image.BufferedImage;
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.net.URL;
|
|
|
|
|
import java.net.URLConnection;
|
|
|
|
|
import java.net.URLEncoder;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class ImageExcelUtil {
|
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
private static final Log log = LogFactory.getLog(ImageExcelUtil.class);
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
/**
|
|
|
|
|
* excel工具类,可导出带图片或不带图片的数据
|
|
|
|
|
*
|
|
|
|
|
* @param titles 第一行的标题列
|
|
|
|
|
* @param rows 数据行量
|
|
|
|
|
* @param maps 装载导出数据的封装了map的list数据集合,注意:此中的map尽量用本类中的方法 javaBean2Map直接生成,或自己拼接;但需与参数titles[]的标题相关数据对应上
|
|
|
|
|
* @param fileName 导出到本地的文件路径和文件名
|
|
|
|
|
* @param response response
|
|
|
|
|
* @param path 保存到本地的图片地址(我这里是为了删除该目录下的图片,因为我是把网络图片保存到到本地的,如果图片已经是本地图片的话就不需要删除)
|
|
|
|
|
* @date 2024/03/20
|
|
|
|
|
*/
|
|
|
|
|
public static void excelOut(String[] titles, int rows, List<Map<String, Object>> maps, String fileName,
|
|
|
|
|
HttpServletResponse response, String path) {
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
OutputStream out = null;
|
|
|
|
|
BufferedImage bufferImg = null;
|
|
|
|
|
HSSFWorkbook wb = null;
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
try {
|
|
|
|
|
//创建工作sheet
|
|
|
|
|
wb = new HSSFWorkbook();
|
|
|
|
|
HSSFSheet sheet = wb.createSheet(fileName);
|
|
|
|
|
//设置单元格内容水平垂直居中
|
|
|
|
|
HSSFCellStyle style = wb.createCellStyle();
|
2024-03-22 09:37:32 +08:00
|
|
|
|
// style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
|
|
|
|
|
// style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
|
2024-03-25 09:36:21 +08:00
|
|
|
|
style.setWrapText(true); //设置内容自动换行
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
//画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
|
|
|
|
|
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
|
|
|
|
|
HSSFRow row0 = sheet.createRow(0);
|
|
|
|
|
row0.setHeightInPoints(25);
|
|
|
|
|
if (titles.length == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
HSSFCell cell = null;
|
|
|
|
|
//第一行、标题行列
|
|
|
|
|
for (int i = 0; i < titles.length; i++) {
|
|
|
|
|
cell = row0.createCell(i); //第一个单元格
|
|
|
|
|
cell.setCellValue(titles[i]); //设定值
|
|
|
|
|
cell.setCellStyle(style);
|
|
|
|
|
sheet.setColumnWidth(i, 6000);
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
HSSFRow row = null;
|
|
|
|
|
HSSFCell cellRow = null;
|
|
|
|
|
HSSFClientAnchor anchor = null;
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
for (int i = 1; i <= rows; i++) {
|
|
|
|
|
int cellColumn = 0;
|
|
|
|
|
//创建行
|
|
|
|
|
row = sheet.createRow(i);
|
|
|
|
|
//设置默认行高
|
|
|
|
|
row.setHeightInPoints(15);
|
|
|
|
|
//行数据处理
|
|
|
|
|
Map<String, Object> stringObjectMap = maps.get(i - 1);
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
for (Object value : stringObjectMap.keySet()) {
|
|
|
|
|
//行单元格
|
|
|
|
|
cellRow = row.createCell(cellColumn);
|
|
|
|
|
cellRow.setCellStyle(style);
|
|
|
|
|
//如果行数据中有图片时候的处理
|
|
|
|
|
if ("USER_SIGN_FILE".equals(value) || "PORTRAIT".equals(value)) {
|
|
|
|
|
File file = (File) stringObjectMap.get(value);
|
|
|
|
|
if (file == null) {
|
|
|
|
|
cellRow.setCellValue("");
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
row.setHeightInPoints(50);
|
|
|
|
|
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
|
|
|
|
|
cellRow = row.createCell(cellColumn);
|
|
|
|
|
cellRow.setCellStyle(style);
|
|
|
|
|
sheet.setColumnWidth(cellColumn, 5000);
|
|
|
|
|
log.error("图片路径" + file);
|
|
|
|
|
bufferImg = ImageIO.read(file);
|
|
|
|
|
ImageIO.write(bufferImg, "jpg", byteArrayOut);
|
|
|
|
|
anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) cellColumn, i, (short) cellColumn, i);
|
|
|
|
|
patriarch.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG));
|
|
|
|
|
cellColumn++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (stringObjectMap.get(value) != null) {
|
|
|
|
|
cellRow.setCellValue(stringObjectMap.get(value).toString());
|
|
|
|
|
} else {
|
|
|
|
|
cellRow.setCellValue("");
|
|
|
|
|
}
|
|
|
|
|
cellColumn++;
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
}
|
|
|
|
|
if (wb != null) {
|
|
|
|
|
out = response.getOutputStream();
|
|
|
|
|
response.setContentType("application/x-msdownload");
|
|
|
|
|
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
|
|
|
|
|
// 写入excel文件
|
|
|
|
|
wb.write(out);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} finally {
|
|
|
|
|
if (out != null) {
|
|
|
|
|
try {
|
|
|
|
|
out.close();
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
//执行删除生成的图片 TODO
|
2024-03-22 09:37:32 +08:00
|
|
|
|
// File file = new File("E:\\data\\nginxd\\sportsApplets");//输入要删除文件目录的绝对路径
|
|
|
|
|
// File file = new File("/data/nginxd/sportsApplets/excelDeleteImage/");//输入要删除文件目录的绝对路径
|
2024-03-25 09:36:21 +08:00
|
|
|
|
File file = new File(path);//输入要删除文件目录的绝对路径
|
|
|
|
|
deleteFile(file);//由于是保存网络图片到本地服务区,所以画完图片到excel就要删除文件
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
/**
|
|
|
|
|
* 删除文件夹目录下的所有文件 (我是怕到时候本地服务器图片越来越多,占用资源,所以把图片洗完到excel里面就删除)
|
|
|
|
|
*
|
|
|
|
|
* @param file
|
|
|
|
|
* @date 2021/01/11
|
|
|
|
|
*/
|
|
|
|
|
public static void deleteFile(File file) {
|
|
|
|
|
//判断文件不为null或文件目录存在
|
|
|
|
|
if (file == null || !file.exists()) {
|
|
|
|
|
log.error("文件删除失败,请检查文件路径是否正确");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//取得这个目录下的所有子文件对象
|
|
|
|
|
File[] files = file.listFiles();
|
|
|
|
|
//遍历该目录下的文件对象
|
|
|
|
|
for (File f : files) {
|
|
|
|
|
//打印文件名
|
|
|
|
|
String name = file.getName();
|
|
|
|
|
log.error("删除的文件名" + name);
|
|
|
|
|
//判断子目录是否存在子目录,如果是文件则删除
|
|
|
|
|
if (f.isDirectory()) {
|
|
|
|
|
deleteFile(f);
|
|
|
|
|
} else {
|
|
|
|
|
f.delete();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//删除空文件夹 for循环已经把上一层节点的目录清空。
|
|
|
|
|
file.delete();
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
/**
|
|
|
|
|
* 保存图片到本地
|
|
|
|
|
*
|
|
|
|
|
* @param imageUrl
|
|
|
|
|
* @param path
|
|
|
|
|
* @return
|
|
|
|
|
* @date 2021/01/11
|
|
|
|
|
*/
|
|
|
|
|
public static String saveFile(String imageUrl, String path) {
|
|
|
|
|
String filename = imageUrl.substring(imageUrl.lastIndexOf("/") + 1, imageUrl.length());
|
|
|
|
|
log.error("图片====" + filename);
|
2024-03-22 09:37:32 +08:00
|
|
|
|
// Random rand = new Random();
|
|
|
|
|
// int s = rand.nextInt(900)+ 100;
|
2024-03-25 09:36:21 +08:00
|
|
|
|
int s = (int) (Math.random() * 10000);
|
|
|
|
|
log.error("随机数==" + s);
|
|
|
|
|
filename = s + filename; //这里如果有文件名称重复的,就取一个随机数拼接文件名
|
|
|
|
|
File sf = null;
|
|
|
|
|
OutputStream os = null;
|
|
|
|
|
InputStream is = null;
|
|
|
|
|
try {
|
|
|
|
|
// 构造URL
|
|
|
|
|
URL url = new URL(imageUrl);
|
|
|
|
|
// 打开连接
|
|
|
|
|
URLConnection con = url.openConnection();
|
|
|
|
|
//设置请求超时为5s
|
|
|
|
|
con.setConnectTimeout(5 * 1000);
|
|
|
|
|
// 输入流
|
|
|
|
|
is = con.getInputStream();
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
// 1K的数据缓冲
|
|
|
|
|
byte[] bs = new byte[1024];
|
|
|
|
|
// 读取到的数据长度
|
|
|
|
|
int len;
|
|
|
|
|
// 输出的文件流
|
2024-03-22 09:37:32 +08:00
|
|
|
|
// String path = "E:\\data\\nginxd\\sportsApplets";
|
|
|
|
|
// String path = "/data/nginxd/sportsApplets/excelDeleteImage/";
|
2024-03-25 09:36:21 +08:00
|
|
|
|
sf = new File(path);
|
|
|
|
|
if (!sf.exists()) {
|
|
|
|
|
sf.mkdirs();
|
|
|
|
|
}
|
|
|
|
|
os = new FileOutputStream(sf.getPath() + "/" + filename);
|
|
|
|
|
// 开始读取
|
|
|
|
|
while ((len = is.read(bs)) != -1) {
|
|
|
|
|
os.write(bs, 0, len);
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} finally {
|
|
|
|
|
// 完毕,关闭所有链接
|
|
|
|
|
try {
|
|
|
|
|
if (os != null) {
|
|
|
|
|
os.close();
|
|
|
|
|
}
|
|
|
|
|
if (is != null) {
|
|
|
|
|
is.close();
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return sf.getPath() + "/" + filename;
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
/**
|
|
|
|
|
* 将java类对象属性-值转换成map的键值对 去除getClass方法属性,以及自定义的file属性放置最后。
|
|
|
|
|
*
|
|
|
|
|
* @param javaBean
|
|
|
|
|
* @return Map
|
|
|
|
|
* @throws Exception
|
|
|
|
|
* @date 2021/01/11
|
|
|
|
|
*/
|
|
|
|
|
public static Map<String, Object> javaBean2Map(Object javaBean) throws Exception {
|
|
|
|
|
Map<String, Object> map = new LinkedHashMap<>();
|
|
|
|
|
//反射的实现方式:第一种
|
2024-03-22 09:37:32 +08:00
|
|
|
|
/*Class<Student> studentClass = Student.class;
|
|
|
|
|
studentClass.getClass();*/
|
2024-03-25 09:36:21 +08:00
|
|
|
|
//第二种实现方式
|
|
|
|
|
Method[] methods = javaBean.getClass().getMethods(); // 获取所有方法
|
|
|
|
|
//第三种实现方式
|
|
|
|
|
/*Class.forName("类路径");*/
|
|
|
|
|
String fileName = null;
|
|
|
|
|
File file = null;
|
|
|
|
|
for (Method method : methods) {
|
|
|
|
|
if (method.getName().startsWith("get")) {
|
|
|
|
|
String field = method.getName(); // 拼接属性名
|
|
|
|
|
if (field.contains("getClass")) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
field = field.substring(field.indexOf("get") + 3);
|
|
|
|
|
Object value = method.invoke(javaBean, (Object[]) null); // 执行方法
|
|
|
|
|
if (field.equals("USER_SIGN_FILE") || field.equals("PORTRAIT")) {
|
|
|
|
|
fileName = field;
|
|
|
|
|
file = (File) value;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (fileName != null) {
|
|
|
|
|
map.put(fileName, file);
|
|
|
|
|
fileName = null;
|
|
|
|
|
} else {
|
|
|
|
|
map.put(field, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
2024-03-25 09:36:21 +08:00
|
|
|
|
/**
|
|
|
|
|
* 递归调用让字符串对中调换
|
|
|
|
|
*
|
|
|
|
|
* @param originStr
|
|
|
|
|
* @return String
|
|
|
|
|
* @date 2021/01/11
|
|
|
|
|
*/
|
|
|
|
|
public static String reverse(String originStr) {
|
|
|
|
|
if (originStr == null || originStr.length() <= 1)
|
|
|
|
|
return originStr;
|
|
|
|
|
String substring = originStr.substring(1);
|
|
|
|
|
String s = reverse(substring) + originStr.charAt(0);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2024-03-22 09:37:32 +08:00
|
|
|
|
|
|
|
|
|
}
|