Spring boot web app not running on tomcat 9 - java

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.

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.

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.

Related

Integrate New Relic with Spring Boot using Micrometer

I am trying to integrate a simple Spring Boot Application with New Relic using Micrometer.
Here are the configurations details:-
application.properties
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.metrics.export.newrelic.enabled=true
management.metrics.export.newrelic.api-key:MY_API_KEY // Have added the API key here
management.metrics.export.newrelic.account-id: MY_ACCOUNT_ID // Have added the account id here
logging.level.io.micrometer.newrelic=TRACE
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>springboot.micrometer.demo</groupId>
<artifactId>micrometer-new-relic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>micrometer-new-relic</name>
<description>Demo project for actuator integration with new relic using micrometer</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-new-relic</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
I was able to integrate Prometheus with this application using micrometer-registry-prometheus dependency. I had set up Prometheus to run in a Docker container in my local system. I used the following set of commands-
docker pull prom/prometheus
docker run -p 9090:9090 -v D:/Workspaces/STS/server_sent_events_blog/micrometer-new-relic/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
prometheus.yml
global:
scrape_interval: 4s
evaluation_interval: 4s
scrape_configs:
- job_name: 'spring_micrometer'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- targets: ['my_ip_address:8080']
When I navigated to localhost:9090/targets I can see that Prometheus dashboard shows my application details and that it can scrape data from it. And in the dashboard, I can see my custom metrics as well along with other metrics.
So my question is I want to achieve the same thing using New Relic. I have added the micrometer-registry-new-relic pom dependency. I have shared the application.properties file as well. I can see logs in my console saying it is sending data to New Relic-
2021-10-24 12:42:04.889 DEBUG 2672 --- [trics-publisher] i.m.n.NewRelicInsightsApiClientProvider : successfully sent 58 metrics to New Relic.
Questions:
What are the next steps?
Do I need a local running server of New Relic as I did for Prometheus?
Where can I visualize this data? I have an account in New Relic, I see nothing there
https://discuss.newrelic.com/t/integrate-spring-boot-actuator-with-new-relic/126732
As per the above link, Spring Bootctuator pushes metric as an event type “SpringBootSample”.
With NRQL query we can confirm this-
FROM SpringBootSample SELECT max(value) TIMESERIES 1 minute WHERE metricName = 'jvmMemoryCommitted'
What does the result of this query indicate? Is it a metric related to my application?
Here is the GitHub link to the demo that I have shared here.
I did not find any clear instructions on this, there are some examples out there but that uses Java agent.
Any kind of help will be highly appreciated.
From what I have learned so far.
There are 3 ways to integrate New Relic with a Spring Boot Application-
Using the Java Agent provided by New Relic
Using New Relic's Micrometer Dependency
Micormeter's New Relic Dependency
1. Configuration using Java Agent Provided By New Relic
Download the Java Agent from this URL- https://docs.newrelic.com/docs/release-notes/agent-release-notes/java-release-notes/
Extract it.
Modify the newrelic.yml file inside the extracted folder to inlcude your
license_key:
app_name:
Create a SpringBoot application with some REST endpoints.
Build the application.
Navigate to the root path where you have extracted the newrelic java agent.
Enter this command
java -javagent:<path to your new relic jar>\newrelic.jar -jar <path to your application jar>\<you rapplication jar name>.jar
To view the application metrics-
Log in to your New Relic account.
Go to Explorer Tab.
Click on Services-APM
You can see the name of your application(which you had mentioned in the newrelic.yml file) listed there.
Click on the application name.
The dashboard should look something like this.
Using New Relic's Micrometer Dependency is the preferred way to do it.
2. Configuration using New Relic's Micrometer Dependency
Add this dependency
<dependency>
<groupId>com.newrelic.telemetry</groupId>
<artifactId>micrometer-registry-new-relic</artifactId>
<version>0.7.0</version>
</dependency>
Modify the MicrometerConfig.java class to add your API Key and Application name.
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.newrelic.telemetry.Attributes;
import com.newrelic.telemetry.micrometer.NewRelicRegistry;
import com.newrelic.telemetry.micrometer.NewRelicRegistryConfig;
import java.time.Duration;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.util.NamedThreadFactory;
#Configuration
#AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
#AutoConfigureAfter(MetricsAutoConfiguration.class)
#ConditionalOnClass(NewRelicRegistry.class)
public class MicrometerConfig {
#Bean
public NewRelicRegistryConfig newRelicConfig() {
return new NewRelicRegistryConfig() {
#Override
public String get(String key) {
return null;
}
#Override
public String apiKey() {
return "your_api_key"; // for production purposes take it from config file
}
#Override
public Duration step() {
return Duration.ofSeconds(5);
}
#Override
public String serviceName() {
return "your_service_name"; // take it from config file
}
};
}
#Bean
public NewRelicRegistry newRelicMeterRegistry(NewRelicRegistryConfig config) throws UnknownHostException {
NewRelicRegistry newRelicRegistry = NewRelicRegistry.builder(config)
.commonAttributes(new Attributes().put("host", InetAddress.getLocalHost().getHostName())).build();
newRelicRegistry.config().meterFilter(MeterFilter.ignoreTags("plz_ignore_me"));
newRelicRegistry.config().meterFilter(MeterFilter.denyNameStartsWith("jvm.threads"));
newRelicRegistry.start(new NamedThreadFactory("newrelic.micrometer.registry"));
return newRelicRegistry;
}
}
Run the application.
To view the Application metrics-
Log in to your New Relic account.
Go to Explorer Tab.
Click on Services-OpenTelemetry
You can see the name of your application(which you had mentioned in the MicrometerConfig file) listed there.
Click on the application name.
The dashboard should look something like this.
What are the next steps?
It seems you are done and successfully shipped metrics to NewRelic.
Do I need a local running server of New Relic as I did for Prometheus?
No, NewRelic is a SaaS offering.
Where can I visualize this data? I have an account in New Relic, I see nothing there
It seems you already found it (screenshot).
What does the result of this query indicate? Is it a metric related to my application?
From the screenshot, I can't tell if it is your application but this seems to be the jvm.memory.committed metric pushed by a Spring Boot app (so likely).
In order to see if this is your app or not, you can add common tags which can tell the name of the app and some kind of an instance ID (or hostname?) in case you have multiple instances from the same app, see:
Spring Boot Docs (I would do this)
Micrometer Docs (do this if you don't use Spring Boot or want to do something tricky)
Real-World Example

JSP in Spring Boot application yields 404 Error no matter what I do

I'll start off by saying I've looked at and tried the solutions in every question regarding this that I can find. The biggest problem is that most of these solutions are very old, and Spring Boot has changed a lot in the last several years. To be clear, I've tried this, this, this, this, and more. I've also read numerous tutorials. Nothing works.
I have a brand new Spring Boot application and I'm trying to get JSP rendering working with it. These are my dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>[2.8.0,3)</version>
</dependency>
<dependency>
<groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId>
<version>[2.7,3)</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>[8.0.21,9)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>[2.3.2,)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>[9.0.38,)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
My project is laid out as follows:
- source
- production
- java
- [my source code packages]
- resources
- WEB-APP
- jsp
- initialization
- begin.jsp
- [my resource packages]
- test
- java
- resources
"WEB-APP/jsp" is just the latest iteration I've tried. I've tried "WEB-INF/jsp", "META-INF/jsp", "webapp/jsp", no parent (just "jsp"), etc., all with the same results.
I know the parent directories are a bit non-standard, but it's configured correctly in Maven and I've confirmed it's not the source of my problems:
<build>
<sourceDirectory>source/production/java</sourceDirectory>
<resources>
<resource>
<directory>source/production/resources</directory>
</resource>
</resources>
...
</build>
My Application class is as follows:
#SpringBootApplication(scanBasePackages="com.my.project")
#EnableWebMvc
#EnableJpaRepositories("com.my.project.repository")
#EntityScan("com.my.project.model")
public class Application
{
private static final Logger LOGGER = LogManager.getLogger(Application.class);
public Application()
{
}
#Bean
public ViewResolver viewResolver()
{
LOGGER.info("Constructing InternalResourceViewResolver[JstlView]");
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-APP/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setRedirectContextRelative(true);
resolver.setRedirectHttp10Compatible(false);
return resolver;
}
public static void main(final String[] args)
{
SpringApplication.run(Application.class, args);
}
}
And my Controller:
#Controller
public class InitializationController
{
private static final Logger LOGGER = LogManager.getLogger(InitializationController.class);
#GetMapping("/initialize_application")
public String beginInitialization(ModelMap model)
{
LOGGER.info("Beginning initialization");
...
LOGGER.info("Returning view");
return "initialization/begin";
}
...
}
On startup I see the "Constructing InternalResourceViewResolver" log entry (my view resolver bean is created). When I go to /initialize_application, I get the following error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Oct 18 21:45:26 CDT 2020
There was an unexpected error (type=Not Found, status=404).
Looking in the log again, I see "Beginning initialization" and "Returning view," so I know that the 404 is for my JSP and not my controller. My controller is working.
Other things I've tried:
Initially I did not have #EnableWebMvc on my application. Without it, the log was empty except my log statements. When I added #EnableWebMvc, this is now logged with the 404: No mapping for GET /WEB-APP/jsp/initialization/begin.jsp (or whatever other directory I've tried other than "WEB-APP").
I've tried running this directly on the pure command line with mvn spring-boot:run
I've tried running this in IntelliJ IDEA with a Maven run configuration and command spring-boot:run (same result)
I've tried both <packaging>jar</packaging> and <packaging>war</packaging>, but neither make a difference, because neither a JAR nor a WAR are ever made. Maven runs the application directly out of the target/classes directory instead of creating an artifact.
When I've tried WEB-INF or META-INF instead of WEB-APP or webapp or something else, I've seen a logged warning: Path with "WEB-INF" or "META-INF": [WEB-INF/jsp/initialization/begin.jsp]
I have also confirmed that my JSPs are present in target/classes/WEB-APP/jsp (or whatever other directory I've tried other than "WEB-APP"), so they do exist.
I'm at a loss how to proceed. I'm beginning to think I need to ditch Spring Boot and stick with a traditional boilerplate Spring Web MVC application with a Servlet config and a Tomcat installation, but I was really excited about the "just runs" aspect of Spring Boot. Any help would be appreciated.
UPDATE 1
After reading this Spring documentation about JSP limitations, I now know that I have to use <packaging>war</packaging>, and I'm using that now, but it hasn't made a difference. I'm starting to suspect that the underlying problem here is that maven spring-boot:run doesn't create a WAR and run it, it just builds everything to target/classes and runs it from there.
Also, after finding this old, official Spring boot samples application, I've changed my project structure a little:
- source
- production
- java
- [my source code packages]
- resources
- [my resource packages]
- webapp
- META-INF
- WEB-INF
- jsp
- initialization
- begin.jsp
- test
- java
- resources
Updated my view resolver configuration:
resolver.setPrefix("/jsp/");
resolver.setSuffix(".jsp");
And added this to my POM:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warSourceDirectory>source/production/webapp</warSourceDirectory>
</configuration>
</plugin>
If I run mvn package, my WAR gets created correctly (classes and JSPs all where they should be), but neither mvn spring-boot:run nor mvn package spring-boot:run work—I still get 404 errors resolving my JSPs.
The old Spring Boot sample application linked to above puts the JSPs in WEB-INF/jsp, but I can't do that, because that results in the warning Path with "WEB-INF" or "META-INF": [WEB-INF/jsp/initialization/begin.jsp] (and still 404). What's frustrating is that this sample application doesn't exist anymore, nor does any new variation of it. I can't find any updated version that works with the newest version of Spring Boot. The sample application was deleted in 2.2.x.
Can you try by changing the scope of tomcat-embed-jasper to provided as this dependency is needed to compile JSPs.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>[9.0.38,)</version>
<scope>provided</scope>
</dependency>
Edit:
I looked for various spring-boot + jsp projects over internet. I noticed that they have they also have spring-boot-starter-tomcat with provided scope. Can you try this.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>provided</scope>
</dependency>
References :
https://mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/
https://dzone.com/articles/spring-boot-2-with-jsp-view
Edit-2 :
So this time i created a new springboot project. Did bare minimum setup to get jsp rendered. So basically i followed this tutorial and my project was running fine.
Then I replaced the pom.xml with yours and the i got the same error you mentioned in the question.
Then while doing trial and error i removed the <version>[9.0.38,)</version> from <artifactId>tomcat-embed-jasper</artifactId> and it started working for me.
<!--I have removed version here and it started working for me-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!-- <version>[9.0.38,)</version>-->
<scope>provided</scope>
</dependency>
Although i have different directory structure. But as you mentioned that is not the cause of issue.
I have uploaded the project to github. Feel free to pull it run it locally.
Github
Assuming the following location for your web content (which should be outside the classpath AFAIK) source/production/webapp. Spring Boot will ignore this due to a hardcoded path in DocumentRoot for detection of directories when running from the command-line or IDE (it will work when building a war and running that).
As a workaround you can add a TomcatContextCustomizer as a bean to detect the path and set it as the correct base.
package com.my.project;
#SpringBootApplication
public class Application extends SpringBootServletInitializer
{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(DemoApplication.class);
}
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public TomcatContextCustomizer docBaseCustomizer()
{
return new TomcatContextCustomizer()
{
public void customize(Context context)
{
File root = new File("source/production/webapp");
if (root.exists() && root.isDirectory())
{
context.setDocBase(root.getAbsolutePath());
}
}
}
}
}
Now add the following to your application.properties
spring.mvc.view.prefix=/jsp/
spring.mvc.view.suffix=.jsp
NOTE: The removal of the other annotations can only be done if your #SpringBootApplication annotated class is in the com.my.project package. It will then automatically detect the other classes (like entities and repositories).

Spring boot MVC: RequestMapping isn't recognized in Spring boot 2.1.4

Can someone answer this silly question - How to configure Thymeleaf in Spring boot release 2.1.4?
I have declared the right dependencies:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Also the config:
#SpringBootApplication
#ComponentScan("org.mystuff.myproj")
#EnableAutoConfiguration
public class Init extends SpringBootServletInitializer{
And the controller looks regular:
#Controller
#RequestMapping("/a")
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
#PostConstruct
private void test() {
logger.info("********************************************************************");
}
#RequestMapping("/")
private String index() {
return "index2";
}
I do see that the #Controller bean gets initiated (the "*****..."), but when I try to locate in the logs the "mapped" or atleast something related, the only thing I find is:
2019-04-23 15:55:15 WARN [localhost-startStop-1] JpaBaseConfiguration$JpaWebConfiguration$JpaWebMvcConfiguration.openEntityManagerInViewInterceptor: spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2019-04-23 15:55:16 INFO [localhost-startStop-1] WelcomePageHandlerMapping.<init>: Adding welcome page: ServletContext resource [/index.html]
And I'm failing to find an answer to the "What has changed" question.
After a while I realized that Spring Boot 2.1.4 requires TomCat 9, while I was using 8.5.
After this I started to get progress, but still the Thymeleaf isn't working, and if /templates has a index.html, the default Resolver is used, which ignores Thymeleaf's "fragments" and stuff (loads like a regular html page).

Spring Boot App Terminating at Startup

I am trying out a simple spring boot application it always shuts down automatically
:: Spring Boot :: (v1.4.1.RELEASE)
2016-10-23 13:05:21.681 INFO 16532 --- [ main] com.example.RestBootApplication : No active profile set, falling back to default profiles: default
2016-10-23 13:05:21.766 INFO 16532 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#6e20b53a: startup date [Sun Oct 23 13:05:21 EDT 2016]; root of context hierarchy
2016-10-23 13:05:23.682 INFO 16532 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-10-23 13:05:23.704 INFO 16532 --- [ main] com.example.RestBootApplication : Started RestBootApplication in 2.632 seconds (JVM running for 5.168)
2016-10-23 13:05:23.705 INFO 16532 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#6e20b53a: startup date [Sun Oct 23 13:05:21 EDT 2016]; root of context hierarchy
2016-10-23 13:05:23.708 INFO 16532 --- [ Thread-2] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>rest-boot</name>
<description>Demo project for Spring Boot</description>
<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.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Main Class
#SpringBootApplication
public class RestBootApplication {
public static void main(String[] args) {
SpringApplication.run(RestBootApplication.class, args);
}
}
Controller
#Controller
public class HelloController {
#RequestMapping("/hello")
String helloWorld(){
return "helloWorld";
}
}
Trying to run in spring tool suite. it always stops after starting. I even added "spring-boot-starter-web" after looking at some stackoverflow questions, but still facing the issue.
Please can you someone point out the issue.
In my case just adding following to pom file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This was happening to me and it turned out to be a corrupted maven apache repository.
To fix it I removed the apache repo - on my Mac it was located at /Users/myname/.m2/repository/org/apache.
On a pc it should be c:\users\myname.m2\repository\org\apache.
I then ran Maven - Update Project and then I ran my class and it was fixed.
Check what exit code you are getting.
If you get "Process finished with exit code 1" means an exception is being thrown. Thus you can put a try catch block around your SpringApplication.run() statement and print out the stack trace.
public static void main(String[] args) {
try {
SpringApplication.run(MyApplication.class, args);
} catch (Exception e) {
e.printStackTrace();
}
}
Example talen from: https://stackoverflow.com/a/59017774/9531109
Solution to your Question
I reviewed your POM.xml, it looks fine and doesn't require any changes to it.
spring-boot-starter-web is an opinionated dependency, it automatically pulls your other dependencies. Please check whether it has pulled your embedded Tomcat in your Maven Dependencies as shown below.
Go to application.properties file or application.yml to change the server port server.port=9081and run the maven goal as mvn clean install spring-boot:run -e
If these options doesn't workout please try this approach posted by me.
First of all check if the port 8080 is available or is being used by some other process.
If this port is not available, try adding server.port=someAvailablePortNumber in the application.properties file located in "resources" folder.
I was also facing same problem. Tried a lot of changes suggested in pom.xml file and also tried multiple suggestion related to maven (e.g: deleting folder, updating project etc) but nothing worked for me. In my case the port 8080 wasn't available so application wasn't able to start tomcat using default port(i.e.: 8080) causing it to shutdown immediately.
Changing the port number helped to start tomcat and it started working. Hope it helps :)
For me the embed tomcat was corrupted. I have done a mvn build and found below line as a WARNING.
[WARNING] error reading /home/syam/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.23/tomcat-embed-core-8.5.23.jar; invalid LOC header (bad signature)
So deleted the tomcat embed directory and did a maven clean, things started working.
My suggestion is to remove this dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
You may also try to add this tomcat dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
I had the same problem and there is how I resolved it :
I deleted maven's local repository
run again maven install
run the app as spring boot app
====> Hallelujah, and it worked just by magic !
I just took your code and started a Spring-Boot application from scratch. On my machine, your code starts up as expected when I run
mvn spring-boot:run
To make sure, we have the very same code, I uploaded my solution to Github, see https://github.com/michaellihs/stackoverflow-40205600
Just an idea why it doesn't work for you: do have another Tomcat instance running that is listening on port 8080 - this will stop your application immediately (but normally shows a different log / error message).
In my case as well , I had to clear the complete .m2 directory and run clean install to make it to work. Not sure what is conflicting.
i changed the port from 8080 to 8083 in application.properties which is under resources folder. server.port=8083 and it worked.
Adding this for posterity.
For these kind of issues it is very advantageous to run mvn help:effective-pom and look at the versions that have been picked up. It is common to have a parent module that is overriding a module/version that spring-boot is expecting to be available.
I had the same problem and there is how I resolved it :
I changed version in pom.xml from 1.4.2.RELEASE to 1.4.1.RELEASE
If you have created the project using start.spring.io you might have missed to add 'Spring Web' dependency.
alternate we can add below code to pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This property spring.main.web-application-type= none from the application properties file was causing the application to shut down as soon as started. Removing this would do the job.
I deleted the maven dependencies folder and it worked for me

Spring Boot web application doesn't serve standard endpoints

I have a problem with a Spring Boot Application that is supposed to run from command line and at the same time serve some metrics from the standard /metrics endpoint. When I just created the application all the metrics were served correctly, but at some point I seem to have "broken" something and my application stopped serving from default endpoints. I can't just revert to the initial state because there's a lot of code already and I don't want to lose version control history. Maybe someone could point at what I am doing wrong?
I don't override dispatcher servlet and don't add any custom filters.
Spring Boot version 1.3.7.
Error when accessing /metrics or any other default endpoint:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing
this as a fallback.
Mon Oct 03 17:53:12 PDT 2016 There was an unexpected error (type=Not
Found, status=404). No message available
Application file:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
Main runner file:
#EnableConfigurationProperties(ApplicationProperties.class)
#SpringBootApplication
public class Runner implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
// shortened ...
}
}
POM file fragment:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Debug output shows that the filters are created:
2016-10-03 17:26:14.461 DEBUG 85880 --- [ost-startStop-1] o.s.b.c.e.ServletContextInitializerBeans : Added existing Servlet initializer bean 'dispatcherServletRegistration'; order=2147483647, resource=class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletConfiguration.class]
2016-10-03 17:26:14.720 DEBUG 85880 --- [ost-startStop-1] o.s.b.c.e.ServletContextInitializerBeans : Created Filter initializer for bean 'metricFilter'; order=-2147483648, resource=class path resource [org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.class]
I created a sample clean application to compare and there are lines in output that I don't have in my app:
2016-10-03 18:06:48.075 DEBUG 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : 2 request handler methods found on class org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint: {public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)={[/{name:.*}],methods=[GET],produces=[application/json]}, public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()={[],methods=[GET],produces=[application/json]}}
2016-10-03 18:06:48.076 INFO 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2016-10-03 18:06:48.076 INFO 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
So, the filters/servlet seem to be created but not mapped in my app.
What am I possibly missing here?
OK I was stupid. Could say it twice.
So, after all, the problem was my bad memory. I actually was overriding application properties like this:
management.contextPath=/services/admin
Guess what, my /metrics was there all the time. It was just under /services/admin/metrics, which I completely forgot to have overridden. Duh.

Categories

Resources