当前位置: 首页 > 知识库问答 >
问题:

Apache POI OPCPackage无法保存生成的Jasper Report XLSX

尚声
2023-03-14

总的行动计划是使用JasperReports API生成一个XLSX文件,然后将其输入Apache POI的加密代码。这里找到的例子:http://www . quick ly Java . com/create-password-protected-excel-using-Apache-poi/。

不幸的是,当文件从Jasper报告生成时,我无法对其进行加密,但是如果我在MS Excel中创建一个文件并通过代码加载它,那么它可以很好地加密。因此,阿帕奇POI库可以很好地处理来自Excel的文件。

调试后,我相信我能够查明问题。

我们使用OPCPackage类打开文件(或者在另一种情况下加载InputStream),该类有一个设置所有字段的方法getParts()。其中一个是packageProperties。packageProperties似乎正在加载特定的Package Part'application/vnd.openxmlformats-Package。核心属性xml“。然而,在Jasper Report生成的XLSX文件中找不到该部分,因此仍为空。

// Check OPC compliance rule M4.1
if (part.getContentType().equals(ContentTypes.CORE_PROPERTIES_PART)) {
    if (!hasCorePropertiesPart) {hasCorePropertiesPart = true;

如果这通过了,下面几行我们指定this.packageProperties:

// Core properties case-- use first CoreProperties part we come across
// and ignore any subsequent ones
if (unmarshallPart instanceof PackagePropertiesPart && needCorePropertiesPart) {
    this.packageProperties = (PackagePropertiesPart) unmarshallPart;

该文件打开正常,但是当我尝试保存文件时,saveImpl方法调用一个名为addPackagePart的方法,传入“包属性”变量。然后,该类将引发异常,因为该字段为 null。从拉链包装#保存简单

// If the core properties part does not exist in the part list,
// we save it as well
if (this.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES).size() == 0 && this.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES_ECMA376).size() == 0    ) {
    logger.log(POILogger.DEBUG,"Save core properties part");
        // Add core properties to part list ...
        addPackagePart(this.packageProperties);

这是例外:

org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException: Fail to save: an error occurs while saving the package : part
    at org.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPackage.java:503)
    at org.apache.poi.openxml4j.opc.OPCPackage.save(OPCPackage.java:1425)
    at com.krfs.web.controller.report.BaseReportController.encryptXlsxOutputStream(BaseReportController.java:717)
    at com.krfs.web.controller.report.BaseReportController.generateJasperReportOutput(BaseReportController.java:547)
    at com.krfs.web.controller.report.BaseReportController.processReportRunningAndGeneration(BaseReportController.java:382)
    at com.krfs.web.controller.report.StandardReportController.processReportRunningAndGeneration(StandardReportController.java:25)
    at com.krfs.web.controller.report.StandardReportController.run(StandardReportController.java:82)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:177)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.krfs.web.filter.RedirectFilter.doFilter(RedirectFilter.java:62)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.krfs.web.filter.XssFilter.doFilter(XssFilter.java:17)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.switchuser.SwitchUserFilter.doFilter(SwitchUserFilter.java:181)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at com.krfs.web.filter.CustomLoginFilter.doFilter(CustomLoginFilter.java:156)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at com.krfs.web.filter.CsrfFilter.doFilter(CsrfFilter.java:52)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at fr.xebia.servlet.filter.ExpiresFilter.doFilter(ExpiresFilter.java:1243)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.krfs.web.filter.SecurityHeadersFilter.doFilter(SecurityHeadersFilter.java:22)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.krfs.web.filter.LoggingFilter.doFilter(LoggingFilter.java:44)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.IllegalArgumentException: part
    at org.apache.poi.openxml4j.opc.OPCPackage.addPackagePart(OPCPackage.java:873)
    at org.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPackage.java:448)
    ... 104 more

Jasper Reports代码是导出XLSX文件的标准代码。

JRXlsAbstractExporter exporter = new JRXlsxExporter();

JasperPrint jasperPrint = fillJasperPrint(reportMessenger, reportFile, reportParameters);

exporter.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, outputStream);
exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);                    
exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);

exporter.exportReport();

这很好地创建了XLSX,但是当我提取内容并查看包时,我没有看到属性Partapplication/vnd.openxmlformats-package.core-properties xml,这显然是Apache POI保存文件所必需的。

加密代码:

POIFSFileSystem fs = new POIFSFileSystem();
        EncryptionInfo info = new EncryptionInfo(fs, EncryptionMode.agile);
        Encryptor enc = info.getEncryptor();
        enc.confirmPassword(reportPassword);

        try (OPCPackage opc = OPCPackage.open(new ByteArrayInputStream(xlsxOutputStream.toByteArray()))) {
            OutputStream os = enc.getDataStream(fs);
            opc.save(os);
        }

        fs.writeFilesystem(encryptedOutputStream);

依赖项版本:

碧玉报告 - 4.7.1(我也尝试了6.0.2,结果相同)

阿帕奇波伊 - 3.11

所以我的问题是,我如何才能让这两个库协调工作,这样我就可以加密来自jasper报告的文件?有没有办法在导出文件之前注入输出类型的部件核心属性xml?有没有办法绕过Apache POI库跳过查找该部件?

