Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serve angular application from war

I have a web application that is built as a war using maven. This web application contains my backend as rest service.

I also have and angular application that I want to use to consume said web application (it uses npm and webpack for bundling).

How can I serve my angular application from the same war that contains my backend? Say, in path .../index.html?

like image 638
Daniel Calderon Mori Avatar asked Apr 20 '26 07:04

Daniel Calderon Mori


1 Answers

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.

like image 161
toongeorges Avatar answered Apr 21 '26 20:04

toongeorges