Want to learn how to seamlessly combine Angular 2 with a Java Maven web application?

I have developed an Angular 2 front-end Application and a Java Rest WS Back-end Application that is connected to a database.

Here is the folder structure for my Angular 2 App:

Angular2App
  confg
  dist
  e2e
  node_modules
  public
  src
     app
     favicon.ico
     index.html
     main.ts
     system-config.ts
     tsconfig.json
     typings.d.ts
  tmp
  typings
  .editorconfig
  .gitignore
  angular-cli.json
  angular-cli-build.js
  package.json
  README.md
  tslint.json
  typings.json

And here is the structure of my Java Maven Web Application:

JerseyWebApp
  src
   main
     java
       Custom Package
       java classes
     resources
     webapp
       WEB-INF
         web.xml
       index.html
  pom.xml

I am looking for a way to combine these two applications into one, producing just one war file. Can anyone advise on how to achieve this integration?

Answer №1

Below are the steps I followed:-

  • First, I installed Nodejs v6.9+
  • Next, I ran npm install @angular/cli –g to install Angular CLI
  • Then, I either installed Apache Maven or used a Maven friendly IDE
  • I set up my required Maven configuration, opting for a simple webapp (WAR).

Directory Structure (The structure follows the standard Maven layout except for the ngapp folder.)

ngfirst
├── pom.xml
├── src
│   └── main
│       ├── java
│       ├── resources
│       ├── webapp
│       └── ngapp

Angular Component

To begin with the Angular setup, navigate to the ngapp folder in the terminal and execute the ng init command. This will initialize the node and npm configuration, resulting in an example Angular2 application structured as follows within the ngapp folder:-

             ├── angular-cli.json
             ├── e2e
             ├── karma.conf.js
             ├── node_modules
             ├── package.json
             ├── protractor.conf.js
             ├── README.md
             ├── tslint.json
             ├── src
                 ├── app
                 ├── assets
                 ├── environments
                 ├── favicon.ico
                 ├── index.html
                 ├── main.ts
                 ├── polyfills.ts
                 ├── styles.css
                 ├── test.ts
                 └── tsconfig.json

This structure mirrors the Maven project layout, with the src directory housing the source code of the Angular Application. Similar to how the maven build command generates output in the target folder, the ng build command outputs to the dist folder.

To include the generated Angular application within the Maven-built WAR file, adjust the build configuration to change the output directory from dist to webapp. Open the angular-cli.json file and modify the outDir as shown below:-

"outDir": "../webapp/ng"

With this setting, running the ng build command will place the built Angular Application inside the ng directory of ngfirst/src/main/webapp.

Maven Configuration

Edit the pom.xml file and configure the following three maven plugins:-

  1. compiler-plugin: Exclude any Java compilation tasks in /src/main/ngapp by specifying an exclusion.
  2. war-plugin: Since /src/main/ngapp is an Angular project folder, exclude it from the WAR packaging process.
  3. exec-plugin: Use this plugin to execute NPM Install and Angular-CLI Build commands for generating the Angular Application in the webapp folder prior to packaging. Ensure to include the --base-href argument to load Angular resources correctly from the webapp's context path.

The plugin configurations should look like this:-

<plugins>
    <plugin>
        ...
</plugins>  

Building the Maven Project (and the Angular App)

In the project root folder ngfirst, open Terminal and run the mvn package command to generate a WAR file (ngfirst.war) in the target folder.

Deploy the ngfirst.war file in a container, then access http://localhost:8080/ngfirst/ng/index.html in your browser. Make sure to adjust the hostname and port if needed.

If all goes well, you should see app works! displayed in the browser, indicating that the Angular Application is functioning correctly.

JSP Integration

You can combine the dynamic capabilities of JSP technology with the Angular application. By configuring the JSP Engine to pre-process html files, all JSP functionalities can be integrated into the Angular SPA Page. Include the following snippet inside the web.xml file:

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>

After saving and rebuilding the Maven project, deploying the WAR file will enable the JSP magic on your Angular SPA Page.

Answer №2

On one side, I have a Maven module for Angular sources named prj-angular, and another one for the war application called prj-war.

First, the prj-angular is built:

  • It utilizes the maven-exec-plugin to execute commands like npm install and ng build (thanks to @J_Dev!)
  • The default resource directory is changed to dist/
  • JAR MANIFEST generation is skipped
  • The resulting Maven module is a JAR containing only the generated Angular dist/ content!

