6

I created a Spring Boot Application using Spring Initilizr. I then included Apache's Freemarker template engine to load the templates from my project. The engine by default loads templates from: src/main/resources/templates/ folder.

I am trying to load a simple index.ftl file as template when the user visits the webpage http://localhost:8080. But I need to load the templates from src/main/webapp/ folder. Whenever I try to load the templates from outside the resources folder, the template engine fails to find the templates.

I have gone through various tutorials and Stack Overflow questions. None answer my question and I'm stuck with a 404 ERROR because the engine is not able to find the files.

The file structure is:

|-src
|---main
|-----java
|-------MainApplication.java
|-------controllers
|---------ViewController.java
|-----resources
|-------static
|-------templates
|-------application.properties
|-----webapp
|-------index.ftl

After a lot of digging, I came across a post where they suggested changing the location where the template engine searches the files. It suggested adding following lines in application.properties:

spring.freemarker.enabled=true
spring.freemarker.template-loader-path=classpath:src/main/webapp/

This doesn't seem to work at all.

I am trying to resolve simple index page when I visit the webpage at http://localhost:8080. I've written following code for mapping the HTTP request in ViewController.java:

@RequestMapping("/")
public ModelAndView home(Model model)
{
    return new ModelAndView("index");
}

No idea if I am totally getting it wrong or I've missed some configuration.

Shivam Naik
  • 115
  • 11
  • Using a source code path (`src`) is pretty much never right (consider, you only deploy a jar or war or ear, neither contains source code). As the file is in the servlet context, certainly you should just use `/` as the template loader path (which usually means servlet context resource, not a classpath resource). – ddekany Jul 09 '19 at 23:03
  • Okay. Thank you.. I'll make changes to the code. Although again, how do I make sure, the context path can be set to point at ```webapps``` folder..?? I know it's silly but truly eating my head.. – Shivam Naik Jul 10 '19 at 02:58
  • In Maven `src/main/webapps` corresponds to the Servlet Context root directory, i.e., that what it copies into the root of the output `war` file (try it if it does). So on runtime its content should be accessible via `ServletContext.getResource`. If the template path doesn't start with an URL scheme (like `classpath:`), for a Spring web application it should default to load from the `ServletContext`, so the path is already relative to the Servlet Context root. Of course it assumes a proper build, and so on, but this is the idea. – ddekany Jul 10 '19 at 06:08
  • Are you using tomcat? Can you add details on deployment – Ori Marko Jul 12 '19 at 10:00
  • do you see a webapps folder in your packaged war ? If yes you could try /webapps/ for the template path. Did you intend to use webapp instead of webapps ? do you use maven war plugin to create war ? – s7vr Jul 12 '19 at 10:26
  • Actually spring by default is using Tomcat for hosting the webpage. Jar file is being created. Do I have to configure it to create war files? I don't see any webapp folder present in JAR file and I don't think I am using a plugin to create a war. The war files are not at all created. Is it what I am missing? – Shivam Naik Jul 12 '19 at 11:10
  • 1
    https://stackoverflow.com/a/55451851/592355 might be helpful/duplication warning!!! – xerx593 Jul 12 '19 at 15:01
  • 1. *outdated* 2. Try `file://` prefix/protocol 3. if all above fails: overwrite the (FreeMarkerConfigurer)bean (as accepted solution in most dups.) – xerx593 Jul 12 '19 at 15:08
  • I'll try with the suggested solutions. Will update if any of the solutions works. – Shivam Naik Jul 12 '19 at 16:51
  • 1
    For spring boot static context use `spring.mvc.static-path-pattern=` see https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html – Ori Marko Jul 12 '19 at 17:01
  • See if this will help? https://stackoverflow.com/questions/53466970/how-to-add-in-spring-boot-project-multiple-local-jars-as-dependency – Tarun Lalwani Jul 12 '19 at 17:36
  • `But I need to load the templates from src/main/webapps/`. Why do you need it? What is the point of doing so? – Nikolai Shevchenko Jul 13 '19 at 08:06
  • I want to segregate the templates, js files and angular part in a seperate webapp folder. – Shivam Naik Jul 13 '19 at 08:50

