Spring Boot alternative index page - java

My app uses Spring Boot on the back end and a SPA (Angular) site on the front end. Currently I am serving the index.html page from the webapp folder, which works automatically no configuration needed. Now I integrated a build process for the front end using gulp and all the created sources are "copied" into a build directory. Now I would like to serve the index.html file from the build directory as my main page.
I tried spring.application.index=build/index.htmland some other spring boot settings, but nothing worked. I believe no code is needed from my current code base but if anything is missing let me know.
Is there a way to configure this in the applications.properties file? Do I need to create a controller for the index page? Or is there any other way to change the default behavior?
thanks

Going by the common Spring Boot properties, you should be able to modify this property:
spring.application.index=
Admittedly, I do tend to create a minimal 'home' controller with a #RequestMapping("/") anyway. :)
It's worth noting that the build directory will only be on the classpath if it's under src/main/resources. It's also worth mentioning that the contents of src/main/webapp don't get bundled into the jar automatically. src/main/resources/static is where Spring Boot will look for your static web files. As such, there are a couple of alternatives for you.
Option 1: Configure your Grunt build to output to a directory under src/main/resources/static.
Option 2: Configure your Java build tool to take the Grunt output and put it in your resources directory, so that it's on the classpath. For example, using Maven, the following would move the contents of a directory called build into your src/main/rescources/static.
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</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>build</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

Related

Spring Boot - Host JaCoCo coverage as static HTML

I am working with Spring Boot 2.2.5 and Java 8.
I have a Spring Boot webservice that I deploy and run as a linux service using the embedded Tomcat in Spring Boot.
During my Maven build, I generate code coverage metrics using the JaCoCo Maven plugin, and I would like to package and host these static HTML pages when I deploy to my server.
The output for these files is target/site/jacoco/index.html.
I know that you can deploy and host webpages through Spring Boot, but I have never accomplished it, and everything I lookup online seems to be more complicated than what im actually trying to do. The only thing i seem to have gathered so far, is that it need to get the html into my /resources directory.
Does anyone know how I can package all of the JaCoCo generated html pages into my .jar file, and host it on my webserver so that I can access it in a similar fashion to how I access any other API in the app?
I build and deploy the app with Jenkins. So if there is some nifty Jenkins way of doing it through my Jenkins.groovy script, that would be nice too.
I would like to be able to access something like: localhost:8080/my-app-context/coverage
Well, after some more digging and the right google questions, the solution was simpler than I thought. I stumbled across this article from Baeldung.
The goal:
get target/site/jacoco into the src/main/resources/static directory
get target/apidocs into the src/main/resources/static directory
The challenge:
Do it during a Maven/Jenkins build only.
The solution:
Use a Maven plugin to move the files after successful build
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-javadocs</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources/static/apidocs</outputDirectory> <!-- output directory -->
<resources>
<resource>
<directory>${basedir}/target/apidocs</directory> <!-- source directory -->
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-jacoco</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources/static/jacoco</outputDirectory> <!-- output directory -->
<resources>
<resource>
<directory>${basedir}/target/site/jacoco</directory> <!-- source directory -->
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
After putting the above code in my pom.xml, once the app is deployed to my server, both my JaCoCo coverage and my JavaDoc static html pages can be accessed at:
<context-root>/apidocs/index.html
<context-root>/jacoco/index.html
I hope this simplifies it for others looking to do the same.

Rename application.properties in spring boot, also for use with spring boot test

