Search code examples
spring-bootstruts2embedded-tomcat-8

Spring Boot + Tomcat Embedded + Struts 2 - JSP are not invoked


I'm trying to migrate a web application with spring boot and struts 2 (struts.xml file) from Jboss 7.1.1 to tomcat embedded.

Now, my configurations is like that:

Application.java

@SpringBootApplication()
@ServletComponentScan()
public class Application extends JbossDefaultPropertiesInitializer {

    public static void main(String[] args) {
        configureApplication(new SpringApplicationBuilder()).run(args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        setRegisterErrorPageFilter(false);
        return configureApplication(builder);
    }

    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
        builder.initializers(new DefaultPropertiesInitializer());
        return builder.sources(Application.class);
    }
}

pom.xml

<resources>
    <resource>
        <directory>src/main/webapp</directory>
        <targetPath>/static</targetPath>
        <excludes>
            <exclude>**/*.jsp</exclude>
        </excludes>
    </resource>
    <resource>
        <directory>src/main/webapp</directory>
        <targetPath>/WEB-INF/jsp</targetPath>
        <includes>
            <include>**/*.jsp</include>
        </includes>
    </resource>
</resources>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
</plugin>

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.5.6.RELEASE</version>
    <configuration>
        <mainClass>com.myapplication.Application</mainClass>
        <executable>true</executable>
        <layout>WAR</layout>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<dependency>
    <groupId>org.apache.struts</groupId>
    <artifactId>struts2-spring-plugin</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

struts.devMode=true

Every filter, servlet and listener were migrated from web.xml to @WebFilter, @WebListener and @WebServlets.

Everything seems to works fine when I start tomcat and I'm able to get some static resources like html, css and js.

When I call some struts page like http://localhost:8080/myapplication/login.go, everything happens fine, the filters and servlets are called, my action is called but when the action returns "success" to call the "/myapplication/jsp/login.jsp" It doesn't rendered. The jsp file is not called or there is some error and I don't get nothing in console.

The log before my action call the jsp page:

