You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Apache POI创建EncryptionInfo实例时ClassCastException问题(Weblogic12)

解决Weblogic 12下Apache POI加密Excel的ClassCastException问题

从你给出的异常栈来看,核心问题是org.apache.poi.poifs.crypt.agile.AgileEncryptionInfoBuilder cannot be cast to org.apache.poi.poifs.crypt.EncryptionInfoBuilder,这种类转换异常几乎都是类加载器冲突导致的——Weblogic服务器自带了旧版本的Apache POI相关类,和你应用中打包的POI版本不一致,导致同一个逻辑类被不同的类加载器加载,JVM认为它们是不同类型,从而抛出转换异常。

解决方案步骤

1. 确保POI依赖版本完全一致

首先检查你的项目依赖,确保所有POI相关组件(poipoi-ooxmlpoi-ooxml-schemaspoi-scratchpad等)使用同一个稳定版本,比如4.1.2或者5.2.3(避免混合不同版本,这本身就容易引发问题)。

如果用Maven,在pom.xml里统一管理版本:

<properties>
    <poi.version>4.1.2</poi.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <!-- 其他POI组件也用同样版本 -->
</dependencies>

2. 配置Weblogic优先加载应用的POI类

Weblogic默认会优先加载自身库中的类,所以需要修改应用的weblogic.xml(放在WEB-INF下),配置prefer-application-packages,让应用优先使用自己打包的POI及相关依赖类:

<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.7/weblogic-web-app.xsd">
    <container-descriptor>
        <prefer-application-packages>
            <!-- 覆盖所有POI相关包 -->
            <package-name>org.apache.poi.*</package-name>
            <!-- XMLBeans是POI依赖的,也需要优先加载 -->
            <package-name>org.apache.xmlbeans.*</package-name>
            <!-- OpenXML格式相关包 -->
            <package-name>org.openxmlformats.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>

3. 验证类加载器(可选)

如果不确定是否是类加载器问题,可以在代码中加入日志,打印两个类的加载器:

logger.info("EncryptionInfoBuilder loaded by: " + EncryptionInfoBuilder.class.getClassLoader());
logger.info("AgileEncryptionInfoBuilder loaded by: " + AgileEncryptionInfoBuilder.class.getClassLoader());

如果输出的类加载器不同,就确认是冲突问题,上面的配置就能解决。

4. 优化代码中的资源关闭

另外注意你代码里的finally块,资源关闭没有做异常处理,一个资源关闭失败会导致后续资源无法关闭。推荐使用Java 7+的try-with-resources语法,自动管理资源:

public static void parseFileToSecureFile(String fullFileName, String password) throws MyException{
    try (POIFSFileSystem fs = new POIFSFileSystem();
         OPCPackage opc = OPCPackage.open(new File(fullFileName), PackageAccess.READ_WRITE);
         FileOutputStream fos = new FileOutputStream(fullFileName)) {

        EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes256, HashAlgorithm.sha512, -1, -1, null);
        Encryptor enc = info.getEncryptor();
        enc.confirmPassword(password);
        
        try (OutputStream os = enc.getDataStream(fs)) {
            opc.save(os);
        }
        fs.writeFilesystem(fos);
    } catch (Exception e) {
        logger.error("Error encrypting file: "+e.getMessage(), e);
        throw new MyException("Failed to encrypt Excel file");
    }
}

这样不用手动关闭资源,JVM会自动确保所有资源被正确关闭,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Bal_lam

火山引擎 最新活动