SSM integrates EasyPoi to solve the problem of ArrayIndexOutOfBoundsException when exporting images

 

Reference blog:

https://blog.csdn.net/qq_34988540/article/details/83050187

https://blog.csdn.net/breakaway_01/article/details/103895099

Preface

Recently, due to the needs of JavaWeb final works, EasyPoi was introduced in the SSM project to export order data to Excel. Talk about the two pits encountered

Manually import the jar package

Since the project is co-coded with the team members, I manually import the jar package from the beginning, without using maven. The official EasyPoi documentation does not say which jar packages should be included in the manual import, and the error java.lang.NoClassDefFoundError is reported , which is obviously a lack of jar packages.

In Eclipse, there is no way to trace the source code by manually importing the jar package. I don't know which jar package is missing after reading the error.

Later, there was no way, so I created a new maven project, used maven to import EasyPoi, and then exported it as a war package. Then unzip the war package and find that EasyPoi 3.2.0 needs to import the following jar packages in total

commons-lang3-3.2.1.jar

guava-16.0.1.jar

easypoi-base-3.2.0.jar

easypoi-annotation-3.2.0.jar

easypoi-web-3.2.0.jar

Image export error ArrayIndexOutOfBoundsException

As for the reason, the reference blog in the preface is very detailed. Here I will talk about how to replace the default configuration of EasyPoi in the SSM project to solve the path resolution problem.

package easymall.component;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.apache.commons.io.IOUtils;

import com.google.common.cache.CacheLoader;

import cn.afterturn.easypoi.cache.manager.POICacheManager;

/**
 * 自定义EasyPoiFixedCacheLoader,以替换EasyPoi的默认CacheLoader实现
 * 解决图片路径解析的bug
 * 参考博客:https://blog.csdn.net/qq_34988540/article/details/83050187
 * 
 * @author	passerbyYSQ
 * @date	2020-12-29 15:26:04
 */
public class EasyPoiFixedCacheLoader extends CacheLoader<String, byte[]> {

	@Override
	public byte[] load(String imagePath) throws Exception {
		InputStream is = POICacheManager.getFile(imagePath);
        BufferedImage bufferImg = ImageIO.read(is);
        ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferImg,
            		// lastIndexOf 为修改源码的地方
                    imagePath.substring(imagePath.lastIndexOf(".") + 1, imagePath.length()),
                    byteArrayOut);
            return byteArrayOut.toByteArray();
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(byteArrayOut);
        }
	}

}
package easymall.component;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.afterturn.easypoi.cache.manager.FileLoaderImpl;
import cn.afterturn.easypoi.cache.manager.IFileLoader;

/**
 * 解决EasyPoi网络图片下载并导出的问题
 * 参考博客:https://blog.csdn.net/breakaway_01/article/details/103895099
 * 
 * @author	passerbyYSQ
 * @date	2020-12-29 15:33:22
 */
public class EasyPoiFixedFileLoaderImpl implements IFileLoader {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileLoaderImpl.class);

    @Override
    public byte[] getFile(String url) {
        InputStream fileis = null;
        ByteArrayOutputStream baos = null;
        try {

            //判断是否是网络地址
            if (url.startsWith("http")) {
                URL urlObj = new URL(url);
                URLConnection urlConnection = urlObj.openConnection();
                urlConnection.setConnectTimeout(3 * 1000);
                urlConnection.setReadTimeout(60 * 1000);
                urlConnection.setDoInput(true);
                urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
                fileis = urlConnection.getInputStream();

            } else {
                //先用绝对路径查询,再查询相对路径
                try {
                    fileis = new FileInputStream(url);
                } catch (FileNotFoundException e) {
                    //获取项目文件
                    fileis = FileLoaderImpl.class.getClassLoader().getResourceAsStream(url);
//                    if (fileis == null) {
//                        //最后再拿相对文件路径
//                        String path = PoiPublicUtil.getWebRootPath(url);
//                        fileis = new FileInputStream(path);
//                    }
                }
            }

            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fileis.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(fileis);
            IOUtils.closeQuietly(baos);
        }
        LOGGER.error(fileis + "这个路径文件没有找到,请查询");
        return null;
    }
}

When tomcat starts, it will read the configuration of the web.xml file and initialize our Spring container. After the initialization of the Spring container is completed, we can perform a "replacement" operation to fix EasyPoi bugs. Therefore we need to customize our own ContextLoaderListener 

package easymall.component;

import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContextEvent;

import org.springframework.web.context.ContextLoaderListener;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;

import cn.afterturn.easypoi.cache.ImageCache;
import cn.afterturn.easypoi.cache.manager.POICacheManager;

/**
 * @author	passerbyYSQ
 * @date	2020-12-29 15:15:41
 */
public class MyContextLoaderListener extends ContextLoaderListener {

	@Override
	public void contextInitialized(ServletContextEvent event) {
		
		super.contextInitialized(event); // 不能去掉
		
		// 容器初始化完成后,替换EasyPoi的ImageCache
		// 以解决EasyPoi源码中导出本地图片的路径解析的bug
		
		EasyPoiFixedCacheLoader cacheLoader = new EasyPoiFixedCacheLoader();
		LoadingCache<String, byte[]> loadingCache = CacheBuilder.newBuilder()
				.expireAfterWrite(1, TimeUnit.DAYS)
                .maximumSize(2000).build(cacheLoader);
		// 替换
		ImageCache.setLoadingCache(loadingCache);
		
		// 替换
		EasyPoiFixedFileLoaderImpl fileLoader = new EasyPoiFixedFileLoaderImpl();
		POICacheManager.setFileLoder(fileLoader);
		
		System.out.println("容器初始化完毕!!!");
	}

}

web.xml

 <!-- 指定一ContextLoaderListener方式启动Spring容器
  原本:org.springframework.web.context.ContextLoaderListener
  修改后:easymall.component.MyContextLoaderListener(自定义的ContextLoaderListener的路径)
   -->
  <listener>
  	<listener-class>
  		easymall.component.MyContextLoaderListener
  	</listener-class>
  </listener>

 

Guess you like

Origin blog.csdn.net/qq_43290318/article/details/111932803