Servlet

What is Servlet?

Servlet is a Java-based technologies for creating programs such as bulletin boards. Just as the java.sql package is called JDBC, the javax.servlet and javax.servlet.http packages are called Servlet. Servlet is designed to be independent of the network protocol, but it is mostly used to create dynamic content in the HTTP protocol environment. JSPs can easily make the application element corresponding to the screen than Servlet. When you learn Servlet, it is a good start to first learn the basic structure of Servlet.

The basic structure of Servlet

The basic structure of Servlet consists of:

  • The javax.servlet.Servlet interface that all servlets must implement.
  • Javax.servlet.GenericServlet abstract class which most servlets inherit.
  • The javax.servlet.http.HttpServlet class that the servlets that use the HTTP protocol inherit.

As shown in the figure1 below, GenericServlet implements the javax.servlet.ServletConfig interface for programmers' convenience.
Servlets Framework

Servlet Interface

The javax.servlet.Servlet interface is the heart of the servlet architecture. All servlets must implement this Servlet interface. Servlet lifecycle methods are declared in the body of the servlet interface.

  • init(): initializes a servlet.
  • service(): services to client requests.
  • destroy(): stops service, returns resources.

init()

The servlet container calls the init() method once after the servlet object is created. The servlet can be serviced only when the init() method completes without errors. The request before the init() method completes is blocked. When the init() method is called, it receives the object of the ServletConfig interface type as argument, If you set the Servlet initialization parameters in web.xml, this ServletConfig will have the Servlet initialization parameters information set in web.xml. If there are the Servlet initialization parameters, then the init() method should have code to do the initialization of the servlet.

void init(ServletConfig config) throws ServletException;

service()

Each time a client sends a request to a servlet, the servlet container calls the service() method of the servlet. The service() method reads the request information using an object of the ServletRequest type, which is the first argument, and responds to the client using an object of the ServletResponse type, which is the second argument. Note that the servlet container executes the service() method on the new thread whenever the client requests it. The service() method runs simultaneously on a separate thread, so it can respond to a large number of client requests without delay. However, critical section problems can arise with the resources that the servlet uses (eg, files, network connections, static variables, instance variables, etc.). Therefore, it is best not to create static or instance variables that can cause problems with your servlets. Synchronizing the resources used by the servlet is not good code in most cases.

void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

destroy()

It is called by the servlet container when the servlet should no longer be serviced. This method is not what the programmer calls in code. To call destroy(), you must use the "Tomcat manager" to unload the application or shut down Tomcat. Tomcat manager is a web application that can be accessed at http://localhost:8080/manager. It is the web application that manages web applications. To view the Tomcat Manager screen, you must log in using the administrator and administrator password you set when installing Tomcat. If you do not remember your administrator and Administrator password, open CATALINA_HOME/conf/tomcat-users.xml and you'll see it.

void destroy();

GenericServlet abstract class

Most servlets inherit the GenericServlet class. The GenericServlet class implements the ServletConfig interface. GenericServlet implements the Servlet interface incompletely. Because GenericServlet does not implement the service() method of the Servlet interface, GenericServlet's service() method is an abstract method, so GenericServlet is an abstract class. Subclasses that inherit GenericServlet must implement the service() method.

public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

The init(ServletConfig config) method is implemented in GenericServlet as follows:

public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}

The init(ServletConfig config) method calls the init() method with no parameters on the last line. The parameterless init() method was added to the GenericServlet for convenience, This method has nothing in the method body as shown below.

public void init() throws ServletException {

}

It is convenient to override this method rather than overriding the init(ServletConfig config) method in the sub class. This is because you do not have to worry about storing the ServletConfig object. When overriding the init(ServletConfig config) method in a sub class, you need to add super(config); code on the first line. Without this code, the servlet will not store ServletConfig objects.

The init(ServletConfig config) method saves the ServletConfig object received as an argument in the instance variable config. The getServletConfig() method of GenericServlet returns this config.

public ServletConfig getServletConfig() {
	return config;
}

The getServletContext() is method of ServletConfig interface. GenericServlet implements ServletConfig interface. The getServletContxt() method of GenericServlet returns an object of type ServletContext as shown below.

public ServletContext getServletContext() {
	return getServletConfig().getServletContext();
}

The getInitParameter() and getInitParameterNames() methods of the ServletConfig interface are implemented as follows in the GenericServlet.

public String getInitParameter(String name) {
	return getServletConfig().getInitParameter(name);
}
public Enumeration getInitParameterNames() {
	return getServletConfig().getInitParameterNames();
}   

It is for the convenience of the programmer that GenericServlet implements ServletConfig. Let's look at examples. It is convenient to use this.getServletContext(); rather than this.getServletConfig().GetServletContext(); to get a reference to a ServletContext object in a servlet. It is convenient to use String driver = this.getInitParameter("driver"); rather than String driver = this.getServletConfig().GetInitParameter("driver"); to get servlet initialization parameter information.

HttpServlet class

A servlet servicing an HTTP request must inherit HttpServlet. The HttpServlet class inherits the GenericServlet abstract class and is a servlet specific to the HTTP protocol. The HttpServlet class provides methods for handling HTTP requests. The client's request is passed to the servlet as the HttpServletRequest object type, and the servlet responds using the HttpServletResponse object type. The HttpServlet class implements the GenericServlet's service() abstract method by simply calling the protected void service (HttpServletRequest req, HttpServletResponse resp) method.

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
	
	HttpServletRequest  request;
	HttpServletResponse response;
	
	try {
		request = (HttpServletRequest) req;
		response = (HttpServletResponse) res;
	} catch (ClassCastException e) {
		throw new ServletException("non-HTTP request or response");
	}
	
	service(request, response);
}

Eventually, the following method handles the HTTP request.

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	String method = req.getMethod();

	if (method.equals(METHOD_GET)) {
		long lastModified = getLastModified(req);
		if (lastModified == -1) {
			// servlet doesn't support if-modified-since, no reason
			// to go through further expensive logic
			doGet(req, resp);
		} else {
			long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
			if (ifModifiedSince < (lastModified / 1000 * 1000)) {
				// If the servlet mod time is later, call doGet()
				// Round down to the nearest second for a proper compare
				// A ifModifiedSince of -1 will always be less
				maybeSetLastModified(resp, lastModified);
				doGet(req, resp);
			} else {
				resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			}
		}
	} else if (method.equals(METHOD_HEAD)) {
		long lastModified = getLastModified(req);
		maybeSetLastModified(resp, lastModified);
		doHead(req, resp);
	} else if (method.equals(METHOD_POST)) {
		doPost(req, resp);
	} else if (method.equals(METHOD_PUT)) {
		doPut(req, resp);
	} else if (method.equals(METHOD_DELETE)) {
		doDelete(req, resp);
	} else if (method.equals(METHOD_OPTIONS)) {
		doOptions(req,resp);
	} else if (method.equals(METHOD_TRACE)) {
		doTrace(req,resp);
	} else {
		//
		// Note that this means NO servlet supports whatever
		// method was requested, anywhere on this server.
		//
		String errMsg = lStrings.getString("http.method_not_implemented");
		Object[] errArgs = new Object[1];
		errArgs[0] = method;
		errMsg = MessageFormat.format(errMsg, errArgs);

		resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
	}
}	

