Java Server Pages (JSP)

  1. What is JSP?
  2. Directives
    1. page directive
    2. include directive
    3. taglib directive
  3. Scripting
    1. Declarations
    2. Expressions
    3. Scriptlets
  4. Actions
    1. jsp:useBean
    2. jsp:setProperty
    3. jsp:getProperty
    4. jsp:param
    5. jsp:include
    6. jsp:forward
  5. Implicit Objects
    1. out
    2. request
    3. response
    4. pageContext
    5. session
    6. application
    7. config
    8. page
    9. exception
  6. Things to check in JSP syntax
    1. The differences between include directive and include action
    2. The relationship between ServletContext and Web application
    3. The page directive's session attributee
    4. The jsp:useBean action's scope
  7. JSP Examples
    1. JSP error handling in the early Servlet/JSP spec
    2. JSP error handling set in web.xmlc
    3. Cookie
    4. Separate pages using include directive
    5. Login using JavaBeans (using session)
    6. Modify the 'Login using JavaBeans (using session)' to be an example using action.
    7. JSP examples related to files

1. What is JSP?

JSP emerged as a Java-side countermeasure for ASP as Microsoft's ASP becomes popular. JSP is Servlet-based technology. JSP file inself cannot respond to client requests. JSP file is translated into a servlet by a servlet container, such as tomcat, and this servlet reacts to the client's request. A servlet java source translated from JSP is similar to the servlet we learned in the Servlet chapter, but they are not precisely the same.

It isn't enjoyable job to write Java code and HTML code together. Servlet compels us to generate the HTML design as a Java String and pass it as an argument to an output stream method. It means that you have to insert the HTML code into the Java code iff you use Servlet. In JSP, this is the opposite. Your job turns into inserting Java code into the HTML code. When writing HTML code and Java code together, JSP is much easier to write than Servlet. When you need to show your users the dynamically generated HTML with an intricate design, you should choose JSP.

In the chapter: Creating a new web application, we changed the application named myapp to the ROOT application. (The DocuementBase for the myapp application is C:/www/myapp) I recommend you should practice all the examples below in the ROOT application. Write JSP file in C:\www\myapp or its subdirectories with a regular editor, not Eclipse.

Create the following file in the DocumentBase of your ROOT application (C:\www\myapp).

/hello.jsp
<html>
<body>
Hello, World!
</body>
</html>

Visit http://localhost:8080/hello.jsp. When Tomcat first receives the /hello.jsp request, Tomcat generates a servlet from hello.jsp as follows:

// .. omit ..

try {
  response.setContentType("text/html");
  pageContext = _jspxFactory.getPageContext(this, request, response,
  			null, true, 8192, true);
  _jspx_page_context = pageContext;
  application = pageContext.getServletContext();
  config = pageContext.getServletConfig();
  session = pageContext.getSession();
  out = pageContext.getOut();
  _jspx_out = out;

  out.write("<html>\n");
  out.write("<body>\n");
  out.write("Hello, World!\n");
  out.write("</body>\n");
  out.write("</html>\n");
} catch (java.lang.Throwable t) {
  if (!(t instanceof javax.servlet.jsp.SkipPageException)){
    out = _jspx_out;
    if (out != null && out.getBufferSize() != 0)
      try {
        if (response.isCommitted()) {
          out.flush();
        } else {
          out.clearBuffer();
        }
      } catch (java.io.IOException e) {}
    if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
    else throw new ServletException(t);
  }
} finally {
  _jspxFactory.releasePageContext(_jspx_page_context);
}

// .. omit ..

Because hello.jsp is created in the DocumentBase of the ROOT application,the full path to the generated servlet is CATALINA_HOME\work\Catalina\localhost\_\org\apache\jsp\hello_jsp.java. Tomcat compiles this servlet, creates a servlet object from the servlet bytecode, and invokes the servlet object's service method. When /hello.jsp request arrives again, Tomcat checks the changes in the the hello.jsp file contents. If the file hasn't changed, Tomcat searches the servlet object in memory and calls its service method. If a servlet object is not in memory, Tomcat creates a servlet object. If there is a change in the JSP file, Tomcat make a new servlet Java source from the JSP file, compiles it, loads it in memory, and calls its service method.

