Servlet
What is a Servlet?
Servlet is a Java-based technology for creating programs such as bulletin boards. Just as the java.sql and javax.sql packages are called JDBC, the javax.servlet and javax.servlet.http packages are called Servlet. Servlet is independent of the network protocol but mainly used to create server-side components which operate in the HTTP protocol environment.
The basic structure of Servlet
The basic structure of Servlet consists of:
- The javax.servlet.Servlet interface which all servlets must implement
- The javax.servlet.GenericServlet abstract class which most servlets inherit
- The javax.servlet.http.HttpServlet class which servlets operate in the HTTP protocol inherit
As shown in the figure below, GenericServlet implements the javax.servlet.ServletConfig interface.
The figure does not show all properties and methods of GenericServlet and HttpServlet.
Servlet Interface
The javax.servlet.Servlet interface is the heart of a Servlet architecture. All servlets must implement this interface. The Servlet interface declares the lifecycle methods of Servlet.
- init() initializes the servlet
- service() services to client requests
- destroy() stops service, returns resources
init()
The servlet container calls the init() method once after it created the servlet object. A servlet can service only after the init() method completes without errors. Before the init() completes, requests are blocked. The init() method receives the object of the ServletConfig interface type as an argument. If you set the Servlet initialization parameters in web.xml, this ServletConfig will have servlet initialization information set in web.xml. If there is servlet initialization information, you have to write the code to initialize the servlet in the body of the init() method.
void init(ServletConfig config) throws ServletException;
service()
A client sends a request to a servlet. The servlet container intercept the client's request and then calls the corresponding servlet's service() method. The service() method reads the request information from the ServletRequest type instance that is the first argument and responds to the client using the ServletResponse type instance that is the second argument.
Note that the servlet container executes the service() method on a new thread whenever a client sends a request. So a servlet can respond to a large number of client requests without delay. However, the critical section problem can arise with resources that the servlet uses (files, network connections, static variables, instance variables, etc.). Synchronizing resources used by the servlet is not good code in most cases. It is best not to create static or instance variables within the servlet class's body.
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
destroy()
It is called by the servlet container when the servlet is no longer in service. This method is not what the programmer calls in code. If you unload the web application using the tomcat manager or shut down Tomcat, the destroy() of servlets executes. The tomcat manager is a web application that you can access at http://localhost:8080/manager. You can manage web applications with the tomcat manager. The tomcat manager needs you to log in with the administrator id and password you set when installing Tomcat. If you do not remember your administrator id and password, you can see that in the CATALINA_HOME/conf/tomcat-users.xml.
void destroy();
GenericServlet abstract class
Most servlets inherit GenericServlet. GenericServlet implements Servlet and ServletConfig interface. Because GenericServlet does not implement the service() method of Servlet interface, GenericServlet's service() method remains an abstract method, so GenericServlet is an abstract class. Subclasses that inherit GenericServlet must implement the following 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 like below.
public void init() throws ServletException { }
You better override the parameterless init() rather than the init(ServletConfig config) in the subclass because you don't have to worry about storing the ServletConfig object. if you overrie the init(ServletConfig config) method in a subclass, you need to add super.init(config); code on the first line. Without this code, the servlet will not store the ServletConfig object.
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 variable's value.
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.
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(); }
The Enumeration interface has two methods to access the data in order: hasMoreElements() and nextElement().
It is for the convenience of the programmer that GenericServlet implements ServletConfig. It is easier to use this.getServletContext() rather than this.getServletConfig().GetServletContext() to get the reference to an object of type ServletContext in servlet. It is easier to use String driver = this.getInitParameter("driver") rather than String driver = this.getServletConfig().GetInitParameter("driver") to get servlet's initialization parameter information.
HttpServlet
Servlet responding HTTP requests should inherit HttpServlet abstract class. HttpServlet inherits GenericServlet abstract class. HttpServlet provides methods for handling HTTP requests.
The service() of HttpServlet has the following two parameters.
- HttpServletRequest
- HttpServletResponse
When the user's request reaches the server, the servlet container intercepts the request, creates two instances. One is the object of type HttpServletRequest from the user's request information. Another is the object of type HttpServletResponse required when the servlet sends the result to the user. The servlet container delivers created two objects to the servlet by calling the service(ServletRequest req, ServletResponse resp) method and this method the service(HttpServletRequest req, HttpServletResponse resp) method.
HttpServlet class implements the GenericServlet's service() abstract method by 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 HttpServlet class runs, this method reads the HTTP METHOD (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 "POST", it calls the doPost() method. Methods like doGet() and doPost() are the methods we need to override.
HttpServletRequest interface inherits ServletRequest interface. HttpServletResponse interface inherits ServletResponse interface. A vendor making servlet container makes classes that implement HttpServletRequest and HttpServletResponse interfaces.
Summary of Servlet API
- Servlet Interface
- init(ServletConfig config)
- service(ServletRequest req, ServletResponse resp)
- destroy()
- getServletConfig():ServletConfig
- Returns a ServletConfig object, which contains initialization and startup parameters for this servlet.
- getServletInfo():String
- Return simple information about this servlet
- ServletConfig Interface
- getInitParameter(String name):String
- Gets the value of the initialization parameter with the given name.
- getInitParameterNames():Enumeration
- Return the names of the servlet's initialization parameters as an Enumeration of String objects, or an empty Enumeration if the servlet has no initialization parameters.
- getServletContext():ServletContext
- Return a reference to the ServletContext
- getServletName():String
- Return the name of this servlet instance
- +GenericServlet Abstract class
- This class defines a generic, protocol independent servlet. This class implements Servlet and 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 a set of methods that a servlet uses to communicate with its servlet container. These methods do following:
- Get the MIME type of a file
- Get the full path of a file
- Dispatch requests
- Write to a log file
There is one ServletContext instance per web application. This instance serves as a common repository for dynamic components. In other words, data stored in the ServletContext is freely accessible form servlets and JSPs within the same web application. - setAttribute(Strng name, Object value)
- Stores data as a name-value pair.
- getAttribute(String name):Object
- Returns 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 corresponding to the given virtual path.
- getResource(String path):URL
- Returns a URL to the resource, which is mapping to the given path.
- RequestDispatcher Interface
- Used to sends requests from the client to any resource (such as a servlet, HTML file, or JSP file) on the server or adds another resource's contents to the response.
- forward(ServletRequest req, ServletResponse res)
- Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server.
- include(ServletRequest req, ServletResponse res)
- Includes the contents of a resource (servlet, JSP file, HTML file) in the response.
- ServletRequest Interface
- Contains client request information.
- setAttribute(String name, Object o)
- Stores data as a name-value pair in this request.
- 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. This method returns multiple values in a single HTTP parameter, such as a checkbox or a multiple-selection list.
- getRemoteAddr():String
- Returns the client's IP address.
- HttpServletRequest Interface
- Inherits ServletReqeust.
- getCookies():Cookie[]
- Returns an array containing all cookie objects the client sent with this request.
- getSession():HttpSession
- Returns current session associated with this request, or if the request does not have a session, creates one.
- getSession(boolean create):HttpSession
- Returns the current session associated with this request or, if there is no current session and create's value is true, returns a new session. If create is false, returns null.
- getContextPath():String
- Returns the part of the request URI that indicates the context of this request. 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".
- getServletPath():String
- Returns the part of this request's URL that calls the servlet.
- getQueryString():String
- If you request http://localhost:8080/ContextPath/board/list.jsp?page=1, it will return "page=1".
- ServletResponse Interface
- Used to send a response to client.
- getOutputStream():ServletOutputStream
- Returns an output stream for writing binary data in the response.
- getWriter():PrintWriter
- Returns an output stream for writing character text in the response.
- setContentType(String type)
- Sets the content type of the response being sent to the client. (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) It should be called before the getWriter() method.
- getContentType():String
- Return the content type specified by the setContentType() method or returns null if not specified.
- setCharacterEncoding(String charset)
- Sets the character encoding (MIME charset) of the response. 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. It should be called before the getWrite() method is executed.
- getCharacterEncoding():String
- Returns the name of the character encoding (MIME charset) used for the body of this response. Returns "ISO-8859-1" if no character encoding is specified.
- setContentLength(int length)
- Sets the length of the content body in the response with an int value. This method sets the HTTP Content-Length header.
- HttpServletResponse Interface
- Inherits the ServletResponse interface. Used to send an HTTP response to the client.
- addCookie(Cookie cookie)
- Adds the specified cookie to the response header.
- sendRedirect(String location)
- Sends a temporary redirect response to the client using the given location 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. For maintaining the session, the web browser adds the cookie information to the request whenever it sends a request to the server that sent the cookie. Cookies can store multiple name-value pairs. Also, cookies can have optional values for path, domain, expiration date, and security. To create a cookie on a server-side component, you need to write 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 whenever it sends a client request. The cookie information passed to the server-side component can be obtained as an array type using the getCookie() method of HttpServletRequest. Cookie or session is the technology that overcomes the HTTP protocol's limitations 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 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 subelement 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 exists and compile as shown below.
C:\ Command Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp "C:/apache-tomcat-9.0.87/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. Because you did not add the full path to the servlet-api.jar file as the javac's cp option value, if the classpath you are adding as cp option's value contains whitespace character, you must enclose it with double quotes character (").
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 and character encoding of the document to be output to a web browser. This code can be used only once in servlet and must run before getting the PrintWriter object. You can obtain the PrintWriter instance by calling the getWriter() of HttpServletResponse.
out.println("<html>"); out.println("<body>"); //Output the IP of client out.println("Your IP Address is " + req.getRemoteAddr() + ".\n");
SimpleServlet uses PrintWriter's println() method to send HTML code to the client. PrintWriter's println() method ouputs string passed as an argument to the client's web browser. HttpServletRequest's getRemoteAddr() is a method that returns the IP address of the client. HttpServeltRequest object contains information sent by the client and about the client.
Let's take a look at the process until the SimpleServlet servlet responds. The client uses the web browser to request the SimpleServlet. Tomcat intercepts the request and calls the +service(ServletRequest req, ServletResponse res) method of SimpleServlet. At this time, Tomcat passes the HttpServletRequest object that encapsulates the client's request and the HttpServletResponse object as method arguments to the +service() method. The +service(ServletRequest req, ServletResponse res) method merely calls the #service(HttpServletRequest req, HttpServletResponse resp) method. The #service() invokes methods such as doGet() or doPost() depending on HTTP Method (GET, POST, etc.). You requested SimpleServlet by typing directly into the web browser address bar. This request is a GET Method request. So the doGet() method runs.
How to send data to server-side resources and how server-side resources receive data from the client
In the Web environment, dynamic components are respond differently depending on the string data sent by the client. Web programmers who need to create dynamic web components need to know how to send string data to server-side resources using their web browser and obtain string data from clients on server-side resources. Web programmers mainly use form element and its subelements to allow clients to send string data to server-side resources. The web browser passes the client's data to the server-side resource specified by the form element's action attribute.
In the table below, the "HTML Form" item shows the HTML tag to receive data from the user, and the "Servlet" item shows code to get values from parameters sent by clients.
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 web browser. 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 HttpServletRequest is needed to get these values on the server-side resource. This method returns an array of strings consisting of the values chosen by the user. You can send multiple values with one parameter with the following HTML elements:
- <select multiple="multiple" ..><option..></option>..</select>
- <input type="checkbox"../>
If the select element has multiple= "multiple" attribute, the user can select multiple options using the Ctrl or Shift key. An input element whose type attribute value is "checkbox" is called a checkbox. Multiple checkboxes with same name attribute value belong to the same group. A checkbox differs from a radio button in that multiple checkboxes within the same group can be selected.
getParamterNames()
To figure out what parameters sent by the user on the server-side components, you need the getParamterNames() method of HttpServletRequest. The getParameterNames() method returns an Enumeration object containing all parameter names.
- <input type="file" ../>
- The input element whose type attribute value is "file" transfers binary data such as images to the server. It's parent element, the form must have attributes such as method="post" enctype="multipart/form-data". If you need to send other additional string data (For example, name, title, content, etc.) as well as binary data, add other elements to the form element in which <input type="file" /> exists. If you submit the form element in which <input type="file" /> exists, the web browser will transmit data with a different protocol than when sending only string data. In this case, the getParameter(String name) method can not access data sent from the client. Most programmers use external libraries to access data sent with binary data and binary data.
String transfer example
Let's practice how to get data sent by the client in the servlet. 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.
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 Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/apache-tomcat-9.0.87/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() passes control to another resource and retakes control when another resource completes its work. As a result, It adds messages produced by other resources to the response. The forward() passes control to another resource, which response 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 Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/apache-tomcat-9.0.87/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.
The process until the doPost() method runs.
We added servlet declaration and servlet-mapping of ControllerServlet 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 ControllerServlet's +servlet(servletRequest req, ServletResponse res). The +service(ServletRequest req, ServletResponse res) simply calls the #service(HttpServletRequest req, HttpServletResponse resp). The #service (HttpServletRequest req, HttpServletResponse resp) is responsible for checking the HTTP METHOD of the request and calling the appropriate method according to HTTP METHOD. HTTP METHOD of the request is the GET method because you requested http://localhost:8080/example/SignUp.action in the address bar of your web browser. So, #service() calls doGet() method. The doGet() calls the doPost() as we implemented it.
The following summarizes the HttpServletRequest methods used in the body of doPost().
getRequestURI() |
---|
Returns the part of this request's URL from the protocol name to the query string in the HTTP request. When requesting http://localhost:8080/example/SignUp.action in a web browser, it returns "/example/SignUp.action". The string following the quotation mark (?) after the URL is called a query string. The query string passes to the server-side resource corresponding to the URL. If there is more than one information in the query string, use & from the second. (e.g., http://localhost:8080/list.jsp?board=chat&page=1) |
getContextPath() |
Returns the portion of the request URI that indicates the context of the request. As we work in the ROOT application, the value we get through this method is "". |
The example detects the URL requested by the user with the following code.
req.getRequestURI().substring(req.getContextPath().length()):
The code returns "/example/SignUp.action".
The user requesting /example/SignUp.action receives a response of /example/SignUp.html.
Therefore, the user requested /example/SignUp.action gets a response from /example/SignUp.html.
TODO
In ControllerServlet.java, change isRedirect to true and recompile and test.
Servlet using database
Let's convert the GetEmp.java file, which we practiced in the JDBC chapter, into a servlet.
This task describes how to turn 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 Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/apache-tomcat-9.0.87/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 of GetEmpServlet added correctly to the web.xml file?
- Is there 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>
You can obtain values of the initialization parameters with the getInitParameter(String name) method of ServletConfig.
After restarting Tomcat, visit http://localhost:8080/initParam.
Using ServletContext Initialization Parameters
All servlets and JSPs can reference the ServletContext initialization parameters in the web application. The ServletContext initialization parameter is set in web.xml using the context-param element. The elements in web.xml have a specified order. The following excerpts from http://java.sun.com/dtd/web-app_2_3.dtd.
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>
The getServletContext() method return a reference of ServletContext instance.
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 SimpleServlet.java and recompile.
ServletContext sc = getServletContext(); String url = sc.getInitParameter("url"); out.println(url);
After restarting Tomcat, visit http://localhost:8080/simple.
Listener
The listener runs on the web application event. Two types of Web application events:
- 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.
Application shutdown events occur when the web application is shut down.
Session creation events occur when the servlet container creates a new session.
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 ServletContextListener interface.
ServletContextListener interface consists of two methods:
- public void contextInitialized(ServletContextEvent sce);
- public void contextDestroyed(ServletContextEvent sce);
If you want listeners for session creation and session invalidation events, implement HttpSessionListener interface.
HttpSessionListener interface consists of two methods:
- public void sessionCreated(HttpSessionEvent se);
- public void sessionDestroyed(HttpSessionEvent se);
Write the following Listener class, which, 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 declarations.
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";
When the ROOT web application starts, out Listener will create an OracleConnectionManager object and store its reference 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.
(We have already set up the declaration and mapping for the GetEmpServlet 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 log messages in the Tomcat log file.
Filter
If there is code to execute before a user's request reaches a server resource, use filter.
For the filter to work, you need to add declaration and mapping about the filter to web.xml.
If filter one followed by filter two in web.xml in order, filter one - filter two - Server resource - filter two - filter one runs.
A filter class must implement the following interface:
javax.servlet.filter
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 the servlet container calls this method, 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 the servlet container, the filter is no longer able to service. Mainly it used to return resources.
The doFilter() method's arguments show that the filter can access the ServletRequest, ServletResponse, and javax.servlet.FilterChain objects when it intercepts the request or response. A FilterChain has a list of filters to run in order.
In the doFilter() method, the code before FilterChain's doFilter() is the code to run before the request reaches the server resource, and the code after FilterChain's doFilter() is the code to run 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 Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/apache-tomcat-9.0.87/lib/servlet-api.jar ^ CharsetFilter.java
Open the web.xml file and add the following:
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>
You have to place the above code between the context-param element and the listener element-
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.
You can set up filter initialization parameters using the filter's subelement, 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.
The servlet container adds filters to the FilterChain in the order 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
This section introduces two external libraries to upload files.
MultipartRequest
Download the latest file 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 its name is the same as a file of the server file system.
public MultipartRequest(HttpServletRequest request, String saveDirectory, int maxPostSize, String encoding, FileRenamePolicy policy) throws IOException
Methods of MultipartRequest
If the MultipartRequest constructor has done successfully, the upload was successful.
The following shows the methods of MultipartRequest 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 file's extension is a 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 filename |
getParameter(String name); |
---|
Return the value of parameter with the given name. |
getParameterNames(); |
Return all parameter names as Enumeration type. |
getParameterValues(String name); |
Returns values of the parameter with the given name. |
MultipartRequest Example
Create the following HTML file in the DocumentBase/example directory of the ROOT application.
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 the following servlet in the WEB-INF/src/example directory.
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>"); } }
When compiling, you need to tell the Java compiler the path to the cos.jar file.
C:\ Command Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/www/myapp/WEB-INF/lib/cos.jar ^ UploadTest.java
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>
TEST
- Create a subdirectory named upload in the DocumentBase of the ROOT 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 the same name file, you will see a number appended to the file name's end.
If the test fails, check the list below.
- Check that the bytecode of the UploadTest servlet exists.
- Make sure that there is a subdirectory named upload in the DocumentBase of the ROOT application.
- Make sure the cos.jar file is in WEB-INF/lib in the ROOT application.
- Make sure the UploadTest servlet is correctly registered and mapped in the web.xml.
- Make sure the ROOT web application is loaded.
commons-fileupload
Commons-fileupload is a file upload library provided by The Apache Software Foundation.
Download the latest binary files from the following addresses:
- 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-<version>.jar and commons-io-<version>.jar files to the ROOT application's /WEB-INF/lib.
Example
Create the following HTML file in the DocumentBase/example directory of the ROOT application.
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>
Create the following servlet in the WEB-INF/src/example directory of the ROOT application.
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>"); } }
Compile it like below.
C:\ Command Promptjavac -d C:/www/myapp/WEB-INF/classes ^ -cp C:/www/myapp/WEB-INF/lib/commons-fileupload-<version>.jar; ^ C:/www/myapp/WEB-INF/lib/commons-io-<version>.jar ^ CommonsUpload.java
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.
When uploading the same name file, unlike cos.jar, it overwrites the existing file.
Cookie
The HTTP protocol does not maintain a state. A cookie is one of technologies for overcoming a web browser's inabilty to hold a communication session with a server due to the HTTP protocol's characteristics.
The server sends a cookie to the web browser.
First, the server makes and sends the cookie to a web browser. The cookie looks like as follows:
Set-Cookie : name = value ; expires = date ; path = path ; domain = domain ; secure
A web browser stores the cookie passed from the server into a file or memory.
The web browser sends the cookie to the server.
Once the web browser stores the cookie, the web browser sends the cookie whenever it requests the server resource. The cookie looks like the following:
Cookie ; name = value1 ; name2 = value2 ;
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) |
---|
Reset the value of the created cookie. |
setDomain(String pattern) |
By default, a web browser can send cookies the server that sent them. If you want to send a cookies to another server that belongs to the same domain group, use the setDomain() method. But you cannot specify domains not related to the server with setDomain(). |
setMaxAge(int expiry) |
Set the validity period of the cookie in seconds. If you set a negative number, a web browser deletes the cookie when it terminates. |
setPath(String uri) |
Sets the path to which cookies will be applied. If you specify a Uri, a web browser will send the cookie to the web server only if it visit the Uri. |
setSecure(boolean flag) |
If the 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's methods to set the cookie appropriately, you need to send it to a web browser. The following is the code that sends a cookie to a web browser.
resp.addCookie(cookie);
Access cookies sent by web browser
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 the code snippet that gets cookie value on 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; } } }
The following code shows how to delete a cookie. 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);
The JSP chapter covers cookie examples.
Session
A session is a cookie-based technology for overcoming weaknesses in cookie security. Unlike cookies, a web browser stores only session ID as a cookie. Session ID cookie stored in a web browser and session object (HttpSession Type) mapped to session ID cookie in server cooperate to maintain the user's data. The code snippet for creating a 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, returns null.
Once you create a session object, you can store the user's data in the session.
User user = new User("Alison", "11111111"); session.setAttribue("user", user);
The JSP chapter covers session examples.
References- https://java.net/downloads/servlet-spec/Final/servlet-3_1-final.pdf
- https://tomcat.apache.org/tomcat-8.0-doc/servletapi/
- https://jcp.org/en/jsr/detail?id=315
- http://docs.oracle.com/javaee/7/api/index.html?overview-summary.html
- http://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/
- https://java.net/downloads/servlet-spec/Final/servlet-3_1-final.pdf
- https://tomcat.apache.org/tomcat-8.0-doc/servletapi/
- https://jcp.org/en/jsr/detail?id=315
- http://docs.oracle.com/javaee/7/api/index.html?overview-summary.html
- http://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/
- http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
- http://commons.apache.org/proper/commons-io/download_io.cgi
- http://commons.apache.org/proper/commons-fileupload/using.html
- http://www.albumbang.com/board/board_view.jsp?board_name=free&no=292
- http://www.docjar.com/docs/api/javax/servlet/GenericServlet.html