【问题标题】:Load Font from /WEB-INF/resources/fonts/foobar.ttf with iTextPdf FontFactory使用 iTextPdf FontFactory 从 /WEB-INF/resources/fonts/foobar.ttf 加载字体
【发布时间】:2015-08-27 14:11:38
【问题描述】:

这个问题几乎说明了一切。我得到以下异常:

ExceptionConverter: java.io.IOException: /fonts/CALIBRI.TTF not found as file or resource.
Caused By: java.io.IOException: /fonts/CALIBRI.TTF not found as file or resource.
    at com.itextpdf.text.io.RandomAccessSourceFactory.createByReadingToMemory(RandomAccessSourceFactory.java:263)
    at com.itextpdf.text.io.RandomAccessSourceFactory.createBestSource(RandomAccessSourceFactory.java:173)
    at com.itextpdf.text.pdf.RandomAccessFileOrArray.<init>(RandomAccessFileOrArray.java:148)
    at com.itextpdf.text.pdf.TrueTypeFont.process(TrueTypeFont.java:641)
    at com.itextpdf.text.pdf.TrueTypeFont.<init>(TrueTypeFont.java:375)
    at com.itextpdf.text.pdf.BaseFont.getAllFontNames(BaseFont.java:1229)
    at com.itextpdf.text.FontFactoryImp.register(FontFactoryImp.java:446)
    at com.itextpdf.text.FontFactory.register(FontFactory.java:341)
    at bean.createPdf.makePdf(createPdf.java:358)
    at bean.auswahl.buttonProbenbegleitschein(auswahl.java:188)
    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:497)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:254)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:148)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at org.apache.myfaces.trinidad.component.UIXComponentBase.broadcast(UIXComponentBase.java:1113)
    at org.apache.myfaces.trinidad.component.UIXCommand.broadcast(UIXCommand.java:179)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at oracle.adf.view.rich.event.ProxyEvent.broadcastWrappedEvent(ProxyEvent.java:72)
    at oracle.adf.view.rich.component.fragment.UIXRegion.broadcast(UIXRegion.java:124)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent$1.run(ContextSwitchingComponent.java:168)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent._processPhase(ContextSwitchingComponent.java:510)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent.broadcast(ContextSwitchingComponent.java:171)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.UIXInclude.broadcast(UIXInclude.java:111)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent$1.run(ContextSwitchingComponent.java:168)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent._processPhase(ContextSwitchingComponent.java:510)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent.broadcast(ContextSwitchingComponent.java:171)
    at oracle.adf.view.rich.component.fragment.UIXInclude.broadcast(UIXInclude.java:115)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._invokeApplication(LifecycleImpl.java:1074)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:402)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:225)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:346)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:192)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:105)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:327)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:229)
    at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at de.lkvsh.rdv.portal.authlib.servlet.PortalFilter.doFilter(PortalFilter.java:116)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:137)
    at java.security.AccessController.doPrivileged(Native Method)
    at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
    at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:460)
    at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:120)
    at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:217)
    at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:81)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:220)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3436)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3402)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
    at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2285)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2201)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1572)
    at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:255)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)

字体文件的物理位置是/WEB-INF/resources/fonts/CALIBRI.TTF 所以据我所知,在iTextPDf FontFactory的资源中找不到它。

【问题讨论】:

  • META-INF 还是 WEB-INF?你的代码是什么?
  • 请添加Weblogic版本,以及代码createPdf.java靠近358行的一小部分

标签: java jakarta-ee fonts itext itextpdf


【解决方案1】:

基于 iText 的 RandomAccessSourceFactory#createBestSource()source codeFontFactory#register() 只能采用表示有效(相对)磁盘文件系统路径或资源 URL(例如 HTTP URL 或类路径 URL)的路径,而不是WAR 资源路径。您实际上提供了一个 WAR 资源路径,您通常可以将其传递给 ServletContext#getResource()getResourceAsStream()getRealPath()getRequestDispatcher()