2017-11-28 13:03:19.881  INFO 7376 --- [nio-8080-exec-3] c.o.x.c.p.XmlConfigurationProvider       : Parsing configuration file [struts-default.xml]
2017-11-28 13:03:19.933  WARN 7376 --- [nio-8080-exec-3] com.opensymphony.xwork2.util.DomHelper   : Local DTD is missing for publicID: -//Apache Software Foundation//DTD Struts Configuration 2.5//EN - defined mappings: {-//Apache Struts//XWork 1.1.1//EN=xwork-1.1.1.dtd, -//Apache Software Foundation//DTD Struts Configuration 2.0//EN=struts-2.0.dtd, -//Apache Struts//XWork 1.0//EN=xwork-1.0.dtd, -//Apache Software Foundation//DTD Struts Configuration 2.1//EN=struts-2.1.dtd, -//Apache Struts//XWork 1.1//EN=xwork-1.1.dtd, -//Apache Struts//XWork 2.1.3//EN=xwork-2.1.3.dtd, -//Apache Software Foundation//DTD Struts Configuration 2.3//EN=struts-2.3.dtd, -//Apache Struts//XWork 2.0//EN=xwork-2.0.dtd, -//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN=struts-2.1.7.dtd, -//Apache Struts//XWork 2.1//EN=xwork-2.1.dtd, -//Apache Struts//XWork 2.3//EN=xwork-2.3.dtd}
2017-11-28 13:03:20.220  INFO 7376 --- [nio-8080-exec-3] c.o.x.c.p.XmlConfigurationProvider       : Parsing configuration file [struts-plugin.xml]
2017-11-28 13:03:20.301  INFO 7376 --- [nio-8080-exec-3] c.o.x.c.p.XmlConfigurationProvider       : Parsing configuration file [struts.xml]
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (spring) for (com.opensymphony.xwork2.ObjectFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.ActionFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.ResultFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.ConverterFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.InterceptorFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.ValidatorFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.factory.UnknownHandlerFactory)
2017-11-28 13:03:20.304  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.FileManagerFactory)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.XWorkConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.CollectionConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.ArrayConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.DateConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.NumberConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.StringConverter)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionFileProcessor)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor)
2017-11-28 13:03:20.305  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.TypeConverterCreator)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.TypeConverterHolder)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.TextProvider)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.LocaleProvider)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.ActionProxyFactory)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ObjectTypeDeterminer)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.dispatcher.mapper.ActionMapper)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (jakarta) for (org.apache.struts2.dispatcher.multipart.MultiPartRequest)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.views.freemarker.FreemarkerManager)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.views.velocity.VelocityManager)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.components.UrlRenderer)
2017-11-28 13:03:20.306  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.validator.ActionValidatorManager)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.util.ValueStackFactory)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.util.reflection.ReflectionProvider)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.util.reflection.ReflectionContextFactory)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.util.PatternMatcher)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.util.ContentTypeMatcher)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.dispatcher.StaticContentLoader)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.UnknownHandlerManager)
2017-11-28 13:03:20.307  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.views.util.UrlHelper)
2017-11-28 13:03:20.308  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.util.TextParser)
2017-11-28 13:03:20.308  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (org.apache.struts2.dispatcher.DispatcherErrorHandler)
2017-11-28 13:03:20.308  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.security.ExcludedPatternsChecker)
2017-11-28 13:03:20.308  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.AbstractBeanSelectionProvider    : Choosing bean (struts) for (com.opensymphony.xwork2.security.AcceptedPatternsChecker)
2017-11-28 13:03:20.310  INFO 7376 --- [nio-8080-exec-3] o.a.s.c.DefaultBeanSelectionProvider     : Loading global messages from [messageResources]
2017-11-28 13:03:20.699  INFO 7376 --- [nio-8080-exec-3] c.o.xwork2.spring.SpringObjectFactory    : Setting autowire strategy to name
2017-11-28 13:03:21.764 ERROR 7376 --- [nio-8080-exec-3] c.o.x.interceptor.ParametersInterceptor  : Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'cp' on 'class com.myapplication.account.actions.LoginNavigationAction: Error setting expression 'cp' with value ['false', ]
2017-11-28 13:03:21.769 ERROR 7376 --- [nio-8080-exec-3] c.o.x.interceptor.ParametersInterceptor  : Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'forwardURL' on 'class com.myapplication.account.actions.LoginNavigationAction: Error setting expression 'forwardURL' with value ['/myapplication/html/login.html', ]
2017-11-28 13:03:21.844  INFO 7376 --- [nio-8080-exec-3] c.m.account.actions.LoginPageAction    : ========================= Result from LoginPageAction: success

UPDATE

When I try java -jar myapplication.war, I could access my static pages but I've got another error accessing struts pages:

2017-11-29 08:55:41.536  WARN 7968 --- [nio-8080-exec-8] c.o.xwork2.util.fs.JarEntryRevision      : Could not create JarEntryRevision for [jar:file:/C:/workspaces/workspace/dev/myapplication/target/myapplication-war-0.0.0.war]!

java.lang.NullPointerException: null
        at com.opensymphony.xwork2.util.fs.JarEntryRevision.build(JarEntryRevision.java:52)
        at com.opensymphony.xwork2.util.fs.DefaultFileManager.monitorFile(DefaultFileManager.java:97)
        at com.opensymphony.xwork2.util.fs.DefaultFileManager.loadFile(DefaultFileManager.java:74)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadConfigurationFiles(XmlConfigurationProvider.java:1015)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadDocuments(XmlConfigurationProvider.java:167)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.init(XmlConfigurationProvider.java:134)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:239)
        ....
2017-11-29 08:55:41.636  WARN 7968 --- [nio-8080-exec-8] c.o.xwork2.util.fs.JarEntryRevision      : Could not create JarEntryRevision for [jar:war:file:/C:/workspaces/workspace/dev/myapplication/target/myapplication-war-0.0.0.war*/WEB-INF/lib/struts2-core-2.3.34.jar]!

java.io.FileNotFoundException: war:file:\C:\workspaces\workspace\dev\myapplication\target\myapplication-war-0.0.0.war*\WEB-INF\lib\struts2-core-2.3.34.jar (The filename, directory name, or volume label syntax is incorrect)
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(ZipFile.java:219)
        at java.util.zip.ZipFile.<init>(ZipFile.java:149)
        at java.util.jar.JarFile.<init>(JarFile.java:166)
        at java.util.jar.JarFile.<init>(JarFile.java:130)
        at com.opensymphony.xwork2.util.fs.JarEntryRevision.build(JarEntryRevision.java:50)
        ...
