Spring boot war not working on EAP 6

2019-08-04 07:08发布

问题:

I have created a small REST-based application using spring boot. The application is deployed on EAP 6(JBoss) as a war package. As EAP 6 is based on Java 1.7 I have configured that in my maven pom to compile and use Java 1.7 version. When I am deploying the application I can see in the server logs that the controller is getting registered but when I am hitting it I am getting 404. Also I JBoss is not picking up my context root configuration but taking the application name as the context root. I am tested all the possible endpoints but everything is giving 404. Can someone suggest me something which can help me to proceed forward?

POM file:

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.7</java.version>
</properties>

....

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Application configuration

package com.org.orderhistory.v2.orderhistory.v2;
import ...
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(Application.class);
}

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

}

package com.org.orderhistory.v2.orderhistory.v2.controllers;

import ...

@RestController
@RequestMapping(value="/myorder/weborders")
public class WebOrderControllers {

@RequestMapping(value="/{webUserId}",method = RequestMethod.GET, produces = "application/json")
public List<WebOrder> getWebOrdersForUser(@PathVariable Long webUserId) {

JBoss Logs

2017-10-09 02:24:29,744 [ServerService Thread Pool -- 594] INFO  [org.springframework.boot.web.servlet.FilterRegistrationBean] Mapping filter: 'requestContextFilter' to: [/*]
2017-10-09 02:24:30,368 [ServerService Thread Pool -- 594] INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter] Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5a46b924: startup date [Mon Oct 09 02:24:27 EDT 2017]; root of context hierarchy
2017-10-09 02:24:30,451 [ServerService Thread Pool -- 594] INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] Mapped "{[/org/weborders/{webUserId}],methods=[GET],produces=[application/json]}" onto public java.util.List<com.org.www.order.model.WebOrder> com.org.orderhistory.v2.orderhistory.v2.controllers.WebOrderControllers.getWebOrdersForUser(java.lang.Long)

回答1:

Exact same issue here. Try this:

1. In pom.xml:

<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <scope>provided</scope>
</dependency>

2. Add a class implements WebApplicationInitializer:

@Configuration
public class WebApplicationInitializerImpl implements WebApplicationInitializer{

    @Override 
    public void onStartup(ServletContext container) throws ServletException {
        WebApplicationContext context = getContext();

        Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(context));
        registration.setLoadOnStartup(1);
        registration.addMapping("/*");
    } 

    private WebApplicationContext getContext() { 
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation(ApplicationMain.class.getName());
        return context;
    } 

}

3. Remember to extend SpringBootServletInitializer by your application:

@SpringBootApplication
public class ApplicationMain extends SpringBootServletInitializer{

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
      return builder.sources(ApplicationMain.class);
   }

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

If it works, then the problem is related to dispatcherServlet.
When using Spring boot, a dispatcherServlet should have been configured automatically. (That is a part of auto Configuration)
And this situation seems to be the issue of jboss, according to Redhat's explanation:

Because JBoss enforces the servlet specification's requirements about not registering conflicting mappings even for it's own server-added DefaultServlet.

To check if your dispatcherServlet is registered as expected, try this:

[standalone@localhost:9999 /] /deployment=spring-boot-application.war/subsystem=web:read-resource(recursive=true)

Not working:

{
    "outcome" => "success",
    "result" => {
        "context-root" => "/spring-boot-application",
        "servlet" => undefined,
        "virtual-host" => "default-host"
    }
}

Working:

{
    "outcome" => "success",
    "result" => {
        "context-root" => "/spring-boot-application",
        "virtual-host" => "default-host",
        "servlet" => {"appServlet" => {
            "servlet-class" => "org.springframework.web.servlet.DispatcherServlet",
            "servlet-name" => "appServlet"
        }}
    }
}

Hope it solves your problem.

Reference:
https://access.redhat.com/solutions/1211203
https://blog.csdn.net/u011160656/article/details/78809239