2. Directives

Directives provide general information about a JSP to a Servlet Container. There are three directives: page, include, and taglib.

2.1 page directive

<%@ page {attribute="value"} %>
attribute="value" Description
language="scriptLanguage" The server-side language to compile the page (mostly java)
import="importList" The Java package or Java package list that the page imports. Commas (,) separate lists.
session="true | false" It determines whether the page uses session data (default is true).
errorPage="error_uri" The relative path of the error page that handles the JSP exceptions.
isErrorPage="true | false" It determines whether this page is an error page (default is false).
contentType="ctinfo" It sets the content type and charset of the response.
pageEncoding="charset" It sets the charset of the JSP file. You should specify the same as the charset specified by contentType.

If omitted, there are many attributes to which the default value applies. Therefore, you do not need to set all.

Most first page directives set the contentType attribute. You can set this attribute only once.

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>

The above directive sets the content type of the response to text/html and the response content's character set to UTF-8.

<%@ page import="java.util.HashMap,java.util.ArrayList" %>

This setting is required for the JSP's Java code to use the HashMap and ArrayList belonging to the java.util package. You can change the above to:

<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.ArrayList" %>

It is recommended to code this way because it is easy to see.

2.2 include directive

The include directive add documents to the JSP. The texts you add must be in the web application.

<%@ include file="header.jsp" %>

2.3 taglib directive

The taglib directive specifies the tag library used by the JSP page. A tag library is a technology for creating a tag that changes to Java code when the servlet container translates a JSP into a servlet. If you can use tags instead of Java code in JSP, you can manage your design efficiently. The tag library uses the uri and the prefix attributes to distinguish its tag set uniquely.

<%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>

The uri is a URI Information that uniquely names the tag library. The prefix distinguishes the tag libraries within a JSP page.

This book does not explain how to create a tag library. But the JSP Standard Tag Library (JSTL) included in the JSP specification is covered in the chapter: JSP Project.

3. Scripting

Scripting is used to insert Java code into JSP pages. There are three scripting: Declarations, Expressions, Scriptlets,

3.1 Declarations

Declarations declare instance variables and instance methods of the servlet within the JSP page. The following statement makes the instance variable of the servlet class.

<%! String name = new String("Alison"); %>

The following declaration makes instance method of the servlet class.

<%! 
public String getName() {
  return name;
} 
%>

3.2 Expressions

Expressions are converted to a Java String by the servlet container. If it can't become a Java String, ClassCastException occurs. The following works with the previous code to print Hello, Alison to the web browser.

Hello, <%=getName()%>

3.3 Scriptlets

You can insert Java statements freely within scriptlets. Java statements in Scriptlets are included in the servlet's _jspSevice() method when the servlet container translates a JSP into a servlet.

4. Actions

Actions create or modify objects.

4.1 <jsp:useBean>

This action creates a bean or finds the bean that already made. First, it looks for objects that use the same scope and id. If it cannot find that object, it creates an object according to the specified scope and id attributes.

<jsp:useBean id="name" scope="application" class="net.java_school.db.dbpool.OracleConnectionManager" />
<jsp:useBean>'s attributes
attribute Description
id The key for identifying the object in the same scope.
scope The range in which the generated bean's reference is valid. The scope's value is one of the following: page(default), request, session, application
class FQCN(Fully Qualified Class Name)
type The superclass or interface of the class defined in the class attribute.

<jsp:useBean id="cart" scope="request" class="example.Cart" /> action is like the following scriptlet:

<%
  example.Cart cart;
  cart = (example.Cart) request.getAttribute("cart");
  if (cart == null) {
    cart = new example.Cart();
    request.setAttribute("cart", cart);
  }
%>

4.2 <jsp:setProperty>

This action sets the property value of the bean.

<jsp:useBean id="login" scope="page" class="example.User" />
<jsp:setProperty name="login" property="passwd" />

