How to integrate an Angular 4 app with a Spring Boot stack? - java

i would like to integrate an Angular 4 client app with a Java Spring application working on http://localhost:8080/ and offering some Rest endpoints.
My goal is to be able to call the Angular app from a url like http://localhost:8080/adminisitration. How can I do that?
Thanks in advance,

You would need to prod build your ng app and place that in spring-boot folder:
Create a public folder under resources in your spring-boot project
ng build --prod, type this command on you angular project which will create a dist folder under your angular project directory
Copy files from you dist folder and place it in public folder under resources of your spring-boot project.
This will help you run your angular-app under spring-boot.
Then hit http://localhost:8080/adminisitration, it should work fine

There are two ways first is that you serve angular app from your spring boot application as static resources so you need to pack it into jar and that's not easy when you have two different repositories for frontend and backend and doesn't look to good from maintenance point of view.
Second is that you have angular static resources on nginx and spring boot app is reachable to angular thru reverse proxy configured on nginx like
location /api/ {
proxy_pass http://localhost:8080/api/;
}
So when angular asks for GET http://localhost/api/somerest it forwards it to GET http://localhost:8080/api/somerest

The easiest way to serve an angular front-end from a spring-boot application , is to have a multi-module project. Then automate the build process to copy the dist folder from the ui module into the service module during maven clean install itself.This way, you could have a single executable jar that serves the angular as well.For instance, consider the following project structure :
SampleMultiModuleProject
|__SampleMultiModuleService
|__SampleMultiModuleUI
In this case, you will have three different pom files like as follows.
SampleMultiModuleProject main pom.xml : (where all main dependencies are present)
<modules>
<module>SampleMultiModuleUI</module>
<module>SampleMultiModuleService</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
</parent>
//add rest of the dependencies here.
SampleMultiModuleService service pom.xml : (for service module and add the springboot maven plugin to make it executable with embedded tomcat, and add other dependencies that are needed in service module , for instance lombok)
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
and finally configure the ui module to build angular like SampleMultiModuleUI pom.xml :
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.9.1</version>
<configuration>
<workingDirectory>./</workingDirectory>
<nodeVersion>v13.3.0</nodeVersion>
<npmVersion>6.13.1</npmVersion>
<nodeDownloadRoot>http://nodejs.org/dist/</nodeDownloadRoot>
<npmDownloadRoot>http://registry.npmjs.org/npm/-/</npmDownloadRoot>
<installDirectory>./</installDirectory>
<npmInheritsProxyConfigFromMaven>false</npmInheritsProxyConfigFromMaven>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<phase>generate-resources</phase>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm run-script build-prod</id>
<phase>prepare-package</phase>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run-script build</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
So what happens is when you do maven clean install, it will trigger the build of the ui module which in turn uses the frontend builder to install a local npm which runs the command specified in the arguments. The package.json file in your angular application will by default contain something like :
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"stats": "webpack-bundle-analyzer dist/stats.json"
},
So you are essentially calling this ng build --prod through this process.Also in angular.json set the output path as the resources folder under the service module in your project, so that the assets will be created there.
"newProjectRoot": "projects",
"projects": {
"SampleMultiModuleUI": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "../SampleMultiModuleService/src/main/resources/static",
//rest of the config

as i understand your question just create new file named proxy.config.json and paste below code in that file, place file next to .angular-cli.json
{
"/": {
"target": "http://localhost:8080",
"secure": false,
"logLevel": "debug"
}
}
for hitting url to backend server don't use http://localhost:8080/administration instead use /administration as we use http://localhost:8080/ in our proxy file.
in app.component.ts file place below code in ngOnInit()
this.http.get('/adminisitration',someRequestOption).subscribe(res =>{
console.log('happy...!');
})
start backend server: (tomcat on port 8080) and
start frontend server:
ng serve --proxy-config proxy.config.json open browser and type url http://localhost:4200 you will see logs on server and client if any.
NOTE:
above ports are default as provided by spring boot and angular 4

I think best way is to separate angular 4 app and java spring app.
In my case java spring app is API handling all requests from angular 4 app via proxy (angular-cli proxy -> easy to configure).
Angular 4 app on node.js, developed in visual studio code, and java spring on embedded tomcat (undertow) developed in eclipse. They can be on separated servers (eg. my angular 4 app is on localhost:4200 while java spring API is on http://mydomain.ch:8900)
If you need more info then add comment.
Hope in helps
PS. proxy is handled on client side (angular 4 app) not on server side (java spring)

Related

Native Image with Spring Boot 3.0.0 logging trouble

When I start native Image of Spring Boot 3.0.0 spring-boot-starter-web with Docker, it shows strange log messages like this:
:: Spring Boot :: (v3.0.0)
%PARSER_ERROR[d] %PARSER_ERROR[p] 1 --- [%PARSER_ERROR[t]] %PARSER_ERROR[logger] : %PARSER_ERROR[m]%PARSER_ERROR[n]%PARSER_ERROR[d] %PARSER_ERROR[p] 1 --- [%PARSER_ERROR[t]] %PARSER_ERROR[logger] : %PARSER_ERROR[m]%PARSER_ERROR[n]%PARSER_ERROR[d] %PARSER_ERROR[p] 1 ---
Before I tried dependency spring-boot-starter-webflux in this case the build of the native image failed with error:
com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of ch.qos.logback.classic.Logger are allowed in the image heap
With Spring Initializr I generated a new project:
Maven
Java 17
Spring Boot version 3.0.0
Jar
Dependencies: spring-boot-starter-web & lombok
Then I build native Image with Maven "mvn -p native spring-boot:build-image".
I had the expectation, that native Images just work with the new Spring release for simple configuration like the one I made here. Am I missing something or has Spring Boot 3.0.0 big issues in supporting native Images?
At the time when I asked this question, Spring Initializr did not offer (plugin-)dependency "GraalVM Native Support" for Spring Boot 3.0.0.
Now this dependency is available. As confirmed at SpringOne event, it has to be used. After adding it the mentioned errors do not appear. The minimal required part in Maven config is this:
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
You need to make sure you add reachability of metadata goal in your build plugin see github issue
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
<requiredVersion>22.3</requiredVersion>
</configuration>
<executions>
<execution>
<id>add-reachability-metadata</id>
<goals>
<goal>add-reachability-metadata</goal>
</goals>
</execution>
</executions>
</plugin>

How to debug Spring Boot with Netbeans via Maven

After fiddling around for way too long till I got proper debuging setup in Netbeans 8.2 with Spring Boot 1.4.3 I figured I write down my findings as Q&A for others.
The problem is that the default configuration for Netbeans fails to properly launch Spring in debug mode and when you search the internet you only find the outdated information in the Spring docs that won't work.
The solution is simple if you know how. Please find the correct setup instructions below.
Tested and works with Netbeans 8.2 and Spring-Boot 1.4.3:
First of all make sure you have the Spring Maven plugin included (this should be already included when making a new Netbeans Spring project):
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
Also it is a good idea to include the Spring Devtools like this:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
...
</dependencies>
Now navigate to your project settings -> Actions -> Debug project and set the following:
Execute goals:
spring-boot:run
Set properties:
run.jvmArguments=-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address}
jpda.listen=true
Now run your application via the usual debug button and Spring should properly connect to the JVM debugger.
Spring Boot 2.x
To enable Netbeans debugging for a Spring Boot 2.x project (and more specifically version 2.x of the spring-boot-maven-plugin) the procedure is exactly the same, except the run.jvmArguments property name has changed to spring-boot.run.jvmArguments:
spring-boot.run.jvmArguments=-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address}
jpda.listen=true
Testing NetBeans 8.2 and Spring Boot 2.0.1, I was not able to make things work following #TwoThe's instructions. First, I encountered an issue where all I saw was "JPDA Listening Start..." in the output window. To resolve that problem, I added Spring Devtools as an optional dependency. Second, even though debugging appeared to be running okay, the "Debugging" window, which normally displays the list of active threads, was empty and breakpoints that I set were not triggered. Third, attempting to stop the debugging session by pressing the red "Finish Debugger Session" button would not stop the Tomcat server.
Instead of changing the execute goals to "spring-boot:run", I found that it was sufficient to use the default "Debug project" action execute goals:
process-classes org.codehaus.mojo:exec-maven-plugin:1.2.1:exec
.. and properties:
exec.args=-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath ${packageClassName}
exec.executable=java
jpda.listen=true
(As a sidenote, debugging as a regular Java application is apparently the recommended approach to debugging Spring Boot applications in Eclipse; see How to debug Spring Boot application with Eclipse?)
One helpful tip is that if you want to debug using a certain Spring Boot profile, say "debug", you can prepend "-Dspring.profiles.active=debug " to the "exec.args" property. See also: Spring boot running a fully executable JAR and specify -D properties
Tested on NetBeans9
Action: Add any name
Set Properties: select Add> button, select Debug Maven Build
And debug as always -> IDE debug button
If you are still having the problem after applying all above mentioned fixes, remove all your breakpoints and try again.
Window -> Debugging -> Breakpoints -> Delete All Breakpoints
POW
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
buld
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Debug Project
Excute Goals : package
Set Properties:netbeans.deploy.debugmode=true netbeans.deploy=true
Change
Excute Goals : spring-boot:run
Set Properties: spring-boot.run.jvmArguments=-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address}
jpda.listen=true
and Netbeans Press debug project -- not navigator--> spring-boo-run ... What was the difference? spring-boot.run.jvmArguments:

