Reputation: 3341
I'm new to Spring Boot and struggling to deploy a simple HTML web app (AngularJS) to Tomcat 8. This web app simply serves some HTML/CSS/JS content with no REST calls to a backend. It has been "compiled" using Webpack -- this produces JS/CSS bundles and a single index.html file that points to them via <script> / <link>
tags -- and has been tested on ExpressJS and Spring Boot w/ Embedded tomcat and works as expected. But going down the path of a stand-alone WAR and deploying to Tomcat 8 does not seem to work properly.
For the Spring Boot project, I've included all the HTML/CSS/JS files in the src/main/resources/public
folder (no subfolders) and have also configured the pom.xml
as follows (basic config):
<?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.my-app</groupId>
<artifactId>my-app</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<name>my-app</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
"Main" class:
package com.example.my.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
@SpringBootApplication
public class MyAppApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyAppApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyAppApplication.class, args);
}
}
Here are the steps I used to do the Tomcat deployment:
mvn clean package
to generate the WARUnfortunately all I see are 404 errors because it couldn't find some JS/CSS file. Is there a config I'm missing?
Updated: Here is the index.html file (auto-generated via Webpack):
<!doctype html>
<html>
<head>
<base href="/">
<meta charset="utf-8">
<title>My App</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="icon" type="image/png" href="./assets/images/favicon.ico" />
<link href="/main-aa49893f83cc830596563d81f09a9611.css" rel="stylesheet"><link href="/main-5949f1f257a55a77e48bc4ab62fbc99a.css" rel="stylesheet"></head>
<body ng-app="myapp">
<ui-view></ui-view>
<script type="text/javascript" src="vendor-353ddb48f4ffe6546d59.js"></script><script type="text/javascript" src="app-353ddb48f4ffe6546d59.js"></script></body>
</html>
Here are the errors I'm seeing in Chrome Web Inspector when visiting localhost:8080/my-app/index.html
:
http://localhost:8080/main-5949f1f257a55a77e48bc4ab62fbc99a.css Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/main-aa49893f83cc830596563d81f09a9611.css Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/vendor-4ba9083ed9802279c207.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/app-4ba9083ed9802279c207.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/vendor-4ba9083ed9802279c207.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/app-4ba9083ed9802279c207.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/main-aa49893f83cc830596563d81f09a9611.css Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/main-5949f1f257a55a77e48bc4ab62fbc99a.css Failed to load resource: the server responded with a status of 404 (Not Found)
One more thing I forgot to mention. When I generate the war using mvn clean package
, all the files that are under src/main/resources/public are placed into the WEB-INF/classes/resource
subfolder. According to research, these files are not publicly visible (i.e. if I try to access localhost:8080/my-app/foo.css, it'll give 404). Is this why the index.html file is unable to "see" the JS/CSS files it depends on?
Upvotes: 4
Views: 5309
Reputation: 855
I had the same problem, and it is related to Webpack more than to Spring-boot. In your webpack.common.js / webpack.prod.js you have to set :
metada.baseUrl = './';
and inject this in your <base>
link in index.html
And you also have to set
output.publicPath: './'
With both variable set, this worked for me.
Upvotes: 0
Reputation: 3341
I ended up figuring it out but not using Spring Boot to package the WAR file. There was another project lying around on my local that used plain old Maven + pom.xml + web.xml
to create WARs, which I used as a reference to figure out why the current project was not working. There were multiple issues:
http://localhost:8080/my-app
. The "compiled" AngularJS app's index.html
had a <base href="/">
tag that needed to point to /my-app/
instead of /
. This was the main reason why the JS/CSS files were not visible in Web Inspector > Sources
.<link>
tag's src
attribute was not supposed to contain a leading /
There were other errors related to finding resources like .ttf
files but at least the app was able to run.
Update:
Looks like its possible to serve the WAR file from the Tomcat 8 root by adding the following near the bottom of the server.xml
file:
<Context path="" docBase="my-app" debug="0" reloadable="true"></Context>
This will prevent the need to modify the index.html file.
Awesome :)
Upvotes: 4
Reputation: 3440
The most common issue with the setup you have described, without more context, is that you are most likely using absolute URLs to point at your js / css files. As such when you put them into the servlet container under /my-app
they no longer reference properly as they are trying to go to the root /
. You need to use relative URLs when describing the location of the resource files on the path.
Upvotes: 1
Reputation: 2203
Uhmm i've tried some of this on my spring-boot
project.
First i'd add a dependency on my project pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
then i'd add an index.html
on src/main/resources/templates
after that you should add a controller to point to that index
@Controller
public class AppController {
@RequestMapping("/")
String index() {
return "index";
}
}
For more information see this guide. Spring-boot and Thymeleaf
Upvotes: -1