The only thing the HttpServlet's +service() method does is call the #service() method. (Where + denotes the public access modifier and # the protected access modifier) When the #service() method of the HttpServlet class is called, this method reads the HTTP METHOD (eg, POST, GET etc.) in the request object (an object of type HttpServletRequest) and calls the matching method according to this value. For example, if the HTTP method is "GET", it calls doGet() and if it is "POST" it calls the doPost() method. Methods like doGet() and doPost() are the methods we need to override. The HttpServletRequest interface inherits the ServletRequest interface. The HttpServletResponse interface inherits the ServletResponse interface. When a client's request comes in, the servlet container creates an object of type HttpServletRequest and an object of type HttpServletResponse and passes them as the argument values to the servlet's +service(ServletRequest req, ServletResponse res) method. Making classes that implement the HttpServletRequest and HttpServletResponse interfaces is the responsibility of the vendor making the servlet container.

Summary of Servlet API

Servlet Interface
init(ServletConfig config)
service(ServletRequest req, ServletResponse res)
destroy()
getServletConfig():ServletConfig
Returns a ServletConfig object that contains variables related to servlet initialization
getServletInfo():String
Return simple information about the servlet
ServletConfig Interface
getInitParameter(String name):String
Returns the initialization parameter value corresponding to name
getInitParameterNames():Enumeration
Return all servlet initialization parameter names as Enumeration type
getServletContext():ServletContext
Return ServletContext
getServletName():String
Return the name of the servlet instance
+GenericServlet Abstract class
This class provides basic services that are protocol independent. This class implements the Servlet, ServletConfig interface.
+init()
Servlet initialization method, which is called by GenericServlet's init(ServletConfig config) method
<<abstract>> +service(ServletRequest req, ServletResponse res)
The GenericServlet abstract class still does not implement the service() method of the Servlet interface.
HttpServlet Abstract class
Inherits GenericServlet.
#doGet(HttpServletRequest req, HttpServletResponse resp)
Method to handle HTTP GET requests
#doPost(HttpServletRequest req, HttpServletResponse resp)
Method to handle HTTP POST
+service(ServletRequest req, ServletResponse res)
This method overrides GenericServlet's abstract method service(). This method does nothing other than call the #service() method.
#service(HttpServletRequest req, HttpServletResponse resp)
Call one of doGet(req, resp), doHead(req, resp), doPost(req, resp), doGet(req, resp), doDelete(req, resp), doOptions(req, resp), doTrace(req, resp) according to the HTTP METHOD.
ServletContext Interface
This interface provides methods that the servlet uses to communicate with the servlet container. It also provides functions to get the MIME type of the file, the full path of the file, the RequestDispatcher reference, or log the log file. There is one ServletContext object for each Web application, which serves as a common repository for the dynamic components that make up the Web application. In other words, the data stored in the ServletContext is freely accessible from servlets or JSPs within the same web application.
setAttribute(Strng name, Object value)
Stores the data as a name-value pair.
getAttribute(String name):Object
Returns the data with the given name.
removeAttribute(String name)
Removes the data with the given name.
getInitParameter(String name):String
Returns the value of the web application initialization parameter with the given name.
getRequestDispatcher(String path):RequestDispatcher
Returns a RequestDispatcher object for the resource located at the given path.
getRealPath(String path):String
Returns the real path for a given virtual path.
getResource(String path):URL
Returns a URL to the resource that is mapped to a specified path.
RequestDispatcher Interface
It is used to pass a client's request to another resource (servlet, JSP) or to include the contents of another resource in a response.
forward(ServletRequest req, ServletResponse res)
Forward the client's request to another resource.
include(ServletRequest req, ServletResponse res)
Include the contents of other resources in the response.
ServletRequest Interface
Contains client request information.
setAttribute(String name, Object o)
Stores the data as a name-value pair.
getAttribute(String name):Object
Returns the stored data with the given name.
removeAttribute(String name)
Removes the stored data with the given name.
getInputStream():ServletInputStream
Returns an input stream to read the binary data in the body of the request
getParameter(String name):String
Returns the value of the HTTP parameter with the given name
getParameterNames():Enumeration
Return all HTTP parameter names as an Enumeration type
getParameterValues(String name):String[]
Returns all the values of the HTTP parameter with the given name as a String array. Used when there are multiple values in a single HTTP parameter, such as a checkbox or a multiple-selection list.
getServletPath():String
Returns the path starting with "/". The returned path does not include the query string.
getRemoteAddr():String
Returns the client's IP address.
HttpServletRequest Interface
Inherits ServletReqeust.
getCookies():Cookie[]
Returns an array of cookies passed by the browser
getSession():HttpSession
Returns current session (HttpSession).
getSession(boolean created):HttpSession
Returns current session. If the session is not created, if the created is true, the session is created and returned. If the created is false, the null is returned.
getContextPath():String
Returns the part of the request URI that points to the context. If you request http://localhost:8080/contextPath/board/list.jsp?page=1, it will return "/contextPath".
getRequestURI():String
If you request http://localhost:8080/ContextPath/board/list.jsp?page=1, it will return "/ContextPath/board/list.jsp".
getQueryString():String
If you request http://localhost:8080/ContextPath/board/list.jsp?page=1, it will return "page=1".
ServletResponse Interface
Used to send responses to clients.
getOutputStream():ServletOutputStream
Returns an output stream to send binary data in response.
getWriter():PrintWriter
Returns an output stream to send character data in response.
setContentType(String type)
Used to set the MIME type of response data. (For example, if the response data is HTML, set MIME to text/html, if plain text, set MIME to text/plain, if binary data, set MIME to application/octet-stream. Should be called before the getWriter() method)
getContentType():String
Return the MIME type specified by the setContentType() method Returns null if not specified
setCharacterEncoding(String charset)
Set the character set of response data. To set it to UTF-8, code as setCharacterEncoding ("UTF-8");. SetCharacterEncoding("UTF-8"); is equivalent to charset=UTF-8 in setContentType("text/html; charset=UTF-8"); in JSP code. Should be called before the getWrite() method is executed.
getCharacterEncoding():String
Returns the character set of the response data. Returns "ISO-8859-1" if no character set is specified.
setContentLength(int length)
Sets the size of the response data to an int value. Can be used to indicate to what extent the client is downloading the response data from the server.
HttpServletResponse Interface
Inherits the ServletResponse interface. Used to send an HTTP response to the client.
addCookie(Cookie cookie)
Adds a cookie to the response.
sendRedirect(String location)
Redirects to the given URL.
HttpSession Interface
Used to store user information needed for session maintenance on the server side.
getAttribute(String name):Object
setAttribute(String name, Object value)
removeAttribute(String name)
invalidate()
Cookie
Cookies are the information stored on the client side for session maintenance. To maintain the session, the web browser adds this cookie information to the request whenever it sends a request to the server that sent the cookie. Cookies can store multiple name-value pairs. In addition, cookies can have optional values for path, domain, expiration date, and security. To create a cookie on a server element, you need code that adds a string of the promised format to the response header. A web browser that receives a response containing cookie information will also send cookie information every time it sends the request to the server. The cookie information passed to the server element can be obtained as an array type using the getCookie() method of HttpServletRequest. Cookie or session are the technology that overcomes the limitations of the HTTP protocol to disconnect after a response.
Cookie(String name, String value)
getName():String
getValue():String
setValue(String newValue)
getPath():String
setPath(String uri)
getDomain():String
setDomain(String pattern)
getMaxAge():int
setMaxAge(int expiry)
getSecure():boolean
setSecure(boolean flag)

