Chapter 5. A Simple Web Application

Introduction

In this chapter, we create a simple web application with the Maven Archetype plugin. We’ll run this web application in a Servlet container named Jetty, add some dependencies, write a simple Servlet, and generate a WAR file. At the end of this chapter, you will be able to start using Maven to accelerate the development of web applications.

Downloading This Chapter’s Example

The example in this chapter is generated with the Maven Archetype plugin. While you should be able to follow the development of this chapter without the example source code, we recommend downloading a copy of the example code to use as a reference. This chapter’s example project may be downloaded with the book’s example code at http://www.sonatype.com/book/mvn-examples-1.0.zip or http://www.sonatype.com/book/mvn-examples-1.0.tar.gz. Unzip this archive in any directory, and then go to the ch05/ directory. In the ch05/ directory you will see a directory named simple-webapp/ that contains the Maven project developed in this chapter. If you wish to follow along with the example code in a web browser, go to http://www.sonatype.com/book/examples-1.0 and click on the ch05/ directory.

Defining the Simple Web Application

We’ve purposefully kept this chapter focused on Plain-Old Web Applications (POWA)—a servlet and a JavaServer Pages (JSP) page. We’re not going to tell you how to develop your Struts 2, Tapestry, Wicket, Java Server Faces (JSF), or Waffle application in the next 20-odd pages, and we’re not going to get into integrating an Inversion of Control (IoC) container such as Plexus, Guice, or the Spring Framework. The goal of this chapter is to show you the basic facilities that Maven provides for developing web applications—no more, no less. Later in this book, we’re going to take a look at developing two web applications: one that uses Hibernate, Velocity, and the Spring Framework; and the other that uses Plexus.

Creating the Simple Web Project

To create your web application project, run mvn archetype:create with an artifactId and a groupId. Specify the archetypeArtifactId as maven-archetype-webapp. Running this will create the appropriate directory structure and Maven POM:

~/examples$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch05 
                                  -DartifactId=simple-webapp 
                                  -DpackageName=org.sonatype.mavenbook 
                                  -DarchetypeArtifactId=maven-archetype-webapp
[INFO] [archetype:create]
[INFO] ----------------------------------------------------------
[INFO] Using following parameters for creating Archetype: 
           maven-archetype-webapp:RELEASE
[INFO] ----------------------------------------------------------
[INFO] Parameter: groupId, Value: org.sonatype.mavenbook.ch05
[INFO] Parameter: packageName, Value: org.sonatype.mavenbook
[INFO] Parameter: basedir, Value: ~/examples
[INFO] Parameter: package, Value: org.sonatype.mavenbook
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: simple-webapp
[INFO] ********************* End of debug info from resources from 
           generated POM *******
[INFO] Archetype created in dir: ~/examples/simple-webapp

Once the Maven Archetype plugin creates the project, change directories into the simple-web directory and take a look at the pom.xml. You should see the XML document shown in Example 5-1.

Example 5-1. Initial POM for the simple-web project
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook.ch05</groupId>
  <artifactId>simple-webapp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>simple-webapp Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>simple-webapp</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Notice the packaging element contains the value war. This packaging type is what configures Maven to produce a web application archive in a WAR file. A project with war packaging is going to create a WAR file in the target/ directory. The default name of this file is ${artifactId}-${version}.war. In this project, the default WAR would be generated in target/simple-webapp-1.0-SNAPSHOT.war. In the simple-webapp project, we’ve customized the name of the generated WAR file by adding a finalName element inside of this project’s build configuration. With a finalName of simple-webapp, the package phase produces a WAR file in target/simple-webapp.war.

Configuring the Jetty Plugin

Once you’ve compiled, tested, and packaged your web application, you’ll likely want to deploy it to a servlet container and test the index.jsp that was created by the Maven Archetype plugin. Normally, this would involve downloading something like Jetty or Apache Tomcat, unpacking a distribution, copying your application’s WAR file to a webapps/ directory, and then starting your container. Although you can still do such a thing, there is no need. Instead, you can use the Maven Jetty plugin to run your web application within Maven. To do this, we’ll need to configure the Maven Jetty plugin in our project’s pom.xml. Add the plugin element shown in Example 5-2 to your project’s build configuration.

Example 5-2. Configuring the Jetty plugin
<project>
  [...]
  <build>
    <finalName>simple-webapp</finalName>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
      </plugins>
    </plugins>
  </build>
  [...]
</project>

Once you’ve configured the Maven Jetty plugin in your project’s pom.xml, you can then invoke the run goal of the Jetty plugin to start your web application in the Jetty Servlet container. Run mvn jetty:run as follows:

~/examples$ mvn jetty:run
...
[INFO] [jetty:run]
[INFO] Configuring Jetty for project: simple-webapp Maven Webapp
[INFO] Webapp source directory = 
       /Users/tobrien/svnw/sonatype/examples/simple-webapp/src/
       main/webapp
[INFO] web.xml file = 
       /Users/tobrien/svnw/sonatype/examples/simple-webapp/src/
       main/webapp/WEB-INF/web.xml
[INFO] Classes = /Users/tobrien/svnw/sonatype/examples/simple-webapp/
       target/classes
2007-11-17 22:11:50.532::INFO:  Logging to STDERR via 
       org.mortbay.log.StdErrLog
[INFO] Context path = /simple-webapp
[INFO] Tmp directory =  determined at runtime
[INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
[INFO] Web overrides =  none
[INFO] Webapp directory = 
       /Users/tobrien/svnw/sonatype/examples/simple-webapp/src/
       main/webapp
[INFO] Starting jetty 6.1.6rc1 ...
2007-11-17 22:11:50.673::INFO:  jetty-6.1.6rc1
2007-11-17 22:11:50.846::INFO:  No Transaction manager found - if
       your webapp requires one, please configure one.
2007-11-17 22:11:51.057::INFO:  Started [email protected]:8080
[INFO] Started Jetty Server

After Maven starts the Jetty Servlet container, load the URL http://localhost:8080/simple-webapp/ in a web browser. The simple index.jsp generated by the Archetype is trivial; it contains a second-level heading with the text “Hello World!”. Maven expects the document root of the web application to be stored in src/main/webapp. This is the directory where you will find the index.jsp file shown in Example 5-3.

Example 5-3. Contents of src/main/webapp/index.jsp
<html>
  <body>
    <h2>Hello World!</h2>
  </body>
</html>

In src/main/webapp/WEB-INF, we will find the smallest possible web application descriptor in web.xml, shown in Example 5-4.

Example 5-4. Contents of src/main/webapp/WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

Adding a Simple Servlet

A web application with a single JSP page and no configured servlets is next to useless. Let’s add a simple servlet to this application and make some changes to the pom.xml and web.xml to support this change. First, we’ll need to create a new package under src/main/java named org.sonatype.mavenbook.web:

$ mkdir -p src/main/java/org/sonatype/mavenbook/web
$ cd src/main/java/org/sonatype/mavenbook/web

Once you’ve created this package, change to the src/main/java/org/sonatype/mavenbook/web directory and create a class named SimpleServlet in SimpleServlet.java, which contains the code shown in Example 5-5.

Example 5-5. SimpleServlet class
package org.sonatype.mavenbook.web;

import java.io.*;
import javax.servlet.*;                                                         
import javax.servlet.http.*;

public class SimpleServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws ServletException, IOException {
    
        PrintWriter out = response.getWriter();
        out.println( "SimpleServlet Executed" );
        out.flush();
        out.close();
    }
}

Our SimpleServlet class is just that: a servlet that prints a simple message to the response’s Writer. To add this servlet to your web application and map it to a request path, add the servlet and servlet-mapping elements shown in Example 5-6 to your project’s web.xml file. The web.xml file can be found in src/main/webapp/WEB-INF.

Example 5-6. Mapping the simple servlet
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>simple</servlet-name>
    <servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>simple</servlet-name>
    <url-pattern>/simple</url-pattern>
  </servlet-mapping>
</web-app>

Everything is in place to test this servlet; the class is in src/main/java and the web.xml has been updated. Before we launch the Jetty plugin, compile your project by running mvn compile:

~/examples$ mvn compile
...
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to ~/examples/ch05/simple-webapp/target/classes
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Compilation failure

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[4,0] 
  package javax.servlet does not exist

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[5,0] 
  package javax.servlet.http does not exist

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[7,35] 
  cannot find symbol
  symbol: class HttpServlet
  public class SimpleServlet extends HttpServlet {

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[8,22] 
  cannot find symbol
  symbol  : class HttpServletRequest
  location: class org.sonatype.mavenbook.web.SimpleServlet

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[9,22] 
  cannot find symbol
  symbol  : class HttpServletResponse
  location: class org.sonatype.mavenbook.web.SimpleServlet

/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[10,15] 
  cannot find symbol
  symbol  : class ServletException
  location: class org.sonatype.mavenbook.web.SimpleServlet

The compilation fails because your Maven project doesn’t have a dependency on the Servlet API. In the next section, we’ll add the Servlet API to this project’s POM.

Adding J2EE Dependencies

To write a servlet, we’ll need to add the Servlet API as a project dependency. The Servlet specification is a JAR file that can be downloaded from Sun Microsystems at http://java.sun.com/products/servlet/download.html. Once the JAR file is downloaded, you’ll need to install the resulting JAR in your local Maven repository located at ~/.m2/repository. The same process will have to be repeated for all of the Java Platform Enterprise Edition (J2EE) APIs maintained by Sun Microsystems—Java Naming and Directory Interface (JNDI), Java Database Connectivity (JDBC), Servlet, JSP, Java Transaction API (JTA), and others. If this strikes you as somewhat tedious, you are not alone. Lucky for you, there is a simpler alternative to downloading all of these libraries and installing them manually—Apache Geronimo’s independent open source implementations.

For years, the only way to get the Servlet specification JAR was to download it directly from Sun Microsystems. You had to go to the Sun web site, agree to a click-through licensing agreement, and only then could you access the Servlet JAR. This was all necessary because the Sun specification JARs were not made available under a license that allowed for redistribution. Manually downloading Sun artifacts was something you just had to do to write a Servlet or to use JDBC from a Maven project for a few years. It was tedious and annoying until the Apache Geronimo project was able to create a Sun-certified implementation of a number of enterprise specifications releasing these specification JARs under the Apache Software License version 2.0, a license that allows for free redistribution of source and binary. Now, for the purposes of your programming, there is little to no difference between the Servlet API JAR downloaded from Sun Microsystems and the Servlet API JAR implemented by the Apache Geronimo project. Both have passed a rigorous Test Compatibility Kit (TCK) from Sun Microsystems.

Adding a dependency on something like the JSP API or the Servlet API is now very straightforward, and it does not require you to manually download a JAR file from a web site and install it in your local repository. The catch is that you have to know where to look: what groupId, artifactId, and version to use to reference the appropriate Apache Geronimo implementation. To add the Servlet specification API as a dependency to your project’s POM, add the dependency element shown in Example 5-7 to pom.xml.

Example 5-7. Add the Servlet 2.4 specification as a dependency
<project>
  [...]
  <dependencies>
    [...]
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-servlet_2.4_spec</artifactId>
      <version>1.1.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  [...]
</project>

The groupId for all of the Apache Geronimo specification implementations is org.apache.geronimo.specs. The artifactId contains the version of the specification that you are most familiar with; for example, if you were going to include the Servlet 2.3 specification, you would have an artifactId of geronimo-servlet_2.3_spec, and if you were targeting the Servlet 2.4 specification, your artifactId would be geronimo-servlet_2.4_spec. As for the version, you’ll have to take a look at the public Maven repository to figure out which version you should use. For versions, your best bet is going to be the latest version for a particular specification implementation. If you are looking for a specific alternative to a Sun specification from the Apache Geronimo project, we’ve assembled a list of available specifications in Appendix B.

It is also worth pointing out that we have used the provided scope for this dependency. This tells Maven that the JAR is “provided” by the container and thus should not be included in the WAR.

If you were interested in writing a custom JSP tag for this simple web application, you would need to add a dependency on the JSP 2.0 spec. Use the configuration shown in Example 5-8 to add this dependency.

Example 5-8. Adding the JSP 2.0 specification as a dependency
<project>
  [...]
  <dependencies>
    [...]
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-jsp_2.0_spec</artifactId>
      <version>1.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  [...]
</project>

Once you’ve add the Servlet specification as a dependency, run mvn clean install followed by mvn jetty:run.

[tobrien@t1 simple-webapp]$ mvn clean install
...
[tobrien@t1 simple-webapp]$ mvn jetty:run
[INFO] [jetty:run]
...
2007-12-14 16:18:31.305::INFO:  jetty-6.1.6rc1
2007-12-14 16:18:31.453::INFO:  No Transaction manager found - if your webapp 
           requires one, please configure one.
2007-12-14 16:18:32.745::INFO:  Started [email protected]:8080
[INFO] Started Jetty Server

At this point, you should be able to retrieve the output of the SimpleServlet. From the command line, you can use curl to print the output of this servlet to standard output:

~/examples$ curl http://localhost:8080/simple-webapp/simple
SimpleServlet Executed

Conclusion

After reading this chapter, you should be able to bootstrap a simple web application. This chapter didn’t dwell on the million different ways to create a complete web application. Other chapters provide a more comprehensive overview of projects that involve some of the more popular web frameworks and technologies.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.119.170