Java导出Excel里包含图片(包括GIF)

2023-01-01 00:00:00 包括 导出 包含

导出的效果

《Java导出Excel里包含图片(包括GIF)》

要求

《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
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章