29

I'm becoming a bit crazy because I can't find a guide to setup an angular 4 app inside a java war project that will be built with maven. This is because I want to run it into a wildfly server.

Any help?

Thanks

TimeTraveler
  • 1,223
  • 12
  • 15
Giamma
  • 808
  • 2
  • 10
  • 21

3 Answers3

42

I had similar requirement to have one source project which has java web-services project as well as angular project(an angular-cli based project) and maven build should create a war with all angular files in it. I used maven-frontend-plugin with few configuration changes for base path.

The goal was to create a war file with all the java code in it plus all the aot compiled angular code in root folder of war, all this with single command mvn clean package.

One more thing for all this to work is to avoid conflict between angular-app router urls and your java application urls, You need to use HashLocationStrategy. one way set it up in app.module.ts like below

app.module.ts -

providers: [
    { provide: LocationStrategy, useClass: HashLocationStrategy },

]

Folder structure for Angular App is below-

angular-project

  • dist
  • e2e
  • node_modules
  • public
  • src
    • app
    • assets
    • environments
    • favicon.ico
    • index.html
    • main.ts
    • polyfills.ts
    • style.css
    • tsconfig.json
    • typings.d.ts
    • etc-etc
  • tmp
  • .angular-cli.json
  • .gitignore
  • karma.conf.js
  • package.json
  • README.md
  • tslint.json
  • etc - etc

Maven Project -

  • src
    • main
      • java
      • resources
      • webapp
        • WEB-INF
        • web.xml
  • angular-project (place your angular project here)
  • node_installation
  • pom.xml

Add maven-frontend-plugin configuration to pom.xml

 <properties>
    <angular.project.location>angular-project</angular.project.location>
    <angular.project.nodeinstallation>node_installation</angular.project.nodeinstallation>
</properties>

 <plugin>
            <groupId>com.github.eirslett</groupId>
            <artifactId>frontend-maven-plugin</artifactId>
            <version>1.0</version>
            <configuration>
                <workingDirectory>${angular.project.location}</workingDirectory>
                <installDirectory>${angular.project.nodeinstallation}</installDirectory>
            </configuration>
            <executions>
                <!-- It will install nodejs and npm -->
                <execution>
                    <id>install node and npm</id>
                    <goals>
                        <goal>install-node-and-npm</goal>
                    </goals>
                    <configuration>
                        <nodeVersion>v6.10.0</nodeVersion>
                        <npmVersion>3.10.10</npmVersion>
                    </configuration>
                </execution>

                <!-- It will execute command "npm install" inside "/e2e-angular2" directory -->
                <execution>
                    <id>npm install</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <configuration>
                        <arguments>install</arguments>
                    </configuration>
                </execution>
                <!-- It will execute command "npm build" inside "/e2e-angular2" directory 
                    to clean and create "/dist" directory -->
                <execution>
                    <id>npm build</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <configuration>
                        <arguments>run build</arguments>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- Plugin to copy the content of /angular/dist/ directory to output 
            directory (ie/ /target/transactionManager-1.0/) -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.4.2</version>
            <executions>
                <execution>
                    <id>default-copy-resources</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <overwrite>true</overwrite>
                        <!-- This folder is the folder where your angular files 
                        will be copied to. It must match the resulting war-file name.
                        So if you have customized the name of war-file for ex. as "app.war"
                        then below value should be ${project.build.directory}/app/ 
                        Value given below is as per default war-file name -->
                        <outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}/</outputDirectory>
                        <resources>
                            <resource>
                                <directory>${project.basedir}/${angular.project.location}/dist</directory>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>

As above plugin call 'npm run build' internally, make sure package.json should have build command in script like below -

package.json

"scripts": {
    -----//-----,
    "build": "ng build --prod",
   -----//------
}

index.html should always be loaded when someone hit application from browser that's why make it a welcome file . For web services lets say we have path /rest-services/* will explain this later.

web.xml -

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