Then, the second prj-war is built:

  • This module has a dependency on prj-angular
  • During the build process, it unzips the previously generated JAR into the web app destination
  • The final outcome of this module is an application WAR file with the latest Angular distribution.

Below are the plugin configurations used:

prj-angular (extract from pom.xml)

<build>
    <resources>
        <resource>
            <directory>dist</directory>
        </resource>
    </resources>
   .............(remaining code)............
</build>

prj-war (extract from pom.xml)

        <plugin>
           ..........(remaining code)............
        </plugin>

Answer №3

Interestingly, I completed a similar task just last week!

I utilized Netbeans 8.1 along with Tomcat servlet version 8.0.27

This project involved an Angular and Java file structure.

The Java Project was named Foo and the Angular Project was Bar.

Foo (Java Maven Project)
|__ src
|    |__ main
|    |    |__ webapp (This directory contains the entire Angular Project)
|    |    |    |__ META-INF
|    |    |    |    \__ context.xml 
|    |    |    |__ WEB-INF
|    |    |    |    \__ web.xml
|    |    |    |__ includes
|    |    |    |    |__ css
|    |    |    |    |__ images
|    |    |    |    \__ js
|    |    |    |
|    |    |    | ## Bar project files reside here ##
|    |    |    |
|    |    |    |__ app
|    |    |    |    \__ All .ts and compiled .js files are located here
|    |    |    |__ node_modules
|    |    |    |    \__ any dependencies used for Bar are located here
|    |    |    |__ typings
|    |    |    |    \__ typings for Typescript located here
|    |    |    |
|    |    |    |__ README.txt
|    |    |    |__ index.jsp
|    |    |    |__ package.json
|    |    |    |__ systemjs.config.js
|    |    |    |__ tsconfig.json
|    |    |    |__ typings.json
|    |    |    \ ## Bar project files end here
|    |    | 
|    |    |__ resources
|    |    |    |__META-INF
|    |    |    |    \__ persistence.xml
|    |    |__ java
|    |    |    |__ hibernate.cfg.xml
|    |    |    |__ com
|    |    |    |    |__ orgName
|    |    |    |    |    |__ packageName
|    |    |    |    |    |    \__ .java files can be found here
|__ pom.xml
\__ nb-configuration.xml

Answer №4

My suggestion is to keep the two applications separate for increased modularity. By doing this, you are able to make changes to the Angular App without impacting your service, and vice versa. Additionally, having Apache or Nginx serve your js and html files from Angular tends to be faster than using Tomcat. However, if you still prefer to include the Angular application within the war file, it is recommended to place all web resources in src/main/webapp.

Answer №5

Here's the approach I take when setting up my Angular/Java projects. Here are some key points:

  1. I structure my project as a single Maven project, giving me the flexibility to build it as a whole or separately for client and backend components.

  2. While my project is built on the Spring Boot framework, you can easily customize this setup to fit your needs. I place the generated Angular project output code in the 'META-INF' folder, but this can be adjusted if you're not using Spring Boot.

  3. In my setup, the angular project is published in the 'public' folder.

  4. During development, I run the Angular project and Java part of the backend separately - Angular with 'ng serve' and the Java backend in Eclipse IDE.

Let's dive into the project structure, visually represented below.

https://i.sstatic.net/guCQs.png

The Angular project resides in the 'src\main\ngapp' directory, while the Java backend is managed in Eclipse IDE. You have the freedom to choose your preferred IDE combination for handling both aspects of the project.

To build the Angular project using Maven, I utilize the following maven profile definition.

<profile>
    <id>build-client</id>

    <build>
        <plugins>
            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>1.3</version>
                <configuration>
                    <nodeVersion>v10.13.0</nodeVersion>
                    <npmVersion>6.4.1</npmVersion>
                    <workingDirectory>src/main/ngapp/</workingDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>npm run build-prod</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run build</arguments>
                        </configuration>
                    </execution>
                    <execution>
                        <id>prod</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run-script build</arguments>
                        </configuration>
                        <phase>generate-resources</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

The setup involves utilizing the 'com.github.eirslett:frontend-maven-plugin' plugin to handle node installation and npm execution for building the Angular project. The profile 'build-client' triggers this process.

  • This includes verifying and installing the specified node version (v10.13.0) in the Angular project directory ('src/main/ngapp/').

  • Executing the command 'npm run build', which is the build alias defined in 'package.json' of the Angular project.

"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.conf.json",
    "build": "ng build --configuration=production",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
}