The above actions are like the scriptlet below.

<%
  example.User user;
  user = (example.User) pageContext.getAttribute("user");
  if (user == null) {
    user = new example.User();
    pageContext.setAttribute("user", user);
  }
  String _jspParam;
  _jspParam = request.getParameter("passwd");
  if (_jspParam != null && !_jspParam.equals(""))
    user.setPasswd(_jspParam);
%>
<jsp:setProperty>'s attributes
attribute Description
name The name of the bean instance defined in <jsp:useBean>.
property Beans property whose value you want to change. If property="*", all the bean properties may change by calling the setter methods that matches each parameter name in the HTTP request. But if the parameter's value is empty, the property of the corresponding bean is not modified.
param The value of the param attribute is one of the parameter names of the HTTP request. The value of the bean's property set in the property attribute becomes the param attribute's value.
value Change the property of the bean to the string defined in the value attribute.

Suppose you have the following form page.

<form action="register.jsp" method="post">
  <input type="text" name="id" />
  <input type="password" name="passwd" />
</form>

Suppose there is the following action in register.jsp that receives the form input values:

<jsp:setProperty name="user" property="*" />

The above action is like the scriptlet below.

<%
  String _jspParam;
  _jspParam = request.getParameter("passwd");
  if ( _jspParam != null && !_jspParam.equals("") )
    user.setPasswd(_jspParam);
  _jspParam = request.getParameter("id");
  if ( _jspParam != null && !_jspParam.equals("") )
    user.setId(_jspParam);
%>

Suppose you have the following form page:

<form action="signUp.jsp" method="post">
  <input type="text" name="member_id" />
</form>

Suppose you have the following action in signUp.jsp that receives a form input value:

<jsp:setProperty name="user" property="id" param="member_id" />

The above action is like the scriptlet below.

<%
  String _jspParam;
  _jspParam = request.getParameter("member_id");
  if (_jspParam != null && !_jspParam.equals(""))
    user.setId(_jspParam);
%>

if the name of the bean's variable and the name of the form's parameter are not equal, you need to use the param attribute.

The following is an example of the setProperty action.

<jsp:setProperty name="user" property="id" value="admin" />

The above setProperty action is like the following scriptlet.

<%
  user.setId("admin");
%>

4.3 <jsp:getProperty>

The getProperty action takes the property value of the bean and puts it into the output stream.

<jsp:getProperty name="name" property="propertyName" />
<jsp:getProperty>'s attributes
attribute Description
name The bean instance's name
property The bean instance's property

4.4 <jsp:param>

This action is used to define the parameters to pass to <jsp:include> and <jsp:forward>.

<jsp:param name="name" value="value" />

4.5 <jsp:include>

This action adds static (HTML) or dynamic web components (JSP, Servlet) to the JSP.

<jsp:include page="urlSpec" flush="true">
  <jsp:param ... />
</jsp:include>
<jsp:include>'s attributes
attribute Description
page Relative path of the resources to include
flush Whether the buffer is flushed

4.6 <jsp:forward>

This action does forwarding. Forwarding means that the resource that received the client's request transfers control to another resource. The page attribute's value is the relative address of the target resource to which controll passes. You can use param element as the forward action's child to pass extra parameters to the target resource.

<jsp:forward page="relativeURL">
  <jsp:param .../>
</jsp:forward>

5. Implicit Objects

The JSP specification provides users with some implicit objects ready to use.

5.1 out

It is the reference to the instance of type: javax.servlet.jsp.JspWriter. It writes data to the response stream.

Create helloworld.jsp in the DocumentBase of the ROOT application as shown below and visit http://localhost:8080/helloWorld.jsp.

/helloWorld.jsp
<html>
<body>
<%
out.println("Hello, World!");
%>
</body>
</html>

Compare the servlet made from hello.jsp with the servlet made from helloworld.jsp. The full path of each servlet is:

  • CATALINA_HOME\work\Catalina\localhost\_\org\apache\jsp\hello_jsp.java
  • CATALINA_HOME\work\Catalina\localhost\_\org\apache\jsp\helloworld_jsp.java