我希望有人看到类似的东西,他们可以帮助我。

干杯,谢谢!

共有2个答案

阎慈
2023-03-14

更新:堆栈溢出不允许上传文件,因此您可以在github中找到整个项目:https://github.com/nestoru/xlsxenc

我可以确认这是apache POI库的错误,而不是jasper报告的错误。我在这里附上了相关文件和一项临时工作,其中涉及使用libreoffice(迄今为止最好的开源excel处理套件、实用程序,甚至可能是库)。解决方法包括将libreoffice作为shell进程调用,以POI“理解”它的方式“纠正”来自jasper报告的xlsx。

以下是如何根据提供的文件从头开始重新创建所有内容或部分内容:

>

  • 从 ireport 加载附加的 jrxml 文件,该文件将仅输出我的徽标。
  • 从 ireport 中选择 xlsx 输出类型,您将获得报告1.xlsx也附加。
  • 现在尝试使用附加的java程序加密文件,您将收到如下所示的错误:

    $ javac-CP " " Enc.java $ Java-CP "。:" Enc/home/dev/xlsxenc/report 1 . xlsx/tmp/out . xlsx

    线程“main”org.apache.poi.openxml4j.exceptions中出现异常。OpenXML4JRuntimeException:无法保存:保存包时发生错误:位于Enc.java:34)的org.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPacket.java:503)的org.apache.poi.openxml4j.poc.OPCPackage.save(OPCPackage.java:1425)导致的错误:java.lang.IllegalArgumentExceptionorg.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPackage.java:448)…还有2个

    现在是解决问题的时候了。运行以下命令以“更正”xlsx:

    $ libreoffice --无头 --转换为 xlsx /home/dev/xlsxenc/report1.xlsx --outdir /tmp

    转换 /首页/开发/xlsxenc/报告1.xlsx -

    并确认程序现在对文件进行加密。当你打开它时,它会要求输入密码。只需键入“密码”,它就会打开。

    $ java -cp “.:*” Enc /tmp/report1.xlsx /tmp/out.xlsx

    $libreoffice /tmp/out.xlsx

    Xlib:扩展名“XINERAMA”在显示“:10.0”上丢失。

  • 邢寒
    2023-03-14

    据我所知,Jasper Reports正在编写稍微不符合规范的文件。没有到Excel无法使用它们的支持程度,但仍然不符合规范。

    Apache POI可以很好地读取这些文件,正如像这样的单元测试所示。Apache POI也可以保存它们,如果通过XSSFWorkbook或类似的东西打开并保存,就会触发缺失部分的创建。

    不幸的是,对于您的用例,您正在OPCPackge级别下工作,那里有一个POI错误。此问题已在r1662971中修复,并将在POI 3.12 beta 2及更高版本中修复。

    现在,您可以通过更改以下行来触发核心属性的创建:

    OPCPackage opc = OPCPackage.open(inputFilePath, PackageAccess.READ_WRITE);
    OutputStream os = enc.getDataStream(fs);
    opc.save(os);
    

    改为:

    OPCPackage opc = OPCPackage.open(inputFilePath, PackageAccess.READ_WRITE);
    OutputStream os = enc.getDataStream(fs);
    opc.getProperties();
    opc.save(os);
    

    使用POI 3.12 beta 2或更高版本后,您将不需要对getProperties()进行额外调用。

    此外,您链接到的github中的代码中有一些不推荐使用的调用,您可能需要查看TestEncryptor。encryptPackageWithoutCoreProperties(),了解如何稍微调整它,使其在不推荐使用的方法的情况下工作。

     类似资料:
    • 我设法通过.proto文件生成了类,但它们在构建中。 我希望在main中生成类,因为当我要扩展存根时,不可能实现这些方法。 瞧: 文件.proto: proto文件在主文件夹中。 有人知道怎么解决吗?

    • 我正对着< code > org . Apache . poi . open XML 4j . exceptions . open XML 4 jruntimeexception:保存失败:保存包时出错:无法用marshaller在流中保存零件/docProps/app.xml 在每个测试场景执行完成后,尝试将每个测试场景结果(通过或失败)写入Excel表(.xlsx)时出现异常。为此,我编写了以

    • 服务器:版本:1.12.6 API版本:1.24 Go版本:Go1.6.3 Git提交:78D1802 build:Tue Jan 31 23:47:34 2017 OS/arch:linux/amd64 Docker--Version docker Version1.12.6,构建78D1802 docker-compose-版本docker-compose版本1.5.2,构建未知

    • 我以这种格式将私钥保存在DB中。 我需要从中提取公钥。openssl\u pkey\u get\u详细信息需要资源,但如何从字符串创建资源? 我试过这个 错误是openssl\u pkey\u get\u details()期望参数1是资源,给定布尔值 编辑1: 我试图从@kbarborak bellow获得解决方案,但$pk\u get是错误的: var_转储的输出为:

    • 本文向大家介绍vue生成token保存在客户端localStorage中的方法,包括了vue生成token保存在客户端localStorage中的方法的使用技巧和注意事项,需要的朋友参考一下 前面我们已经了解了可以通过localStorage在客户端(浏览器)保存数据。 我们后端有这样一个接口: http://localhost/yiiserver/web/index.php/token?clie