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.
Related
I'm building a self contained trading simulator using the quickfix/j library. Up untill now I'd been using mvn package, then the intelli J "Run button" to run my program from an entry point within my client-application class. I tried using the java -jar target/.....1.1.0.jar . and get the following error
java -jar Broker/target/Broker-1.0.0.jar
Error: Could not find or load main class Broker.ClientApplication
Caused by: java.lang.NoClassDefFoundError: quickfix/Application
I thought the error might have something to do with my pom file not fetching a dependecy properly. So to make sure I ran the ordermatch example from the quickfix/J github, but i get a similar error.
java -jar /homes/antonga/IdeaProjects/Desktop/quickfixj-parent/quickfixj-examples/ordermatch/target/quickfixj-examples-ordermatch-2.1.1-sources.jar
no main manifest attribute, in /homes/antonga/IdeaProjects/Desktop/quickfixj-parent/quickfixj-examples/ordermatch/target/quickfixj-examples-ordermatch-2.1.1-sources.jar
To be clear using the Intellli J "Run" button inside the main calss works percfectly even for the ordermacth example. From what I gather the command IntelliJ uses is something like this
"/path/to/java/" "-javagent/.../.jar" "/pathtolocalmavenrepo/quickfix-core.jar "/pathtolocalmavenrepo/anotherquickfixdependecy.jar" ....."more quickfix dependency jar files" packagestructure.Main
I don't see why this would work but my execution wouldn't. I can include my pom files and other info if this would help. I'm also using a multi-module maven project but that doesn't seem to the problem.
Turns out I was beeing a noob. The Maven package lifecycle bundles the specified class files without the dependencies into a jar. I needed to create an uber jar with all the necessary bianries, and then run that. See the SO question create excecutable jar with dependencies using maven
What is required is the following:
java -classpath <list-of-all-jars> <main-class>
Where <list-of-all-jars> is a ; (Windows) or : (*nix) separated list of all jars needed to run your program (quickfixj jars, your own jar and any jars needed), and <main-class> is the fully qualified class name of your main class (the class that has the main entry to your application)
You have to create an executable jar.
You can use Maven to do this. In your pom.xml can use maven-assembly-plugin to generate your executable jar
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>myour.main.Class</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
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)
I am trying to create an RPM package to install a piece of software however whenever I try to build it using the rpm plugin it will run the install script while building which will fail since my machine is not the intended target (nor should it be)
The setup is this
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>2.1.2</version>
<extensions>true</extensions>
<configuration>
<group>Applications/Software</group>
<mappings>
<mapping>
<directory>/tmp/${project.artifactId}</directory>
<filemode>755</filemode>
<username>user</username>
<groupname>group</groupname>
<sources>
<source>
<location>src/main/resources/</location>
</source>
</sources>
</mapping>
</mappings>
<requires>
<require>unzip</require>
</requires>
<preinstallScriptlet>
<scriptFile>src/main/scripts/preinstall.sh</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</preinstallScriptlet>
<installScriptlet>
<scriptFile>src/main/scripts/install.sh</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</installScriptlet>
</configuration>
</plugin>
I have also configured the pom packaging to be rpm and I am running "mvn clean package" to generate the rpm.
This is just a builder project meaning that all it is meant to do is to package all files within src/main/resources in the rpm together with scriptlets which will execute when that rpm is run on some target machine.
Am I missing something?
I am building the rpm on an Ubuntu 14.04 machine with rpmbuild installed
I just read the RPM documentation and found out that this is totally correct. The install scriptlet is called when the RPM is build, what you probably need is a preinstall or postinstall scriptlet. The installation itself (copying the files) is done by RPM.
Reference: http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html
How can I get a Tomcat instance started with tomcat7-maven-plugin on the command line to reload JSPs when I edit and save them in Eclipse? It's of note that I don't want to start Tomcat via Eclipse, as I depend on some Maven plugin executions that m2e doesn't know how to map.
I start Tomcat thusly, on the command line:
mvn clean package -U tomcat7:run-war-only
Here is the configuration of the Tomcat plugin:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<systemProperties>
<spring.profiles.active>local</spring.profiles.active>
</systemProperties>
<path>/</path>
<port>8080</port>
<contextReloadable>true</contextReloadable>
</configuration>
</plugin>
When I change and save a JSP in the source of the project, it'd be lovely if Tomcat could reload that without having to go through a full clean/compile/test/package/start cycle.
This can be done by adding a tomcat server plugin to your eclipse and then deploying your war in tomcat through eclipse and not from command line.
If you do that, when you make any changes in JSP or Java, eclipse auto refreshes your war with out you manually triggering it.
Try
mvn clean package -U tomcat7:run
As run-war-only run a packaged war so won't see your code changes.
if you want debug in your ide use
mvnDebug clean package -U tomcat7:run
Then attach a debugger to port 8000
HTH
How does Heroku calculate slug size?
I was doing a simple Google web toolkit web app. I used Spring Roo to help me with the boiler code and it created a small app "expenses", the same app as showed at Google IO.
To the generated POM.xml file I added a <artifactId>jetty-runner</artifactId> as one do in the spring mvc tutorial for Heroku.
Now when I run git push heroku master in the terminal maven start fetching dependencies on the Heroku side and I get [INFO] BUILD SUCCESS but then Heroku rejects my push.
-----> Push rejected, your compiled slug is 138.0MB (max is 100MB).
See: http://devcenter.heroku.com/articles/slug-size ! Heroku push rejected, slug too large
My generated war file ends up 31Mb when locally created. But the target directory ends up something like the compiled slug size so I added a slugignore file.
$ cat .slugignore
target/*
!target/*.war
Pushed up this to Heroku and it still throws this at me Push rejected, your compiled slug is 138.0MB (max is 100MB).
So my question is Heroku calculate its slug size? I have read their documentation but it's very sparse.
Since this is one of the first links on Google for this, I figured I'd add the solution that I found, via a simple blog post by Chris Auer which details adding a maven plugin execution: http://enlightenmint.com/blog/2012/06/22/reducing-slug-size-for-heroku.html
EDIT: based on oers comment, the highlights from the above link are to declare the maven-clean-plugin in your plugin executions and include the target/ directory (and all subdirectories) while excluding *.war files. The executions phase of that plugin should be invoked on the install phase (not just the clean phase).
In it's entirety (in case that site goes down), it looks about like this:
<plugins>
....
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<filesets>
<fileset>
<directory>target/</directory>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>dependency/*.jar</exclude>
<exclude>*.war</exclude>
</excludes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
</configuration>
<executions>
<execution>
<id>auto-clean</id>
<phase>install</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
....
Slug size from https://devcenter.heroku.com/articles/slug-compiler
Your slug size is displayed at the end of a successful compile. You can roughly estimate slug size locally by doing a fresh checkout of your app, deleting the .git directory, and running du -hsc.
$ du -hsc | grep total