Load freemarker templates from folder outside of classpath - spring-boot

I'm adding this configuration to my project:
#freemarker
spring.freemarker.prefer-file-system-access=true
spring.freemarker.template-loader-path=/Users/leo/dev/project/templates/
Spring loading tells me the path does not exist, but it does.
2016-12-30 11:47:09.791 WARN 3430 --- [ main] o.s.b.a.f.FreeMarkerAutoConfiguration : Cannot find template location(s): [/Users/leo/dev/project/templates/] (please add some templates, check your FreeMarker configuration, or set spring.freemarker.checkTemplateLocation=false)
If I use the standard configuration it works fine.
#freemarker
spring.freemarker.template-loader-path=classpath:/templates/

can you try with file:/ before adding exact path location
visit here http://www.sandc.software/blog/how-to-load-freemarker-templates-from-external-file-system-folder-with-spring-boot/

Related

Tomcat common class loader not working as expected

I'm trying to build a Docker image of Tomcat that uses Elastic logging. I followed the ECS Logging Java Reference documentation and added the required jars to $CATALINA_HOME/lib, however, it seems that the classes are not loaded by Tomcat.
Tomcat's class loader documentation states the following about the common class loader:
This class loader contains additional classes that are made visible to both Tomcat internal classes and to all web applications.
Normally, application classes should NOT be placed here. The locations searched by this classloader are defined by the common.loader property in $CATALINA_BASE/conf/catalina.properties. The default setting will search the following locations in the order they are listed:
unpacked classes and resources in $CATALINA_BASE/lib
JAR files in $CATALINA_BASE/lib
unpacked classes and resources in $CATALINA_HOME/lib
JAR files in $CATALINA_HOME/lib
If I understand the above correctly, placing the jars in $CATALINA_HOME/lib should be enough for the common loader to find them. However the logging is not formatted by the Elastic formatter.
As a workaround I added a setenv.sh file with a CLASSPATH variable that points to the jars I added. The logging is then printed correctly in ECS format.
Can someone please explain to me how I can get this to work without using the workaround and make use of the common class loader instead?
Below is my Dockerfile:
FROM tomcat:9-jre17
COPY conf/logging.properties conf/logging.properties
COPY lib/ecs-logging-core-1.5.0.jar lib/ecs-logging-core.jar
COPY lib/jul-ecs-formatter-1.5.0.jar lib/jul-ecs-formatter.jar
COPY lib/logback-ecs-encoder-1.5.0.jar lib/logback-ecs-encoder.jar
# Workaround
COPY bin/setenv.sh bin
RUN chmod +x bin/setenv.sh
EXPOSE 8080
CMD ["catalina.sh", "run"]
This is my logging.properties file:
handlers = java.util.logging.ConsoleHandler
.handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = co.elastic.logging.jul.EcsFormatter
co.elastic.logging.jul.EcsFormatter.serviceName = tomcat
java.util.logging.ConsoleHandler.encoding = UTF-8
And this is the setenv.sh file that I use as a workaround, but that I would like to get rid of:
#!/bin/sh
export CLASSPATH="/usr/local/tomcat/lib/ecs-logging-core.jar:/usr/local/tomcat/lib/jul-ecs-formatter.jar:/usr/local/tomcat/lib/logback-ecs-encoder.jar"
The result that I'm expecting looks like this:
{"#timestamp":"2022-11-28T12:29:43.276Z","log.level": "INFO","message":"Server version name: Apache Tomcat/9.0.69","ecs.version": "1.2.0","service.name":"tomcat","event.dataset":"tomcat","process.thread.name":"main","log.logger":"org.apache.catalina.startup.VersionLoggerListener"}
But the result that I'm getting without adding setenv.sh looks like this:
2022-11-28 13:44:20 Nov 28, 2022 12:44:20 PM org.apache.catalina.startup.VersionLoggerListener log
2022-11-28 13:44:20 INFO: Server version name: Apache Tomcat/9.0.69

