Reputation: 122
I'm working on a Spring-Boot Web Application that needs to be deployed on tomcat (WAR file). When running the application as Java (right click application.java file and run as Java in Eclipse) or running via mvnw.cmd spring-boot:run, everything works PERFECTLY (home page shows, all CRUD operations work).
When I export a WAR file and deploy to tomcat, my static web content and homepage still load fine, but any API calls return a 404 response.
This project was created using Spring Initializr. I've tried exporting via Eclipse war export, and mvnw.cmd package. Placed the WAR file in webapps directory on server and ran.
package com.blank.systemshare;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SystemshareApplication {
public static void main(String[] args) {
SpringApplication.run(SystemshareApplication.class, args);
}
}
package com.blank.systemshare;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SystemshareApplication.class);
}
}
package com.blank.systemshare.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.blank.systemshare.exception.ResourceNotFoundException;
import com.blank.systemshare.model.System;
import com.blank.systemshare.repository.SystemRepository;
@RestController
@RequestMapping("/api/v1/")
public class SystemController {
@Autowired
private SystemRepository systemRepository;
// get systems
@GetMapping("systems")
public List<System> getSystems() {
return this.systemRepository.findAllByOrderByVersionDesc();
}
// create system
@PostMapping("systems")
public System createSystem(@RequestBody System system) {
return this.systemRepository.save(system);
}
// update system
@PutMapping("systems/{id}")
public ResponseEntity<System> updateSystem(@PathVariable(value = "id") Long systemId,
@Valid @RequestBody System systemDetails) throws ResourceNotFoundException {
System system = systemRepository.findById(systemId)
.orElseThrow(() -> new ResourceNotFoundException("System not found - ID: " + systemId));
system.setVersion(systemDetails.getVersion());
system.setUrl(systemDetails.getUrl());
system.setCredentials(systemDetails.getCredentials());
system.setFrameworks(systemDetails.getFrameworks());
system.setFw_credentials(systemDetails.getFw_credentials());
system.setNotes(systemDetails.getNotes());
system.setOwner(systemDetails.getOwner());
return ResponseEntity.ok(this.systemRepository.save(system));
}
//delete system
@DeleteMapping("systems/{id}")
public Map<String, Boolean> deleteSystem(@PathVariable(value = "id") Long systemId) throws ResourceNotFoundException {
System system = systemRepository.findById(systemId)
.orElseThrow(() -> new ResourceNotFoundException("System not found - ID: " + systemId));
this.systemRepository.delete(system);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
package com.blank.systemshare.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.blank.systemshare.model.System;
@Repository
public interface SystemRepository extends JpaRepository<System, Long>{
public List<System> findAllByOrderByVersionDesc();
}
var systemShareApp = angular.module('systemShareApp', [])
.controller('mainController', ($scope, $http, $window) => {
$scope.version = '1.0';
$scope.systemData = {};
$scope.createSystemFormData = {};
$scope.editSystemFormData = {};
$scope.dbErrorStatus = false;
// Get all systems
var getAllSystems = function() {
$http.get('/systemshare/api/v1/systems')
.success((data) => {
$scope.systemData = data;
$scope.dbErrorStatus = false;
console.log(data);
})
.error((error) => {
console.log('Error: ' + error);
$scope.dbErrorStatus = true;
});
};
//initial load of page - get systems.
getAllSystems();
// Create a new system
$scope.createSystem = () => {
$http.post('/systemshare/api/v1/systems', $scope.createSystemFormData)
.success((data) => {
$scope.createSystemFormData = {};
getAllSystems();
})
.error((error) => {
console.log('Error: ' + error);
});
};
// Delete a system
$scope.deleteSystem = (systemID) => {
$http.delete('/systemshare/api/v1/systems/' + systemID)
.success((data) => {
getAllSystems();
})
.error((data) => {
console.log('Error: ' + data);
});
};
// Update a system
$scope.updateSystem = (systemID) => {
$http.put('/systemshare/api/v1/systems/' + systemID, $scope.editSystemFormData)
.success((data) => {
$scope.editSystemFormData = {};
getAllSystems();
})
.error((data) => {
console.log('Error: ' + data);
});
};
//select system function for transfer of object data in list to modal.
$scope.selectSystem = function(system) {
$scope.thisSystem = system;
//editSystemFormData Modal updates:
$scope.editSystemFormData.owner = system.owner;
$scope.editSystemFormData.version = system.version;
$scope.editSystemFormData.url = system.url;
$scope.editSystemFormData.credentials = system.credentials;
$scope.editSystemFormData.frameworks = system.frameworks;
$scope.editSystemFormData.fw_credentials = system.fw_credentials;
$scope.editSystemFormData.notes = system.notes;
};
});
spring.datasource.url=jdbc:postgresql://xx.xx.xxx.xxx:5432/systemshare
spring.datasource.username=xx
spring.datasource.password=xx
spring.jpa.show-sql=true
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=update
server.servlet.contextPath=/systemshare
<?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.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.blank</groupId>
<artifactId>systemshare</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>systemshare</name>
<description>System Share Project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
mvnw.cmd spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------< com.blank:systemshare >------------------------
[INFO] Building systemshare 0.0.1-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) > test-compile @ systemshare >>>
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ systemshare ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 4 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ systemshare ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 8 source files to C:\Users\user\Documents\JavaProjects\systemshare\target\classes
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ systemshare ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\user\Documents\JavaProjects\systemshare\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ systemshare ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to C:\Users\user\Documents\JavaProjects\systemshare\target\test-classes
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) < test-compile @ systemshare <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) @ systemshare ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-04-21 14:50:58.430 INFO 19748 --- [ restartedMain] c.p.systemshare.SystemshareApplication : Starting SystemshareApplication on L37853WUS with PID 19748 (C:\Users\user\Documents\JavaProjects\systemshare\target\classes started by userin C:\Users\mck
eb2\Documents\JavaProjects\systemshare)
2020-04-21 14:50:58.435 INFO 19748 --- [ restartedMain] c.p.systemshare.SystemshareApplication : No active profile set, falling back to default profiles: default
2020-04-21 14:50:58.513 INFO 19748 --- [ restartedMain] o.s.b.devtools.restart.ChangeableUrls : The Class-Path manifest attribute in C:\Users\user\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.2\jaxb-runtime-2.3.2.jar referenced one or more files th
at do not exist: file:/C:/Users/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.xml.bind-api-2.3.2.jar,file:/C:/Users/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/txw2-2.3.2.jar,file:/C:/Users/user/.m2/repository/org/glassfi
sh/jaxb/jaxb-runtime/2.3.2/istack-commons-runtime-3.0.8.jar,file:/C:/Users/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/stax-ex-1.8.1.jar,file:/C:/Users/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/FastInfoset-1.2.16.jar,file:/C:/U
sers/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.activation-api-1.2.1.jar
2020-04-21 14:50:58.513 INFO 19748 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-04-21 14:50:58.513 INFO 19748 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2020-04-21 14:50:59.303 INFO 19748 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-04-21 14:50:59.383 INFO 19748 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 71ms. Found 1 JPA repository interfaces.
2020-04-21 14:51:00.475 INFO 19748 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-04-21 14:51:00.489 INFO 19748 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-04-21 14:51:00.490 INFO 19748 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-04-21 14:51:00.674 INFO 19748 --- [ restartedMain] o.a.c.c.C.[.[localhost].[/systemshare] : Initializing Spring embedded WebApplicationContext
2020-04-21 14:51:00.675 INFO 19748 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2161 ms
2020-04-21 14:51:00.858 INFO 19748 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-04-21 14:51:00.942 INFO 19748 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.12.Final
2020-04-21 14:51:01.117 INFO 19748 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-04-21 14:51:01.228 INFO 19748 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-04-21 14:51:01.603 INFO 19748 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-04-21 14:51:01.621 INFO 19748 --- [ restartedMain] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
2020-04-21 14:51:02.803 INFO 19748 --- [ restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-04-21 14:51:02.810 INFO 19748 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-04-21 14:51:02.825 INFO 19748 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2020-04-21 14:51:03.186 WARN 19748 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : 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
2020-04-21 14:51:03.334 INFO 19748 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-21 14:51:03.402 INFO 19748 --- [ restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2020-04-21 14:51:03.571 INFO 19748 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '/systemshare'
2020-04-21 14:51:03.575 INFO 19748 --- [ restartedMain] c.p.systemshare.SystemshareApplication : Started SystemshareApplication in 5.624 seconds (JVM running for 6.47)
2020-04-21 14:51:17.737 INFO 19748 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/systemshare] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-21 14:51:17.737 INFO 19748 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-21 14:51:17.745 INFO 19748 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-04-21 14:55:49.434 INFO 12280 --- [ost-startStop-1] com.blank.systemshare.ServletInitializer : Starting ServletInitializer v0.0.1-SNAPSHOT on L37853WUS with PID 12280 (C:\Users\user\Documents\Software\apache-tomcat-8.5.29\webapps\systemshare\WEB-INF\classes started by user in C:\Users\user\Documents\Software\apache-tomcat-8.5.29\bin)
2020-04-21 14:55:49.451 INFO 12280 --- [ost-startStop-1] com.blank.systemshare.ServletInitializer : No active profile set, falling back to default profiles: default
2020-04-21 14:55:52.213 INFO 12280 --- [ost-startStop-1] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-04-21 14:55:52.458 INFO 12280 --- [ost-startStop-1] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 200ms. Found 1 JPA repository interfaces.
2020-04-21 14:55:53.923 INFO 12280 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4212 ms
2020-04-21 14:55:55.125 INFO 12280 --- [ost-startStop-1] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-04-21 14:55:55.675 INFO 12280 --- [ost-startStop-1] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.12.Final
2020-04-21 14:55:56.461 INFO 12280 --- [ost-startStop-1] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-04-21 14:55:57.051 INFO 12280 --- [ost-startStop-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-04-21 14:55:57.633 INFO 12280 --- [ost-startStop-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-04-21 14:55:57.728 INFO 12280 --- [ost-startStop-1] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
2020-04-21 14:56:01.538 INFO 12280 --- [ost-startStop-1] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-04-21 14:56:01.578 INFO 12280 --- [ost-startStop-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-04-21 14:56:03.216 WARN 12280 --- [ost-startStop-1] JpaBaseConfiguration$JpaWebConfiguration : 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
2020-04-21 14:56:03.699 INFO 12280 --- [ost-startStop-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-21 14:56:04.075 INFO 12280 --- [ost-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2020-04-21 14:56:04.472 INFO 12280 --- [ost-startStop-1] com.blank.systemshare.ServletInitializer : Started ServletInitializer in 16.741 seconds (JVM running for 32.139)
21-Apr-2020 14:56:04.517 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [C:\Users\user\Documents\Software\apache-tomcat-8.5.29\webapps\systemshare.war] has finished in [25,067] ms
{
"timestamp":"2020-04-21T19:50:27.749+0000",
"status":404,
"error":"Not Found",
"message":"No message available",
"path":"/systemshare/api/v1/systems"
}
Also, tomcat logs don't show anything useful.
Upvotes: 2
Views: 2523
Reputation: 39
Try server.servlet.context-path
instead of server.servlet.contextPath
.
Upvotes: 0
Reputation: 122
Removing the ServletInitializer.java class and updating my application file to the following resolved the issue (extending SpringBootServletInitializer and overriding the configure method). Note that I tried this before, but built the application using both Eclipse and InteliJ. Both times the same issue still occurred. This final time I built using mvnw package
and the WAR generated in the target directory worked.
package com.blank.systemshare;
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 SystemshareApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SystemshareApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SystemshareApplication.class);
}
}
Upvotes: 2