依赖冲突查找与解决办法(以EasyPoi为例,出现 NoSuchMethodError 或 NoClassDefFoundError )

1、问题

  最近学习了 EasyPoi,相对原生的 poi 来说,操作更加的方便。因此想升级一下项目中 excel 的导入功能,但是编写完成后,测试了一下发现报错了:is java.lang.NoSuchMethodError: org.apache.poi.ss.usermodel.Cell.getCellType()

2、代码结构

2.1 pom.xml

  原本项目中存在 org.apache.poi,现想引入 EasyPoi,但不影响原先功能。主要相关依赖如下:

        <!--   apache POI  -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <!--   Easy POI  -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.1.0</version>
        </dependency>

2.2 Excel 表结构图

在这里插入图片描述

2.3 Excel 接收实体类

import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.io.Serializable;

/**
 * 公章信息Excel导入【接收】实体
 * @author pky
 */
@Data
public class SealInfoExcelVo implements Serializable {

    @Excel(name = "公章名称")
    @NotBlank(message = "公章名称不可为空")
    @Length(max = 50, message = "公章名称字数范围[1~50]")
    private String sealName;

    @Excel(name = "保管人姓名")
    @NotBlank(message = "保管人姓名不可为空")
    private String userName;

    @Excel(name = "办公电话")
    @NotBlank(message = "办公电话不可为空")
    @Pattern(regexp = "^\\d{3}-\\d{7,8}|\\d{4}-\\d{7,8}$", message = "固话格式不正确")
    private String officeTel;
    
    @Excel(name = "保管地址")
    @NotBlank(message = "保管地址不可为空")
    @Length(max = 30, message = "保管地址字数范围[1~30]")
    private String address;

    @Excel(name = "备注信息")
    @Length(max = 200, message = "备注信息字数范围[0~200]")
    private String remark;
}

2.4 工具类

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import org.apache.poi.ss.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.NoSuchElementException;

/**
 * EasyPoi 工具类,导出导入Excel
 * @author pky
 */
public class EasyPoiUtil {
    /**
     * 功能描述:根据接收的Excel文件来导入Excel,并封装成实体类
     *
     * @param file 上传的文件
     * @param titleRows 表标题的行数(不是行号)
     * @param headerRows 表头行数(不是行号)
     * @param boClass Excel实体类
     * @return Excel 实体类
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> boClass) {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), boClass, params);
        } catch (NoSuchElementException e) {
            throw new RuntimeException("excel文件不能为空");
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return list;
    }
}

具体工具类可以网上搜索,这里只展示相关的方法。

2.5 Controller

    /**
     * 导入公章基本信息
     * @param file 文件
     * @return 通用返回结果
     */
    @PostMapping(value = "seal/info/import")
    public BaseResult importExcel(MultipartFile file) {
        if(file == null) {
            return error("文件不可为空");
        }
        sealInfoBoService.importSealExcel(file);
        return success();
    }

2.6 Service

  • 接口
    /**
     * 导入公章信息
     * @param file 文件
     */
    void importSealExcel(MultipartFile file);

  • impl
    /**
     * 导入公章信息
     * @param file 文件
     */
    @Override
    public void importSealExcel(MultipartFile file) {
        // 1、解析文件数据
        List<SealInfoExcelVo> excelVoList = EasyPoiUtil.importExcel(file, 1, 1, SealInfoExcelVo.class);
        for(SealInfoExcelVo excelVo : excelVoList) {
        	// todo 数据校验
        }
    }

3、分析与排查

  NoSuchMethodError 、NoClassDefFoundError 是在运行时 JVM 加载不到类或者找不到类。多数情况下可能的原因是工程里没有将 jar 添加到 classpath 中,而我这里是 maven 项目,也就是 EasyPoi 依赖中没有对应的类或方法。

注:有时会和 ClassNotfoundException 混淆,其是在编译时 JVM 加载不到类或者找不到类导致的;

  但是资料上 EasyPoi 确实是这么用的,为了进一步确认,我单独在其他项目中只引入 EasyPoi 的依赖,测试代码是通过的。初步确认是依赖冲突问题,然后在原本的项目的类库中分别找 EasyPoi 和 apache poi 下的方法:org.apache.poi.ss.usermodel.Cell.getCellType(),两者返回的类型不一样,而 maven 却选择了低版本的,导致出现上述报错信息。

说明: maven 仲裁机制

  • 优先按照依赖管理 <dependencyManagement> 元素中指定的版本声明进行仲裁,此时下面的两个原则都无效了。
  • 若无版本声明,则按照“短路径优先”的原则(Maven2.0)进行仲裁,即选择依赖树中路径最短的版本。
  • 若路径长度一致,则按照“第一声明优先”的原则进行仲裁,即选择 POM 中最先声明的版本。

4、解决

  • 在 IDEA 中点开项目最右边的 maven 窗口,然后打开依赖关系树,如下图:
    在这里插入图片描述

  • 查找冲突的依赖,如下图,点击显示冲突项,再点击显示实际大小,即可查到具体的冲突包。

在这里插入图片描述

  • 上述的问题(org.apache.poi.ss.usermodel.Cell.getCellType())就是图中 poi 包冲突问题,而 easypoi 需要的 poi 包是当前 easypoi 版本,因此只需要去除掉旧版本的 poi 包即可,如下
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

有些 IDEA 操作更加方便,右键点击上图不需要的冲突的包,然后选择点击 Exclude,即可在相应的依赖中自动加入去除的冲突包。我的 IDEA 没有这个功能,所以需要手写加入。

这样,查找和解决都已完成。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值