logging.level.root doesn't work in springboot

I want to setting the default logging level to error on springboot
enter image description here
But the console still has the dubug and info output. It seems that logging.level.root=error doesn't work.
Be carefull if you are using Spring Boot Devtools, the properties defined in $HOME/.config/spring-boot folder will override all other properties as specified in Spring Boot documentation : https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html
I found a environment variable named debug,even though its value is a string not true,which caused the problem.Actually,I tried to remove the variable before,but I didn't restart the eclipse.Now,I remove the varibale named DEBUG and restart the eclipse,and it success.

Spring boot not finding template when deployed on docker

My app works just fine if I run the application on my host using the
mvn spring-boot:run
but when I deploy it on docker, it does not work and I get this error:
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/store/index", template might not exist or might not be accessible by any of the configured Template Resolvers] with root cause org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/store/index", template might not exist or might not be accessible by any of the configured Template Resolvers
but if I go on the url: http:localhost:8080/login which is controlled by spring security, renders the template normally. Seems to be a permission problem but I'm not sure.
here is my Dockerfile:
FROM openjdk
VOLUME /tmp
RUN touch engdevcommerce.jar
COPY target/engdevcommerce.jar engdevcommerce.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/engdevcommerce.jar"]
Solution:
Turns out the problem I was having, had nothing to do with the docker deployment. I ran the jar file on my host, and I was getting the same error.
The problem was that, where I returned the view url at the controllers methods, I was starting with slash like this: "/.../..." . And spring does not load view with double slash when the application is packed as .jar file. I had to remove the slash character at the beginning of the url every where I returned a ModelAndView and at the th:insert tags too on my html files.
this link helped me a lot :
spring-boot-thymeleaf-not-resolving-fragments-after-packaging
Always check the application execution first with 'java -jar your_app_name.jar' command!
In general this issue is mostly resolved by checking following 3 points-
Your application.properties should have the entry-
spring.thymeleaf.prefix=classpath:/templates/
Your controller should return name of the template without any preceding slash. As the thymeleaf configuration is case sensitive.
Your Project should follow standard spring boot thymeleaf directory structure. If not, then make changes accordingly in your application.properties file.
add your local index directory to dockerfile so it will create /store and copy the index directory to /store then your docker vm will have /store/index with the contents from you local index directory
...
...
ADD <local-index-directory> /store
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-
jar","/engdevcommerce.jar"]

Spring Boot: When application.properties and application.yml are loaded by a spring boot application

