tutorials / java-server / jsp

JSP

tutorial java server jsp

Now we know how to add servlets to our web apps. A servlet looks like this:

import java.io.PrintWriter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<title>My Web App</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>My Web App</h1>");
		out.println("<p>The current time is: " + new Date().toString() + "</p>");
		out.println("</body>");
		out.println("</html>");
	}
}

This code uses the out.println() function to output HTML one line at a time. In other words, this is HTML inside Java.

There are a few problems with having HTML inside Java:

Basically, it’s just annoying to work this way.

This tutorial introduces JSP, or JavaServer Pages, which are more like Java inside HTML.

JSP Files

Instead of writing a Java program that contains HTML, JSP allows you to write HTML that contains Java code. Here’s a JSP file that outputs the same dynamic content (the current date) as the above servlet:

<%@ page import="java.util.Date" %>
<!DOCTYPE html>
<html>
	<head>
		<title>My Web App</title>
	</head>
	<body>
		<h1>My Web App</h1>
		<p>The current time is: <%= new Date().toString() %></p>
	</body>
</html>

Save this to a file named date.jsp in your web app’s directory. Your file structure should look like this:

Now open a browser to http://localhost:8080/MyWebApp/date.jsp, and you should see this:

date jsp

When you visit the .jsp file, the Jetty server automatically compiles it into a servlet class, which then works just like any other servlet. Note that this requires a Java server! So you can’t upload a .jsp file to any file host. It has to be a Java server.

But now instead of writing Java code that contains HTML, you can write HTML that contains Java code. This makes it much easier to write a webpage.

There are a few ways to include Java code in a JSP page.

Scriptlets

A scriptlet is Java code that does something and is placed between opening <% and closing %> scriptlet tags. Here’s an example:

<!DOCTYPE html>
<html>
	<head>
		<title>Coin Flipper</title>
	</head>
	<body>
		<h1>Coin Flipper</h1>
		<p>Flipping a coin...</p>
		<% if(Math.random() < .5){ %>
			<p>Heads!</p>
		<% } 
		else{ %>
			<p>Tails!</p>
		<% } %>
		<hr />
		<p>Refresh to flip again.</p>
	</body>
</html>

This code uses an if statement and the Math.random() function to show Heads! or Tails! randomly.

coin flipper jsp

Notice a couple things in the above code:

Expressions

An expression is Java code that evaluates to a value and is placed between opening <%= and closing %> expression tags. Here’s an example:

<!DOCTYPE html>
<html>
	<head>
		<title>Unix Time</title>
	</head>
	<body>
		<h1>Unix Time</h1>
		<p>The current Unix time is: <%= System.currentTimeMillis() %></p>
		<hr />
		<p>Showing number of milliseconds since midnight on January 1, 1970.</p>
		<p>Click <a href="https://en.wikipedia.org/wiki/Unix_time">here</a> for more info.</p>
	</body>
</html>

This code uses an expression to insert the value returned from the System.currentTimeMillis() function into the HTML of the page.

unix time JSP

Mixing Scriptlets and Expressions

You can use both scriptlets (code that does something) and expressions (code that evaluates to a value) in the same JSP file. Here’s a very basic example:

<% String message = "hello!"; %>
<p>Here's some HTML</p>
<p>Message: <%= message %></p>

Notice that we use a scriptlet to create a message variable. Then later on in the code, we use an epression to insert the value of that variable into the HTML.

Here’s a more complicated example:

<% String[] animals = {
	"lions", "tigers", "bears", "lizards", "zebras",
	"kangaroos", "elephants", "cows", "monkeys", "anteaters"
	}; %>
<!DOCTYPE html>
<html>
	<head>
		<title>JSP Zoo</title>
	</head>
	<body>
		<h1>JSP Zoo</h1>
		<p>Here are the animals we visited at the zoo:</p>
		<% for(int i = 0; i < animals.length; i++){ %>
			<p><%= i+1 %>: <%= animals[i] %></p>
		<% } %>
	</body>
</html>

This code uses a scriptlet to define an array named animals. Then it uses another scriptlet to iterate over that array using a for loop. Inside the for loop, it uses an expression to print the index, and the value in the array at that index. Finally, it uses another scriptlet to close the loop.

JSP zoo

Directives

So far, we’ve learned that scriptlets contain code that does something, and expressions contain code that evaluates to a value. Directives are placed between opening <%@ and closing %> tags, and they contain code that tells the page itself what to do.

Directives can contain things like Java import statements, like in the first line of this code:

<%@ page import="java.util.Date" %>
<!DOCTYPE html>
<html>
	<head>
		<title>My Web App</title>
	</head>
	<body>
		<h1>My Web App</h1>
		<p>The current time is: <%= new Date().toString() %></p>
	</body>
</html>

Directives can also be used to include content from other files. For example, we can use this to create a navigation bar in one file, and then include that file in all of our JSP pages.

Save this content to a file named header.html:

<div style="border: thin solid black; padding:5px;">
	<a href="home.jsp">Home</a>
	<a href="about.jsp">About</a>
	<a href="pictures.jsp">Pictures</a>
	<a href="help.jsp">Help</a>
</div>

Now that we have that file, we can use a directive to include that on our JSP pages:

<!DOCTYPE html>
<html>
	<head>
		<title>Header Example</title>
	</head>
	<body>
		<%@ include file = "header.html" %>
		<p>Content goes here.</p>
	</body>
</html>

The include directive inside the <body> tag copies the content from header.html into the content of the JSP file, so we see the header in our page:

JSP header include

This makes it easy to share content between multiple pages. If we had 100 pages that included the header, we would only need to change one file to change the header on every page.

Errors

Remember that JSP files are compiled into servlets automatically. That means we have to pay attention to the output, so we know when errors happen.

Let’s take this example JSP:

<!DOCTYPE html>
<html>
	<head>
		<title>Error Example</title>
	</head>
	<body>
		<% String messageOne = "hello"; %>
		<p>Message: <%= messageTwo %></p>
	</body>
</html>

This code creates a messageOne variable, but then tries to read a messageTwo variable. The messageTwo variable doesn’t exist, so this code won’t compile.

If we try to visit this page, we’ll see an error:

JSP error

This can seem overwhelming at first, but it’s actually telling you exactly what the problem is.

An error occurred at line: 8 in the jsp file: /index.jsp
messageTwo cannot be resolved to a variable
5: 	</head>
6: 	<body>
7: 		<% String messageOne = "hello"; %>
8: 		<p>Message: <%= messageTwo %></p>
9: 	</body>
10: </html>

This is telling you that the error is on line 8, and that it can’t find the messageTwo variable.

For better or worse, encountering errors like this is a natural part of programming! If you can’t figure out where an error is coming from, try to isolate the problem in a smaller example.

Mixing Servlets and JSP Files

Now we know how to use servlets. A servlet looks like this:

import java.io.PrintWriter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<title>My Web App</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>My Web App</h1>");
		out.println("<p>The current time is: " + new Date().toString() + "</p>");
		out.println("</body>");
		out.println("</html>");
	}
}

And we know how to use JSP files. A JSP file looks like this:

<%@ page import="java.util.Date" %>
<!DOCTYPE html>
<html>
	<head>
		<title>My Web App</title>
	</head>
	<body>
		<h1>My Web App</h1>
		<p>The current time is: <%= new Date().toString() %></p>
	</body>
</html>

There are pros and cons to both approaches. Servlets make it easier to use Java code, but it can be very annoying to program HTML in them. On the other hand, JSP files make it easy to mix HTML and Java, but it can be annoying to include complicated logic inside a JSP file.

We can use a mix of both servlets and JSP files to get the best of both worlds: we can use servlets to execute our logic with Java code, and we can use JSP files to render a page using parameters generated from the servlet.

For example, let’s redo our above example to use a servlet that generates the current time and passes it as a parameter to a JSP file for rendering.

Here’s what our Servlet would look like:

import java.io.PrintWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DateServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

		// 5:12 PM on Saturday, June 3, 2017
		SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm aa 'on' EEEE, MMMM dd, yyyy");
		Date now = new Date();
		String formattedDate = dateFormat.format(now);

		request.setAttribute("date", formattedDate);
		request.getRequestDispatcher("dateView.jsp").forward(request,response);
	}
}

This code uses the SimpleDateFormat class to format the current time. It then uses the request.setAttribute() function to include the formatted date in the request, and then it uses the request.getRequestDispatcher("path/to/view.jsp").forward(request, response) function to send the request to a JSP file.

Next, we’d need need a dateView.jsp file that handles the request:

<!DOCTYPE html>
<html>
	<head>
		<title>Current Time</title>
	</head>
	<body>
		<h1>Current Time</h1>
		<p>The current time is <%= request.getAttribute("date") %></p>
	</body>
</html>

Notice the <%= request.getAttribute("date") %> expression, which gets the date attribute that the servlet added.

