How to create a JSP + Angular development environment

I am a Java Web Application developer, and I am learning Angular Framework recently.
I found that there are many problems when developing a web application using JSP and
Angular Framework (such as Angular routing, CORS).

In order to solve the problem, so I am looking for a solution in Google, the solutions found are as follows:

  1. Modify the Tomcat Server setting, you may click here for detail
  2. Implement a Servlet Filter to perform a URL redirect

I don’t want to modify the Tomcat Server setting, so I chose the second solution.
Although someone has made a UrlRewriteFilter, it can’t achieve the desired effect.
After a round of research and testing, it was finally done.

Before I go ahead, let me introduce my folder structure:

E:.
└─workspace
    └─DemoWeb
        ├─frontEnd <==This folder is used to store Angular project files
        └─jsp	   <==This folder is used to store the files of the Dynamic Web(JSP) project

My development environment is as below:

  1. Eclipse Version 2019-06 (4.12.0)
  2. Angular CLI version 8.3.3
  3. Node version 10.16.3
  4. Tomcat version 8.5
  5. Windows 10

Create a simple Java Web Application:

For the convenience of explanation, let’s create a simple Java Web Application:

  1. Start the Eclipse environment
  2. Click File -> New Project -> Dynamic Web Project
  1. Click “Next", Enter “DemoWeb" for the Project name
  1. Click “Finish"
  2. Right-click the project, and click “Java EE Tools" -> “Generate Deployment Descriptor stub" to generate the web.xml file.
  1. Finally, add an index.jsp to the context root to show that this is the “JSP site".
  2. In the index.jsp, using the following coding to replace the existing content.
<%@ page language="java" contentType="text/html; charset=UTF-8″ pageEncoding="UTF-8″%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8″>
<title>This is a JSP page.</title>
</head>
<body>
<%="This is a JSP page." %>
</body>
</html>
  1. Press Ctrl-S to save the file.
  2. Right-click the jsp, click “Run as", and then click “Run on Server".
    The default browser should automatically popup and display the following screen:
  1. At this point back to Eclipse, stop the tomcat server by pressing the red circled button.

Build an Angular Project

  1. Start VS code,click File->Open Folder ->Select E:\workspace\DemoWeb
  1. Press Ctrl-`, and the terminal would be shown.
  1. In the terminal, to create a new Angular Project enter the following command:

    ng new frontEnd
  2. Then press “Y" and enter once, after that wait for the project building process complete.
  3. Click “frontEnd" on the left pane, then click “src"->"app"
  4. Finally, open the file “app.component.html"
  1. Delete all the contents of this file and replace it with the following:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8″>
<title>This is Angular page.</title>
</head>
<body>
This is Angular page.<br>
<a href="admin/">Go To Admin. Page</a>
<router-outlet></router-outlet>
</body>
</html>
  1. In the terminal, change to the project directory by entering the below command:

    cd frontEnd

  2. Enter the following command to start the Angular built-in server.

    ng serve -o

  3. The default browser should automatically popup and display the following screen:
  1. At this point, go to the terminal press ctrl-c to stop the Angular build-in server.

Create an Admin. Page

I create an admin. component to show the Angular routing is working properly.

  1. In the terminal, enter the following command to generate the admin. component:

    ng g component Admin

Create an Angular Routing

  1. Click “frontEnd" on the left pane, then click “src"->"app"
  2. Open the file “app-routing.module.ts"
  3. Add routing as below:
import { NgModule } from ‘@angular/core’;
import { Routes, RouterModule } from ‘@angular/router’;
import { AdminComponent } from ‘./admin/admin.component’;
const routes: Routes = [
{ path:  ‘admin’, component:  AdminComponent}
];
@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }

  1. Press Ctrl-S to save the file

Test the Angular Routing

  1. Enter the below command in terminal

    ng serve -o

  2. The default browser should automatically popup and display the following screen:
  1. Click the “Go To Admin. Page" link. The following screen should appear:
  1. At this point, go to the terminal press ctrl-c to stop the Angular build-in server.

Configure the Angular’s output folder

  1. Click “frontEnd" on the left pane, then open the “angular.json"
  2. Change the below setting from

    “outputPath": “dist/frontEnd"

    to

    “outputPath": “E:\workspace\DemoWeb\jsp\WebContent\frontEnd",

  3. Press Ctrl-S to save the file. After that, Angular will copy all the compiled files to the “frontEnd" folder of the Eclipse project directory.
  4. In the terminal, enter the following command:

    ng build -–watch –base-href /DemoWeb/frontEnd/

    • We need to set the base href to fit the JSP context path.
    • Because the end of the output path setting is “frontEnd", so the end here is “frontEnd" also.

According to this page, to make the Angular routing work properly, we need to forward all access “frontEnd/"
request to /frontEnd/index.html. To achieve this goal, we need a servlet filter.

Add a servlet filter

  1. Back to the Eclipse environment, right the project->"New"->"Filter"
  1. Enter the package name and filter class name
  1. Click “Next", then Click “/AngularFilter"
  1. Click on “Edit" button, enter “/frontEnd/*", then “Ok" Button.
  2. Click on the “Finish" button to complete the process.
  3. At this point, the editor should display the content of “AngularFilter.java"
  4. Delete all the contents of this file and replace it with the following:
/*
 * Copyright 2004-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.filter;
import java.io.File;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author Roy Tsang
 *
 */
/**
 * Servlet Filter implementation class AngularFilter
 */
@WebFilter("/frontEnd/*")
public class AngularFilter implements Filter {
	FilterConfig filterConfig;
    /**
     * Default constructor. 
     */
    public AngularFilter() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		this.filterConfig = null;
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		String destination,angularRootPath,realPath; 
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse=(HttpServletResponse)response;
		ServletContext context = httpRequest.getServletContext();
		destination =httpRequest.getServletPath();
		realPath =context.getRealPath(destination);
		angularRootPath="";
		File f = new File(realPath);
		if (f.exists()) {
			chain.doFilter(request, response);
		} else {
			FilterRegistration fr= context.getFilterRegistration(this.getClass().getName());
			for (String mapping: fr.getUrlPatternMappings()) {
				mapping=mapping.replace("/*", "");
				if (destination.indexOf(mapping)>-1) {
					angularRootPath=mapping;
					break;
				}
			}
			if (angularRootPath.equals("")) {
				httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
			} else {
				filterConfig.getServletContext().getRequestDispatcher(angularRootPath+"/index.html").forward(request, response);
			}
		}
		f=null;		
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		this.filterConfig=fConfig;
	}

}
  1. Save the file
  2. Right-click the project, click “Run as", and then click “Run on Server".
    The default browser should automatically popup and display the following screen:
  1. Browse http://localhost:8080/DemoWeb/frontEnd/, and the browser should appear on the following screen:
  1. Click the “Go To Admin. Page" link. The following screen should appear:
  1. If “admin works!" Appears, the setting is successful.

The related source code can be downloaded from here.