Serving Static resources from file system | Spring Boot Web - spring-mvc

Using a Spring Boot web application I trying to serve my static resource from a file system folder outside my project.
Folder structure looks like:-
src
main
java
resources
test
java
resources
pom.xml
ext-resources (I want to keep my static resources here)
test.js
Spring Configuration:-
#SpringBootApplication
public class DemoStaticresourceApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(DemoStaticresourceApplication.class, args);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/test/**").addResourceLocations("file:///./ext-resources/")
.setCachePeriod(0);
}
}
Hitting 'http://localhost:9999/test/test.js' in my browser gives back a 404.
How should I configure ResourceHandlerRegistry to serve static resources from the above mentioned 'ext-resources' folder?
I should be able to switch cache on/off for dev/prod environment.
Thanks
UPDATE 1
Giving absolute file path works:-
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/test/**")
.addResourceLocations(
"file:///C:/Sambhav/Installations/workspace/demo-staticresource/ext-resources/")
.setCachePeriod(0);
}
How can I provide relative location? Absolute path will make my life tough during build & deploy process.

file:/// is an absolute URL pointing to the root of the filesystem and, therefore, file:///./ext-resources/ means that Spring Boot is looking for resources in a directory named ext-resources in the root.
Update your configuration to use something like file:ext-resources/ as the URL.

This is what I did in the WebConfig class, inside the addResourceHandlers method:
boolean devMode = this.env.acceptsProfiles("development");
String location;
if (devMode) {
String currentPath = new File(".").getAbsolutePath();
location = "file:///" + currentPath + "/client/src/";
} else {
location = "classpath:static/";
}

Spring Boot Maven Plugin can add extra directories to the classpath. In your case you could include that in your pom.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<folders>
<folder>${project.build.directory}/../ext-resources</folder>
</folders>
...
</configuration>
</plugin>
So that way you don't need inlcude any hard-code in your classes. Simply start your webapp with
mvn spring-boot:run

static resources (eg:html js css etc) can be placed in the same level directory of project or jar, named public. contents will be servered without additional config.

Related

spring boot - How to load context configuration file

I am trying to convert spring mvc app to spring boot. I used to deploy this application in tomcat and test. Now with spring boot I am trying to do the same thing but I am facing issues to load xml file configuration.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Data sources -->
<Environment name="/source/schema" value="${schema}" type="java.lang.String" />
<Resource auth="Container" driverClass="org.postgresql.Driver"
factory="org.apache.naming.factory.BeanFactory"
idleConnectionTestPeriod="30" jdbcUrl="${url}"
maxAdministrativeTaskTime="0" maxConnectionAge="30" maxIdleTime="9" maxPoolSize="3" minPoolSize="2"
name="/source/DataSource" password="${password}"
preferredTestQuery="select 1" testConnectionOnCheckout="true" type="com.mchange.v2.c3p0.ComboPooledDataSource" user="${user}"/>
</Context>
This is my configuration file which I am trying to load. When I put
#ImportResource({"classpath:applicationContext.xml", "classpath:context.xml"})
I am able to load all the bean configuration from applicationcontext.xml but while loading context.xml it is giving
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'Context'.
How should I load these entries when deploying spring boot app in tomcat?
By default, JNDI is disabled in embedded Tomcat. You need to call Tomcat.enableNaming() to enable it.
If you can live by Java config,you can try below snippet to add JNDI and other configurations from context.xml using the java config.
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
Example :
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("jdbc/myDataSource");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "your.db.Driver");
resource.setProperty("url", "jdbc:yourDb");
context.getNamingResources().addResource(resource);
}
};
}
#Bean(destroyMethod="")
public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("java:comp/env/jdbc/myDataSource");
bean.setProxyInterface(DataSource.class);
bean.setLookupOnStartup(false);
bean.afterPropertiesSet();
return (DataSource)bean.getObject();
}
Have a look at this github link for related sample
context.xml should go into the /META-INF/ directory in your war files. It is instructions to the Tomcat server, there's no need to configure anything in Spring to try to load it.

Exclude documentation when deploying to production

I have a Web API project in ASP .NET where I have some web services.
I use the comments of the methods to generate the help pages created by default in Visual Studio.
// GET api/version
/// <summary>
/// Test
/// </summary>
/// <returns></returns>
public string Get()
{
return "Last version : 74";
}
It is usefull for a development environment but we don't want these pages to appear on the production environment.
Is there any way to exclude them from deployment on production?
I tried to delete the files and make sure the web services calls still works, they do, but I am not sure of which files I can delete and I am wondering if there is any safer/automatic way to do it?
Here is the list of files I have at the moment :
ApplicationInsights.config
App_Data
Areas
bin
Content
favicon.ico
fonts
Global.asax
Scripts
Views
Web.config
WsCommon.wpp.targets
Publish the web site to a local folder and deploy those contents, they will only contain the essential files.
Deploy that folder, or if possible, just publish to your target site.
I ended up doing the following :
File App_Start/RouteConfig.cs
Ignore the route to the HelpPages in DEBUG Configuration
public static void RegisterRoutes(RouteCollection routes)
{
[...]
#if DEBUG
routes.IgnoreRoute("Help");
#endif
[...]
}
File Global.asax.cs
protected void Application_Start()
{
[...]
#if DEBUG
AreaRegistration.RegisterAllAreas();
#endif
[...]
}
File Controllers/HomeController.cs
Should return a 404 error instead of an index in production :
public ActionResult Index()
{
ViewBag.Title = "Home Page";
#if DEBUG
return View();
#else
return HttpNotFound();
#endif
}
This way, the help pages url return the help pages in Debug and 404 errors in Release. No need to do any further manipulation with the files from

Configure Spring MVC application to make changes to html files/templates without recompiling

I have a very simple Spring 4.0 Boot project. I would like to start the application and be able to make changes to the html files located in /templates/ on the fly, without having to stop and restart the application. Changes to static assets, like java scripts or css files, is no problem.
Below are the details of my program:
There are no XML configuration files. This class is used for configuration.
#Configuration
public class MVCConfiguration extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("assets/**")
.addResourceLocations("classpath:/templates/assets/");
registry.addResourceHandler("/css/**")
.addResourceLocations("/css/");
registry.addResourceHandler("/img/**")
.addResourceLocations("/img/");
registry.addResourceHandler("/js/**")
.addResourceLocations("/js/");
}
}
This is my controller.
#Controller
public class ControlFreak {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String index(){
return "index";
}
}
I have index.html located in templates/
I run the application using this class.
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
What you are trying to achieve is easily done using an IDE and will save a heck of a lot of time during development.
First of all you need to configure Spring Boot to not cache Thymeleaf templates by setting:
spring.thymeleaf.cache=false
Then you just need to start the application using the IDE in debug mode (just Debug the class with the main method) and whenever you make change to a Thymeleaf Template you just need to instruct the IDE to reload the project.
In IntelliJ IDEA, that is done from the Reload Changed Classes option in the Run menu.
I think you can configure Eclipse to automatically update the project on each change, but it's been a while since I have used it.
Path to project
project.base-dir=file:///C:/temp/auth/
Templates reloading during development
spring.thymeleaf.prefix=${project.base-dir}/src/main/resources/templates/
spring.thymeleaf.cache=false
Static resources reloading during development
spring.resources.static-locations=${project.base-dir}/src/main/resources/static/
spring.resources.cache-period=0

How to get the relative path in spring controller to get resources

in my project my file dir is like this -->projectname ->src ->WebContent ->images ->WEB-INF I am using above file path. but I am getting error "The system cannot find the path specified". I want to get the image from the "images" folder. please help me to get the relative path of images folder in Controller. I am using the code File newFile = new File("/./images/userimages/"+fileName);.
Try to use the resource loader from Spring.
public class YourClass implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
resourceLoader.getResource("./images/userimages/" + file);
#Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}

Spring 3.1 ReloadableResourceBundleMessageSource and Apache Tiles 2.2.2

What seemed to be a simple task has turned out to be a few hours of suffering.
I am building a Spring 3.1 MVC application on the JavaEE 6 and Servlet 3.0.1 api without a web.xml file. I have a WebMvcConfiguration class like this fragment:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "be.collectortools.collectorsite")
public class MvcConfig extends WebMvcConfigurationSupport {
#Bean
public ReloadableResourceBundleMessageSource messageSourceBean() {
String[] basenames = {"classpath:messages"};
ReloadableResourceBundleMessageSource resourceBundle = new ReloadableResourceBundleMessageSource();
resourceBundle.setBasenames(basenames);
resourceBundle.setDefaultEncoding("UTF-8");
return resourceBundle;
}
}
I have successfully setup Apache Tiles 2.2.2 together with 2 basic controllers.
Now I would like to add ResourceBundles to the working Spring/Tiles application and I can't get them to work.
After searching I found some this that might go wrong:
Do I use fmt:message key="application.header" or should I use spring:message code="application.header" in my JSP pages? The first ignores not found values the second throws errors.
I use ReloadableResourceBundleMessageSource which should be 'better' or at least newer then ResourceBundleMessageSource is this ok?
ReloadableResourceBundleMessageSource loads files from more locations so I have specified classpath:
I placed the messages.properties file in the src/main/resources folder
Is it still correct that, when not adding a locale to the end of a bundle's name, this is used as a (default) fallback? Either way adding the "en_US" locale doesn't help.
The error:
root cause
javax.servlet.jsp.JspTagException: No message found under code 'application.header' for locale 'en_US'.
org.springframework.web.servlet.tags.MessageTag.doStartTagInternal(MessageTag.java:184)
also the war file is not being run inside Eclipse I deploy it manually to my local tomcat 7.0.23. This also allows me to see the deployed file structure more easily and gives me better control.
I have no clue what is I am doing wrong any help would be appreciated.
The MessageSource bean has to be named messageSource not messageSourceBean - if you change your #Bean to the following it should resolve the messages correctly:
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
String[] basenames = {"classpath:messages"};
ReloadableResourceBundleMessageSource resourceBundle = new ReloadableResourceBundleMessageSource();
resourceBundle.setBasenames(basenames);
resourceBundle.setDefaultEncoding("UTF-8");
return resourceBundle;
}

Resources