The Angular client is intended to reside in the 'public' folder within the web application. To facilitate this, the Angular project configuration specifies 'baseHref=/public'. Additionally, the compiled project is positioned in 'src/main/resources/META-INF/resources/public'. Configuration details can be found in 'angular.json'.

"build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
    "baseHref":"/public/",
    "outputPath": "../resources/META-INF/resources/public",
    ...    

In scenarios without Spring Boot, placing the compiled Angular project directly in 'src/main/webapp/public' may be necessary. Modifications should be made accordingly in 'angular.json'.

You can access the complete project code on my GitHub repository. For reference, the frontend-maven-plugin project is hosted here.

Answer №6

Guidelines for building an Angular project using the command line:

npm install --verbose
npm run ng build

Requirements:

src/main/frontend
src/main/webapp

Implementation with maven-war-plugin + exec-maven-plugin:

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
            <webResources>
                <resource>
                    <directory>src/main/frontend/dist</directory>
                </resource>
            </webResources>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.0.0</version>
        <executions>
            <execution>
                <id>npm-install</id>
                <phase>generate-sources</phase>
                <configuration>
                    <workingDirectory>src/main/frontend</workingDirectory>
                    <executable>npm</executable>
                    <arguments>
                        <argument>install</argument>
                    </arguments>
                </configuration>
                <goals>
                    <goal>exec</goal>
                </goals>
            </execution>
            <execution>
                <id>npm-ng-build</id>
                <phase>generate-sources</phase>
                <configuration>
                    <workingDirectory>src/main/frontend</workingDirectory>
                    <executable>npm</executable>
                    <arguments>
                        <argument>run</argument>
                        <argument>ng</argument>
                        <argument>build</argument>
                    </arguments>
                </configuration>
                <goals>
                    <goal>exec</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

Using maven-war-plugin + maven-antrun-plugin (alternative method):

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
            <webResources>
                <resource>
                    <directory>src/main/frontend/dist</directory>
                </resource>
            </webResources>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>3.0.0</version>
        <executions>
            <execution>
                <id>exec-gen-sources</id>
                <phase>generate-sources</phase>
                <configuration>
                    <target name="Build Frontend">
                        <exec executable="cmd" dir="src/main/frontend" failonerror="true">
                            <arg line="/c npm install --verbose" />
                        </exec>
                        <exec executable="cmd" dir="src/main/frontend" failonerror="true">
                            <arg line="/c npm run ng build" />
                        </exec>
                    </target>
                </configuration>
                <goals>
                    <goal>run</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

Answer №7

<component>
                        <groupID>com.github.eirslett</groupID>
                        <elementID>frontend-maven-plugin</elementID>
                        <versionNumber>1.3</versionNumber>
                        <configurationSettings>
                            <nodeVersion>v10.13.0</nodeVersion>
                            <npmVersion>6.4.1</npmVersion>
                            <location>src/main/ngapp/</location>
                        </configurationSettings>
                        <tasks>
                            <task>
                                <identification>install node and npm</identification>
                                <objectives>
                                    <goal>install-node-and-npm</goal>
                                </objectives>
                            </task>
                            <task>
                                <identification>npm install</identification>
                                <objectives>
                                    <goal>npm</goal>
                                </objectives>
                            </task>
                            <task>
                                <identification>npm run build-prod</identification>
                                <objectives>
                                    <goal>npm</goal>
                                </objectives>
                                <configurationSettings>
                                    <arguments>run build</arguments>
                                </configurationSettings>
                            </task>
                            <task>
                                <identification>prod</identification>
                                <objectives>
                                    <goal>npm</goal>
                                </objectives>
                                <configurationSettings>
                                    <arguments>run-script build</arguments>
                                </configurationSettings>
                                <phaseOfExecution>generate-resources</phaseOfExecution>
                            </task>
                        </tasks>
                    </component>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Custom Validators in Angular to Enhance Accessibility

I'm struggling to access my service to perform validator checks, but all I'm getting is a console filled with errors. I believe it's just a syntax issue that's tripping me up. Validator: import { DataService } from './services/da ...

Angular's POST request to Web.API was blocked due to cross-origin restrictions

