Building a web application is not too much different to working with other types such as JARs in Maven. You still create a project descriptor, add your source code and resources, and build an archive to finish.
However, a few extra steps must be taken to create the appropriate web application structure.
The first step is to add the web application contents. Unlike a JAR, resources are not included in the root of
the WAR - they will be located in /WEB-INF/classes
, as the purpose of the resources is to make
them available in the classloader inside the application.
To include the contents of your web application (JSPs, images, etc., as well as some of the contents of
WEB-INF), create a directory called src/main/webapp
. These will all reside in the base of the web
application when it is packaged up.
To configure the web application to use these resources, set the property:
maven.war.src=${basedir}/src/main/webapp
You can include whatever you like in this structure, including a WEB-INF
directory and anything
underneath it. However, you should not have a /WEB-INF/classes
or /WEB-INF/lib
directory as Maven will populate this from your project.
As mentioned, resources and classes will be compiled and copied into the /WEB-INF/classes
directory. The lib
directory is populated from the project's dependency list, as shown in the
next section.
Since Maven requires that you declare all of the dependencies of your project, it is quite easy to also set
up the lib
directory in your web application.
Note however, libraries are not bundled into the web application by default - you must list those that you want included. This is quite simple to do, by adding a property to those dependencies that are required in the WAR:
<dependency> <groupId>mycompany</groupId> <artifactId>mycompany-utils</artifactId> <version>1.0.0</version> <properties> <war.bundle>true</war.bundle> </properties> </dependency>
There are two particular goals that are used to build a web application: war:webapp
and
war:war
.
The first builds an unpacked directory structure in the target
directory
that is the same as it would be exploded into an application server. This can be most effective for deploying
directly into an application server with reloading enabled in the development environment so that
reconstructing the WAR in this directory after making changes will be loaded.
The second will build a .war
archive which is later deployed into the servlet container as is.
To automatically deploy into a servlet container will rely on scripting up the appropriate goals or locating an existing plugin for the container. There is currently one available for JBoss - see the JBoss Plugin. Tomcat also has several deployment Ant tasks which can easily be used from Maven.
If you would like an example, please refer to
The simple-webapp
example project.
For more information on goals and configuration, see the WAR plugin reference.
How to precompile JSPs is a common question when developing Web Applications, as doing so can bring a performance boost to the first time deployment of your application in a production environment.
The following code snippet can be used in maven.xml
if you are using a Tomcat 4.1 based
servlet container. It should also serve as a starting point for implementing a similar task for other containers.
<preGoal name="war:webapp"> <j:set var="precompileJsp" value="${precompile.jsp}"/> <j:if test="${precompileJsp == 'true'}"> <attainGoal name="precompile-jsp"/> </j:if> </preGoal> <postGoal name="war:webapp"> <j:set var="precompileJsp" value="${precompile.jsp}"/> <j:if test="${precompileJsp == 'true'}"> <maven:set var="target" property="maven.war.webapp.dir" plugin="maven-war-plugin" /> <util:available file="${maven.build.dir}/web-fragment.xml"> <util:loadText var="fragment" file="${maven.build.dir}/web-fragment.xml"/> <ant:replace file="${target}/WEB-INF/web.xml" token="<!-- [INSERT FRAGMENT HERE] -->" value="${fragment}"/> </util:available> </j:if> </postGoal> <goal name="precompile-jsp" description="Precompile all JSPs into java classes, and then into classes" prereqs="war:load,java:compile"> <maven:set var="warSource" property="maven.war.src" plugin="maven-war-plugin" /> <ant:mkdir dir="${maven.build.dir}/jspc"/> <ant:mkdir dir="${maven.build.dir}/jspc-processed"/> <ant:mkdir dir="${maven.build.dir}/jspc-classes"/> <j:set var="jspOutDir" value="${maven.build.dir}/jspc"/> <j:set var="jspClassesOutDir" value="${maven.build.dest}"/> <ant:path id="jspc.classpath"> <ant:pathelement location="${tomcat.home}/common/lib/jasper-runtime.jar"/> <ant:pathelement location="${tomcat.home}/common/lib/jasper-compiler.jar"/> <ant:pathelement location="${tomcat.home}/common/lib/servlet.jar"/> <ant:path refid="maven.dependency.classpath"/> <ant:pathelement path="${maven.build.dest}"/> </ant:path> <ant:taskdef name="jasper2" classname="org.apache.jasper.JspC" classpathref="jspc.classpath"/> <ant:jasper2 webXmlFragment="${maven.build.dir}/web-fragment.xml" package="${pom.package}.jsp.${pom.artifactId}" outputDir="${jspOutDir}" srcdir="${warSource}" uriroot="${warSource}" uribase="/${pom.artifactId}" verbose="2"/> <ant:javac srcdir="${jspOutDir}" destdir="${jspClassesOutDir}" debug="${maven.compile.debug}" deprecation="${maven.compile.deprecation}" optimize="${maven.compile.optimize}" classpathref="jspc.classpath"/> </goal>
To execute this code, set the precompile.jsp
property to true
. When building the web
application, the JSPs will be compiled and added to the generated WAR file.
These servlets will not be utilised by Tomcat by default. To do so, you must include them in the
web.xml
file. The script above does this, as long as you include the following comment in your
web.xml
file in between the last servlet
and first servlet-mapping
declaration:
<!-- [INSERT FRAGMENT HERE] -->