This allows us to keep our JSP code simple, and all of our logic in our servlets.

Tying it together, we’d need a web.xml file that mapped a request to the servlet:

<web-app>

	<servlet>
		<servlet-name>CurrentTimeServlet</servlet-name>
		<servlet-class>DateServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>CurrentTimeServlet</servlet-name>
		<url-pattern>/current-time</url-pattern>
	</servlet-mapping>

</web-app>

This XML creates a CurrentTimeServlet from our DateServlet class and then maps the /current-time URL to that servlet.

At this point, our directory structure should look like this:

And now if we navigate to http://localhost:8080/MyWebApp/current-time in our browser, we should see:

current time webpage

Expression Language

So far, we’ve been using a simplified version of web.xml just to keep it short. But now that we’re getting more complicated, we’re ready to use more advanced features. To activate them, let’s use a deployment descriptor in our web.xml file.

<web-app
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
		http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">

	<servlet>
		<servlet-name>CurrentTimeServlet</servlet-name>
		<servlet-class>DateServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>CurrentTimeServlet</servlet-name>
		<url-pattern>/current-time</url-pattern>
	</servlet-mapping>

</web-app>

The only thing that changes is the addition of attributes in the opening <web-app> tag. These tell the server that we want to use the latest features, including expression language in our JSP files.

Expression language (or EL) gives us a simplified syntax for doing things like accessing attributes. So now we can use ${date} instead of <%= request.getAttribute("date") %>:

<!DOCTYPE html>
<html>
	<head>
		<title>Current Time</title>
	</head>
	<body>
		<h1>Current Time</h1>
		<p>The current time is ${date}</p>
	</body>
</html>

Hiding JSP Files

Remember that users can’t directly access stuff inside the WEB-INF directory. But because our dateView.jsp file is not inside the WEB-INF directory, it’s publicly available. That means users can visit http://localhost:8080/MyWebApp/dateView.jsp directly, which shows a page like this:

blank current time webpage

Notice that the current time is blank. Because we’re accessing the dateView.jsp file directly, the servlet wasn’t triggered, so it didn’t add the current time to the attributes. We probably want to prevent users from being able to see buggy pages like this, so let’s hide our JSP files.

We can do this by moving the dateView.jsp file inside the WEB-INF directory. Let’s put it inside a jsp folder, so our directory structure looks like this:

Now we would just need to change our DateServlet code to point to the new location of dateView.jsp:

import java.io.PrintWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DateServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

		// 5:12 PM on Saturday, June 3, 2017
		SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm aa 'on' EEEE, MMMM dd, yyyy");
		Date now = new Date();
		String formattedDate = dateFormat.format(now);

		request.setAttribute("date", formattedDate);
		request.getRequestDispatcher("/WEB-INF/jsp/dateView.jsp").forward(request,response);
	}
}

Notice how we now forward the request to /WEB-INF/jsp/dateView.jsp. Our code is allowed to access the WEB-INF directory, but users can’t see what’s inside it. This allows us to keep things mostly hidden from users.

MVC

This approach of using servlets to contain our logic and JSP files to contain our rendering code gets us closer to Model-View-Controller, or MVC.

MVC is the idea of separating your data from your logic from your rendering. It allows you to focus on one thing at a time, and makes debugging and making changes to one piece much easier. You can use this idea in any type of programming, but when developing server code it generally works like this:

You don’t have to worry about getting everything exactly correct, and concepts like MVC are more of a way of thinking about organization than it is a strict set of rules. But keeping your data, your logic, and your rendering separate will definitely make your life easier. And this approach of splitting your servlets and your JSP files will help with that.

Static Files

We can still use static files with this approach. So we can have an index.html file that looks like this:

<!DOCTYPE html>
<html>
	<head>
		<title>My Home Page</title>
	</head>
	<body>
		<h1>Welcome to my web page!</h1>
		<p>Click <a href="http://localhost:8080/MyWebApp/current-time">here</a> to see the current time.</p>
	</body>
</html>

Put this in your MyWebApp directory (not inside the WEB-INF folder), and then visit http://localhost:8080/MyWebApp/index.html to see a page like this:

static home page

Note that this static file links to our dynamic page that shows the current time. You can also go the other way and link from a dynamic page to static files. This allows us to load stuff like images and CSS files in our JSP views. Remember: the end result is just regular HTML, so anything you can do in HTML, you can do with servlets and JSP files.

Next: Eclipse