To follow the first part of this tutorial, download our sample Web application archive file cs144.war, copy it to $CATALINA_BASE/webapps in your VM, and access http://localhost:1448/cs144/p1 using your host browser. If you see the following page, you have successfully deployed our sample Web application. (If you get an error, try restarting your Tomcat server.)
Now look at the contents in the the $CATALINA_BASE/webapps directory in your VM. Note that Tomcat has created the cs144 subdirectory (from the cs144.war file that we just copied). For efficiency reasons, when a new application archive is installed, Tomcat by default extracts and "caches" all the files in the archive into the subdirectory of the same name. This way, it can avoid reading the large .war file repeatedly to handle HTTP requests and read only the necessary files in the subdirectory. (Unfortunately, this default "caching" behavior makes it difficult to update an existing application with a new version. If you want to update an existing application, you must replace the old war file with the new one AND delete the subdirectory that Tomcat created.)
Mapping an HTTP request to an application: Since a Tomcat server may host multiple .war files, it uses the URL of an HTTP request to determine which web application should handle it. For example, an HTTP GET request for the the cs144 application we just deployed at http://localhost:1448/cs144/p1 would look something like:
GET /cs144/p1 HTTP/1.1
Since the first URL path component of this request is cs144, Tomcat determines that this request should be handled by cs144.war archive. Similarly, Tomcat will forward all HTTP requests starting with /axis2/ to the axis2.war file that we deployed as part of Project 3.
Structure of a WAR file: We now explain how the rest of the request URL (like /p1 in /cs144/p1) is mapped to a file and/or a Java class in the WAR file. Most web applications consist of a number of "static" files (.html, .jpg, ...) and Java class files (.class). Within a WAR file, all static files are stored at the root directory of a WAR file. As an example, take a look at the files inside our cs144.war file in $CATALINA_BASE/webapps (in principle, you will have to "unzip" the cs144.war file first to see its content, but since Tomcat has already expanded and "cached" its contents in the cs144 subdirectory, you can just look at the cs144 directory instead). You will see two files README.txt and results.jsp in the directory. These static files are accessible simply by appending their names to the URL of the application. For example, the README.txt file can be accessed at http://localhost:1448/cs144/README.txt. Similarly, if there were a file another.html in the subdirectory dir, the file would have been available at http://localhost:1448/cs144/dir/another.html.
Now what about http://localhost:1448/cs144/p1? This URL returns the above configuration page, but you may have noticed that there is no p1 file! The reason why there is no file named p1 is because the page is generated dynamically by a Java class in the WAR file. Then how does the Tomcat server know that /cs144/p1 should be generated by a Java class?
This is where the deployment descriptor file comes in, located at WEB-INF/web.xml
in the WAR file. This XML file is processed by Tomcat automatically when your web application is deployed and describes the important "mapping" information between a URL and the Java class files.
Now open the WEB-INF/web.xml
file. You will see the following content:
<?xml version="1.0" encoding="UTF-8"?> <web-app id="cs144.config" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"> <display-name>CS144</display-name> <servlet> <servlet-name>ConfigurationTest</servlet-name> <servlet-class>edu.ucla.cs.cs144.ConfigurationTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>ConfigurationTest</servlet-name> <url-pattern>/p1</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
The important part is the <servlet>
and <servlet-mapping>
elements. The element <servlet>
connects a Java Servlet class (edu.ucla.cs.cs144.ConfigurationTest) to the servlet named ConfigurationTest. Then the element <servlet-mapping>
maps the servlet ConfigurationTest to the URL pattern /p1. Combined together, the two elements essentially say that requests to this web application at the URL /p1 should be handled by the class edu.ucla.cs.cs144.ConfigurationTest. In a WAR file, all Java class files are placed in the WEB-INF/classes/ directory, so Tomcat will search for
WEB-INF/classes/edu/ucla/cs/cs144/ConfigurationTest.class in the WAR file.
<html> <head><title>Hello World</title></head> <body><h1>Hello World</h1></body> </html>
<web-app id="simple" version="2.4"> <welcome-file-list> <welcome-file>hello.html</welcome-file> </welcome-file-list> </web-app>This descriptor file will make the hello.html page as the "default page" that your application returns.
Since you are not including any servlet classes in the WAR file yet, you can skip steps 4 and 5 below and move directly to step 6.
WEB-INF/classes
folder and copy your servlet classes into it.WEB-INF/lib
folder and place all JAR library files that your servlet code depends on. After these steps, the layout of your temporary folder may look like the following, for example:
simple_temp | +- hello.html | +- WEB-INF +- web.xml | +- lib | +- core-library.jar | +- classes +- edu +- ucla +- hello.class
jar
command to create your WAR file. For example:
jar cfM simple.war *
Follow the above instructions to build your "hello, world" page and web.xml as simple.war file and deploy it by placing the war file into the $CATALINA_BASE/webapps directory of your Tomcat server. Once deployed, point your browser to http://localhost:1448/simple. You should see the "Hello World" HTML page you specified as the welcome-file.
We now implement a very simple servlet and make it available at http://localhost:1448/simple/hello by adding it to simple.war created above. Before you proceed, review the Java Servlet and JSP tutorials.
Notes on CLASSPATH: When you implement a Java servlet,
your code will depend on the Tomcat servlet library,
$CATALINA_HOME/lib/servlet-api.jar. Be sure to
make the library available to your Java compiler
by passing its location with the -classpath option or through an Ant script. Do NOT copy servlet-api.jar
or any of the other standard Tomcat jars into your Web application's WEB-INF/lib
folder. They will already available to your deployed Web Application (all jars in $CATALINA_HOME/lib
are), they will be ignored by Tomcat, and may actually cause classloader problems.
First, create a class which extends javax.servlet.http.HttpServlet, and override the inherited doGet method like the following:
import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class Hello extends HttpServlet implements Servlet { public Hello() {} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>Servlet Example</title></head>"); out.println("<body>Hello from a Java Servlet</body>"); out.println("</html>"); out.close(); } }
By overriding the inherited doGet() method, you can customize what your servlet should do when the Tomcat server forwards an HTTP GET request to the servlet. Modify your web.xml
to include the correct <servlet>
and <servlet-mapping>
elements like the following:
<servlet> <servlet-name>Hello</servlet-name> <servlet-class>Hello</servlet-class> </servlet> <servlet-mapping> <servlet-name>Hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
Build a new simple.war file which now includes your servlet and the web.xml file. Deploy the simple.war, and point your browser to http://localhost:1448/simple/hello. You should see a web page with the HTML content printed in the servlet. Note that by pointing your browser to that URL, you have issued an HTTP GET request, which has been handled by the doGet() method of your Java servlet. Since we're implementing the response to an HTTP GET request, your reply should contain HTML data, which can be written directly into the response parameter as shown above.
As you can see, it is relatively easy to write a Java class which returns HTML. It should also be apparent that returning an entire HTML page with println statements quickly becomes tedious and leads to an unmanageable spaghetti code of Java and HTML. For these reasons (and many others), we strongly suggest the separation of your main application logic from data presentation (this separation is often refered to as the Model-View-Controller design pattern). Although we will not be using a special MVC Java framework for this separation (such as Struts), conceptually you can still think of your Web site as having two distinct layers: a "business logic layer" handled by Java Servlets and a "presentation" layer, which we will handle with JSP.
The "business logic" in our application consists of retrieving the appropriate data for a user query. Once we have this data (e.g. a set of ItemIds and Names), we will forward it along with the request to a JSP page, which is, in some sense, a template HTML page. The JSP page will generate an HTML page using a combination of static HTML content and JSP "scriptlets".
The HTTP GET request issued by your browser was received by your servlet, which executed the doGet method. The last line of doGet forwards the original request object (now updated to include a "title" attribute with value "My Page Title") to the JSP page. The character sequences <%= and %> in the JSP page enclose Java expressions, which are evaluated at run time when the page is returned. Since we set the "title" attribute of request to "My Page Title", the above expression will be evaluated to "My Page Title" and become the title of the page.
This example has shown a simple way (setAttribute
/getAttribute
) to pass (name, value) pairs from a Java servlet (the logic) to a JSP page (the presentation). The "request" HttpServletRequest object is available in both your Java Servlet and in the JSP page, and can be used to pass objects from the servlet to the JSP in these named attributes. In this case, the value was a String, but it can be an arbitrarily complex Java object. The HttpServletRequest also contains information about any parameters sent along with the GET request. For example, if you accessed your servlet as http://localhost:1448/simple/hello?foo=bar
, the "request" object will contain a parameter named "foo" with the value "bar". Take some time to read the Javadoc for HttpServletRequest to learn what methods are available and how you can extract information about the HTTP GET request that your servlet or JSP page received. Make sure you understand the difference between parameters and attributes. Also, make sure to read this JSP tutorial to learn how you can embed Java code in a JSP page
The files that you created as part of this tutorial are included in simple-war.zip. The zip file also includes a build.xml, whose target "build" will create the simple.war file in the current directory using files located in WebContents, src, and lib. Go over the build.xml script to learn how you can use ant to automate the creation of a WAR File.