5.2 request

It is the reference to the instance of type: javax.servlet.http.HttpServletRequest. This reference allows you to access request parameters, information sent by users in the header, and information about the user.

Create the following file in the DocumentBase of the ROOT application as shown below and visit http://localhost:8080/request.jsp?user=alison

/request.jsp
<html>
<body>
<%
out.println("Hello, " + request.getParameter("user"));
%>
</body>
</html>

5.3 response

It is the reference to the instance of type: javax.servlet.http.HttpServletResponse.

5.4 pageContext

It is the reference to the instance of type: javax.servlet.jsp.PageContext. It provides access to all available resources within the JSP. For example, it provides access to ServletRequest, ServletResponse, ServletContext, HttpSession, and ServletConfig.

5.5 session

It is the reference to the instance of type: javax.servlet.http.HttpSession.

Create the following file in the DocumentBase of the ROOT application as shown below and visit http://localhost:8080/session.jsp several times.

/session.jsp
<html>
<head>
  <title>session</title>
</head>
<body>
<%
Integer count = (Integer)session.getAttribute("count");
  
if (count == null) {
  count = new Integer(1);
  session.setAttribute("count", count);
} else {
  count = new Integer(count.intValue() + 1);
  session.setAttribute("count", count);
}
out.println("COUNT: " + count); 
%> 
</body>
</html>

5.6 application

It is the reference to the instance of type: javax.servlet.ServletContext interface.

5.7 config

It is the reference to type: javax.servlet.ServletConfig. The ServletConfig type instance contains servlet initialization parameter information.

5.8 page

It is a reference of type Object that refers to the servlet instance itself. So, you cannot declare a variable named page in JSP scripting. You seldom use this reference.

5.9 exception

The exception implicit object provides access to the uncaught exception that occurred in JSP. This reference is available only within pages whose page directive's isErrorPage attribute is true.

6. Things to check in JSP syntax

6.1 The differences between include directive and include action

If you use the include directive, one servlet made from one JSP into which all JSPs combined will responds to the client's request. If you use the include action, JSsP of the include action become each independent servlet and participates in a single response.

6.2 The relationship between ServletContext and Web application

According to the servlet specification, only one ServletContext instance must exist per web application. ServletContext has methods that communicate with the server-side components of the web application and the servlet container. So ServletContext serves as a common repository for JSPs and servlets. The resources stored in ServletContext exist for the lifetime of the web application.

6.3 The page directive's session attribute

When the page directive's session attribute is false, such as <%@ page session="false" ..>, the page can not create a session object nor can it obtain a reference to the existing session instance. If you try to access the session while session attribute is false, an exception occurs.

6.4 The jsp:useBean action's scope

The scope attribute of <jsp:useBean> determines how far to use the JavaBean. Depending on how the scope attribute is specified, the bean instance is available without being destroyed on several pages. For example, if the scope attribute'value is session, this bean will not be destroyed until the end of the session. The scope's default value is page. You can select one of four values.

Scope Description
page It is the default value of scope. If you omit the scope attribute, this becomes the value of the scope attribute. A page scope bean is valid only on the page. A page scope bean is created each time users request the JSP page and eliminates when the page finishes execution. A page scope bean isn't available on the target page of the target page of the include or forward action. Even if there is the useBean action with the same id and scope bean on the target page, this action creates a new bean. Also, the page scope bean made on the target page of the include action isn't available on the page that tabkes back control. A page scope bean is appropriate when the state of the bean does not need to be maintained.
request If necessary, A useBean action with scope="request" creates a new bean and stores it in the HttpServletRequest instance. Therefore, A request scope bean is available on the target page of the include or forward actions.
session If necessary, A useBean action with scope="session" creates a new bean and stores it in the HttpSession instance. Therefore, a session scope bean is available on all JSP pages and servlets until the session is invalidated. On the other hand, page scope beans and request scope beans disappear after the server-side components finish their job. The session created for each user maintains values that all server-side components can reference until the session is invalidated. But JSP with <%@ page session="false"> cannot use session scope beans.
application If necessary, A useBean action with scope="application" creates a new bean and stores it in the ServletContext instance. Therefore, an application scope bean is available until the web application terminates. Beans in the ServletContext are common resources for the web application because all JSPs and servlets in the same web application can access beans in the ServletContext. You should think carefully before deciding to use application scope beans.

