使用iTextPdf FontFactory从/WEB-INF/resources/fonts/foobar.ttf加载字体

m3t*_*kas 4 java fonts itext java-ee itextpdf

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

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)
Run Code Online (Sandbox Code Playgroud)

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

Bal*_*usC 6

基于源代码的iText年代RandomAccessSourceFactory#createBestSource()时,FontFactory#register()只能采取较有效的(相对)磁盘文件系统路径的路径,或资源URL(如HTTP URL或类路径URL),不是战争资源路径.事实上,你提供的,你通常可以传递给WAR资源路径ServletContext#getResource(),getResourceAsStream(),getRealPath()getRequestDispatcher()只.

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

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

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

    需要注意的是,这种方法具有很高的不可移植性和环境依赖性.其中,当服务器配置为将WAR直接扩展到内存而不是本地磁盘文件系统或使用虚拟文件系统时,这将失败.例如,默认情况下,它可以在Tomcat上运行,但它可能无法在WebLogic上运行.堆栈跟踪确认您正在使用WebLogic.机会很大,getRealPath()默认情况下总是会返回null.


  2. 将字体文件移动到文件/WEB-INF夹外部,以便HTTP URL可以公开访问它.如果你可以将整个/resources文件夹向上移动一层,在外面移动/WEB-INF,并且可以通过http://localhost:8080/context/resources/fonts/foobar.ttf(首先在普通的webbrowser中测试)来访问该字体,然后只提供该路径.

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

    如有必要,您可以动态构造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);
    
    Run Code Online (Sandbox Code Playgroud)

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


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

    String path = "/fonts/foobar.ttf";
    FontFactory.register(path);
    
    Run Code Online (Sandbox Code Playgroud)

    这显然是首选方式.


  4. 如果以上选项都不适用,您最后的办法是File#createTempFile()在容器管理的临时文件夹的帮助下创建一个临时文件,获取WAR资源内容ServletContext#getResourceAsStream(),将其写入临时文件,最后提供绝对临时文件路径.

    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);
    
    Run Code Online (Sandbox Code Playgroud)

注意:上面的答案假定代码放在"普通"Java EE servlet类中.如果您正在使用JSF - 由堆栈跟踪确认 - 您可以获取ServletContextby ExternalContext#getContext(),HttpServletRequestby ExternalContext#getRequest(),ServletContext属性ExternalContext#getApplicationMap(),实际路径ExternalContext#getRealPath()和资源流ExternalContext#getResourceAsStream().

  • 感谢您提供优质而完整的答案! (3认同)