<servlet-mapping>
    <servlet-name>restservices</servlet-name>
    <url-pattern>/restservices/*</url-pattern>
</servlet-mapping>

The above configuration is enough if your application does not have any context path and is deployed on root path on server. But if your application has any context path like http://localhost:8080/myapplication/ then make changes to index.html file as well -

angular-project/src/index.html - Here document.location will be myapplication/ (the context path of your app otherwise / if application has no context path )

The purpose of making context path a base path for angular-app is that whenever you make ajax http call from angular, it will prepend base path to url. for example if i try to call 'restservices/persons' then it will actually make calls to 'http://localhost:8080/myapplication/restservices/persons'

index.html

 <!doctype html>
 <html lang="en">
 <head>
   <meta charset="utf-8">
   <title>E2E</title>
   <script>document.write('<base href="' + document.location + '" />');     </script>

   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
 </head>
 <body>
   <app-root></app-root>
 </body>

After all above changes once you run mvn clean package it will create required war. Check if all the content of angular 'dist' folder is in root of war file.

TimeTraveler
  • 1,223
  • 12
  • 15
  • What does dist folder contain here? – Abhijeet Mohanty Dec 26 '17 at 09:15
  • @abhijeet-mohanty, it is a target directory for build artifact for angular similar to target dir of maven where final war or jar is created. Angular cli transpile all typescript code to JavaScript and put it in dist dir. – TimeTraveler Dec 26 '17 at 14:13
  • Do we need to install Angular first? – Santosh Shelke Jan 16 '18 at 10:10
  • @santosh-shelke This is about how to combine angular cli project inside Java maven project. You should first have Angular cli project itself building and running fine independently. Above process is not necessary if you can deploy angular app and Java web services app seperately. After doing the above setup, running mvn clean package will build a war having Java + angular files in it. You don't need to install node.js and angular packages separately for this because maven front end plugin install node and packages automatically. – TimeTraveler Jan 17 '18 at 16:09
  • What does the "node_installation" folder contains? What files do I need to put in there? – Jack Jul 27 '18 at 15:03
  • 2
    Don't put anything in node_installation folder. It is place holder where nodejs will be downloaded and installed by front-end plugin automatically. You can choose different name but need to mention same name in pom.xml so that plugin can know about it. – TimeTraveler Jul 29 '18 at 04:46
  • Would the files/folders disposition be something like `target/-/dist folder contents` and `target/`? – mutlei Aug 07 '18 at 13:12
  • When I use `clean package`, I have a folder with the appname+version that contains the would be dist folder's contents, and the war file, but the war file doesn't have that folder inside. – mutlei Aug 07 '18 at 13:38
  • I'd also add that you should put a mapping of the desired unpacked war file layout. – mutlei Aug 07 '18 at 16:28
  • check pom.xml for 'maven-resources-plugin' configurations. this plugin decides what goes inside war. the xml tag 'resource/directory' is 'dist' and the tag 'outputDirectory' is '${project.build.directory}/${project.artifactId}-${project.version}/' this becomes target/appname-appversion/. This means content of dist goes into the root of war. you may need to customize this plugin configs to fit as per your requirement. – TimeTraveler Aug 08 '18 at 05:46
  • 'but the war file doesn't have that folder inside.' - yes right, war will not have dist folder in it, content of dist is in root of war like parallel to web-inf. – TimeTraveler Aug 08 '18 at 09:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/177631/discussion-between-mutlei-and-timetraveler). – mutlei Aug 08 '18 at 11:44
  • Hello TimeTraveler, I asked a question (flamant) at the end of your post. Can you take a look at it. Thank you – flamant Sep 09 '18 at 08:26
  • Thanks, this helped me. Only one change, `web.xm` has to be inside `WEB_INF` for me. – adev Jul 18 '19 at 08:03
  • I am getting `Cannot resolve symbol 'install-node-and-npm' ` when adding `` in POM – NoobCoder Jan 14 '20 at 06:34
  • went through the discussion. my package looks fine. i have combined my angular project with a springboot app. Now the the question I have is how do I start the UI? usually we do npm start in local which brings up the UI. how do we achieve it in this setup? – Tushar Banne Jan 20 '20 at 10:20
  • @TusharBanne your springboot app runs on some port. Hit something like this in browser http://localhost:8080/myapplication/ and welcome file will open. – TimeTraveler Jan 21 '20 at 11:48
  • You saved my life – AndresChica Dec 01 '20 at 00:57
0

I have a similar issue : I have a maven web application module named Tourism-Services containing the web services and a maven project containing the angular project (I created the angular project with CLI in the src/main/angular5/tourism folder)

enter image description here

contrary to this post and accordingly to the following link (how to integrate Angular 2 + Java Maven Web Application) that was given by Parth Ghiya, I think that The angular project should be placed in the webapp folder of Tourism-Services module project. Considering this I have further questions :

  1. Normally, all the compilation result in dist folder should be placed under webapp folder. But in dist folder, there are not all the Angular project ressources (as images, css that should be present in angular assets folder, am I right ?)

  2. Considering the angular dependencies that are in node_modules, should we integrate them also in webapp folder ? There is one obstacle : first there are Typescript files and sould be also compiled to be interprated by the server, but maybe there are compiled and added when they are imported in the custom application angular files ? What is the solution ?

  3. Should we includes other type of ressources coming from the angular project in webapp folder ? (like typings folder as suggested Scrambo in the above link post)

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
flamant
  • 733
  • 4
  • 15
  • 41
  • I think you can keep angular project anywhere you want but provide its correct relative path in pom.xml. 1. war plugin picks whatever is inside webapp folder and put it in root of war file. if you put content of dist in webapp then it will go to root of war, in my answer instead of putting dist folder in webapp we are using maven-resources-plugin to copy content of dist folder into root of war. both way you will get same result. the dist folder contains all dependencies including asset folder. 2. As i said dist folder contains all dependencies no need to integrate node_modules. 3.not necessary – TimeTraveler Sep 13 '18 at 04:36
  • Web server will not interpret typescript, angular-cli already transpile it to javascript, css. after that web server only acts a http server which serve javascript and css as static content. – TimeTraveler Sep 13 '18 at 04:40
  • At the end I decided to split my projects in two parts: the first in an ear with jar and war, containing all the backend services (db manager, rest services and so on), the second in an angular project containing all the front end. At the end the first part is deployed in jboss and the second in a normal site (for example apache). I think this is the best solution – Giamma Sep 14 '18 at 14:40
  • @giamma yes that is the best. – TimeTraveler Sep 15 '18 at 03:52
0

I tried those instructions and other articles. those are great however it is a bit ambiguous. So someone who doesn't get it at once .. checks this.

GitHub

Follow the below instructions..

  1. Add your angular project under java project. My angular project name is tdf project structure

2.open app.module.ts (in your angular project/src/app/app.module.ts) Add import and providers

import { LocationStrategy, HashLocationStrategy } from '../../node_modules/@angular/common';

      providers: [
        { provide: LocationStrategy, useClass: HashLocationStrategy },
      ],

3.open package.json (angularproject/package.json) add "build": "ng build --prod" like below

{
  "name": "tdf",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
     **"build": "ng build --prod",** //change like this
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

4.update your pom.xml -add forntend maven plugin -add ng build directory

      <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>angular</groupId>
          <artifactId>angular7java</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <packaging>war</packaging>

          <name>angular7java</name>
          <url>http://maven.apache.org</url>

          <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   
            **<angular.project.location>tdf</angular.project.location>**
            <!--your project name -->
            <angular.project.nodeinstallation>node_installation</angular.project.nodeinstallation>
          </properties>

          <dependencies>
            <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>3.8.1</version>
              <scope>test</scope>
            </dependency>
          </dependencies>

          <build>
           <plugins>    
                <plugin>
                        <groupId>com.github.eirslett</groupId>
                        <artifactId>frontend-maven-plugin</artifactId>
                        <version>1.6</version>
                        <configuration>
                        <workingDirectory>${angular.project.location}</workingDirectory>
                        <installDirectory>${angular.project.nodeinstallation}</installDirectory>
                         </configuration>
                        <executions>
                            <execution>
                                <id>install node and npm</id>
                                <goals>
                                    <goal>install-node-and-npm</goal>
                                </goals>
                                <configuration>
                                   <nodeVersion>v9.9.0</nodeVersion>
                                </configuration>
                            </execution>

                            <execution>
                                <id>npm install</id>
                                <goals>
                                    <goal>npm</goal>
                                </goals>
                                <!-- Optional configuration which provides for running any npm command -->
                                <configuration>
                                    <arguments>install</arguments>
                                </configuration>
                            </execution>

                             <execution>
                            <id>npm build</id>
                            <goals>
                                <goal>npm</goal>
                            </goals>
                            <configuration>
                                <arguments>run build</arguments>
                            </configuration>
                        </execution>

                        </executions>
                    </plugin>

                <!-- Plugin to copy the content of /angular/dist/ directory to output 
                    directory (ie/ /target/transactionManager-1.0/) -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>2.4.2</version>
                    <executions>
                        <execution>
                            <id>default-copy-resources</id>
                            <phase>process-resources</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <overwrite>true</overwrite>
                                <!-- This folder is the folder where your angular files 
                                will be copied to. It must match the resulting war-file name.
                                So if you have customized the name of war-file for ex. as "app.war"
                                then below value should be ${project.build.directory}/app/ 
                                Value given below is as per default war-file name -->
                                <outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}/</outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>${project.basedir}/${angular.project.location}/dist</directory>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
        <!--         <attachClasses>true</attachClasses>
                <webXml>target/web.xml</webXml>
                <webResources>
                    <resource>
                        <directory>src/main/webapp</directory>
                        <filtering>true</filtering>
                    </resource>
                </webResources> -->
            </configuration>
        </plugin>

                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.1</version>
                        <configuration>
                            <fork>true</fork>
                            <executable>C:\Program Files\Java\jdk1.8.0_181\bin\javac.exe</executable>

<!--make sure above directory is correct (make it same as your local javac.exe-->
                        </configuration>
                    </plugin>
            </plugins>
        </build>



        </project>

5. right click your maven project maven - maven install or terminal : mvn clean install

and wait until it stalled. once it installed, you can see node-installation folder and war file are created enter image description here

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Energy
  • 940
  • 13
  • 20
  • can i run any java business logic inside this java project. – Hemanth Poluru Apr 29 '19 at 05:58
  • 1
    @HemanthPoluru Yes, you can. this project is for java and angular . put your java logic in /src (like normal java project). when you get the war file(after maven install), you will see that your java also in there with angular. – Energy May 01 '19 at 11:20
  • can we also use an other routing strategy instead of hash. – Hemanth Poluru May 03 '19 at 14:47
  • 1
    @HemanthPoluru Can, but what you are exactly trying to do ? There are a few ways to integrate java and angular. This answer is to use eirslett pugin but the other way uses another lib. Or you could use spring boot as well(https://dzone.com/articles/angular-7-spring-boot-application-hello-world-exam). – Energy May 04 '19 at 16:26
  • I've a requirement in which I've to connect to an other api, that api doesn't accept routes with '#' in them. Thanks for your quick responses. – Hemanth Poluru May 06 '19 at 05:37
  • i've found out the solution for excluding "#" from the url. follow this link https://stackoverflow.com/questions/41687562/angular-2-remove-hash-from-the-url – Hemanth Poluru May 06 '19 at 12:17
  • I am getting `Element workingDirectory is not allowed here` also same with `` – NoobCoder Jan 06 '20 at 13:22
  • @NoobCoder when did u encounter this? let me take look later – Energy Jan 07 '20 at 04:06
  • Yesterday. let me post a snippet – NoobCoder Jan 07 '20 at 05:56