To have my Angular project work in a WAR, I created a Maven project with only 2 files in it (next to the Angular files):
- pom.xml
- src/main/java/com/stackoverflow/AngularFilter.java
The content of pom.xml:
<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.stackoverflow.example</groupId>
<artifactId>angular-example</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>${basedir}/src/angular/dist/angular</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
In the warSourceDirectory element, I refer to the Angular build output. (The Angular files have to be built with the correct --base-href value.)
The pom.xml file alone is sufficient to have the Angular application working.
However, without the AngularFilter.java file, refreshing Angular routes will not work. With the following filter class, also refreshing Angular routes works:
package com.stackoverflow;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
@WebFilter("/*")
public class AngularFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = ((HttpServletRequest) request);
String contextPath = httpRequest.getContextPath();
String requestURI = httpRequest.getRequestURI();
String angularPath = requestURI.substring(contextPath.length());
if (isAngularRoute(angularPath)) {
request.getRequestDispatcher("/index.html").forward(request, response);
} else {
chain.doFilter(request, response);
}
}
private boolean isAngularRoute(String angularPath) {
return
/* Do not reroute files in the Angular root, such as index.html,
main.js, polyfills.js, runtime.js, styles.css and favicon.ico */
((angularPath.indexOf('/', 1) != -1) || (angularPath.indexOf('.') == -1))
/* Do not reroute static files */
&& !angularPath.startsWith("/assets/");
}
@Override
public void destroy() {}
}
There are other solutions that use Spring MVC to enable refreshing Angular routes as explained here: Springboot/Angular2 - How to handle HTML5 urls?
However, I think it is overkill to use Spring if a single Filter class does the job.