4

My web App works fine on Eclipse Photon STS, java 8 and Spring Boot 2.02 with the embeded tomcat using endpoint:

http://localhost:8081/DataViewer/tspsPatentSearch

But when I compile the code into DataViewer.war file (using mvn package) and run it on Tomcat 9 on Linux with endpoint:

http://myserver.com:8081/DataViewer/tspsPatentSearch

I get the infamous:

Whitelabel Error Page
There was an unexpected error (type=Not Found, status=404).
/DataViewer/tspsPatentSearch

My pom.xml file is:

`<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>
<groupId>com.clarivate</groupId>
<artifactId>dataviewer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<name>dataviewer</name>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.2.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.8</java.version>
    <start-class>com.clarivate.dataviewer.DvMain</start-class>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

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

    <!-- DS may need to remove for tomcat installation -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
            </exclusion>
        </exclusions>
    </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>
    </dependency>

    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>11.2.0.1.0</version>
    </dependency>


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>

</dependencies>

   <!-- Required to find ojdbc6, because Oracle don't make it available to maven-->
    <repositories>
        <repository>
          <id>codelds</id>
          <url>https://code.lds.org/nexus/content/groups/main-repo</url>
        </repository>
      </repositories>

<build>
    <finalName>DataViewer</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId> 
            <configuration>
                <mainClass>com.clarivate.dataviewer.DvMain</mainClass>
            </configuration>    
        </plugin>
    </plugins>
</build>


<description>TSPS data viewer</description>

In application.properties I have:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
server.servlet.path=/DataViewer 

My main class is:

package com.clarivate.dataviewer;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication

public class DvMain extends SpringBootServletInitializer {

    static Logger logger = LogManager.getRootLogger();

    public static void main(String[] args) {
        logger.debug("DS1A in main()");
        SpringApplication.run(DvMain.class, args);
        logger.info("DS1C finished.");
    }


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

My MainController.java has:

@GetMapping("/tspsPatentSearch")
public String tspsPatentSearch(Model model) {
     model.addAttribute("tspsPatent", new TspsPatent());

     return "tspsPatentSearch";                 
}

The war file unpacks fine and there are no errors. In catalina.out we have:

2018-10-04 12:09:09.954  INFO 12950 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/tspsPatentSearch],methods=[POST]}" onto public java.lang.String com.clarivate.dataviewer.controller.MainController.tspsPatentSearch(com.clarivate.dataviewer.model.TspsPatent,org.springframework.ui.Model,org.springframework.validation.BindingResult)

and no errors. I've tried this ie my package structure is correct and this ie my jsp's are in the correct location (data_viewer\src\main\webapp\WEB-INF\jsp) and i'm now running short of ideas. Any help much appreciated

Edit: If I copy tspsPatentSearch.jsp into the war file top directory then tomcat finds it. So it looks like tomcat is ignoring:

spring.mvc.view.prefix=/WEB-INF/jsp/

or not finding application.properties at all.

DS.
  • 604
  • 2
  • 6
  • 24
  • Have you tried http://myserver.com:8081/dataviewer/tspsPatentSearch? – Amila Oct 03 '18 at 13:42
  • try `http://localhost:8081/tspsPatentSearch` – benjamin c Oct 03 '18 at 13:53
  • Thanks , I've just tried these 2 endpoints and I get the same 404 error – DS. Oct 03 '18 at 13:56
  • Can you please post full DvMain class including all imports – kj007 Oct 03 '18 at 14:09
  • @kj007 i've updated my original post – DS. Oct 03 '18 at 14:25
  • @benjamin I presume you mean myserver.com:8081/tspsPatentSearch . localhost is on my pc, the web app is running on linux server called myserver.com. Anyway I tried both and no luck – DS. Oct 04 '18 at 10:37
  • might be a noobie check, but just to make sure, have you verified that the tomcat server you've deployed to runs on port 8081? – ConMan Oct 09 '18 at 12:45
  • @ConMan Yes. We had an old application that ran on 8081, I removed that and used the port for the DataViewer. If I reinstate the old application it still works. – DS. Oct 09 '18 at 12:52

2 Answers2

2

Add this to your application.properties:

server.servlet.contextPath=/