Servlet Examples

Write all the examples below in the ROOT application. In the Creating a new web application, we changed the application with the document base C:/www/myapp to the ROOT application. Create JSPs in C:/www/myapp and java sources in C:/www/myapp/WEB-INF/src. Instead of using Eclipse, use a regular editor such as EditPlus.

SimpleServlet.java
package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SimpleServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req,resp);
	}
	
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
			
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
    	
		out.println("<html>");
		out.println("<body>");
    	
		//Output the IP of client
		out.println("Your IP Address is " + req.getRemoteAddr() + ".\n");
		out.println("</body></html>");
		out.close();
	}
  
}

SimpleServlet does not implement servlet lifecycle methods init() and destroy(). These methods are already implemented in the GenericServlet and are not visible in the above sources because there is no reason to override them. Open the /WEB-INF/web.xml file and add the servlet element to the sub element of the web-app element as shown below.

web.xml
<servlet>
	<servlet-name>SimpleServlet</servlet-name>
	<servlet-class>example.SimpleServlet</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>SimpleServlet</servlet-name>
	<url-pattern>/simple</url-pattern>
</servlet-mapping>

At the command prompt, navigate to the folder where SimpleServlet.java is located and compile as shown below.

C:\ Command Prompt
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 8.0/lib/servlet-api.jar" ^
SimpleServlet.java
package javax.servlet.http does not exist
The above compilation error means that the Java compiler can not find the javax.servlet.http package. This is because you did not add the full path to the servlet-api.jar file as the javac's cp option value. If the path you are adding as a cp option value contains a space, you must enclose it with "".

Restart Tomcat and visit http://localhost:8080/simple.

SimpleServlet.java source description

public class SimpleServlet extends HttpServlet

Servlets that inherit the HttpServlet class must be declared public.

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	doPost(req, resp);
}

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	//.. omit ..
}

The doGet() and doPost() methods are methods that override the doGet() and doPost() methods of HttpServlet. A servlet that receives a GET request overrides the doGet() method. It is a request of the GET method to request the resource of the web server by inputting the address in the web browser. In the above example, the doGet() method calls the doPost() method. Therefore, the same code is executed whether it is a GET or a POST request. The doGet() and doPost() methods have HttpServletRequest and HttpServletResponse as parameters.

resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();

resp.setContentType("text/html; charset=UTF-8") sets the content type of the response (HttpServletResponse). That is, this code sets the MIME 2 type of the document to be output in response to the web browser. This code can be used only once in a servlet and must be executed before getting a PrintWriter object. Removing the ; charset=UTF-8 part breaks non-English characters. PrintWriter object can be obtained by calling getWriter() of the HttpServletResponse as follows:

PrintWriter out = resp.getWriter();

out.println("<html>");
out.println("<body>");

//Output the IP of client
out.println("Your IP Address is " + req.getRemoteAddr() + ".\n");

PrintWriter's println() method prints the string passed as argument value to the client's web browser. As you can see, SimpleServlet uses PrintWriter's println() method to send HTML to the client. HttpServletRequest's getRemoteAddr() is a method that returns the IP address of the client. HttpServeltRequest object contains the information sent by the client and information about the client. Let's take a look at the process until the SimpleServlet servlet sends a response. The client uses the web browser to request the server's SimpleSerlvet. Tomcat calls the + service(ServletRequest req, ServletResponse res) method of SimpleServlet and passes the object (HttpSerlvetRequest interface implementation) encapsulating the client 's request and the response object (HttpSerlvetResponse interface implementation) as method arguments. The +service(ServletRequest req, ServletResponse res) method simply calls the #service(HttpServletRequest req, HttpServletResponse resp) method. The #service(HttpServletRequest req, HttpServletResponse resp) method invokes methods such as doGet() or doPost() depending on the HTTP method type (GET, POST, etc.). The above example is a GET request because you requested a servlet resource from the web browser address bar. So the doGet() method is called.

How user sends string data to server-side resources and how server-side resources receive data

In the Web environment, dynamic elements are elements that respond differently depending on the string data sent by the client. Web programmers who need to create dynamic elements on the Web need to know how to let a client send string data to a server-side resource using a web browser, and how to obtain string data sent by a client on a server-side resource. All web programmers mainly use form and its sub-elements to allow clients to send string data to server-side resources.3 The data that the client sends is passed to the server-side resource specified by the form element's action attribute.

How to transfer parameters and how to get the values of the parameters sent

In the table below, the "HTML Form" item shows the HTML tag for receiving the value from the user, and the "Servlet" item shows how servlet to get the parameter values sent from the client.

HTML Form Servlet
<input type="text" name="addr" />
req.getParameter("addr");
<input type="radio" name="os" value="Windows" />
<input type="radio" name="os" value="Linux" />
req.getParameter("os");
<input type="hidden" name="curPage" value="1" />
req.getParameter("curPage");
<input type="password" name="passwd" />
req.getParamter("passwd");
<textarea name="content" cols="60" rows="12">blah blah</textarea>
req.getParamter("content");
<select name="grade">
	<option value="A">A</option>
	<option value="B">B</option>
	<option value="C">C</option>
	<option value="D">D</option>
	<option value="F">F</option>
</select>
req.getParameter("grade");
<input type="checkbox" name="hw" value="Intel" />
<input type="checkbox" name="hw" value="AMD" />
req.getParameterValues("hw");
<select name="sports" multiple="multiple">
	<option value="soccer">Soccer</option>
	<option value="baseball">Baseball</option>
	<option value="basketball">Basketball</option>
</select>
req.getParameterValues("sports");

getParameter(String name)

The getParameter(String name) method of ServletRequest is the most common method used to get data sent by the user. The type of character data that the client sends to the server is a parameter name-value pair. Here, the name of the parameter is the value of the name attribute of the form's subelements (input, textarea, select, etc.), and value is the user input. In the server-side resource code, if the name of the parameter passed by the client is given as the argument of the getParameter(String name) method, this method returns the value that the user has entered or selected. An input element whose type attribute value is radio is called a radio button. Radio buttons with the same name attribute value can form a group and select only one item within a group.

getParameterValues(String name)

When a client sends multiple values with one parameter, the getParamterValues(String name) method of the HttpServletRequest is needed to get these values from the server-side resource. This method returns an array of strings consisting of the values chosen by the user. If you want the client to send multiple values with one parameter, add the checkbox or select element whose multiple attribute value is "multiple" to your HTML. (the checkbox indicates that the value of the type attribute of the input element is "checkbox") If the value of the name attribute is the same, these checkboxes belongs to the same group. A checkbox differs from a radio button in that multiple checkboxes within a group can be selected. With the select element, the user can generally select only one item. However, if the select element's multiple attribute value is set to "multiple", the user can select multiple items using the Ctrl or Shift buttons.

getParamterNames()

To find out what parameter the user is sending, the server side code needs the getParamterNames() method of HttpServletRequest. The getParameterNames() method returns an Enumeration4 type object containing the parameter names.