A demonstration application is being developed at a small scale: Frontend using Angular (http://localhost:4200/) Backend using ASP.Net Core (https://localhost:44333/) Currently, the GET requests from frontend to backend are functioning correctly. Howeve ...

Ways to enhance the type definitions for a built-in HTML element in Vue.js?

Imagine having an element that wraps around an input and inherits all of its properties, along with some extras. In React, you would define this as: interface ExtendedInputProps extends React.ComponentPropsWithoutRef<'input'> { some: T ...

Please ensure the subscription has completed before proceeding with the loop

I am currently working on an Angular application that retrieves data from an API and uses one of its parameters from a looped array. The issue I'm facing is that the data is pushed in a random order due to the continuous looping without waiting for th ...

Can child directives in Angular 2 harness the power of parent providers?

I am facing an issue while trying to utilize a service as a provider for general use in a Directive rather than a Component. The problem arises when the service is not being received in the child Directive, despite my expectation to use it within the direc ...

Encountered a Lubunto code compilation error

I recently installed Lubuntu in a virtual machine and added JRE and JDK OpenJDK-9 to it. As a test, I tried compiling a simple program using the javac compiler, but it's not working. The program is as basic as 'Hello World', so I don't ...

items within an unordered list that can be collapsed

Answer: Nikhil was on the right track with his solution, but I had to make some modifications. Specifically, I needed to create and initialize an empty array to display the details properly. Here's the updated code: if (this.name.toLowerCase() == va ...

Angular Service failing to connect with API endpoint

I have been experimenting with a new service called vpnblocker, designed to identify whether a user is utilizing a VPN or not. I am closely following the specified documentation and referencing the API variables. Despite setting up my angular service to ma ...

Adapting the return type dynamically according to the input given

I have a set of 4 different classes: class AddCommand { // TODO } class AddCommandOutput { // TODO } class RemoveCommand { // TODO } class RemoveCommandOutput { // TODO } I am currently working on creating a function that can take either Ad ...

Storing Your Vapid Key for Web Push Notifications

Hello, I have successfully generated the VAPID key using a specific function. From my understanding, the VAPID key should only be created once for a project and then used for sending push notifications. Now, I need to figure out a way to store the VAPID ke ...

Can you explain the purpose behind using this syntax within the subscribe function?

.subscribe(data=> { this.timezones = data; } Is the 'data' variable used in the .subscribe() method the same as the one declared in the constructor (private: data)? What does the arrow symbol mean and what is its purpose? export class X ...

Encountering the "Element not clickable" problem with Selenium

Unable to interact with the element. The test runs smoothly on a computer, but fails when run on a laptop displaying error message 'Element not clickable'. Attempted various wait times without success. Uncertain of the root cause. My current appr ...

Turn off ESLint for TypeScript documents

I am faced with a large web application that consists of legacy JavaScript code (with eslint) and new TypeScript code (with tslint). The issue I am encountering is that my IDE (WebStorm) is running both linters on all files, causing me to receive eslint e ...

Encountering a ClassCastException error when using the Twitter4J library in

Utilizing the Twitter4J library has been smooth sailing so far. However, in order to avoid the dreaded java.lang.ClassCastException error, I had to include the following declaration in my manifest: <application> android:name=".TwitterApplication" &l ...

Showing the child component as undefined in the view

Within my Angular application, I encountered an issue involving a parent component named DepotSelectionComponent and its child component SiteDetailsComponent. The problem arises when an event called moreDetails is emitted to the parent component, triggerin ...

Even when imperfections inevitably arise, flawless submission is always achieved

When working with a form that has a set minimum and maximum number of characters, I encounter an issue. If the minimum is set to 2 characters and I only input one character, I receive a mat-error message. However, upon clicking save, it allows me to procee ...

Sorting an array of floating point numbers in Java: How to arrange them in descending order?

When attempting to sort an array of floats in reverse order using the following code snippet, I encountered an error message. Can you help me identify the issue? float sortedData[]=new float[100]; ... Arrays.sort(sortedData,Collections.reverseOrder()); ...

Tip for Spinning Tops

Despite searching the web, I couldn't find a solution that meets my specific needs for this issue. In my layout XML, I have a spinner and a string array in strings.xml . <string-array name="days"> <item>Monday</item> ...

Update ng-Bootstrap ToDate field by removing the date when selecting a fromDate

Is there a way to clear the date from the toDate input field while selecting a date from the fromDate input field in ng-bootstrap? <form class="row row-cols-sm-auto" *ngIf="showDateRangeImp"> <div class="col-12" ...

Direct all hash-based URLs to Angular Routes without the hash symbol being displayed

I'm in the process of upgrading from an AngularJS 1.6.x SPA to an Angular 5.x SPA while ensuring a seamless transition for my users. One of my main concerns is users who have bookmarks to the existing app which contain hashes in the URLs (e.g. exampl ...