7. JSP Examples

7.1 JSP error handling in the early Servlet/JSP spec

JSP spec provides a way to deal with errors by giving JSP page handling only errors. If an unhandled exception in JSP occurs, the servlet container passes the user's request to the JSP error page with an occurred exception. To make a JSP error page, set the value of the page directive's isErrorPage attribute to true. Create the following errorPage.jsp in the DocumentBase in the ROOT application.

/errorPage.jsp
<%@ page isErrorPage="true" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<html>
<body>
<p>
The following error has occurred.<br />
<%=exception.getMessage() %>
</p>
</body>
</html>
IsErrorPage="true" 

It tells the container that this page deals with only errors.

<%=exception.getMessage() %>

It prints the message of the exception sent to the JSP error page. Here exception is an implicit object. Only the JSP error page can use this reference. To see how the JSP error page works, write the following file in the DocumentBase of the ROOT application.

/errorMaker.jsp
<%@ page errorPage="errorPage.jsp" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%
if (true) {
  throw new Exception("Intentionally occurred Exception.");
}
%>

Handling errors using the JSP error page is an old way that is not well used nowadays.

7.2 JSP error handling set in web.xml

You can specify several error pages in the web.xml file by HTTP status code and the type of exception.

HTTP status code

403 Forbidden
The client does not have access rights to the content; that is, it is unauthorized, so the server refuses to give the requested resource.

404 Not Found
The server can not find the requested resource.

500 Internal Server Error
The server has encountered a situation it doesn't know how to handle.

Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

WEB-INF/web.xml
<error-page>
  <error-code>404</error-code>
  <location>/error.jsp</location>
</error-page>
<error-page>
  <error-code>403</error-code>
  <location>/error.jsp</location>
</error-page>
<error-page>
  <error-code>500</error-code>
  <location>/error.jsp</location>
</error-page>
/403.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>403</title>
</head>
<body>
<h3>403</h3>
<p>
Forbidden
</p>
</body>
</html>
/404.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>404</title>
</head>
<body>
<h3>404</h3>
<p>
PAGE NOT FOUND
</p>
</body>
</html>
/500.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>500</title>
</head>
<body>
This page isn't working
</body>
</html>

Visit http://localhost:8080/Jaqueline.jsp. If you did not create the Jaqueline.jsp file in the Documentbase, the 404 error occurs, and the 404.jsp file responds. But in Internet Explorer, if the error page's content is less than a particular byte, the error page may not work.

You can also declare several error pages in the web.xml file by the type of exception.

<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/error.jsp</location>
</error-page>

Since all exceptions are subtypes of the Throwable type, the servlet container passes the control to error.jsp no matter what exception occurs. You can add more specific exceptions. If the thrown exception matches multiple exception handlers, the servlet container chooses the most accurate one of them.

With this approach, you can not use the implicit exception object in error.jsp. Instead, you can get information about occurred exception with the request's attribute value like javax.servlet.error.exception.

In Scriptlet:

Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");

Here is a list of the attributes of the request related to the error. You can access all of them in the same way as above.

javax.servlet.error.status_code
Error status code.
Return Type: java.lang.Integer
javax.servlet.error.exception_type
Exception type.
Return Type: java.lang.Class
javax.servlet.error.message
Error message.
Return Type: String
javax.servlet.error.exception
Exceptions occurred.
Return Type: java.lang.Throwable
javax.servlet.error.request_uri
The URI of the resource that caused the problem.
Return Type: String
javax.servlet.error.servlet_name
The name of the servlet that caused the problem.
Return Type: String

In JSTL, which will be discussed later, the above attributes are accessed as follows:

<c:out value="${requestScope['javax.servlet.error.message']}" />

