Where should I store static resources when I build spring-boot app by gradle? - spring

I've found samples that stores static files in /src/main/webapp/ and /src/main/resources/static/. What's the difference and what's the best place to store static files in spring-boot app?

If your resources are in src/main/webapp that suggests you are building a WAR archive. And for a JAR src/main/resources is more appropriate (eg in /static if it's a boot app). It's up to you though if you want to put stuff in non standard places - you just have to configure the build system to understand what you mean.

Related

How to reduce the size of ear file

The size of my EAR file has reached around 100 MB after adding many exetrnal jars.
Environment : Java Spring/Websphere application server/Maven
Please share the tips to reduce the size of an EAR file.
Seems the exteral jars contribute most to the large size. Is it possible to follow an approach like below, if so how to do that?
Do the maven build with compile scope for large jars
Keep the large sized jars in app server lib, with this will the app take these jars at runtime from appserver?
Thanks
Smitha
You should really review your jars, especially poorly done Maven builds add a lot of unnecessary jars to the application (like jta, servlet, jee-api, etc..), so make sure you don't have them. Sometimes jars are duplicated in every web module you have in the EAR.
Second WebSphere is Java EE 6 server, so it provides lots of common features like JAX-WS, JAX-RS, JPA, etc..., so you should consider using them, before throwing all that as third party libraries in your application.
If you want to use shared library approach, do not put the jars in the server lib folder or server classpath. This is not recommended.
Create Shared library via Environment > Shared libraries see here and assign them to the application.
To reduce the War size you can consider
Static Content :Keep the Static content like images etc out of the war file and refer them via application using references to location.
Shared Libs : if majority of the size is contributed by Shared Libs you can separate that out of war. to do that you can place the war libraries in one of the following locations
a) In Server Lib folder, Not Recommended since different apps might use diff versions.
b) In Server App Lib Folder
b) In a shared folder and including that folder into class path .
c) Use exploded war deployment deploying only changes.

Embedded Tomcat, executable jar, ServletContext.getRealPath()

I'm using a standard spring boot approach (a Java project) where we use embedded Tomcat and package as an executable jar.
I place some static resoures e.g index.html in a static folder under src/main/resources of my project. A library we use expects to load some resources using the servlet context by doing servletContext.getRealPath("XXXX").
When I run this project in Eclipse the real path for servletContext.getRealPath("/") resolves to C:\Users\<me>\workspace\springboot-project\src\main\webapp\. I have no idea why it uses this folder when it does not exist in the project? If I create the executable jar and run this then servletContext.getRealPath("/") gives C:\Users\<me>\AppData\Local\Temp\tomcat-docbase.5693809153072003983.8080\. This directory does exist but has nothing in it.
I can obviously see my resources fine if requested via HTTP I just can't get at them as expected via the servlet context.
Any ideas?
Resources in src/main/resources/static aren't served directly by Tomcat. They're served by Spring through its DispatcherServlet and a ResourceHttpRequestHandler that's auto-configured by Spring Boot. By default, this resource handler is configured to serve resources from the following locations:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
It's 3 that's making your resources in src/main/resources/static available.
Using getRealPath() is always going to be problematic as it requires the resource to be available as a file on the filesystem, i.e. it can't be inside the war or jar that you're running, and there's no guarantee that that will be the case. Using ClassLoader.getResource() or ServletContext.getResource() is a much more robust way to find and load resources within your web application as it doesn't rely on the resource being directly on the filesystem.
You haven't said which library it is that's using getRealPath(). Perhaps it can be updated or be configured to use a different resource loading strategy?

Externalizing static content from a WAR and serve both on jetty