2017-11-29 08:55:41.690  INFO 7968 --- [nio-8080-exec-8] c.o.x.c.p.XmlConfigurationProvider       : Parsing configuration file [struts-default.xml]
2017-11-29 08:55:41.802 ERROR 7968 --- [nio-8080-exec-8] o.apache.struts2.dispatcher.Dispatcher   : Dispatcher initialization failed

com.opensymphony.xwork2.config.ConfigurationException: Unable to load configuration.
        at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:70)
        at org.apache.struts2.dispatcher.Dispatcher.getContainer(Dispatcher.java:978)
        at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:446)
        at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:490)
        at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
        ...
Caused by: com.opensymphony.xwork2.config.ConfigurationException: Unable to load bean: type: class:com.opensymphony.xwork2.ObjectFactory
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:247)
        at org.apache.struts2.config.StrutsXmlConfigurationProvider.register(StrutsXmlConfigurationProvider.java:102)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:240)
        at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
        ... 65 common frames omitted
Caused by: com.opensymphony.xwork2.config.ConfigurationException: Bean type class com.opensymphony.xwork2.ObjectFactory with the name struts has already been loaded by bean - jar:file:/C:/workspaces/workspace/dev/myapplication/target/myapplication-war-0.0.0.war!/WEB-INF/lib/struts2-core-2.3.34.jar!/struts-default.xml:65:72
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:231)
        ... 68 common frames omitted

Please, any idea?


Solution

  • I could fix it after three days of research.

    Before start to migrate my legacy application I created some applications to test Spring Boot, Struts 2 and Tomcat and all of them worked fine. The problem was my legacy system has its own parent. I wasn't using the following spring boot parent.

    I can't use it:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>
    

    So, as per Spring Boot documentation:

    "Not everyone likes inheriting from the spring-boot-starter-parent POM. You may have your own corporate standard parent that you need to use or you may prefer to explicitly declare all your Maven configuration.

    If you do not want to use the spring-boot-starter-parent, you can still keep the benefit of the dependency management (but not the plugin management) by using a scope=import dependency, as follows:"

    <dependencyManagement>
            <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.0.BUILD-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    Now, the application is able to show every jsp/struts page.

    NOTE: I didn't need to put any special configuration like ViewResolver or my own DispatcherServlet. I just added the above dependency and copied every static and jsp page to "META-INF/resources" as per @Sébastien PRAT's sugestion. Other folder options are "resources/", "static/" and "public/".

    UPDATE

    This following error occurs because the embedded tomcat container provides two different paths to xwork api of the same file (struts-default.xml), then xwork api fails because try to initialize the same bean twice. So, you should change struts dependencies scope from compile to provided. Spring boot maven plugin will copy your struts dependencies under the web-inf/lib-provided folder. It will work fine as a executable war file but if you need both, executable and deployeable, you should create different profiles to generate different files.

    com.opensymphony.xwork2.config.ConfigurationException: Unable to load configuration.
            at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:70)
            at org.apache.struts2.dispatcher.Dispatcher.getContainer(Dispatcher.java:978)
            at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:446)
            at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:490)
            at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
            ...
    Caused by: com.opensymphony.xwork2.config.ConfigurationException: Unable to load bean: type: class:com.opensymphony.xwork2.ObjectFactory
            at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:247)
            at org.apache.struts2.config.StrutsXmlConfigurationProvider.register(StrutsXmlConfigurationProvider.java:102)
            at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:240)
            at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
            ... 65 common frames omitted
    Caused by: com.opensymphony.xwork2.config.ConfigurationException: Bean type class com.opensymphony.xwork2.ObjectFactory with the name struts has already been loaded by bean - jar:file:/C:/workspaces/workspace/dev/myapplication/target/myapplication-war-0.0.0.war!/WEB-INF/lib/struts2-core-2.3.34.jar!/struts-default.xml:65:72
            at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:231)
            ... 68 common frames omitted
    

    Struts 2 Scope:

    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-spring-plugin</artifactId>
        <version>2.3.34</version>
        <scope>provided</scope>
        <exclusions>
            <exclusion>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.apache.struts.xwork</groupId>
                <artifactId>xwork-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    Now, I can generate a executable war and run with java -jar myapplication.war.

    I hope It helps.