The following file is available as a handler for all HTTP status codes and all exceptions.

/error.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Error</title>
</head>
<body>
<%
//Analyze the servlet exception
Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name");

if (servletName == null) {
  servletName = "Unknown";
}

String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");

if (requestUri == null) {
  requestUri = "Unknown";
}
 
if(statusCode != 500){
  out.write("<h3>Error Details</h3>");
  out.write("<strong>Status Code</strong>:" + statusCode + "<br>");
  out.write("<strong>Requested URI</strong>:"+requestUri);
}else{
  out.write("<h3>Exception Details</h3>");
  out.write("<ul><li>Servlet Name:" + servletName + "</li>");
  out.write("<li>Exception Name:" + throwable.getClass().getName() + "</li>");
  out.write("<li>Requested URI:" + requestUri + "</li>");
  out.write("<li>Exception Message:" + throwable.getMessage() + "</li>");
  out.write("</ul>");
}
%>
</body>
</html>

It is better not to set error pages at the development stage for debugging.

Cookies are simple data stored in the web browser and transmitted to server-side components along with user requests. If the cookie's lifetime is specified using the setMaxAge() method, the web browser stores the cookie information as a file. Cookies without setMaxAge() will eliminate when the web browser exits.

Cookie operation process
  1. The web browser requests a server resource with code that adds cookies to the HTTP response header.
  2. The server resource adds cookies value to the HTTP response header.
  3. The web browser fetches the cookie data from the response header and saves it.
  4. The web browser sends cookie data whenever it requests resources of the server that provided the cookie.

In step 2, the cookie value included in the response header looks like the string below.

Set-Cookie: name=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure

The highlighted string is the required data, Italics are the parts that you need to be change to actual values.

In the fourth step, the cookie information included in the request header looks like the string below.

Cookie: name1=VALUE1; name2=VALUE2;...
One cookie consists of the following information:
  • name
  • value
  • expires
  • domain
  • path
  • secure(https)

The following is Cookie class.

javax.servlet.http.Cookie
Cookie(String name, String value)
getName()
setValue(String)
getValue()
setDomain(String)
getDomain()
setPath(String)
getPath()
setMaxAge(int)
getMaxAge()
setSecure(boolean)
getSecure()

The following code snippet shows how to use the Cookie class.

/*
* Creates a cookie.
*/
Cookie cookie = new Cookie("user", "alison");

/*
* If it starts with a dot, the cookie is sent to the relevant domain.
* www.java-school.net, user.java-school.net, blog.java-school.net, etc.
*/
cookie.setDomain(".java-school.net");

/*
* To create a cookie that applies to your website's every path, specify /. 
* If you set a specific path, such as /user, cookies are sent only to requests containing /user.
*/
cookie.setPath("/");

/*
* Set cookie expire time in seconds.
* If you set a negative value here, the cookie is deleted when the web browser terminates. 
*/
cookie.setMaxAge(60*60*24*30); //Cookies valid for 30 days

Create a subdirectory named cookie in the DocumentBase and make the following files in it.

/cookie/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Cookie Test</title>
</head>
<body>
<h1>Cookie Test</h1>
<ul>
  <li><a href="setCookie.jsp">Burn Cookies</a></li>
  <li><a href="viewCookie.jsp">Confirm Cookies</a></li>
  <li><a href="editCookie.jsp">Modify Cookies</a></li>
  <li><a href="delCookie.jsp">Delete Cookies</a></li>
</ul>
</body>
</html>
/cookie/setCookie.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="java.net.*"  %>
<%
Cookie cookie = new Cookie("name", URLEncoder.encode("Alison", "UTF-8"));