In my project I use Maven to package a web application to a WAR which is later deployed to Jetty using a custom Maven plugin on CentOS. The custom plugin is used by every project that deployes to a production environment. There is now a requirement that all static content (like web site text, properties) is packed outside of the WAR so that it can be changed in production without requiring a new release cycle. I am unsure how to achieve this externalization.
The Jetty server has the directory structure described in Jetty quick start guide. Currently, the web application already offers some .properties files which can be altered externally, and these reside in the resources/ directory. These files are moved here by the custom Maven plugin. The WAR resides in the webapp/ folder. One option for my problem is to use <packagingExcludes> of maven-war-plugin to not include e.g. *.xhtml and *.properties in the WAR. Later, I can use the custom Maven plugin to move excluded files to resources/ directory. But, I have a feeling this is not the correct way to externalize static content... Shouldn't xhtml files live in webapp/ folder while the only the properties file live in resources/ folder?
I have also researched the option of deploying the WAR as exploded, but I am unsure of the implications of such. Clearly, the changes in the exploded WAR files will be overwritten in the next deploy, but the idea is to do static changes both in development and production. Also, I am not sure how to achieve WAR "explosion", is it something that Jetty does for your WAR if configured in jetty.xml or do I have to extract the WAR before deploying?
Lastly, how do people serve static content in Jetty which can be altered in production? Do both the WAR and static files live side by side
The Jetty resources folder should not be used for application files. A J2EE web application (war) should be self-contained -- and in Jetty, reside only on the /webapps folder -- and its only binding to the container (Jetty servlet engine) is via the web.xml deployment descriptor.
Since property files may be read from the classpath and the Jetty resources folder is part of the system classpath, a property file there could be read by the web application class loader. Note that there are other ways to read property files as well and the Jetty resources folder should not be used for application properties. Also, the application may not be portable as other application servers have different forms of webapp classloader isolation.
If the below architecture approach does not work for you, then your only approach would be to expand (explode the war) in the /webapps folder and hope for the best when files are edited.
Tackling this from a different angle,
- if your web application depends on .properties and .xhtml files in order to function properly, then these files are probably not 'content'. The fact that there is a business process that requires them to to be updated ad hoc does not make them content.
- 'content' is something like text, images, and videos that is added, edited and removed by an administrative user. The application does not depend on it for correct execution, it merely reads and passes it on the browser.
Suggestions:
I would suggest that you deploy your application every time there is a change to the .xhtml or .properties files change. If the editors of these files are power business users, you might think of a git push-pull tool for them and a continuous build hook, so that when they make changes and push them to the git repository, the application gets tagged with a newer version and gets built and deployed. If there is a problem (tag not closed in xhtml), then it would be easy to roll back to the last tag.
Alternately, if the changes are minor (such as text descriptions), then modify the application to read them from an arbitrary external file (outside the webapp) -- a location that is provided to the webapp on startup. You can then package a 'default' version of the file in the webapp, but the code would attempt to look in the specified external location first.
I discovered that you can add HTML tags to properties and later use <h:outputFormat> to fetch these properties with parameters. Also, you can do pretty neat stuff with property files as described in MessageFormat API.
My solution was to keep the .xhtml files inside the WAR, but use simple HTML snippets properties from the default resource bundle which is based on a .properties file. These properties were included in the .xhtml using <h:outputFormat>and <h:outputText>. This allows the user to add simple styling like bold and underline to the snippets.
The properties file are copied to the Jetty resource folder using the custom Maven plugin, so I have kept the .properties files in the WAR. For some reason the Jetty resource folder has precedence over the packed .properties files, so this works out fine. Also, as Akber pointed out, I will have the default versions of the properties available if for some reason the WAR was moved to some other application server where the resource folder is not available.
Of course, with this approach the code can break if malformed HTML is placed inside the snippet properties, as pointed out by Akber, but it works for our application as it is very small. I may never have done this if this was a much larger application, but then I might have gone for a database based solution for adding static text (like Joomla/Drupal/Wordpress).

Resource sharing between war files

We've multiple wars being deployed on one server.
The CSS, JS, images, ... are mostly common for all war files.
What is the best way to serve these resources?
Options I've found so far:
Use Maven Overlay plugin (This causes us to loose flexibility of hot-swapping resources in our IDE)
Create a common jar to package in your war (needs Servlet 3.0 api if I'm correct)
Create a war file that contains only resources and that can be deployed on the server as well
If you have may users, then a content delivery network would be an appropriate way to deliver the static files.

Spring Rest Controllers: deployment to Tomcat

I want to develop a RESTful API within my multi-module Spring-based project using Spring Rest. For that purpose, I have a webapp module and some other business/data layer modules. For example, this would be my simplified project structure:
myProject
-- webapp (war-packaged)
-- business (jar-packaged)
-- data (jar-packaged)
Business module depends on data module and so does webapp on business module. Webapp imports successfully every module's application context. Now I want to be able to use some business module classes that do some kind of calculation according to some data retrieved from a DB in order to provide a certain resource. All examples I had a look at were quite simple and this multi-module approach was not covered at all.
What is the problem? As far as I am concerned, Tomcat loads classes in a certain order. Concretely, it first loads WEB-INF/classes and only then WEB-INF/lib (where all webapp dependencies are placed, business module in this case). So, there goes my question. Where should I place my Controller classes? If I place them within the webapp module I won't be able to autowire any business-module bean since Tomcat will throw a ClassNotFoundException when I deploy the webapp war (at least this is the behaviour I have experienced).
The answer is probably easy but I'm quite new to Spring and its world!
Thank you all in advance.
Your business and data jars would go into the WEB-INF/lib directory. Then those jars will automatically be added to the CLASSPATH for your app when you deploy it. You will need to deploy your application as a WAR file.
Ideally, you would build the business and data jars, add them to some repository, and then the build system would pull the proper version of each jar into the WEB-INF/lib directory for you.
And as to the original question, the controller classes go into the webapp/src directory.
Assuming you are using Maven 2. Make sure your assembly creator (e.g. maven war module) is including your dependent .jar files within the final .war file's WEB-INF/lib directory. This should be the default procedure (per: http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html#dependentWarIncludes ). The other concern, then is whether your sub-projects (business and data) are even creating jars so that they could be included in the WAR output.
If you have doubts as to the contents of that war file, browse the listing of it by executing
'jar tvf $WAR_FILENAME' from the command line and by observing the WEB-INF/lib directory contents. You should see your business and data jars in there. Go further by exploding your war file, then browsing the contents of business and data jar (using 'jar xvf $FILENAME' to explode in a new directory).
Hope this helps!

Resources