I wish to log that the application is loading an application-profile.propeties or the application.yml. How to do it. In which method, can i listen to that and detect that it loaded it successfully or it fails.
You could log the loaded property sources by adding a component listening for the ApplicationReadyEvent
#Component
public class LoadedConfigFileListener implements ApplicationListener<ApplicationReadyEvent>, Ordered {
private static final Logger logger = LoggerFactory.getLogger(LoadedConfigFileListener.class);
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
MutablePropertySources propertySources = event.getApplicationContext().getEnvironment().getPropertySources();
Iterator<PropertySource<?>> propertySourceIterator = propertySources.iterator();
propertySourceIterator.forEachRemaining(propertySource -> logger.info("Successfully loaded: \"{}\" into application context", propertySource.getName()));
}
#Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
}
}
If you want to debug loading properties, add following environment variable (command line parameter when launching Java code):
logging.level.org.springframework.core.env=DEBUG
You can see in log lines for example:
2017-05-23 08:37:00.773 DEBUG 26152 --- [ main] o.s.core.env.MutablePropertySources : Adding [applicationConfig: [file:./application.properties]] PropertySource with lowest search precedence
...
2017-05-23 08:37:00.774 DEBUG 26152 --- [ main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'server.port' in [applicationConfig: [file:./application.properties]] with type [String]
...
2017-05-23 08:37:02.087 DEBUG 26152 --- [ main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.datasource.url' in [applicationConfig: [file:./application.properties]] with type [String]
What's wrong with the initial log output of a spring boot app? One of the first 5 lines when I start a spring boot app fresh out of the box is:
2017-05-23 23:09:59 INFO e.r.t.MyApplication - No active profile set, falling back to default profiles: default
That log output tells me the default (application.yml) properties file was loaded. For all profiles that are active, the corresponding properties files will be loaded.
For example, if this was my log output:
2017-05-23 23:14:32 INFO e.r.t.MyApplication - The following profiles are active: cloud, dev, special
then ALL of these properties files would be loaded (Note, you can interchange .properties and .yml):
application.yml
application-cloud.yml
application-dev.yml
application-special.yml
FURTHERMORE, remember that Spring Boot allows property overriding in the order the properties files are read, so the last loaded property file wins. In this case, if I declared a property, call it my.property in all 4 of those above properties files, only the value in application-special.yml would be loaded since it was the last applied profile.
24.4 Profile-specific properties
See the http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-profile-specific-properties
In addition to application.properties files, profile-specific properties can also be defined using the naming convention application-{profile}.properties.
The Environment has a set of default profiles (by default [default]) which are used if no active profiles are set (i.e. if no profiles are explicitly activated then properties from application-default.properties are loaded).
Profile-specific properties are loaded from the same locations as standard application.properties, with profile-specific files always overriding the non-specific ones irrespective of whether the profile-specific files are inside or outside your packaged jar.
If several profiles are specified, a last wins strategy applies. For example, profiles specified by the spring.profiles.active property are added after those configured via the SpringApplication API and therefore take precedence.
Eg: you can set profile name in appliation.properties
spring.profiles.active=dev
so dev profile will be loaded.
https://stackoverflow.com/a/72703413/173149
logging.level:
# For Spring Boot 1.x.x.
"org.springframework.core.env": trace
# For Spring Boot 1.x.x-2.3.x.
"org.springframework.boot.context.config.ConfigFileApplicationListener": trace
# For Spring Boot 2.4.x-3.x.x.
"org.springframework.boot.context.config.ConfigDataEnvironment": trace
Then Spring Framework log it as:
TRACE ...ConfigDataEnvironment
Adding imported property source 'Config resource 'file [application.yml]' via location 'optional:file:./''
TRACE ...ConfigDataEnvironment
Adding imported property source 'Config resource 'class path resource [application-h2-test.yml]' via location 'optional:classpath:/''
TRACE ...ConfigDataEnvironment
Adding imported property source 'Config resource 'class path resource [application.yml]' via location 'optional:classpath:/''

How do I load ${catalina.home}/conf/application.properties in a Spring / Tomcat webapp?

How do I load ${catalina.home}/conf/application.properties in a Spring / Tomcat webapp?
Looking around on StackOverflow and Google I see many discussions which claim it's possible. However, it's just not working for me. In line with the advice from my research my Spring applicationContext.xml file contains the following line:
<context:property-placeholder location="${catalina.home}/conf/application.properties"/>
But I get this in the logs:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/Users/username/Servers/apache-tomcat-6.0.36/conf/application.properties]
From the log entry I can see that ${catalina.home} is expanding correctly. When I expand it by hand in the applicationContext.xml file it returns the same error. The following returns the contents of the application.properties file as expected:
cat /Users/username/Servers/apache-tomcat-6.0.36/conf/application.properties
So the path is clearly correct. Is this a webapp security or Tomcat server configuration issue?
The location of a context:property-placeholder is a Resource, which means that if you provide just a file path (as opposed to a full URL with a protocol) then the path will be resolved against the base directory of the webapp - it is trying to load /Users/username/Servers/apache-tomcat-6.0.36/webapps/<appname>/Users/username/Servers/apache-tomcat-6.0.36/conf/application.properties, which does not exist. If you prefix it with file: it'll work as you require:
<context:property-placeholder location="file:${catalina.home}/conf/application.properties"/>
For annotation based configuration you can use:
#PropertySource("file:${catalina.home}/conf/application.properties")

Resources