2 Answers2

1

From Spring docs:

Do not use the src/main/webapp directory if your application is packaged as a jar. Although this directory is a common standard, it works only with war packaging, and it is silently ignored by most build tools when you generate a war.

src/main/webapp is associated with web archive and will be packaged by maven war plugin when you generate the war.

Assuming you require a separate location to keep ftl templates and you would still like to package as jar you could follow below steps.

Add the resource entry in the build in pom file so resource plugin can copy that directory to classpath.

<build>
    <resources>
      <resource>
         <directory>src/main/webapp</directory>
     </resource>
    <resources>
<build>

Change the loader path to read from the ROOT of classpath.

spring.freemarker.template-loader-path=classpath:

If its only for ftl templates I would change the directory to src/main/ftls to avoid confusion and update the same in the resources.

UPDATE

I actually wanted to build a WAR deployment package

You have to use war plugin to build war. Add the plugin and change the packaging to war in pom.

More about the Traditional Deployment: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html#howto-create-a-deployable-war-file

s7vr
  • 73,656
  • 11
  • 106
  • 127
  • Have you tried my answer ? Let me know if you have questions. You should not create a webapp folder for a jar package. That is not a good practice and should be avoided. It makes application look like a war project. You should follow spring boot recommendations and keep all files inside resources folder.Any files under resources is packaged into jar. – s7vr Jul 13 '19 at 10:18
  • I checked your answer and realized I actually wanted to build a WAR deployment package. I have modified my question as well. Thanks for the eye opener. But yet, my template engine is not able to fetch templates from webapp folder. – Shivam Naik Jul 13 '19 at 10:28
  • Np. You have to use war plugin to build war. Add the plugin and change the type to war in pom. – s7vr Jul 13 '19 at 10:29
  • Actually when I checked the structure of the war file createed, I can see index.ftl page in the root of this package. But still it fails to load it when I enter the URL in browser. – Shivam Naik Jul 13 '19 at 10:30
  • Have you tried `spring.freemarker.template-loader-path=classpath:` ? – s7vr Jul 13 '19 at 10:34
  • Thanks a lot buddy. I converted the packaging to WAR. Added ```spring.freemarker.template-loader-path=classpath:``` to application.properties. Then stored ftl files in ```src/main/webapp/resources/``` folder. Everything works perfectly now. – Shivam Naik Jul 13 '19 at 10:46
  • Why not edit your answer based on the changes done? Might help other people facing similar issues. Adding ```webapps``` as folder instead of ```webapp``` was a silly mistake from my side. I've changed the question now. :) – Shivam Naik Jul 13 '19 at 10:47
0

EDIT

In embedded tomcat you can define static resources path in application-properties

 spring.mvc.static-path-pattern=

If you deploy to tomcat, in tomcat use can define inside server.xml static context that can hold freemarker files, as

 <Context docBase="/home/stuff" path="/static" />

A <Context> element is added inside the <Host> element. Context has two attributes: docBase is the directory on disk that contains your static files and path is the URL that you want to serve the files on.

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • Actually I have not installed Tomcat externally. Spring automatically intialises it. So, I am actually not able to find the server.xml file that you mentioned. – Shivam Naik Jul 12 '19 at 16:50
  • @ShivamNaik see options of spring static resources https://www.baeldung.com/spring-mvc-static-resources – Ori Marko Jul 12 '19 at 21:10
  • I'll go through it and respond if it works. Thank-you – Shivam Naik Jul 13 '19 at 08:52
  • Yeah @user7294900. I actually tried the first solution that you gave. Although, it did not solve my problem. But Now It's solved. I've selected the working answer as the right answer above :) – Shivam Naik Jul 15 '19 at 11:15