/*
* If setPath() is not used, the path is set to the directory where setCookie.jsp is located. (path=/cookie)
*/ 
response.addCookie(cookie);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Burn Cookies</title>
</head>
<body>
Set-Cookie: <%=cookie.getName() %>=<%=cookie.getValue() %><br />
<a href="viewCookie.jsp">Confirm Cookies</a> 
</body>
</html>
/cookie/viewCookie.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Confirm Cookies</title>
</head>
<body>
<%
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 1) {
  int length = cookies.length;
  for (int i = 0; i < length; i++) {
%>
  <%=cookies[i].getName() %>=<%=URLDecoder.decode(cookies[i].getValue(), "UTF-8") %><br />
<%			
  }
}
%>
<a href="./">index.html</a>
</body>
</html>
/cookie/editCookie.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 1) {
  int length = cookies.length;
  for (int i = 0; i < length; i++) {
    if (cookies[i].getName().equals("name")) {
      Cookie cookie = new Cookie("name", URLEncoder.encode("Bill" ,"UTF-8"));
      response.addCookie(cookie);
    }
  }
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Modify Cookies</title>
</head>
<body>
Cookie value changed.<br />
<a href="viewCookie.jsp">Confirm Cookies</a>
</body>
</html>
/cookie/delCookie.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 1) {
  int length = cookies.length;
  for (int i = 0; i < length; i++) {
    if (cookies[i].getName().equals("name")) {
      Cookie cookie = new Cookie("name", "");
      cookie.setMaxAge(0);
      response.addCookie(cookie);
      break;
    }
  }
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Delete Cookies</title>
</head>
<body>
name cookie deleted.<br />
<a href="viewCookie.jsp">Confirm Cookies</a>
</body>
</html>

7.4 Separate pages using include directive

Copy all files in https://github.com/kimjonghoon/example and paste them to the DocumentBase of your ROOT application. Open the index.jsp file and confirm the following:

<%@ include file="sub.jsp" %>

The index.jsp includes the sub.jsp. Separating the parts of the page into independent files and consolidating them using include directives makes maintenance becomes easier. In the sub.jsp code, the path for files, images, style sheets, and so on should be relative to the index.jsp. Because JSP files are combined based on the index.jsp. On the other hand, paths within style sheets should be relative to the style sheet file itself, not index.jsp. Visit http://localhost:8080/example/ex1/index.jsp to confirm this.

7.5 Login using JavaBeans (using session)

The location of this example is /example/ex2/. The login_proc.jsp page is the page that uses the bean of User type (net.java_school.user.User) to process Login. To run the example, write net.java_school.user.User.java like below and compile it to generate bytecode in WEB-INF/classes.

User.java
package net.java_school.user;

public class User {

  private String id;
  private String passwd;
	
  public String getId() {
      return id;
  }
	
  public void setId(String id) {
      this.id = id;
  }
	
  public String getPasswd() {
      return passwd;
  }	
	
  public void setPasswd(String passwd) {
      this.passwd = passwd;
  }

}

Visit http://localhost:8080/example/ex2/index.jsp and test Login.

Confirm the following code in the index.jsp.

<input type="text" name="id" />

The id parameter goes to login_proc.jsp. Confirm the following code in the login_proc.jsp.

String id = request.getParameter("id");

You can get the value of the id parameter in login_proc.jsp using the getParameter() method of the request implicit object. The login_proc.jsp creates a User object and sets its instance variables using the passed id and passwd parameters. The login process completes by putting this User object in the session. To simplify the example, I omitted the code related to the database. Therefore, log in is successful for any ID and password.

login_proc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="net.java_school.user.User" %>

<%
String id = request.getParameter("id");
String passwd = request.getParameter("passwd");

/* 
* Here you need the logic to query the database for members with id and passwd.
*/
User user = new User();
user.setId(id);

//Store the User instance in the session with the key named user.
session.setAttribute("user", user);
%>

<jsp:forward page="index.jsp" />

7.6 Modify the 'Login using JavaBeans (using session)' to be an example using action

The location of the example is /example/ex3/. The login_proc.jsp uses actions.

/login_proc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="net.java_school.user.User" %>
<jsp:useBean id="user" scope="session" class="net.java_school.user.User" />
<jsp:setProperty name="user" property="*"/>
<jsp:forward page="index.jsp" />

The useBean action finds an object with the "user" key in the session. If there is no such object, this action creates a User object from the net.java_school.user.User class and store it in the session with the value of id attribute value of the useBean action, the User object's key. The setProperty action sets the instance variables by calling the JSP beans's setter methods with the parameters's values in the HTTP request.

<jsp:setProperty name="user" property="*"/>

The above action calls the setId() and setPasswd() methods of the User bean. The servlet container finds all setter methods that match the HTTP request parameters and passes the request parameter's value of the setter method as an argument.

JSP or JSP bean Code
index.jsp
<input type="text" name="id" />
login_proc.jsp
<jsp:setProperty name="login" property="id" />
User.java
setId(String id)

In the "setId()" method name, the "I" in Id is an uppercase letter. (We already studied Java naming convention in the Java chapter) The setProperty action will not work unless beans follow the Java naming convention. Here, the Java naming convention is not a recommendation, but a grammar.

7.7 JSP examples related to files

We already covered the file upload example in the Servlet chapter. The following JSP shows a list of uploaded files in the upload folder.

/fileList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="java.io.*" %>
<%@ page import="java.net.*" %>
<%
String upload = application.getRealPath("/upload");

File dir = new File(upload);
File[] files = dir.listFiles();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>List of saved files</title>
<script type="text/javascript">
function goDownload(filename) {
  var form = document.getElementById("downForm");
  form.filename.value = filename;
  form.submit();
}
</script>
</head>
<body>
<%
int len = files.length;
for (int i = 0; i < len; i++) {
  File file = files[i];
  String filename = file.getName();
%>
  <a href="javascript:goDownload('<%=filename %>')"><%=file.getName() %></a><br />
<%
}
%>
<form id="downForm" action="download.jsp" method="post">
  <input type="hidden" name="filename" />
</form>
</body>
</html>

The following JSP responds when you click the file name on the file list page above.

/download.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.io.File" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.io.OutputStream" %>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.commons.io.FileUtils" %>
<%
request.setCharacterEncoding("UTF-8");
String filename = request.getParameter("filename");

String path = application.getRealPath("/upload");
File file = new File(path + "/" + filename);

response.setContentLength((int) file.length());

String filetype = filename.substring(filename.indexOf(".") + 1, filename.length());
if (filetype.trim().equalsIgnoreCase("txt")) {
  response.setContentType("text/plain");
} else {
  response.setContentType("application/octet-stream");
}

String userAgent = request.getHeader("user-agent");
boolean ie = userAgent.indexOf("MSIE") != -1;
if (ie) {
  filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", " ");
} else {
  filename = new String(filename.getBytes("UTF-8"), "8859_1");
}

response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\";");
/* response.setHeader("Content-Transfer-Encoding", "binary"); */

