SpringCloud+JDK17整合EaseExcel记录

文章记录了在SpringCloud项目中使用JDK17时,整合EasyExcel库遇到的版本不兼容和运行时异常问题。主要问题是由于EasyExcel与CGlib版本冲突以及JDK17对反射操作的限制导致。解决方案包括添加CGlib依赖、调整JVM参数以及处理注解解析异常。此外,提供了EasyExcel工具类的部分代码示例。
摘要由CSDN通过智能技术生成

SpringCloud+JDK17整合EaseExcel记录

SpringCloud+JDK17整合EaseExcel以及踩坑

项目搭建使用cloud+jdk17搭建,由于版本不一致搭建,踩坑记录。

版本信息

  1. SpringCloud
 <!-- springcloud start -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2022.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- springcloud end -->

  1. SpringBoot
 <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
  1. EasyExecl
<!--alibaba EasyExcel导入导出-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>${easyexcel.version}</version>
        </dependency>
        <!--cglib-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

之所以加入cglib,下列有原因,如果没有出现错误可以不加入。

整合问题整理

com.alibaba.excel.exception.ExcelGenerateException: java.lang.NoClassDefFoundError:

  • 报错 com.alibaba.excel.exception.ExcelGenerateException: java.lang.NoClassDefFoundError: net/sf/cglib/beans/BeanMap$Generator
  • 原因:
    easyexcel和cglib版本不兼容或者没有安装cglib
  • 解决:
    在pom中添加对应的cglib依赖,找到easyexcel和cglib对应版本。根据版本添加cglib对应版本pom。
    推荐使用IDEA插件maven helper找冲突进行处理。

com.alibaba.excel.exception.ExcelGenerateException: java.lang.ExceptionInInitializerError

  • 报错
com.alibaba.excel.exception.ExcelGenerateException: java.lang.ExceptionInInitializerError
	at com.alibaba.excel.write.ExcelBuilderImpl.addContent(ExcelBuilderImpl.java:64)
	at com.alibaba.excel.ExcelWriter.write(ExcelWriter.java:161)
	at com.alibaba.excel.ExcelWriter.write(ExcelWriter.java:146)
	at com.alibaba.excel.write.builder.ExcelWriterSheetBuilder.doWrite(ExcelWriterSheetBuilder.java:179)
	at cn.cc.ggkt.vod.service.impl.SubjectServiceImpl.exportData(SubjectServiceImpl.java:74)
	at cn.cc.ggkt.vod.service.impl.SubjectServiceImpl$$FastClassBySpringCGLIB$$7317bea1.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685)
	at cn.cc.ggkt.vod.service.impl.SubjectServiceImpl$$EnhancerBySpringCGLIB$$c6b66a85.exportData(<generated>)
	at cn.cc.ggkt.vod.controller.SubjectController.exportData(SubjectController.java:44)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)

查询数据是存在的,在进行写excel失败,未将数据写入excel中。

  • 原因:主要提示在于此处 Caused by:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @1c93084c

其根本在于高版本的JDK对反射的操作做了限制,两种处理方式。
第一种:降低JDK版本(由于我该项目用JDK17,不能降低)
第二种:JVM加上参数设置

--add-opens java.base/java.lang=ALL-UNNAMED

点击Edit Configurations–Modify options–add vm options
在这里插入图片描述

在这里插入图片描述

easyExcel工具类

