We have already seen an application's jar in exploded layout here. In this tutorial we are going to understand web application war and jar project's runtime structure. We will walk through an example to understand both cases.
Creating a web application
@SpringBootApplication
public class WarExplodedExample extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure (SpringApplicationBuilder builder) {
return builder.sources(WarExplodedExample.class);
}
public static void main (String[] args) {
SpringApplication.run(WarExplodedExample.class, args);
}
@Controller
public static class MyController {
@RequestMapping("/")
public String handler (Model model) {
model.addAttribute("date",
LocalDateTime.now());
return "myPage";
}
}
}
src/main/webapp/WEB-INF/pages/myPage.jsp
<h2>A JSP page </h2>
<%@ page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html>
<body>
<spring:message code="test.label" arguments="${date}"/>
</body>
</html>
src/main/resources/messages.properties
test.label = Spring boot exploded war example. Date: {0}
src/main/resources/application.properties
spring.mvc.view.prefix= /WEB-INF/pages/
spring.mvc.view.suffix= .jsp
Now we are going to explore both war and jar packaging with above artifacts
Web application in war packaging
pom.xml
<project ......>
<modelVersion>4.0.0</modelVersion>
<groupId>com.logicbig.example</groupId>
<artifactId>boot-exploded-war</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.2.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Project layout before running spring-boot:run
D:\examples\boot-exploded-war>mvn -q clean
D:\examples\boot-exploded-war>tree /A /F
Folder PATH listing for volume Data
Volume serial number is 0000003F 68F9:EDFA
D:.
| pom.xml
|
\---src
\---main
+---java
| \---com
| \---logicbig
| \---example
| WarExplodedExample.java
|
+---resources
| application.properties
| messages.properties
|
\---webapp
\---WEB-INF
\---pages
myPage.jsp
D:\examples\boot-exploded-war>
Running spring-boot:run
D:\examples\boot-exploded-war>mvn -q spring-boot:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.3.RELEASE)
2017-01-17 14:07:16.382 INFO 1772 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2002c257: startup date [Tue Jan 17 14:07:16 CST 2017]; root of context hierarchy
2017-01-17 14:07:17.539 INFO 1772 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-01-17 14:07:17.550 INFO 1772 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-01-17 14:07:17.551 INFO 1772 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
2017-01-17 14:07:17.717 INFO 1772 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2017-01-17 14:07:17.721 INFO 1772 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-01-17 14:07:17.721 INFO 1772 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1341 ms
2017-01-17 14:07:17.881 INFO 1772 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-01-17 14:07:17.886 INFO 1772 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-01-17 14:07:17.887 INFO 1772 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-01-17 14:07:17.887 INFO 1772 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-01-17 14:07:17.887 INFO 1772 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-01-17 14:07:18.147 INFO 1772 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2002c257: startup date [Tue Jan 17 14:07:16 CST 2017]; root of context hierarchy
2017-01-17 14:07:18.197 INFO 1772 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.logicbig.example.WarExplodedExample$MyController.handler(org.springframework.ui.Model)
2017-01-17 14:07:18.199 INFO 1772 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-01-17 14:07:18.200 INFO 1772 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-01-17 14:07:18.222 INFO 1772 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 14:07:18.223 INFO 1772 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 14:07:18.259 INFO 1772 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 14:07:18.383 INFO 1772 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-01-17 14:07:18.445 INFO 1772 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
output
Project layout after running spring-boot:run
Keep the application running. Open a new cmd.exe and check the layout:
D:\examples\boot-exploded-war>tree /A /F
Folder PATH listing for volume Data
Volume serial number is 00000079 68F9:EDFA
D:.
| pom.xml
|
+---src
| \---main
| +---java
| | \---com
| | \---logicbig
| | \---example
| | WarExplodedExample.java
| |
| +---resources
| | application.properties
| | messages.properties
| |
| \---webapp
| \---WEB-INF
| \---pages
| myPage.jsp
|
\---target
+---classes
| | application.properties
| | messages.properties
| |
| \---com
| \---logicbig
| \---example
| WarExplodedExample$MyController.class
| WarExplodedExample.class
|
+---generated-sources
| \---annotations
\---maven-status
\---maven-compiler-plugin
\---compile
\---default-compile
createdFiles.lst
inputFiles.lst
D:\examples\boot-exploded-war>
The 'target' folder is not a standard war layout. There are just our compiled classes and properties files. There's no WEB-INF and it's contents. spring-boot:run plugin is using WEB-INF contents directly from src/main/webapp, and they are not cached as well, that means we can change our .jsp pages during runtime and changes will get updated without restarting the application.
I changed myPage.jsp page to:
<h2>A JSP page </h2>
<%@ page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html>
<body>
<spring:message code="test.label" arguments="${date}"/>
<p>This page can be updated in real time without restarting</p>
</body>
</html>
Now just refresh the page in browser:
Web application in jar packaging
pom.xml
We are just going to change the packing type to jar with a new artifactId, the rest is almost same.
<groupId>com.logicbig.example</groupId>
<artifactId>boot-exploded-jar-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
Location of WEB-INF
With jar packaging, the WEB-INF should be under src/main/resources/META-INF/resources/. We are going to copy our jsp page there. Please check out this tutorial to know the reason why they have to be in the folder we just mentioned.
Project structure before running spring-boot:run
D:\examples\boot-exploded-jar-webapp>mvn -q clean
D:\examples\boot-exploded-jar-webapp>tree /A /F
Folder PATH listing for volume Data
Volume serial number is 00000061 68F9:EDFA
D:.
| pom.xml
|
\---src
\---main
+---java
| \---com
| \---logicbig
| \---example
| JarWebappExplodedExample.java
|
\---resources
| application.properties
| messages.properties
|
\---META-INF
\---resources
\---WEB-INF
\---pages
myPage.jsp
D:\examples\boot-exploded-jar-webapp>
Running spring-boot:run
D:\examples\boot-exploded-jar-webapp>mvn -q spring-boot:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.3.RELEASE)
2017-01-17 15:23:03.224 INFO 7600 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@21f035ef: startup date [Tue Jan 17 15:23:03 CST 2017]; root of context hierarchy
2017-01-17 15:23:04.324 INFO 7600 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-01-17 15:23:04.335 INFO 7600 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-01-17 15:23:04.336 INFO 7600 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
2017-01-17 15:23:04.504 INFO 7600 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2017-01-17 15:23:04.507 INFO 7600 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-01-17 15:23:04.507 INFO 7600 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1286 ms
2017-01-17 15:23:04.626 INFO 7600 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-01-17 15:23:04.630 INFO 7600 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-01-17 15:23:04.631 INFO 7600 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-01-17 15:23:04.631 INFO 7600 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-01-17 15:23:04.631 INFO 7600 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-01-17 15:23:04.871 INFO 7600 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@21f035ef: startup date [Tue Jan 17 15:23:03 CST 2017]; root of context hierarchy
2017-01-17 15:23:04.925 INFO 7600 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.logicbig.example.JarWebappExplodedExample$MyController.handler(org.springframework.ui.Model)
2017-01-17 15:23:04.929 INFO 7600 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-01-17 15:23:04.929 INFO 7600 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-01-17 15:23:04.955 INFO 7600 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 15:23:04.955 INFO 7600 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 15:23:04.993 INFO 7600 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-17 15:23:05.112 INFO 7600 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-01-17 15:23:05.170 INFO 7600 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
Output:
Project structure after running spring-boot:run
D:\examples\boot-exploded-jar-webapp>tree /A /F
Folder PATH listing for volume Data
Volume serial number is 000000F1 68F9:EDFA
D:.
| pom.xml
|
+---src
| \---main
| +---java
| | \---com
| | \---logicbig
| | \---example
| | JarWebappExplodedExample.java
| |
| \---resources
| | application.properties
| | messages.properties
| |
| \---META-INF
| \---resources
| \---WEB-INF
| \---pages
| myPage.jsp
|
\---target
+---classes
| | application.properties
| | messages.properties
| |
| +---com
| | \---logicbig
| | \---example
| | JarWebappExplodedExample$MyController.class
| | JarWebappExplodedExample.class
| |
| \---META-INF
| \---resources
| \---WEB-INF
| \---pages
| myPage.jsp
|
+---generated-sources
| \---annotations
\---maven-status
\---maven-compiler-plugin
\---compile
\---default-compile
createdFiles.lst
inputFiles.lst
D:\examples\boot-exploded-jar-webapp>
As we can see, the META-INF is created in the 'target/classes/' directory. This is maven default functionality, it will copy everything from src/main/resources to target/classes. spring-boot is not modifying that default behavior of maven. This time, of course, if we make changes to jsp pages, the page in web browser won't get updated in real time.
Note that the jar is executable as well. You just need to package it using:
mvn package
and then run:
java -jar target\boot-exploded-jar-webapp-1.0-SNAPSHOT.jar
Web application war example project
Example ProjectDependencies and Technologies Used:- Spring Boot 1.4.3.RELEASE
Corresponding Spring Version 4.3.5.RELEASE - spring-boot-starter-web : Starter for building web, including RESTful, applications using Spring
MVC. Uses Tomcat as the default embedded container.
- spring-boot-starter-tomcat : Starter for using Tomcat as the embedded servlet container. Default
servlet container starter used by spring-boot-starter-web.
- tomcat-embed-jasper 8.5.6: Core Tomcat implementation.
- JDK 1.8
- Maven 3.3.9
|