input type="file"
<input type="file" ../> is used to transfer binary data such as images to the server. The parent element, form should be <form method="post" enctype="multipart/form-data"...> If you need to send other additional information (For example, string data such as name, title, content, etc.) as well as the file you are uploading, add other elements, which are sending strings in the form element including <input type="file" />. If you press the submit button, the data will be transmitted with a different protocol than when sending only the string. Therefore, you can not access data sent using the getParameter(String name) method. Although you can directly implement methods to access data sent with binary data and binary data using the Servlet API, most programmers use external libraries in this case.

String transfer example

Let's practice how to receive data from the user in the servlet through the below example. Create SignUp.html in the documentbase/example diretory.

/example/SignUp.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sign Up</title>
</head>
<body>
<h3>Sign Up</h3>

<form id="joinForm" action="../RegisterServlet" method="post">
<div>ID <input type="text" name="id" /></div>
<div>Nickname <input type="text" name="nickname" /></div>
<div>Password <input type="password" name="passwd" /></div>
<div>Name <input type="text" name="name" /></div>
<div>Gender Male <input type="radio" name="gender" value="M" /> Female <input type="radio" name="gender" value="F" /></div>
<div>Birthday <input type="text" name="birthday" /></div>
<div>Mobile <input type="text" name="mobile" /></div>
<div>Telephone <input type="text" name="tel" /></div>
<div>Address <input type="text" name="address" /></div>
<div>Email <input type="text" name="email" /></div>
<div>
Sports
<input type="checkbox" name="sports" value="soccer" />soccer
<input type="checkbox" name="sports" value="baseball" />baseball
<input type="checkbox" name="sports" value="basketball" />Basketball
<input type="checkbox" name="sports" value="tennis" />Tennis
<input type="checkbox" name="sports" value="tabletennis" />Tabletennis
</div>
<div>
Lectures
<select name="main-menu" multiple="multiple">
	<option value="">-- Multiple Select --</option>
	<option value="java">JAVA</option>
	<option value="jdbc">JDBC</option>
	<option value="jsp">JSP</option>
	<option value="css-layout">CSS Layout</option>
	<option value="jsp-prj">JSP Project</option>
	<option value="spring">Spring</option>
	<option value="javascript">JavaScript</option>
</select>
</div>
<div>
About Me
<textarea name="aboutMe" cols="40" rows="7"></textarea>
</div>
<div><input type="submit" value="Submit" /></div>
</form>
</body>
</html>

Create RegisterServlet.java in /WEB-INF/src/example directory as shown below.

RegisterServlet.java
package example;

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

public class RegisterServlet extends HttpServlet {
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException,ServletException {
		
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		req.setCharacterEncoding("UTF-8");
		
		String id = req.getParameter("id");
		
		out.println("<html><body>");
		out.println("id : " + id);
		
		String[] sports = req.getParameterValues("sports");
		int len = sports.length;
		
		out.println("<ol>");
		for (int i = 0; i < len; i++) {
			out.println("<li>" + sports[i] + "</li>");
		}
		
		out.println("</ol>");
		
		String path = req.getContextPath();
		out.println("<a href=" + path + "/example/SignUp.html>Join</a>");
		out.println("</body></html>");
	}
}

Open a command prompt and go to /WEB-INF/src/example and compile as below.

C:\ Command Prompt
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 8.0/lib/servlet-api.jar" ^
RegisterServlet.java

Add the following to web.xml:

web.xml
<servlet>			
    <servlet-name>RegisterServlet</servlet-name>
    <servlet-class>example.RegisterServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>RegisterServlet</servlet-name>
    <url-pattern>/RegisterServlet</url-pattern>
</servlet-mapping>

After restarting Tomcat, go to http://localhost:8080/example/SignUp.html. TODO: Add a code to the servlet to check for values other than ID and sports.

RequestDispatcher Interface

RequestDispathcer has two methods, include() and forward(). The include() method is used to pass control to another resource and to take control again when another resource is completed. It is used to add messages produced by other resources to the response. The forward() method passes control to another resource. As a result, the resource that receives the control responds to the client. Let's practice the forward() method example. Create the ControllerServlet.java file in the /WEB-INF/src/example directory as follows:

ControllerServlet.java
package example;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ControllerServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		
		String uri = req.getRequestURI();
		String contextPath = req.getContextPath();
		String command = null;
		String view = null;
		boolean isRedirect = false;
		
		command = uri.substring(contextPath.length());
		
		if (command.equals("/example/SignUp.action")) {
			view = "/example/SignUp.html";
		}
		
		if (isRedirect == false) {
			ServletContext sc = this.getServletContext();
			RequestDispatcher rd = sc.getRequestDispatcher(view);
			rd.forward(req, resp);
		} else {
			resp.sendRedirect(view);
		}
	}
}

Open a command prompt and go to /WEB-INF/src/example and compile as follows:

C:\ Command Prompt
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 8.0/lib/servlet-api.jar" ^
ControllerServlet.java

Add the following to web.xml:

web.xml
<servlet>
    <servlet-name>Controller</servlet-name>
    <servlet-class>example.ControllerServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>

After restarting Tomcat, go to http://localhost:8080/example/SignUp.action and verify that /example/SignUp.html responds. TODO: In ControllerServlet.java, change isRedirect to true and recompile and test.

We have added ControllerServlet servlet declarations and mappings in web.xml so that ControllerServlet would handle all requests ending in .action. When a request string which ends in .action comes, Tomcat interprets the mapping information in web.xml and invokes the +servlet(servletRequest req, ServletResponse resp) method of the ControllerServlet servlet. The +service(ServletRequest req, ServletResponse resp) method simply calls the #service(HttpServletRequest req, HttpServletResponse resp) method. The #service (HttpServletRequest req, HttpServletResponse resp) method checks the HTTP METHOD of the request and calls the appropriate method. This is the GET method because you requested http://localhost:8080/example/SignUp.action in the address bar of your web browser. So, doGet() method is called. The controllerServlet's doGet() method simply calls doPost(). The following table summarizes the HttpServletRequest methods used in the implementation of doPost().

getRequestURI()
When requesting http://localhost:8080/example/SignUp.action in a web browser, it returns "/example/SignUp.action".
getContextPath()
Returns the value of the path property of the context file (this value is called ContextPath). As we work in the ROOT application, the value we can get through this method is "".
req.getRequestURI().substring(req.getContextPath().length())
The above code returns "/example/SignUp.action".

The user requesting /example/SignUp.action receives a response of /example/SignUp.html.

Servlet using database

Let's convert the GetEmp.java file, which we practiced in the JDBC chapter, into a servlet. This is an example of turning a pure Java application into a servlet. Create the GetEmpServlet.java file in the /WEB-INF/src/example directory of the ROOT application.

