Java导出Excel里包含图片(包括GIF)
导出的效果
要求
@ApiOperation("模板采集到的数据导出excel")
@PostMapping("/templateDatas/export")
public void exportImg(FormTemplateVo vo, @ApiIgnore HttpServletRequest request, @ApiIgnore HttpServletResponse response){
AdminUserDto admin = RequestUtils.getLoginUser(request);
HashMap<String,Object> dataMap = formTemplateService.templateDatasExport(vo, admin);
LinkedHashMap headerMap = (LinkedHashMap)dataMap.get("header");// 表头列名
List<HashMap<String, Object>> datas = (List<HashMap<String, Object>>)dataMap.get("list");
for (HashMap<String, Object> m : datas) {
Set<String> keySet = m.keySet();
ArrayList<String> imgList = new ArrayList<>();
for (String key : keySet) {
if (!key.contains("uploadFile")) continue;
if (StringUtils.isBlank(m.get(key))) continue;;
//imgList = new ArrayList<>((List<String>) m.get(key));
imgList = new ArrayList<>(JSON.parseArray(m.get(key).toString(), String.class));
File[] files = new File[imgList.size()];
if(imgList.size()>0){
for (int i =0 ; i< imgList.size(); i++){
String url = imgList.get(i);
if (StringUtils.isBlank(url)) continue;
String filePath = ExcelUtil.saveFile(url, ExcelUtil.path); //远程服务器的网络图片,所以先保存到本地,如果是本地服务器图片,不需要保存这一步
files[i] = new File(filePath);
// 判断是否是gif格式
if (url.contains(".gif")){
// gif转二进制流
byte[] gifByte = ExcelUtil.GifToJpg(files[i]);
// 二进制流转图片
if (ExcelUtil.ioToImg(gifByte, i+".png", files[i].getName()) > 0){
files[i] = new File(ExcelUtil.path + i + ".png");
}
}
}
}
m.put(key, files);
}
}
String fileName = "表单采集数据列表" + new Date().getTime() + ".xls";
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment; filename="+fileName);
ExcelUtil.excelOut(headerMap, datas.size(), datas, fileName, response, ExcelUtil.path);
}
ExcelUtil
由于我excelOut方法里包含了业务的处理,仅供参考,建议根据自己的要求来
public static final String path= "./template/excelDeleteImage/";
/**
* excel工具类,可导出带图片或不带图片的数据,注意数据规则
* @date 2022/5/9
* @param headerMap 第一行的标题列
* @param rows 数据行量
* @param maps 装载导出数据的封装了map的list数据集合,注意:此中的map尽量用本类中的方法 javaBean2Map直接生成,或自己拼接;但需与参数titles[]的标题相关数据对应上
* @param fileName 导出到本地的文件路径和文件名
* @param response response
* @param path 保存到本地的图片地址(我这里是为了删除该目录下的图片,因为我是把网络图片保存到到本地的,如果图片已经是本地图片的话就不需要删除)
*/
public static void excelOut(LinkedHashMap headerMap, int rows, List<HashMap<String,Object>> maps, String fileName,
HttpServletResponse response, String path){
OutputStream out = null;
BufferedImage bufferImg = null;
HSSFWorkbook wb = null;
try{
//创建工作sheet
wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet(fileName);
//设置单元格内容水平垂直居中
HSSFCellStyle style = wb.createCellStyle();
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setAlignment(HorizontalAlignment.CENTER);
style.setWrapText(true); //设置内容自动换行
//冻结首行
sheet.createFreezePane(0,1,0,1);
//画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
HSSFRow row0 = sheet.createRow(0);
row0.setHeightInPoints(25);
if (headerMap.size() == 0){
return ;
}
HSSFCell cell = null;
//第一行、标题行列
Object[] headerArr = headerMap.keySet().toArray();
// 每一列占用的单元格数
int[] cellSize = new int[headerMap.size()];
for (int i = 0; i < headerMap.size(); i++){
String value = headerMap.get(headerArr[i]).toString();
String[] valueArr = value.split("->");
// 记录单元格数量的值
cellSize[i] = 1;
// 合并的数量
int merge = 1;
// 开始列
int startLine = Arrays.stream(cellSize).sum() > 1 ? Arrays.stream(cellSize).sum()-1 : 0;
// 合并单元格
if (valueArr.length > 1){
merge = Integer.parseInt(valueArr[1]);
if (merge > 1){
CellRangeAddress address = new CellRangeAddress(0, 0, startLine, startLine + merge - 1);
sheet.addMergedRegion(address);
}
}
cellSize[i] = merge;
cell = row0.createCell(startLine); //第一个单元格
cell.setCellValue(valueArr[0]); //设定值
cell.setCellStyle(style);
sheet.setColumnWidth(startLine,6000);
}
HSSFRow row = null;
HSSFCell cellRow = null;
HSSFClientAnchor anchor = null;
for (int i=1;i<=rows;i++){
int cellColumn = 0;
//创建行
row = sheet.createRow(i);
//设置默认行高
row.setHeightInPoints(25);
//行数据处理
Map<String, Object> stringObjectMap = maps.get(i - 1);
for (int j = 0; j < headerArr.length; j++) {
Object header = headerArr[j];
if (j > 0) cellColumn = sum(cellSize, j);
for(Object value : stringObjectMap.keySet()){
// 匹配列名和列数据
if (!header.toString().equals(value)) continue;
//行单元格
cellRow = row.createCell(cellColumn);
cellRow.setCellStyle(style);
// 设置默认宽度
//sheet.setColumnWidth(cellColumn,20 * 256);
//如果行数据中有图片时候的处理
if (value.toString().contains("uploadFile")){
File[] file = StringUtils.isBlank(stringObjectMap.get(value)) ? null : (File[]) stringObjectMap.get(value);
if (file == null || file.length == 0){
cellRow.setCellValue("");
continue;
}else{
row.setHeightInPoints(50);
for (int x=0;x<file.length;x++){
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
//if (x>0){
// cellRow = row.createCell(cellColumn);
// cellRow.setCellStyle(style);
//}
sheet.setColumnWidth(cellColumn,5000);
//log.error("图片路径"+file[x]);
// ImageIO.read()方法缺陷,会出现导出图片泛红的问题
//bufferImg = ImageIO.read(file[x]);
Image src = Toolkit.getDefaultToolkit().getImage(file[x].getPath());
bufferImg = toBufferedImage(src);
ImageIO.write(bufferImg, "jpg", byteArrayOut);
// 计算图片在单元格的位置
int y = 1023 / file.length;
//anchor = new HSSFClientAnchor(y * x, 0, y * (x + 1), 250,(short) cellColumn, i, (short) cellColumn, i);
anchor = new HSSFClientAnchor(0, 0, 1023, 250,(short) cellColumn, i, (short) cellColumn, i);
anchor.setAnchorType(ClientAnchor.AnchorType.byId(0));
patriarch.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
cellColumn++;
}
continue;
}
}
cellRow.setCellValue(stringObjectMap.get(value).toString());
//cellColumn ++;
}
}
}
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();
//执行删除生成的图片
File file = new File(path);//输入要删除文件目录的绝对路径
deleteFile(file);//由于是保存网络图片到本地服务区,所以画完图片到excel就要删除文件
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static int sum(int a[], int n){
return (n<1)?0:sum(a,n-1)+a[n-1];
}
/**
* 删除文件夹目录下的所有文件 (怕到时候本地服务器图片越来越多,占用资源,所以把图片洗完到excel里面就删除)
* @date 2022/5/9
* @param file
*/
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();
}
/**
* 保存图片到本地
* @date 2022/5/9
* @param imageUrl
* @param path
* @return
*/
public static String saveFile(String imageUrl, String path){
String filename = imageUrl.substring(imageUrl.lastIndexOf("/")+1, imageUrl.length());
//log.error("图片===="+filename);
//Random rand = new Random();
//int s = rand.nextInt(900)+ 100;
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();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流
// String path = "E:\\data\\nginxd\\sportsApplets";
// String path = "/data/nginxd/sportsApplets/excelDeleteImage/";
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;
}
/**
* 将gif格式图片转换为jpg格式文件,并直接返回byte二进制流
* @param file
* @return
*/
public static byte[] GifToJpg(File file){
BufferedImage bufferedImage;
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
try {
// read image file
bufferedImage = ImageIO.read(file);
// create a blank, RGB, same width and height, and a white
BufferedImage newBufferedImage = new BufferedImage(
bufferedImage.getWidth(), bufferedImage.getHeight(),
BufferedImage.TYPE_INT_RGB);
// TYPE_INT_RGB:创建一个RBG图像,24位深度,成功将32位图转化成24位
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
// write to jpeg file
ImageIO.write(newBufferedImage, "png",out);//转换输出到二进制数组流
//ImageIO.write(newBufferedImage, "jpg",new File("c:\\java.jpg"));//转换输出到文件
return out.toByteArray();//二进制流
} catch (IOException e) {
//logger.error("***GifToJpg方法报错***");
e.printStackTrace();
}
return null;
}
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
// 确保加载了图像中的所有像素
image = new ImageIcon(image).getImage();
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
try {
int transparency = Transparency.OPAQUE;
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null),
image.getHeight(null), transparency);
} catch (HeadlessException e) {}
if (bimage == null) {
// 使用默认颜色模型创建缓冲图像
int type = BufferedImage.TYPE_INT_RGB;
bimage = new BufferedImage(image.getWidth(null),
image.getHeight(null), type);
}
// 复制图像到缓冲图像
Graphics g = bimage.createGraphics();
// 将图像绘制到缓冲图像上
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
/**
* @author P
* 将二进制流转换为图片
* @param imageBytes 二进制流(byte数组)
* @param imgAddress 新图片保存地址【包括图片名称包含后缀】
* @param oldAddress 旧的图片保存地址【包括图片名称包含后缀】
* @return 返回0(保存失败)返回1(保存成功)
*
* */
public static int ioToImg(byte[] imageBytes, String imgAddress, String oldAddress) {
//二进制转化为图片
if (imageBytes == null) return 0;
try (FileOutputStream fileOutputStream = new FileOutputStream(new
File(path + imgAddress));) {
fileOutputStream.write(imageBytes);//保存在本地
File oldFile = new File(path + oldAddress);
oldFile.delete();
return 1;
} catch (IOException e) {
System.out.println(e);
return 0;
}
}
原文作者:此一别终不见
原文地址: https://blog.csdn.net/qianqia_n/article/details/124708190
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
原文地址: https://blog.csdn.net/qianqia_n/article/details/124708190
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
相关文章