有几种方法可以让它工作:

  1. 借助ServletContext#getRealPath()将WAR资源路径转换为绝对磁盘文件系统路径:

    String path = getServletContext().getRealPath("/WEB-INF/resources/fonts/foobar.ttf");
    FontFactory.register(path);
    

    需要注意的是,这种方法非常不便携并且依赖于环境。其中,当服务器配置为将 WAR 直接扩展到内存而不是本地磁盘文件系统或使用虚拟文件系统时,这将失败。例如,默认情况下,它可能适用于 Tomcat,但可能不适用于 WebLogic。您的堆栈跟踪确认您正在使用 WebLogic。 getRealPath() 默认总是返回 null 的机会很大。


  2. 将字体文件移到 /WEB-INF 文件夹之外,以便通过 HTTP URL 公开访问。前提是您可以将整个/resources 文件夹向上移动一级,在/WEB-INF 之外,并且http://localhost:8080/context/resources/fonts/foobar.ttf 可以访问该字体(首先在普通的网络浏览器中进行测试以确保),然后只需提供该路径即可。

    String path = "http://localhost:8080/context/resources/fonts/foobar.ttf";
    FontFactory.register(path);
    

    如有必要,您可以动态构造http://localhost:8080/context(基本 URL),如下所示:

    String url = request.getRequestURL().toString();
    String baseURL = url.substring(0, url.length() - request.getRequestURI().length()) + request.getContextPath();
    String path = baseURL + "/resources/fonts/foobar.ttf";
    FontFactory.register(path);
    

    需要注意的是,默认情况下,世界上任何人都可以下载它,即使只是猜测 URL。


  3. 将字体文件移动到类路径。 IE。确保它最终在所有这些 Java 类文件和类资源文件(例如属性文件)中以 /WEB-INF/classes 结尾。假设包名只是fonts。如果您使用 Maven,只需将其放入 /main/resources/fonts/foobar.ttf。如果您使用的“普通”Web 项目只有一个 src 文件夹,您可以在其中放置所有 Java 包和类源文件,然后以通常的方式创建一个包 fonts 并将 foobar.ttf 文件放在正确的位置那里。然后你可以提供/fonts/foobar.ttf的路径。

    String path = "/fonts/foobar.ttf";
    FontFactory.register(path);
    

    这显然是首选方式。


  4. 如果上述选项均不适用,您最后的手段是在容器管理的临时文件夹中借助File#createTempFile() 创建一个临时文件,通过ServletContext#getResourceAsStream() 获取WAR 资源内容,将其写入临时文件并最终提供绝对临时文件路径。

    String tempDir = (String) getServletContext().getAttribute(ServletContext.TEMPDIR);
    File tempFile = File.createTempFile("foobar-", ".ttf", new File(tempDir));
    InputStream input = getServletContext().getResourceAsStream("/WEB-INF/resources/fonts/foobar.ttf");
    Files.copy(input, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    String path = tempFile.getAbsolutePath();
    FontFactory.register(path);
    

注意:以上答案假定代码放置在“普通”Java EE servlet 类中。如果您正在使用 JSF——正如堆栈跟踪所证实的那样——您可以通过ExternalContext#getContext() 获得ServletContext,通过ExternalContext#getRequest() 获得HttpServletRequest,通过ServletContext 获得ServletContext 属性,通过ExternalContext#getApplicationMap() 获得真实路径ExternalContext#getRealPath(),以及ExternalContext#getResourceAsStream()的资源流。

【讨论】:

  • 感谢您提供非常完整的答案!
  • 哇,我认为没有人会回答这个问题:D 但从那以后它一直是个问题。我明天试试看:)
【解决方案2】:

java.io.IOException: /fonts/CALIBRI.TTF not found as file or resource.

我认为 iText 库正在直接在 WEB-INF 文件夹而不是 /WEB-INF/resources 下寻找字体。

【讨论】:

  • 不,它没有。将来,最好先将有根据的猜测作为评论发布,而不是作为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多