Spring Boot - Exploded web application with jar and war packaging

[Updated: Jan 18, 2017, Created: Jan 17, 2017]

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 Project

Dependencies and Technologies Used :

  • spring-boot-starter-web 1.4.3.RELEASE: Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container.
    Corresponding Spring version: 4.3.5.RELEASE
  • spring-boot-starter-tomcat 1.4.3.RELEASE: Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web.
    Corresponding Spring version: 4.3.5.RELEASE
  • tomcat-embed-jasper 8.5.6: Core Tomcat implementation.
  • JDK 1.8
  • Maven 3.3.9

Boot Exploded War Example Select All Download
  • boot-exploded-war
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
        • webapp
          • WEB-INF
            • pages



Web application jar example project

Dependencies and Technologies Used :

  • spring-boot-starter-web 1.4.3.RELEASE: Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container.
    Corresponding Spring version: 4.3.5.RELEASE
  • spring-boot-starter-tomcat 1.4.3.RELEASE: Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web.
    Corresponding Spring version: 4.3.5.RELEASE
  • tomcat-embed-jasper 8.5.6: Core Tomcat implementation.
  • JDK 1.8
  • Maven 3.3.9

Boot Exploded Web Jar Example Select All Download
  • boot-exploded-jar-webapp
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF
            • resources
              • WEB-INF
                • pages

See Also