UI code goes missing when deploying to Heroku

I have a Spring-MVC app that uses AngularJS for the front-end and Java in the backend. The java code is in src/main/java and the UI code is in src/main/resources/static. I'm building a fat jar using Maven.
Running locally = everything works.
I can also run the jar from the command line and everything works.
When I deploy to Heroku, the app returns a 404 on / ... it seems like it can't find the UI code anywhere.
I have an identical app with a different (less fancy) AngularJS UI, and it deploys to Heroku without any issues. The only real difference is the UI code exists at the parent src/main/resources/static while my custom app uses gulp - and gulp builds the ui code src/main/resources/static/dist. My Maven POM moves that /dist to target/classes/static when I run the package job, and that's working fine... After mvn clean package I can run my app through IntelliJ or at the command line using java -jar target/blah.jar. But when I push it to Heroku I get an application error, and the Heroku log cites a 404 on path="/".
Note my starting point for these projects was the Stormpath examples for spring-boot-web-angular. The stock example deploys fine with same Procfile, so the only difference is the /dist that my custom UI code has - but Maven should be taking care of that.
My Procfile contains:
web: java $JAVA_OPTS -Dserver.port=$PORT -jar target/*.jar
Pom excerpt that copies the UI code to the right spot in target/:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/static</outputDirectory>
<resources>
<resource>
<directory>src/main/resources/static/dist</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
I've been googling for days and reached out to Heroku support, but they said they can't help.
I can't tell if the Maven piece isn't getting picked up when I git push heroku master (after packing locally), or if I'm missing a config option or something in my Procfile.
Would very much appreciate a pointer in the right direction.

Getting application version from pom

I have a rest endpoint used to return information about application (so far only app version)
But so far this info is hardcoded, and it's pretty easy to forget to change it.
I will be better to retrieve app version from pom or manifest file. Is there any project that brings such functionality?
Spring Boot can refer to the project version defined in pom.xml and expose it via REST using Actuator:
# application.properties
endpoints.info.enabled=true
info.app.version=#project.version#
Then accessing the /info URL (e.g. http://localhost:8080/info) will return:
{"app": {"version": "<major.minor.incremental>"}}
See also: spring boot/spring web app embedded version number
You better use build-in manifest.
new Manifest(Application.class.getResourceAsStream("/META-INF/manifest.mf"))
For the concrete impl-version:
new Manifest(Application.class.getResourceAsStream("/META-INF/manifest.mf"))
.getMainAttributes()
.get(Attributes.Name.IMPLEMENTATION_VERSION)
Using maven do not forget to create the manifest using:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
There is amazing project named Appinfo, please use it and enjoy! (It has an ugly page, I know - but it works :)
AppInfo allows to automatically feed your application with a current version number, build date or build number.
Also excellent Spring Boot Actuator provides feature named Info Endpoint which can publish version information to web or REST.
By default the Actuator adds an /info endpoint to the main server. It contains the commit and timestamp information from git.properties (if that file exists) and also any properties it finds in the environment with prefix "info".
You could use the resource filtering of maven or something like the maven-substitute-plugin.

Injecting Maven project information into Swing Application Framework resources?

I have a Maven project using the Swing Application Framework and would like to inject project information from the pom.xml into my application's global resources to avoid duplication.
The base application (provided via netbeans) uses Application.title, Application.version, Application.vendor, Application.description resources etc for Window titles and about box configuration but I can't find a way to set these values programatically at run time and I'm not a maven maven so don't have the skills to inject them at build time.
Anyone have any recommendations on how best to achieve the desired result?
You could try using filtered resources. If you create a property file, say src/main/resources/com/myapp/app.properties that looks like this:
version=${project.version}
name=${project.name}
id=${project.artifactId}
Them you need to enable filtering in your pom.xml:
<build>
<resources>
<resource>src/main/resources</resource>
<filtering>true</filtering>
</resources>
</build>
Now when maven builds your project, it'll expand the property file, and place it on the classpath. Then you can just call getResourceAsStream("/com/myapp/app.properties") to read it into your app.
Whist maven does automatically create a file /META-INF/maven/$groupId/$artifactId/pom.properties, this may not have all the information you need.
You can keep those in separte property file and read it from both pom.xml and your application.
Another option is to read pom.xml file from classpath (mvn will put it in META-INF folder) and parse it from there as plain xml file.
I would go with first option.
I would try using the maven-antrun-plugin. Pass the necessary maven properties to ant and create an ant build script which modifies an application properties file or the spring context configuration directly.
Another way would be to generate a separate properties file with the properties-maven-plugin and then add this properties file to the application bundle names:
For the pom.xml to write application.properties file:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>write-project-properties</goal>
</goals>
</execution>
</executions>
<configuration>
<outputFile>${project.build.outputDirectory}/application.properties</outputFile>
</configuration>
</plugin>
...
</plugins>
...
</build>
For including the application.properties into your application:
public class MyApplication extends SingleFrameApplication
public MyApplication() {
super();
addGeneratedApplicationProperties();
}
private void addGeneratedApplicationProperties() {
ResourceManager resourceManager = getContext().getResourceManager();
getContext().setApplicationClass(MyApplication.class);
List<String> bundleNames = new LinkedList<String>(resourceManager.getApplicationBundleNames());
bundleNames.add(0, "application");
resourceManager.setApplicationBundleNames(bundleNames);
}
...
}
However, I find the maven-filter-solution way more elegant.

Categories

Resources