I've taken your sample code and, assuming you annotated your MainController simply as @Controller, put a deployment together. I changed a few things around, but I believe this was the bit that did it. I haven't been able to find any references explaining why it might be required by Tomcat, but I intend to keep looking. I'll update you if I find anything.

Edit:

I noticed some duplicate logging in Spring 2.0.2 related to this issue: https://github.com/spring-projects/spring-boot/issues/13470

The problem appeared fixed in 2.0.4 therefore I upgraded.

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

Additionally, I removed the server.servlet.contextPath=/ entry and tada I still can reach the Hello World jsp I set up. If upgrading is possible for you, maybe you could try that before adding something to application.properties which could be considered duplicated functionality. At least I can promise you a better logging experience.

Edit #2:

No smoking gun, so far, but these (from 2.0.4) could be related:

Provide a consistent way to discover the primary DispatcherServlet's path

Dispatcher servlets with a custom servlet name are not found by the mappings endpoint

Nothing looked likely on a surface scan of 2.0.3. I'm going to give it a rest for now and give you a chance to try some stuff. Good luck!

Edit #3:

I'm sorry to continue suggesting you switch environment stuff around, but one difference I noted between what I tested and what you're working with is that you seem to be using Tomcat-9.0.0.M20 where as I was testing with 9.0.12.

Whether you want to upgrade or not, a few things to note and/or do:

1) Update your question with what you've got now if it's different than before. Include the server.servlet.contextPath=/ in your application.properties just so anyone else looking can see what you've done.

2) The exclusion you have for spring-boot-starter-tomcat under spring-boot-starter-web doesn't appear to do anything - you can verify by comparing the output from running mvn dependency:tree before and after removal.

3) I'm not sure that your spring-web dependency is needed either, as that's brought in by default under the spring-boot-starter.

4) Now to your output. Spring Boot is coming up (note the banner) and your classes are being found and acted upon.

catalina.out.DEBUG also in your DS.log starting ~ 08:35:38.162

2018-10-12 09:30:17.322 DEBUG 55745 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/data/apps/tomcat/apache-tomcat-9.0.0.M20/webapps/DataViewer/WEB-INF/classes/com/clarivate/dataviewer/controller/MainController.class]
2018-10-12 09:30:17.328 DEBUG 55745 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/data/apps/tomcat/apache-tomcat-9.0.0.M20/webapps/DataViewer/WEB-INF/classes/com/clarivate/dataviewer/database/ReadFromDb.class]
2018-10-12 09:30:17.356 DEBUG 55745 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/data/apps/tomcat/apache-tomcat-9.0.0.M20/webapps/DataViewer/WEB-INF/classes/com/clarivate/dataviewer/service/FileFuncs.class]
2018-10-12 09:30:17.357 DEBUG 55745 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/data/apps/tomcat/apache-tomcat-9.0.0.M20/webapps/DataViewer/WEB-INF/classes/com/clarivate/dataviewer/service/StringFuncs.class]
...
2018-10-12 09:30:19.417  INFO 55745 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/tspsPatentSearch],methods=[POST]}" onto public java.lang.String com.clarivate.dataviewer.controller.MainController.tspsPatentSearch(com.clarivate.dataviewer.model.TspsPatent,org.springframework.ui.Model,org.springframework.validation.BindingResult)
2018-10-12 09:30:19.417  INFO 55745 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/tspsPatentSearch],methods=[GET]}" onto public java.lang.String com.clarivate.dataviewer.controller.MainController.tspsPatentSearch(org.springframework.ui.Model)
...
2018-10-12 09:30:19.769  INFO 55745 --- [           main] com.clarivate.dataviewer.DvMain          : Started DvMain in 3.125 seconds (JVM running for 5.845)

And I do indeed note the mapping to /error that's returned for your request at 09:32:11.

I find this strange:

2018-10-12 09:32:11.758 DEBUG 55745 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/DataViewer/DataViewer/error]

And it's different in DS.log:

2018-10-12 08:36:56.136 DEBUG 6992 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/DataViewer /error]

Specifically /DataViewer/DataViewer/error - have you tried requesting http://localhost:8081/DataViewer/DataViewer/tspsPatentSearch

