【问题标题】:Intellij idea spring boot launcher: taglibs doesn't load in freemarkerIntellij idea spring boot 启动器:taglibs 未在 freemarker 中加载
【发布时间】:2018-08-01 17:24:33
【问题描述】:

我有在 spring boot 2.0.4 上启动的 web 应用程序。 依赖关系也存在 taglibs-standard-impl 1.2.5.
我的项目结构如下。

web/
├── src
   ├── main
   │   ├── java
   │   │   
   │   ├── resources
   │   │   ├── i18n
   │   │   ├── static
   │   │   └── templates
   │   └── webapp
   │       ├── META-INF
   │       └── WEB-INF
   └── test
       └── java

在 WEB-INF 中,我有一个包含一个自定义 tld 的文件夹 tld。 我的主要课程:

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class WebMain extends SpringBootServletInitializer implements WebApplicationInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebMain.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(WebMain.class, args);
    }
}

问题如下,基本上影响了开发时间。在我的主要 freemarker 模板中,我包含 taglib,例如:

<#assign form=JspTaglibs["http://www.springframework.org/tags/form"]/>
<#assign spring=JspTaglibs["http://www.springframework.org/tags"]/>
<#assign common = JspTaglibs["/WEB-INF/tld/common.tld"]>

问题是当通过spring boot启动器在intellij IDEA中运行时,这些taglibs不能正确启动。 如果我在Tomcat中部署war或者像java -jar web.war这样不使用intellij直接运行,一切都很好,taglibs被加载了。

据我调试时了解,问题是如果使用IntellijIdea的spring boot启动器,则在TaglibFactory类中找不到WEB-INF文件夹。在其中,通过

引起的任何调用
servletContext.getResourcePaths (path);

路径以“/WEB-INF”开头的位置,始终返回 null,因此无法将任何内容加载到 tldLocations。 Intellij 有 4 种类型的缩短命令行:无、JAR 清单、类路径文件和 user-local-default: none。 我试图全部使用它们,但一切都还保留着。 例如,JAR 清单生成命令如下:

/usr/lib/jvm/java-8-oracle/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:40359,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -javaagent:/home/birthright/IDEA/lib/rt/debugger-agent.jar=file:/tmp/capture128.props -Dfile.encoding=UTF-8 -classpath /tmp/classpath1030746450.jar com.birthright.WebMain

这个问题能解决吗?

【问题讨论】:

  • 我猜这和直接从jar 运行Spring Boot 应用程序是一样的。 src/main/webapp 不包含在其中,与构建 war 时不同。因此,当您从 IDE 启动应用程序时,肯定没有任何东西可以从 src/main/webapp 加载任何内容,因为它不在类路径中,其内容也不能通过 ServletContext 作为资源可见。对吗?
  • @ddekany 对。在 TaglibFactory.get(String tagliburi) 方法中,他尝试在 TldLocation explicitMappedTldLocation = getExplicitlyMappedTldLocation(taglibUri); 行中加载 tld 位置,但始终返回 null 并稍后抛出 TaglibGettingException。是的,如果我构建 jar 并通过 java -jar web.jar 启动,我会得到同样的错误,战争一切都很好。
  • Standalone (jar) Spring Boot 允许您将内容放入 src/main/resources/static/(以及更多:spring.io/blog/2013/12/19/…),而不是 src/main/webapp。我认为它还将这些资源公开为ServletContext 资源。但是,那么当你将它部署为战争时它可能不起作用......
  • 另一个有趣的可能性是,如果应用程序检测到您已通过系统属性请求(我的意思是例如),那么它会调整 TomcatEmbeddedServletContainerFactory 以添加 webapp 作为 servlet 上下文资源根。您可以在此处找到添加资源根的示例:github.com/spring-projects/spring-boot/issues/8525。由于它是可选的,它不会干扰战争部署。

标签: java spring spring-boot intellij-idea freemarker


【解决方案1】:

WAR 部署在许多方面与通过 IDE 中的 Spring Boot 运行配置运行应用程序不同。您可以尝试复制 Gradle/Maven 在运行配置中所做的所有打包,例如通过 IntelliJ 的工件。

【讨论】:

    【解决方案2】:

    当您直接从 IDE 启动应用程序时,不确定您的 TLD 文件到底在哪里,但肯定它们不在 JSP 规范指定的位置之一,并且默认情况下 TaglibFactory 遵循规范。但是您可以通过调用setMetaInfTldSourcessetClasspathTlds 来配置它。所以你必须调整Spring使用的TaglibFactory;请参阅Custom EL functions won't be loaded because no ObjectWarpper was specified 中的示例。

    顺便说一句,FreemarkerServlet 所做的(Spring AFAIR 不使用)是您可以设置 org.freemarker.jsp.classpathTldsorg.freemarker.jsp.metaInfTldSources Java 系统属性来执行此操作,这样您就可以纯粹在 IDE 中进行这些调整启动配置(例如,您将 -Dorg.freemarker.jsp.metaInfTldSources=classpath 添加到 Java 选项中)。您可以轻松地重新实现这个想法。

    【讨论】:

    • 不清楚我应该在 setMetaInfTldSources 方法中指定什么来加载我在帖子中指定的自定义 tld 和其他 spring。
    • 我匆忙阅读了您的原始问题......请参阅我的评论。您可以使用 IntelliJ 将 webapp 添加到运行时类路径吗?那么classpathTlds 可以提供帮助。
    猜你喜欢
    • 2021-07-18
    • 2022-08-03
    • 2016-12-28
    • 2017-01-20
    • 1970-01-01
    • 2015-10-30
    • 2019-01-04
    • 2016-03-29
    • 2016-01-25
    相关资源
    最近更新 更多