I have a project that uses Spring Boot. I need to rename the application.properties file to something else (i.e. othername.properties). The reason I need to rename it is because we have a bunch of other scripts that rely on that naming convention.
How can I tell Spring Boot to use othername.properties instead of the default application.properties? The documentation says that I can use the java command and pass an argument when running the application, but that doesn't help when I run a maven > install because there are spring integration/unit tests to be run as well (which rely on the application.properties file db settings).
Right now I have tried to set an environment property in the maven-surefire plugin like so:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<spring.config.name>othername.properties</spring.config.name>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
When I add that in my pom.xml, it seems that Spring Boot isn't picking up that file, and also isn't reading from application.properties (because the db settings are in application.properties as well as othername.properties right now, and it fails, so I know it isn't being read).
The otherfile.properties is in my project's resources folder, should it go somewhere else? Also, how do I specify a relative path to that file if it were to live somewhere else?
Didn't try it, but I think it should be
<systemPropertyVariables> <spring.config.name>othername</spring.config.name> </systemPropertyVariables>
Without .properties

Obfuscating WAR file with Proguard

I want to obfuscate my web application built as WAR archive, as this sensitive application in first time deployed outside our data center. I tried to use the Proguard GUI tool to obfuscate the input war, with all the service jar required for the UI application, with other external dependencies. Though the Proguard runs successfully with some warnings, ex., duplicate definition of library class [javax.servlet.UnavailableException], the output war contains no classes, but has lib with the library jars and web.xml files. Any steps I mess? Any right document on this? I would appreciate if anyone can provide the right document or steps to successfully obfuscate a WAR file with dependent project (a .jar file) and other external jar files (that needs no obfuscation).
you wouldn't obfuscate a war but rather the jars your using. What you can do here is setup your project so the project that makes up the war - configuration xml, WEB-INF content, resources and the web content and servlet definitions and put your java in a library project. Obfuscate the library project and use those obfuscated jars in your web project.
That's what I do, hope it helps.
Protector4j is the best solution to obfuscate the war file, due to graphic user interface its too easy to use and their eclipse plugin is also available.
You will download it from this link
https://doc.protector4j.com/protect-tomcat-web-app
I have done the same way. I used the below url for code obfuscation and i am successful.
http://bratonfire.blogspot.com/2012/01/war-file-obfuscation-using-proguard.html
I created a new folder and redirected output of classes to this folder. But the strange thing is that i am able to see the .java and .class files in the two locations. I am also worried about recreating a war file. can someone mention the clear and detailed steps.
Thanks,
Rahul
We also have the same issue and need to obfuscate all classes packaged in war file.Here is the approach that I followed.
Firstly we need to set order of plugins **(compiler, proguard, war)**declared in pom.xml file as below.
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.14</version>
<configuration>
</configuration>
<executions>
<execution>
<!-- Dont worry about compiler error. For first time, change this value to package so that plugin installs successfully. -->
<phase>process-classes</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warName>mfs-transaction-management</warName>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- Exclude your default packages from war packaging. Do not include "**" in double quotes in actual code -->
<packagingExcludes>
WEB-INF/classes/com/package/mypackage1/"**",
WEB-INF/classes/com/package/mypackage2/"**",
</packagingExcludes>
<webResources>
<webResource>
<directory>${project.build.directory}/proguardClasses</directory>
<targetPath>WEB-INF/classes</targetPath>
</webResource>
</webResources>
</configuration>
</plugin>
</plugins>`
Then create a file proguard.conf under the root of your project at the same level where pom.xml is placed.
Add your own configuration regarding proguard in the file and the add below two lines in this file to tell input and output folder to proguard plugin.
You need to set paths according to your project structure in these lines
-injars 'C:\Users\Rajdeep\git\dfs-core\mfs-transaction-management\target\classes'
-outjars 'C:\Users\Rajdeep\git\dfs-core\mfs-transaction-management\target\proguardClasses'
Apart from this you need to install proguard-base manually in maven repository using mvn install command.
Provide your own groupid, artifact and version and made same changes to pom.
It is proguard.jar found under proguard6.0.3\lib folder when you download proguard manually.
I think everything will be ok and now when you run mvn clean package, your war file should included obfuscated class files.
Use Proguard GUI to obfuscate war files.
Once you run proguardgu.bat or proguardgui.sh file from bin folder of your proguard directory. You can select wars by clicking Input/output menu.

gwt-maven-plugin: webapp structure

I am using gwt-maven-plugin and eclipse to create GWT+Spring webapp. In the end I want to get .war file to be deployed to some application server(tomcat etc). The problem is that the generated .war file has strange structure.
And then I run in on Tomcat the application doesn't work - SimpleGWT.html page has a link to javascript file which does all the job
<script type="text/javascript" language="javascript" src="SimpleGWT/SimpleGWT.nocache.js"></script>
My guess is that since the SimpleGWT.nocache.js in located inside SimpleGWT folder which is not inside WEB-INF - it is not accessible
Is there any way to alter options of gwt-maven-plugin in order to get normal webapp structure? Here is part of my pom.xml
<!-- GWT Maven Plugin -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<!-- Plugin configuration. There are many available options, see
gwt-maven-plugin documentation at codehaus.org -->
<configuration>
<inplace>true</inplace>
<runTarget>SimpleGWT.html</runTarget>
<hostedWebapp>${webappDirectory}</hostedWebapp>
<i18nMessagesBundle>com.javacodegeeks.gwtspring.client.Messages</i18nMessagesBundle>
</configuration>
</plugin>
Its the issue that is mostly related to access static resources in an HTML page.
You are using relative path that does not have a "/" prefix. That is an absolute path
pointing to the root of the web-server.
In Spring MVC application org.springframework.web.servlet.DispatcherServlet is responsible fore serving all the contents for web apps.
What have you defined as url-pattern for above servlet mapping? Please try with *.html or /* as url-pattern.
For more information read about Unable to load java script files in Jetty webapplication.

Using Maven to run a WAR dynamically in Tomcat, how does one add classpath entries so only Tomcat sees them?

Scenario is such: I have a webapp that I'd like to run dynamically with the tomcat-maven-plugin's tomcat:run goal. The wrinkle is that I have numerous classpath resources that need to differ between the packaged artifact and the one run off a local workstation.
Failed Attempts:
1.) My first attempt was to use the builder-helper-maven-plugin, but it won't work because the target configuration files will (inconsistently!) work their way into the packaged WAR archive.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>add-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${testEnv}</directory>
<targetPath>${basedir}/target/classes</targetPath>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
2.) My second attempt was to add the folder (since the files-to-be-deployed aren't present in Tomcat's classpath yet either) to -Djava.ext.dirs, but it has no effect (I actually suspect that this systemProperties element is misconfigured or otherwise not working at all). See:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.0-beta-1</version>
<configuration>
<tomcatWebXml>${basedir}/src/main/mock/web.xml</tomcatWebXml>
<systemProperties>
<property>
<name>java.ext.dirs</name>
<value>${basedir}/src/main/resources-env/${testEnv}</value>
</property>
</systemProperties>
<path>/licensing</path>
</configuration>
</plugin>
I'm not sure what to attempt next. The heart of the problem seems to be that missing in this plugin is something like Surefire's <additionalClasspathElement> element.
Would the next step be to create a custom catalina.properties and add it to a <configurationDir>? If so, what would catalina.properties need to look like?
Edit: More thorough explanation follows
I understand this question reads somewhat vaguely, so I'll try to elaborate a bit.
My POM uses the webResources functionality of the WAR plugin to copy some environment-specific config files and without using a profile to do it, by copying in a resource named /src/main/resources-env/${env} like so:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
...
<configuration>
...
<webResources>
<!-- Copy Environment-specific resources to classes -->
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
This will copy the (default, DEV) environment resources into the package and currently works fine. Note also that b/c these occur as part of packaging, the tomcat:run goal is never privy to them (which is desired, as the environments differ).
So the problem is this: when the dynamic tomcat:run is executed, the application will fail because its classpath (it looks at target/classes) will lack the needed local workstation environmental config files. All I need to do is get those on the path for tomcat, but would like to do so without adding anything to the command line and definitely without breaking the build's integrity if someone follows up with a mvn package and doesn't clean first.
I hope this is more clear.
I may be missing something but why don't you declare the required dependencies in a profile and use this profile when running Tomcat? I don't get why you would need to put these resources at Tomcat's classpath level.
UPDATE: I'm editing my answer to cover the comment from the OP itself answering my question above.
You're correct, the files really need to be in the webapp classpath, not tomcat's. So how could I make a profile that activate automatically for tomcat:run but without additional cmd line args?
I don't know how to do this without declaring the profile as <activeByDefault> or listing it under the <activeProfiles> (but this is not what I had in mind, I would rather use property activation and call something like mvn tomcat:run -Denv=test, not sure to understand why this is a problem).
And how should I "declare the dependencies" in the profile while ensuring that subsequent invocations never let them into the package WAR via a vanilla mvn package
If the previously mentioned profile is active by default, then you'll need to exclude it if you don't want it, by calling something like mvn package -P !profile-1. A profile can't be magically deactivated for one particular goal (at least, not to my knowledge).
Actually, my understanding is that you really have two different context here: the "testing" context (where you want to include more things in the WAR) and the "normal" context (where you don't want these things to be included). To be honest, I don't know how you could distinguish these two situations without specifying any additional parameter (either to activate a profile or to deactivate it depending on the context). You must have valid reasons but, as I said, I don't really understand why this is a problem. So maybe profiles are not a solution for your situation. But I'd really like to understand why because this seems to be a typical use case for profiles :)
UPDATE2: Having read your comment to the other answer and your update, I realize that my initial understanding was wrong (I though you were talking about dependencies in the maven sense). But, I still think that profiles could help you, for example to customize the <resources> as in this blog post (this is just one way to do, using a property like src/main/resources/${env} in the path is another way to go). But this won't solve all your concerns (like not specifying additional command line params or automagically cleaning the target directory). I don't have any solutions for that.
Add the dependencies element directly to the plugin element.
Here is an example of doing the same with the Jetty plugin from the (still in development) Maven Handbook: http://www.sonatype.com/books/mhandbook-stage/reference/ch06s03.html
Vote for http://jira.codehaus.org/browse/MTOMCAT-77 which addresses this need.
Here's the solution I have in place at the moment.
Special thanks to Pascal's diligent conversation here, but I ultimately decided to make a change to how I was loading my environment-specific config files throughout the goals and now I believe I'm getting most of what I initially wanted.
I removed the config files from <webResources> from the WAR plugin and the test config from <testResources> and am now manually managing the resource-copying with the the maven-resources-plugin to copy them directly into target/classes at the goal they're needed. This way Tomcat can see the config, but the tests aren't broken by having duplicate or differing config files on the path.
It's definitely a mess, but it works. Listing:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>copy-env-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-testEnv-resources</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${testEnv}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-env-resources-again</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
So a mvn clean install will build and test with ${env} and ${testEnv} appropriately. A mvn -Denv=someLocalConfig tomcat:run (which in my case is identical to my default ${testEnv} will make sure the src/main/resources-env/someLocalConfig gets loaded for Tomcat's dynamic execution, but without requiring that I do a clean before successfully rebuilding.
Like I said, messy that I'm rewriting the same cluster of files to the same target location at each phase, but it accomplishes what I'd meant to.

Categories