In general this appears as though everything is coming up but there is a misconfiguration somewhere that isn't allowing a request to map to the handler.

Jon Sampson
  • 1,473
  • 1
  • 21
  • 31
  • Thanks for the suggestion, im looking into it. Problem I have is that when I change the spring-boot-starter-parent version to 2.0.4 I get 2 sets of spring files, 2.0.2 AND 2.0.4 in my war file (but only the 2.0.4 in my build libraries). I've tried the Maven -> Update Project and various other stuff but so far no luck. Hopefully i'll fix it and get back to you. – DS. Oct 11 '18 at 14:18
  • I fixed the double spring files, but now http://localhost:8081/DataViewer/tspsPatentSearch (on Eclipse) which works fine with spring-boot-starter-parent 2.0.2, returns 404 with spring-boot-starter-parent 2.0.4. When I switch back to 2.0.2 it again works (on eclipse only) – DS. Oct 11 '18 at 14:54
  • @DS. I didn't do any testing last night within Eclipse so I've got nothing for you there. I didn't find a satisfactory way to introspect the process to see what's been mapped where. If it helps and if you haven't already done so, you can add `logging.level.root=DEBUG` to `application.properties` and get a flood of output which may contain info about JSP compilation (or absence thereof). I'm not positive about that syntax - I don't have my test bed from last night here with me. – Jon Sampson Oct 11 '18 at 15:05
  • I've turned debug on. The resulting eclipse log file is here: https://drive.google.com/file/d/12KjPkSZkIsmXvubyV1AB2koX5tLfw9hU/view?usp=sharing . The bit before "DS1C" is when spring starts up, the bit after DS1C is when you try to hit endpoint http://localhost:8081/DataViewer/tspsPatentSearch. The file is 150K lines long! – DS. Oct 12 '18 at 07:44
  • Forget spring boot 2.0.4, it doesn't work. I tried 2.0.3, why not, and thats fine on Eclipse, but still not working on Tomcat 9. I've downloaded catalina.out.DEBUG to : https://drive.google.com/open?id=1UW75qWc025rLIdY2BuQqCJ8jBZwlc4Vi and catalina.out.INFO to https://drive.google.com/open?id=1kKwy8vMV8ZDNy2Wj6IjvxVKwuKcqiVrh There is no "DS1C" in either, so my main class is not found. In catalina.out.DEBUG everything after 9:32 is from trying to hit http://myserver.com:8081/DataViewer/tspsPatentSearch – DS. Oct 12 '18 at 10:18
  • 1
    myserver.com:8081/DataViewer/DataViewer/tspsPatentSearch works :), not sure why yet. Thanks a lot. – DS. Oct 12 '18 at 14:23
  • @DS. I saw you updated your question! This `server.servlet.path=/DataViewer` is why you've got nested mappings. Change `/DataViewer` to `/` and you're golden. – Jon Sampson Oct 12 '18 at 14:34
  • @jon_sampson when I do that it doesn't work on Eclipse. The first "DataViewer" in the myserver.com:8081/DataViewer/DataViewer/tspsPatentSearch end point comes from the war file name. If I change the war file name to ROOT.war then the war name is ignored and myserver.com:8081/DataViewer/tspsPatentSearch works on Eclipse AND on the external tomcat. This however is not ideal as we have multiple war files on the same tomcat server. – DS. Oct 12 '18 at 15:13
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/181770/discussion-between-jon-sampson-and-ds). – Jon Sampson Oct 12 '18 at 16:33
1

To confirm. Tomcat adds the war file name to the end point, so if we create DataViewerX.war and set :

server.servlet.path=/DataViewer

then the end point when running on an external tomcat is:

myServer.com/DataViewerX/DataViewer/tspsPatentSearch 

but when we run on Eclispe, using the source code, then the end point is:

http://localhost:8081/DataViewer/tspsPatentSearch

which is a bit annoying but not a major problem. A way round this is to call the war file ROOT.war, then tomcat ignores the war file name and the 2 end points are the same, but I have multiple war files in the webapps dir so this solution isn't acceptable for me. If anyone know's a way to allow the 2 end points to be the same then please say so, but it's not that important.

DS.
  • 604
  • 2
  • 6
  • 24