GetEmpServlet.java
package example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GetEmpServlet extends HttpServlet {
	
	private String DB_URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
	private String DB_USER = "scott";
	private String DB_PASSWORD = "tiger";
	
	/*
	 * GenericServlet's init() method
	 * init(ServletConfig config) invoke this method.
	 * Therefore, you do not need to override the init(ServletConfig config) method.
	 */
	@Override
	public void init() throws ServletException {
		try {
			Class.forName( "oracle.jdbc.driver.OracleDriver" );
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		Connection con = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		String sql = "select * from emp";
		
		try {
			con = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
			stmt = con.createStatement();
			rs = stmt.executeQuery(sql);
			
			while (rs.next()) {
				String empno = rs.getString(1);
				String ename = rs.getString(2);
				String job = rs.getString(3);
				String mgr = rs.getString(4);
				String hiredate = rs.getString(5);
				String sal = rs.getString(6);
				String comm = rs.getString(7);
				String depno = rs.getString(8);
				
				out.println( empno + " : " + ename + " : " + job + " : " + mgr + 
				" : " + hiredate + " : " + sal + " : " + comm+" : " + depno + "<br />" );
			}

		} catch (SQLException e) {
			e.printStackTrace(out);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {

					e.printStackTrace();
				}
			}
			if (con != null) {
				try {
					con.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

Use the command prompt to navigate to the /WEB-INF/src/example directory of the ROOT application and compile it as follows:

C:\ Command Prompt
javac -d C:/www/myapp/WEB-INF/classes ^ 
-cp "C:/Program Files/Apache Software Foundation/Tomcat 8.0/lib/servlet-api.jar" ^
GetEmpServlet.java

Add the following to web.xml:

web.xml
<servlet>
    <servlet-name>GetEmpServlet</servlet-name>
    <servlet-class>example.GetEmpServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>GetEmpServlet</servlet-name>
    <url-pattern>/empList</url-pattern>
</servlet-mapping>

Copy the JDBC driver file to CATALINA_HOME/lib. After restarting Tomcat, visit http://localhost:8080/empList.

7369 : SMITH : CLERK : 7902 : 1980-12-17 00:00:00.0 : 800 : null : 20
7499 : ALLEN : SALESMAN : 7698 : 1981-02-20 00:00:00.0 : 1600 : 300 : 30
7521 : WARD : SALESMAN : 7698 : 1981-02-22 00:00:00.0 : 1250 : 500 : 30
7566 : JONES : MANAGER : 7839 : 1981-04-02 00:00:00.0 : 2975 : null : 20
7654 : MARTIN : SALESMAN : 7698 : 1981-09-28 00:00:00.0 : 1250 : 1400 : 30
7698 : BLAKE : MANAGER : 7839 : 1981-05-01 00:00:00.0 : 2850 : null : 30
7782 : CLARK : MANAGER : 7839 : 1981-06-09 00:00:00.0 : 2450 : null : 10
7788 : SCOTT : ANALYST : 7566 : 1987-04-19 00:00:00.0 : 3000 : null : 20
7839 : KING : PRESIDENT : null : 1981-11-17 00:00:00.0 : 5000 : null : 10
7844 : TURNER : SALESMAN : 7698 : 1981-09-08 00:00:00.0 : 1500 : 0 : 30
7876 : ADAMS : CLERK : 7788 : 1987-05-23 00:00:00.0 : 1100 : null : 20
7900 : JAMES : CLERK : 7698 : 1981-12-03 00:00:00.0 : 950 : null : 30
7902 : FORD : ANALYST : 7566 : 1981-12-03 00:00:00.0 : 3000 : null : 20
7934 : MILLER : CLERK : 7782 : 1982-01-23 00:00:00.0 : 1300 : null : 10

If you do not see the results you want, check the list below.

  • Is the servlet declaration and servlet mapping added correctly to the web.xml file?
  • Is there a GetEmpServlet bytecode in the /WEB-INF/classes/example directory.
  • Is there an Oracle JDBC driver file (ojdbc6.jar) in the CATALINA_HOME/lib directory.
  • Did the ROOT web application load successfully?

Using ServletConfig initialization parameter

Let's modify the GetEmpServlet example to use the ServletConfig initialization parameter. Create the following servlet in the /WEB-INF/src/example directory.

InitParamServlet.java
package example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InitParamServlet extends HttpServlet {
	
	private String url;
	private String user;
	private String passwd;
	private String driver;
	
	@Override
	public void init() throws ServletException {
		url = this.getInitParameter("url");
		user = this.getInitParameter("user");
		passwd = this.getInitParameter("passwd");
		driver = this.getInitParameter("driver");
		
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		String sql = "SELECT * FROM emp";
		
		try {
			con = DriverManager.getConnection(url, user, passwd);
			stmt = con.prepareStatement(sql);
			rs = stmt.executeQuery();
			
			while (rs.next()) {
				String empno = rs.getString(1);
				String ename = rs.getString(2);
				String job = rs.getString(3);
				String mgr = rs.getString(4);
				String hiredate = rs.getString(5);
				String sal = rs.getString(6);
				String comm = rs.getString(7);
				String depno = rs.getString(8);
				
				out.println(empno + " : " + ename + " : " + job + " : " + mgr + 
				  " : " + hiredate + " : " + sal + " : " + comm+" : " + depno + "<br />");
			}
		} catch (SQLException e) {
			e.printStackTrace(out);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (con != null) {
				try {
					con.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

Add the following to web.xml:

web.xml
<servlet>
	<servlet-name>InitParamServlet</servlet-name>
	<servlet-class>example.InitParamServlet</servlet-class>
	<init-param>
		<param-name>driver</param-name>
		<param-value>oracle.jdbc.driver.OracleDriver</param-value>
	</init-param>
	<init-param>
		<param-name>url</param-name>
		<param-value>jdbc:oracle:thin:@127.0.0.1:1521:XE</param-value>
	</init-param>
	<init-param>
		<param-name>user</param-name>
		<param-value>scott</param-value>
	</init-param>
	<init-param>
		<param-name>passwd</param-name>
		<param-value>tiger</param-value>
	</init-param>
</servlet>

<servlet-mapping>
	<servlet-name>InitParamServlet</servlet-name>
	<url-pattern>/initParam</url-pattern>
</servlet-mapping>

The value of the initialization parameter of ServletConfig set above is obtained by using getInitParameter(String name) method of ServletConfig. After restarting Tomcat, visit http://localhost:8080/initParam.

Using ServletContext Initialization Parameters

The ServletConfig initialization parameters can only be referenced in the corresponding servlet. The ServletContext initialization parameters can be referenced in any servlet and JSP in the web application. The ServletContext initialization parameter is set in web.xml using the context-param element. For the schema and dtd there is a specified order. The following excerpts from http://java.sun.com/dtd/web-app_2_3.dtd.

<!ELEMENT web-app (icon?, display-name?, description?, distributable?, context-param*, filter*, filter-mapping*, listener*, servlet*, servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?, error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*, login-config?, security-role*, env-entry*, ejb-ref*, ejb-local-ref*)>

You can see that the context-param must be declared ahead of the servlet. Open web.xml and add the following:

web.xml
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:oracle:thin:@127.0.0.1:1521:XE</param-value>
</context-param>

A reference to a ServletContext object can be obtained using the servlet's getServletContext() method. The value of url, which is the ServletContext initialization parameter declared above, is obtained by using getInitParameter(String name) method of ServletContext. Add the following code to the existing SimpleSerlvet.java in the appropriate location and recompile.

Edit SimpleServlet.java
ServletContext sc = getServletContext();
String url = sc.getInitParameter("url");
out.println(url);

After restarting Tomcat, visit http://localhost:8080/simple. TODO: Modify InitParamServlet.java so that the url is set with the ServletContext initialization parameter.

Listener

The listener runs on the web application event. Web application events have been added to the Servlet 2.3 specification. Web application events are divided into:

  • Application startup and shutdown
  • Session creation and session invalidation

An application startup event occurs when a web application is first loaded and started by a servlet container, such as Tomcat. Application shutdown events occur when the web application is shut down. Session creation events occur when a new session is created. Session invalidation events occur each time a session is invalidated. To use events, you need to write a class called Listener. The Listener class is a pure Java class that implements the following interfaces:

  • javax.servlet.ServletContextListener
  • javax.servlet.http.HttpSessionListener

If you want listeners for application startup or shutdown events, implement the ServletContextListener interface. If you want listeners for session creation and session invalidation events, implement the HttpSessionListener interface. The ServletContextListener interface consists of two methods:

  • public void contextInitialized(ServletContextEvent sce);
  • public void contextDestroyed(ServletContextEvent sce);

The HttpSessionListener interface consists of two methods:

  • public void sessionCreated(HttpSessionEvent se);
  • public void sessionDestroyed(HttpSessionEvent se);

Write the following Listener class, which it, right after the web application startup, creates an OracleConnectionManager object and stores it in the ServletContext.

MyServletContextListener.java
package net.java_school.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import net.java_school.db.dbpool.OracleConnectionManager;

public class MyServletContextListener implements ServletContextListener {

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		ServletContext sc = sce.getServletContext();
		OracleConnectionManager dbmgr = new OracleConnectionManager();
		sc.setAttribute("dbmgr", dbmgr);
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		ServletContext sc = sce.getServletContext();
		sc.removeAttribute("dbmgr");
	}

}

Add the following to web.xml, below the context-param, above the servlet declaration.

web.xml
<listener>
	<listener-class>net.java_school.listener.MyServletContextListener</listener-class>
</listener>

Using a custom connection pool

Add all the java source files from the lession entitled "ConnectionPool" in the JDBC chapter to the ROOT application's WEB-INF/src directory. Open Log.java and modify it as follows:

public String logFile = "C:/www/myapp/WEB-INF/myapp.log";

Copy the orcale.properties file in the "ConnectionPool" to the ROOT application's WEB-INF directory. Open ConnectionManager.java and modify it as follows:

configFile = "C:/www/myapp/WEB-INF/" + poolName + ".properties";

Now when the ROOT web application is started, an OracleConnectionManager object will be created and its reference will be stored in the ServletContext. To test it, modify the GetEmpServlet.java file as shown below.

GetEmpServlet.java
package example;

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

import net.java_school.db.dbpool.*;

public class GetEmpServlet extends HttpServlet {

	private OracleConnectionManager dbmgr;
	
	@Override
	public void init() throws ServletException {
		ServletContext sc = getServletContext();
		dbmgr = (OracleConnectionManager) sc.getAttribute("dbmgr");
	}
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
			
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		String sql = "SELECT * FROM emp";
		
		try {
			con = dbmgr.getConnection();
			stmt = con.prepareStatement(sql);
			rs = stmt.executeQuery();
			
			while (rs.next()) {
				String empno = rs.getString(1);
				String ename = rs.getString(2);
				String job = rs.getString(3);
				String mgr = rs.getString(4);
				String hiredate = rs.getString(5);
				String sal = rs.getString(6);
				String comm = rs.getString(7);
				String depno = rs.getString(8);
				
				out.println( empno + " : " + ename + " : " + job + " : " + mgr +
					" : " + hiredate + " : " + sal + " : " + comm+" : " + depno + "<br>" );
			}
		} catch (SQLException e) {
			e.printStackTrace(out);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (con != null) {
				try {
					con.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

Compile the custom connection pool source and GetEmpServlet.java. Restart Tomcat and visit http://localhost:8080/empList. (The declarations and mappings for the GetEmpServlet servlet have already been set up in previous exercises)

The HttpSessionListener interface consists of two methods. One for session creation events and the other for session invalidation events.

  • public void sessionCreated(HttpSessionEvent se);
  • public void sessionDestroyed(HttpSessionEvent se);

The following is an example of an HttpSessionListener.

SessionCounterListener.java
package net.java_school.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionCounterListener implements HttpSessionListener {

	public static int totalCount;
	
	@Override
	public void sessionCreated(HttpSessionEvent event) {
		totalCount++;
		System.out.println("Session Increase. Total Sessions:" + totalCount);
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent event) {
		totalCount--;.
		System.out.println("Session Reduction. Total Sessions:" + totalCount);
	}
}

Add the following to web.xml:

<listener>
    <listener-class>net.java_school.listener.SessionCounterListener</listener-class>
</listener>

Restart Tomcat and visit http://localhost:8080/simple. Visit http://localhost:8080/simple with another web browser. Check the log messages in the Tomcat log file.

Filter

A filter is used when there is code that must be executed before a user's request is delivered to a server resource. For the filter to work, you need to add filter declarations and filter mappings to web.xml. If filter 1 followed by filter 2 in web.xml is mapped in order, then filter 1 - filter 2 - server resource - filter 2 - filter 1 - web browser will be executed in order. The filter class must implement the javax.servlet.Filter interface.

The following is a pure Java application created to understand the filter mechanism.

ChainFilter.java
package net.java_school.filter;

import java.util.ArrayList;
import java.util.Iterator;

public class ChainFilter {
	private ArrayList<Filter> filters;
	private Iterator<Filter> iterator;

	public void doFilter() {
		if (iterator.hasNext()) {
			iterator.next().doFilter(this);
		} else {
			System.out.println("Run Server resource");
		}
	}

	public ArrayList<Filter> getFilters() {
		return filters;
	}

	public void setFilters(ArrayList<Filter> filters) {
		this.filters = filters;
		this.iterator = filters.iterator();
	}
	
}
Filter.java
package net.java_school.filter;

public interface Filter {
	
	public void doFilter(ChainFilter chain);

}
Filter1.java
package net.java_school.filter;

public class Filter1 implements Filter {

	@Override
	public void doFilter(ChainFilter chain) {
		System.out.println("Run Filter 1 before the server resource runs");
		chain.doFilter();
		System.out.println("Run Filter 1 after the server resource runs");
	}

}
Filter2.java
package net.java_school.filter;

public class Filter2 implements Filter {

	@Override
	public void doFilter(ChainFilter chain) {
		System.out.println("Run Filter 2 before the server resource runs");
		chain.doFilter();
		System.out.println("Run Filter 2 after the server resource runs");
	}

}
Tomcat.java
package net.java_school.filter;

import java.util.ArrayList;

public class Tomcat {

	public static void main(String[] args) {
		ChainFilter chain = new ChainFilter();
		ArrayList<Filter> filters = new ArrayList<Filter>();
		Filter f1 = new Filter1();
		Filter f2 = new Filter2();
		filters.add(f1);
		filters.add(f2);
		chain.setFilters(filters);
		chain.doFilter();
	}

}
Run Filter 1 before the server resource runs
Run Filter 2 before the server resource runs
Run Server resource.
Run Filter 2 after the server resource runs
Run Filter 1 after the server resource runs

Filter Interface

  • init(FilterConfig filterConfig) throws ServletException; When this method is called by the servlet container, the filter is in service state.
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; Called by the servlet container to perform the filtering operation.
  • destroy() When called by a servlet container, the filter is no longer able to service. Mainly used for returning resources.

The arguments of the doFilter() method show that the filter can access the ServletRequest, ServletResponse, and javax.servlet.FilterChain objects when it intercepts the request or response. The FilterChain object has a list of filters that should be called in order. In the doFilter() method of the filter class, the code before FilterChain's doFilter() method call is the filtering code that is executed before the request reaches the server resource and the code after FilterChain's doFilter() method call is the filtering code that is executed before the response.

Filter Example

The following is an example that runs req.setCharacterEncoding("UTF-8"); code before all server resources are executed. Create a CharsetFilter.java file as follows:

/WEB-INF/src/net/java_school/filter/CharsetFilter.java
package net.java_school.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CharsetFilter implements Filter {

	private String charset = null;
	
	@Override
	public void init(FilterConfig config) throws ServletException {
		this.charset = config.getInitParameter("charset");
	}
	
	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
		throws IOException, ServletException {
		
		if (req.getCharacterEncoding() == null) {
			req.setCharacterEncoding(charset);
			chain.doFilter(req,resp);
		}
	}

	@Override
	public void destroy() {
		//Implement it if you have resources to return.
	}

}

At the command prompt, go to the /WEB-INF/src/net/java_school/filter/directory and compile as follows.

C:\ Command Prompt
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 8.0/lib/servlet-api.jar" ^
CharsetFilter.java

Open the following web.xml file and add the following: Note the order with existing elements. The following code should be placed between the context-param element and the listener element.

web.xml
<filter>
   <filter-name>CharsetFilter</filter-name>
   <filter-class>net.java_school.filter.CharsetFilter</filter-class>
   <init-param>
      <param-name>charset</param-name>
      <param-value>UTF-8</param-value>
   </init-param>
</filter>

<filter-mapping>
   <filter-name>CharsetFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

Open the RegisterServlet.java source and comment out the req.setCharacterEncoding("UTF-8"); and recompile RegisterServlet.java. Go to http://localhost:8080/example/SignUp.html and input the non-English characters into the ID and click submit button. If req.setCharacterEncoding("UTF-8"); is executed, the ID will be output correctly.

The filter initialization parameters are set using the filters sub-element, init-param. The getInitParameter() and getInitParameters() methods of FilterConfig are used to read filter initialization parameters. The filter-mapping element in web.xml specifies the resource to be filtered. Filters are added to the FilterChain in the order in which they are listed in web.xml, but the filter mapped to the servlet name is added after the filter that matches the URL pattern. The doFilter() method of FilterChain calls the next filter of FilterChain.

Uploading files

Most programmers are using external libraries to upload files.

MultipartRequest

The MultipartRequest package is a package that is widely used for file upload. Download cos.26Dec2008.zip from the following address. http://www.servlets.com/cos/index.html After decompressing, copy the cos.jar file to the ROOT application's /WEB-INF/lib directory. There are eight constructors for the MultipartRequest class. For a more detailed explanation, please refer to the following address. http://www.servlets.com/cos/javadoc/com/oreilly/servlet/MultipartRequest.html The following constructor resolves the encoding problem for non-English characters and automatically rename the file name when the file name is duplicate.

public MultipartRequest(
	HttpServletRequest request,
	String saveDirectory,
	int maxPostSize,
	String encoding,
	FileRenamePolicy policy) throws IOException

Methods of MultipartRequest

If the MultipartRequest constructor was successfully executed, the upload was successful. The following table shows the member methods of MultipartRequest that are available after uploading files to the server's file system. Suppose you upload the logo.gif image file using the <input type="file" name="photo" />.

getContentType("photo");
Return the MIME type of the uploaded file. For example, if the extension of the file is gif, "image/gif" is returned.
getFile("photo");
Return the File object of the file uploaded and stored in the server.
getFileNames();
Return parameter names whose type attribute is "file" as Enumeration type.
getFilesystemName("photo");
Returns the actual file name that is uploaded and exists in the server file system.
getOriginalFileName("photo");
Return original file name
Methods to provide the same interface as HttpServletRequest
getParameter(String name);
Return value of parameter corresponding to name as String
getParameterNames();
Return all parameter names as Enumeration type.
getParameterValues(String name);
Returns values of the parameter corresponding to name as String[].

MultipartRequest Example

Create the following HTML file in the example subdirectory of the ROOT application's top-level directory:

/example/MultipartRequest.html
<!DOCTYPE html>
<html>
<head>
	<title>MultipartRequest Servlet Example</title>
	<meta charset="UTF-8" />
</head>
<body>

<h1>File Upload Test with MultipartRequest</h1>

<form action="../servlet/UploadTest" method="post" enctype="multipart/form-data">
<div>Name: <input type="text" name="name" /></div>
<div>File 1: <input type="file" name="file1" /></div>
<div>File 2: <input type="file" name="file2" /></div>
<div><input type="submit" value="Submit" /></div>
</form>

</body>
</html>

Create and compile the following servlet. When compiling, you need to tell the Java compiler the path to the cos.jar file.

UploadTest.java
package example;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

public class UploadTest extends HttpServlet {
	
	@Override	
	public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
			
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		ServletContext cxt = getServletContext();
		String dir = cxt.getRealPath("/upload");
		
		try {
			MultipartRequest multi = new MultipartRequest(req, dir, 5*1024*1024, "UTF-8", new DefaultFileRenamePolicy());
					
			out.println("<html>");
			out.println("<body>");
			out.println("<h1>Parameters passed by the user</h1>");
			out.println("<ol>");
			Enumeration<?> params = multi.getParameterNames();
			
			while (params.hasMoreElements()) {
				String name = (String) params.nextElement();
				String value = multi.getParameter(name);
				out.println("<li>" + name + "=" + value + "</li>");
			}
			
			out.println("</ol>");
			out.println("<h1>Uploaded files</h1>");
			
			Enumeration<?> files = multi.getFileNames();
			
			while (files.hasMoreElements()) {
				out.println("<ul>");
				String name = (String) files.nextElement();
				String filename = multi.getFilesystemName(name);
				String originalName =multi.getOriginalFileName(name);
				String type = multi.getContentType(name);
				File f = multi.getFile(name);
				out.println("<li>Parameter name: "  + name + "</li>");
				out.println("<li>File name: " + filename + "</li>");
				out.println("<li>File original name: " + originalName + "</li>");
				out.println("<li>File type: " + type + "</li>");
				
				if (f != null) {
					out.println("<li>File size: " + f.length() + "</li>");
				}
				out.println("</ul>");
			}
		} catch(Exception e) {
			out.println("<ul>");
			e.printStackTrace(out);
			out.println("</ul>");
		}
		out.println("</body></html>");
	}
}

Add the following to web.xml:

web.xml
<servlet>
    <servlet-name>UploadTest</servlet-name>
    <servlet-class>example.UploadTest</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>UploadTest</servlet-name>
    <url-pattern>/servlet/UploadTest</url-pattern>
</servlet-mapping>

Before running the example, create an upload subdirectory in the top-level directory of your ROOT web application. Restart Tomcat and visit http://localhost:8080/example/upload.html. After uploading duplicate files, check the file name in upload folder. If you upload a duplicate file, you can see that the file name except the extension is appended with a number at the end. If the test fails, check the list below.

  1. Check that the bytecode of the UploadTest servlet is generated.
  2. Make sure that there is an upload subdirectory in the root directory of the ROOT application.
  3. Make sure the cos.jar file is in /WEB-INF/lib in the ROOT application.
  4. Make sure the UploadTest servlet is correctly registered and mapped in the web.xml.
  5. Make sure the ROOT web application is loaded.

commons-fileupload

Commons-fileupload is a file upload library provided by Apache, which is famous for its open source. Download the latest binary file from the following address. http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi http://commons.apache.org/proper/commons-io/download_io.cgi Uncompress and copy the commons-fileupload-x.x.jar and commons-io-x.x.jar files to the ROOT application's /WEB-INF/lib.

/example/commons-fileupload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>commons-fileupload Test</title>
</head>
<body>

<h1>Uploading files using commons-fileupload</h1>

<form action="../CommonsUpload" method="post" enctype="multipart/form-data">
<div>File : <input type="file" name="upload" /></div>
<div><input type="submit" value="Submit" /></div>
</form>

</body>
</html>
CommonsUpload.java
package example;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

import java.util.Iterator;
import java.io.File;
import java.util.List;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class CommonsUpload extends HttpServlet {

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp) 
			throws IOException, ServletException {
			
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		//Check that we have a file upload request
		boolean isMultipart = ServletFileUpload.isMultipartContent(req);
		//Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();
		
		//Configure a repository (to ensure a secure temp location is used)
		ServletContext servletContext = this.getServletConfig().getServletContext();
		File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
		factory.setRepository(repository);
		
		//Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload(factory);
		upload.setHeaderEncoding("UTF-8");
		try {
			//Parse the request
			List<FileItem> items = upload.parseRequest(req);
			//Process a file upload
			Iterator<FileItem> iter = items.iterator();
			while (iter.hasNext()) {
				FileItem item = iter.next();
				String fileName = null;
				if (!item.isFormField()) {
					String fieldName = item.getFieldName();
					out.println(fieldName);
					fileName = item.getName();
					out.println(fileName);
					String contentType = item.getContentType();
					out.println(contentType);
					boolean isInMemory = item.isInMemory();
					out.println(isInMemory);
					long sizeInBytes = item.getSize();
					out.println(sizeInBytes);
				}
				// Process a file upload
				ServletContext cxt = getServletContext();
				String dir = cxt.getRealPath("/upload");
				File uploadedFile = new File(dir + "/" + fileName);
				item.write(uploadedFile);
			}
		} catch (Exception e) {
			out.println("<ul>");
			e.printStackTrace(out);
			out.println("</ul>");
		}
		out.println("<a href="/example/commons-fileupload.html">commons-fileupload.html</a>");
	}
}

Add the following to web.xml:

web.xml
<servlet>
    <servlet-name>commonsUpload</servlet-name>
    <servlet-class>example.CommonsUpload</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>commonsUpload</servlet-name>
	<url-pattern>/CommonsUpload</url-pattern>
</servlet-mapping>

Restart Tomcat and visit http://localhost:8080/example/commons-fileupload.html. After uploading duplicate files, check the file name in upload folder. If you upload a duplicate file, you will notice that unlike cos.jar, it overwrites the existing file. An example of showing uploaded files is covered in the JSP chapter.

Cookie

The HTTP protocol is a protocol that can not maintain state. A cookie is one of technologies for overcoming that a web browser cannot maintain a session in communication with a server due to the characteristics of the HTTP protocol. When the server sends a cookie, the web browser passes the cookie to the server for each request so that the user information can be maintained.

Server sends cookie to web browser

For the cookie to work, the server must make and send the cookie to a web browser. The cookie looks like as follows:

Set-Cookie : name = value ; expires = date ; path = path ; domain = domain ; secure

Cookies are stored in files managed by the web browser.

Web browser sends cookie to server

Once the cookie is set in the web browser, the web browser sends the cookie whenever it requests the server resource. The cookie looks like as follows:

Cookie ; name = value1 ; name2 = value2 ;

The cookie name and value can not contain characters such as [] () = "/? @ :;

Cookie's constructor

Creates a cookie using the Cookie (String name, String value) constructor.

Methods of Cookie class

setValue(String value)
It is used to reset the value of created cookie.
setDomain(String pattern)
By default, cookies are only returned to the server that sent them. To send a cookie to a server using the same domain, use the setDomain() method. Domains not related to the server can not be set with setDomain().
setMaxAge(int expiry)
Set the validity period of the cookie in seconds. If you set a negative number, the cookie is deleted when you close the browser.
setPath(String uri)
Sets the path to which cookies will be applied. If the path is set, the web browser will send the cookie to the web server only if it visit the set path.
setSecure(boolean flag)
If flag is true, cookies are sent only for servers using secure channels. (https)

If you create a cookie with the cookie constructor and call the cookie method to set the cookie appropriately, you must send the cookie to the web browser. The following is the code that sends the cookie to the web browser.

resp.addCookie(cookie);

Access cookie sent by web browser from server resource

Cookie[] cookie = req.getCookies();

Use the getCookies() method of HttpServletRequest to get the cookie array. (If there is no cookie, the getCookies() method returns null) You can get information about cookies by using the following method. Among them, getName() and getValue() are mainly used.

getName()
Return cookie name
getValue()
Return cookie value
getDomain()
Return cookie domain
getMaxAge()
Return cookie expiration

Here is a snippet of code that gets the cookie value from the server resource.

String id = null;
Cookie[] cookies = request.getCookies();

if (cookies != null) {

	for (int i = 0; i < cookies.length; i++) {
		String name = cookies[i].getName();
		
		if (name.equals("id")) {
			id = cookies[i].getValue();
			break;
		}
	}
}

Below is an example of deleting cookies. It creates a cookie with the same name as the cookie you want to delete, calls setMaxAge(0), and sends the cookie to a web browser.

Cookie cookie = new Cookie("id","");
cookie.setMaxAge(0);
resp.addCookie(cookie);

Cookie exercises are covered in JSP chapter.

Session

A session is a cookie-based technology, which were made to overcome weaknesses in cookie security. Unlike cookies, the web browser stores only the session ID that the server has set as the cookie value. A session ID cookie stored in a web browser and a session object (HttpSession Type) mapped to a session ID cookie in the server cooperate to maintain the state of the user. The code for creating the session is as follows.

HttpSession session = req.getSession(true); //If there is no session, create it.
HttpSession session = req.getSession(false); //If there is no session, it returns null.

Once the session object has been created, you can store the information in the session.

User user = new User("Alison", "11111111");
session.setAttribue("user", user);

Session exercises are covered in the JSP chapter.

Comments
  1. The figure does not show all the properties and methods of GenericServlet and HttpServlet. To easily understand servlets, you need to be able to draw inheritance relationships between Servlets, ServletConfig, GenericServlet, and HttpServlet.
  2. MIME(Multipurpose Internet Mail Extensions). MIME of .html or .htm is text/html, .txt is text/plain .gif is image/gif.
  3. The string following the ? after the URL is called a query string. The query string is passed to the server-side resource corresponding to the URL. If there is more than one information in the query string, use & from the second. (eg, http://localhost:8080/list.jsp?board=free&page=1)
  4. The Enumeration interface has two methods to access the data in order: hasMoreElements() and nextElement().
References