OutputStream outputStream = response.getOutputStream();

try {
  FileUtils.copyFile(file, outputStream);
} finally {
  outputStream.flush();
}
%>

The following is the JSP replacement of the file upload servlet in the Servlet chapter.

fileupload_proc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="
java.util.Iterator,
java.io.File,java.util.List,
javax.servlet.http.HttpServletRequest,
org.apache.commons.fileupload.FileItem,
org.apache.commons.fileupload.FileItemFactory,
org.apache.commons.fileupload.FileUploadException,
org.apache.commons.fileupload.disk.DiskFileItemFactory,
org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%
//Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
//Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();

//Configure a repository (to ensure a secure temp location is used)
File repository = (File) application.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);

//Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
//Parse the request
List<FileItem> items = upload.parseRequest(request);
//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 : " + fieldName);out.println(",");
    fileName = item.getName();
    out.println("fileName : " + fileName);out.println(",");
    String contentType = item.getContentType();
    out.println("contentType : " + contentType);out.println(",");
    boolean isInMemory = item.isInMemory();
    out.println("isInMemory : " + isInMemory);out.println(",");
    long sizeInBytes = item.getSize();
    out.println("sizeInBytes : " + sizeInBytes);
  }
  // Process a file upload
  String dir = application.getRealPath("/upload");
  File uploadedFile = new File(dir + "/" + fileName);
  item.write(uploadedFile);
}
response.sendRedirect("upload.html");
%>