@Slf4j
public class ExcelUtil {
//下载单sheet
    public static <T> void download(HttpServletResponse response, Class<T> clazz, List<T> data) {
//        StaticComponentContainer.Modules.exportAllToAll();
        Assert.notNull(clazz, "clazz can't be null");
        Assert.isTrue(data != null && !data.isEmpty(), "data can't be empty");
        try {
            ExcelContext excelContext = clazz.getAnnotation(ExcelContext.class);
            buildResponse(response, excelContext.fileName());
            EasyExcel.write(response.getOutputStream(), clazz)
                    .registerConverter(new LocalDateTimeConverter())
                    .registerWriteHandler(new RowWriteHandlerImpl())
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .autoCloseStream(Boolean.FALSE).sheet(excelContext.sheetName())
                    .doWrite(data);
        } catch (Exception e) {
            buildResponse(response, e);
        }
    }
//下载多sheet
    public static void download(HttpServletResponse response, List<List> source) {
        Assert.isTrue(source != null && source.size() > 0, "source can't be empty");
        ExcelWriter excelWriter = null;
        try {
            String fileName = source.get(ZERO).get(ZERO).getClass().getAnnotation(ExcelContext.class).fileName();
            buildResponse(response, fileName);
            excelWriter = EasyExcel.write(response.getOutputStream())
                    .registerConverter(new LocalDateTimeConverter())
                    .registerWriteHandler(new RowWriteHandlerImpl())
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .autoCloseStream(Boolean.FALSE).build();
            for (int i = 0; i < source.size(); i++) {
                List list = source.get(i);
                //Assert.isTrue(!CollectionUtils.isEmpty(list), "source can't be empty");
                if (CollectionUtils.isEmpty(list)) {
                    continue;
                }
                Class<?> clazz = list.get(ZERO).getClass();
                ExcelContext context = clazz.getAnnotation(ExcelContext.class);
                WriteSheet writeSheet = EasyExcel.writerSheet(i, context.sheetName()).registerWriteHandler(new RowWriteHandlerImpl()).head(clazz).build();
                excelWriter.write(list, writeSheet);
            }
        } catch (Exception e) {
            buildResponse(response, e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }

    }

    private static void buildResponse(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
        fileName = URLEncoder.encode(fileName + "-" + DateUtil.dateToStr(LocalDate.now()), "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    }

    private static void buildResponse(HttpServletResponse response, Exception e) {
        StackTraceElement[] stackTrace = e.getStackTrace();
        log.error("Failed to export data. -> {}", String.valueOf(stackTrace[0]) + stackTrace[1] + stackTrace[2], e);
        //response.reset();
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = response.getWriter()) {
            writer.println(JSONObject.toJSONString(HttpResult.error("导出数据失败, " + e.toString())));
        } catch (Exception ignored) {
        }
    }

    /**
     * 判断是否是excel
     *
     * @param file 文件
     * @return 获取结果
     */
    public static boolean checkExcel(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String match1 = "^.+\\.(?i)(xls)$";
        String match2 = "^.+\\.(?i)(xlsx)$";
        return !fileName.matches(match1) && !fileName.matches(match2);
    }

    /**
     * 导出单元格内容含有下拉框的excel 需要使用@ExcelSelected在对应字段上设置字段的下拉框的值
     *
     * @param response
     * @param source
     */
    public static void writeSelectedSheet(HttpServletResponse response, List<List> source) {
        Assert.isTrue(source != null && source.size() > 0, "source can't be empty");
        ExcelWriter excelWriter = null;
        try {
            String fileName = source.get(ZERO).get(ZERO).getClass().getAnnotation(ExcelContext.class).fileName();
            buildResponse(response, fileName);
            excelWriter = EasyExcel.write(response.getOutputStream())
                    .registerConverter(new LocalDateTimeConverter())
                    .registerWriteHandler(new RowWriteHandlerImpl())
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .autoCloseStream(Boolean.FALSE).build();
            for (int i = 0; i < source.size(); i++) {
                List list = source.get(i);
                //Assert.isTrue(!CollectionUtils.isEmpty(list), "source can't be empty");
                if (CollectionUtils.isEmpty(list)) {
                    continue;
                }
                Class<?> clazz = list.get(ZERO).getClass();
                ExcelContext context = clazz.getAnnotation(ExcelContext.class);
                Map<Integer, ExcelSelectedResolve> selectedMap = resolveSelectedAnnotation(clazz);
                WriteSheet writeSheet = EasyExcel.writerSheet(i, context.sheetName()).head(clazz).registerWriteHandler(new RowWriteHandlerImpl()).registerWriteHandler(new SelectedSheetWriteHandler(selectedMap)).build();
                excelWriter.write(list, writeSheet);
            }
        } catch (Exception e) {
            buildResponse(response, e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }

    }

    /**
     * 解析表头类中的下拉注解
     *
     * @param head 表头类
     * @param <T>  泛型
     * @return Map<下拉框列索引, 下拉框内容> map
     */
    private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head) {
        Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();

        // getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
        Field[] fields = head.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            // 解析注解信息
            ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
            ExcelProperty property = field.getAnnotation(ExcelProperty.class);
            if (selected != null) {
                ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
                String[] source = excelSelectedResolve.resolveSelectedSource(selected);
                if (source != null && source.length > 0) {
                    excelSelectedResolve.setSource(source);
                    excelSelectedResolve.setFirstRow(selected.firstRow());
                    excelSelectedResolve.setLastRow(selected.lastRow());
                    if (property != null && property.index() >= 0) {
                        selectedMap.put(property.index(), excelSelectedResolve);
                    } else {
                        selectedMap.put(i, excelSelectedResolve);
                    }
                }
            }
        }

        return selectedMap;
    }
}

代码包已上传

后续有问题踩坑继续补充…

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值