Article

Home » Server-side Coding » Java and J2EE » All Java, No Froth: 6 Easy Steps to MVC Web Apps
SitePoint Feature Article

About the Author

Kevin Yank

author_kev1 Kevin began developing for the Web in 1995 and is a highly respected technical author. He wrote Build your own Database Driven Website using PHP and MySQL, a practical step-by-step guide published by SitePoint, and he's co-author of the SitePoint Tech Times, a bi-weekly newsletter for technically-minded web developers. Kev believes that any good webmaster should have seen at least one episode of MacGyver.

View all articles by Kevin Yank...

All Java, No Froth: 6 Easy Steps to MVC Web Apps

By Kevin Yank

January 25th, 2006

Reader Rating: 9

Page: 1 2 3 4 5 6 Next

It's an exciting time to be a Java web developer. Gaining popularity amongst hosting providers, Java 5 (Java 2 Standard Edition 5.0) contains a pile of new language features to bamboozle complacent developers who had grown used to knowing the language inside and out. Hosts have also largely deployed the latest releases of major Java web application servers, which support the current standards in Java web development (J2EE 1.4). And the major development tools have been updated to support the powerful features of these standards, such as JavaServer Faces. It's all right there, waiting for you to use it.

At the same time, Java is getting a bad reputation among everyday web developers. There's a growing sense that Java isn't easy anymore, that you have to work for a company with the budget equal to the GDP of a small country for web development on this platform to make sense. Competing platforms like Microsoft's .NET are winning loads of cool points for doing things that Java has done for years; nimble scripting languages like Ruby are making amazing things possible with very little code, while Java is perceived as a stagnant monolith by many.

A lot of this sentiment comes from the fact that Java web development was invented in layers. First there was this great, easy-to-learn programming language: Java. Someone wanted to generate web pages with it on the fly, so servlets were invented, and they ran on Java. Someone else wanted to build dynamic web pages without losing the HTML code among all the Java code, so JavaServer Pages (JSP) were invented, and they ran on servlets, which ran on Java.

Years later, the cutting edge of Java web development sits on top of at least a half dozen layers of technology, and as a newcomer you can quickly feel lost in the forest of buzzwords! So now we get hobbyists asking how to build a web-based photo gallery with Enterprise JavaBeans (EJB) - the equivalent of buying a tractor trailer to carry your bread and milk home from the corner store.

In this article, I'll chart a map through that forest of buzzwords, so that as you take your first steps in Java web development you can work out what you really need to know, what you can really use, and what you can safely leave to the multinationals. Most importantly, I'm here to express the joy I find in working with Java. I hope I can help you find it, too.

Let's Start at the Bottom...

As I have mentioned, Java web technology has been built up in layers over many years. Today, there are at least a dozen practical and proven approaches to building web sites with Java. By and large, however, they are all built on the same foundation: Java Enterprise Edition (JavaEE) -- previously Java 2 Enterprise Edition (J2EE) -- a constellation of related specifications that describe the aforementioned layers of server-side Java technology.

Picking our way through J2EE, we'll start by looking at Servlets, then we'll move on to JSP, combine the two as we examine Model 2, extend this to a discussion of MVC frameworks like Struts and Spring, and evenutally explore the various View technologies like Velocity, JavaServer Faces, and XMLC. This is by no means an exhaustive list -- there's lots to explore!

As we do this, I predict you'll notice an interesting trend. Most web development platforms start out being reasonably easy to learn and use, but they tend to get more and more complicated as you try to shoehorn larger, more practical and complex projects into them. PHP comes to mind: much as I love that language's ease of use, you can spend months reading people's thoughts on how best to structure sizeable projects and still not come up with a clean solution.

The trend with Java is different: there is a lot to learn up front, and at first simple tasks can seem stupidly labour-intensive. But as you become comfortable with the layers of complexity, they begin to work for you, and projects that you used to find intimidating will start to seem easy.

To begin our tour, we'll start with a dead simple web application: a database driven to-do list. We'll be building this same application with each of the technologies we explore, and I'll provide downloadable code for each version. Because this is a simple project, it'll allow you to focus on the differences between the techniques, their strenghts and weaknesses, which features are easy to implement, and which are hard.

Each incarnation of this application will rely on the same MySQL database, so let's start with that. If you plan to follow along, now's a good time to make sure you have a healthy MySQL installation on your development machine. If you're really new to databases or server-side web development in general, you can find a solid introduction to MySQL with full installation instructions in the first two chapters of my book, Build Your Own Database Driven Website Using PHP & MySQL. These chapters are available as free articles on sitepoint.com: chapter one and chapter two.

With MySQL in place, create a new database (I'll call it todo) with the following single table in it:

CREATE TABLE todo (
 todoid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 todo VARCHAR(255) NOT NULL
)

That's it! We're all set to look at the Java classes that will interface with this simple database.

Talking to MySQL: Your First Look at JDBC

To build the to-do list application we will use to explore the myriad Java web development technologies that are available, we'll begin with the backbone of the application: a set of classes that connect to a MySQL database to retrieve, model, and update a to-do list.

Before we go any further, you'll need a working knowledge of Java as a programming language. At the very least, you should understand the basic concepts of object oriented programming: classes, objects, methods, properties, and constructors. For an overview of these concepts and the necessary basics of Java programming, see my articles: Getting Started with Java, Java Language Basics, and Object Oriented Concepts in Java (part one and two).

In the following discussion, I'll also make use of many of the built-in utility classes that Java offers in its core APIs. If you're curious about these (and you should be!), you can browse the reference in the Java 5 API documentation, or grab a copy for yourself from the same page where you downloaded JDK.

Since we're connecting to a database, we will be using the Java Database Connectivity (JDBC) classes, which are part of the Java Enterprise Edition (JavaEE) platform, supported by all Java-enabled web servers. JDBC provides a common set of classes for connecting to any database server (you can browse the API reference for these classes if you like).

In order to connect to MySQL with JDBC, we need to grab a copy of MySQL Connector/J, the JDBC driver for MySQL. After telling Java to load the driver, we can ask it to connect to a MySQL database, and all of the standard JDBC classes will know how to work with that connection.

Download and extract the MySQL Connector/J archive. Inside you'll find a mysql-connector-java-version-bin.jar file (version 3.1.12 as of this writing), which is the driver library. Ignore the rest of the fluff and copy the JAR file to the working directory in which you plan to build your to-do list Java application.

We're ready to start coding! In this article, I'll present all the code line-by-line, so that you can type it straight into your favourite text editor. If you're used to some of the more terse scripting languages out there, Java code may seem a bit verbose to you. Indeed, that's one of the main things people who don't like Java tend to complain about. For real world development, I would highly suggest you get yourself a solid Integrated Development Environment (IDE), such as NetBeans or Eclipse (both are free). A good IDE will write much of the code for you, so that Java's verbosity becomes an aid to code readability, not a hindrance to productivity. In these initial learning stages, however, typing all the code by hand will definitely help you absorb exactly what's going on, so I'll leave further exploration of IDEs for a later article.

First of all, let's build a class called ToDoList, which will represent the to-do list stored in the database and will allow us to access and modify its entries. We'll put this class in a Java package (or namespace) called com.sitepoint so, in your working directory, create a directory called com with a subdirectory called sitepoint, and in it create a file named ToDoList.java. Start the file out with the required package declaration:

package com.sitepoint;

In this class, we'll use the JDBC classes from the java.sql and the collection classes from java.util, so let's import those:

import java.util.*;
import java.sql.*;

Finally, we'll declare our class:

public class ToDoList {

To keep the class as database-independent as possible, we'll design its constructor to accept the name of a JDBC driver and a JDBC connection string, which together give it everything it needs to connect to a database through JDBC. The constructor will load the driver class immediately, then store the JDBC connection string in a private property, so that the object can use it to connect to the database when it needs to.

 private String jdbcConnectionString;

 public ToDoList(String jdbcDriver, String jdbcConnectionString) {
   this.jdbcConnectionString = jdbcConnectionString;

   // Load the driver
   try {
     Class.forName(jdbcDriver).newInstance();
   }
   catch (Exception ex) {
     System.err.println("Error loading database driver " + jdbcDriver +
                        ":\n" + ex.getMessage());
   }
 }

Class.forName() obtains a reference to the JDBC driver class, and calling its newInstance() method makes sure it is loaded. We catch any exceptions that may be thrown in case the driver class is not available (if you forget to do this, the compiler will remind you about it).

Now, our first version of this class will allow Java programs (and web pages) to:

  • Get a list of the items on the to-do list.
  • Get the number of items on the list.
  • Add new items to the list.
  • Delete items from the list.

Because fetching the list from the database can be a time consuming operation, we'll make our class keep a copy of the list once it has been fetched, and only update it from the database when necessary.

 private List list = new ArrayList();
 private boolean staleList = true;

The list variable will store the list retrieved from the database, and the second will keep track of when that list needs updating (i.e. when it is "stale"). We start off with an empty ArrayList (Java's stock-standard list class, from the java.util package), which is assumed to be in need of updating.

Now, whether the program wants the actual list of to-do items or it simply wants to know how many items there are, we will need to fetch the list from the database. So let's write a single private method that checks if the stored list (in the list property) is stale, and loads the list from the database if necessary:

 private void refreshList() {
   if (staleList) {
     // Load list from the database...

     staleList = false;
   }
 }

Loading the list from the database is where JDBC comes in. First, we use the JDBC connection string (stored by the constructor in jdbcConnectionString) to connect to the database. Since this is a time consuming operation, we'll store the connection in another private property called conn, and only create a new connection when it is empty:

       if (conn == null) {
         conn = DriverManager.getConnection(jdbcConnectionString);
       }

Next, we create a Statement object from the connection and use it to execute a SELECT query and obtain the resulting ResultSet object:

       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery("SELECT todoid, todo FROM todo");

With the results in hand, we store a new, empty ArrayList in the list property, and fill it with ToDoItem objects created from the contents of the result set:

       list = new ArrayList();
       while (rs.next()) {
         list.add(new ToDoItem(rs.getInt(1), rs.getString(2)));
       }

This may be a confusing bit of code for several reasons. First, we're using a while loop to step through the result set. Calling the next() method of the result set advances it to the next record, or returns false if there are no records remaining, thus ending the while loop.

Within the loop, we're using the add() method of the ArrayList class to add items to the list. But what exactly are we adding? New instances of the ToDoItem class.

ToDoItem is a simple little class that keeps track of an ID (the database ID of a to-do list item) and a string (the text for that item). These two values are "read only", in that there are no methods provided for altering them. Objects like this that represent records in the database are called data objects. Create this class by pasting the following code into a file called ToDoItem.java alongside the ToDoList.java file you're already working on:

package com.sitepoint;

public class ToDoItem {
 private int id;
 private String item;

 ToDoItem(int id, String item) {
   this.id = id;
   this.item = item;
 }

 public int getId() {
   return id;
 }

 public String getItem() {
   return item;
 }

 public String toString() {
   return getItem();
 }
}

The only detail worthy of note in this simple class is that the constructor is not declared public, but is instead left package private, so that only classes within the com.sitepoint package can create ToDoItem objects.

Returning to ToDoList, the constructor of ToDoItem expects to be given the ID and text values for the item. We can fetch these values from the current row of the result set, using getInt(1) to fetch an integer value from the first column (todoid) and getString(2) to get a string value from the second column (todo).

That's it for filling up the list, except that to handle database errors from all this we much catch any SQLExceptions that might be thrown (again, the compiler will remind you if you forget). Here's the completed refreshList() method, and the delcaration for the conn property:

 private Connection conn;

 private void refreshList() {
   if (staleList) {
     try {
       if (conn == null) {
         conn = DriverManager.getConnection(jdbcConnectionString);
       }
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery("SELECT todoid, todo FROM todo");

       list = new ArrayList();
       while (rs.next()) {
         list.add(new ToDoItem(rs.getInt(1), rs.getString(2)));
       }
     }
     catch (SQLException ex) {
       System.err.println(
           "Error retrieving to-do list items from the database:\n" +
           ex.getMessage());
     }
     staleList = false;
   }
 }

With the hard work done in refreshList(), implementing getToDoItems() and getItemCount(), to obtain the to-do list items and the number of such items respectively, is a cinch:

 public Iterator getToDoItems() {
   refreshList();
   return list.iterator();
 }

 public int getItemCount() {
   refreshList();
   return list.size();
 }

The iterator() method of Java's list classes returns an Iterator, an object much like the database result set we just worked with, that lets the requesting object step through the list. size(), meanwhile, is self-explanatory.

The addItem() and deleteItem() methods work much the same way as refreshList(), except they use a PreparedStatement instead of a simple Statement. Consider this code from addItem:

     PreparedStatement stmt = conn.prepareStatement(
         "INSERT INTO todo (todo) VALUES (?)");
     stmt.setString(1, item);
     stmt.executeUpdate();

Notice the question mark in the INSERT query. This indicates a spot where some unknown value will be added to the query (the text for the new to-do list item, in this case). The setString(1, item) method call that follows assigns a string value (provided by the item variable in this case) to the first spot in the query. Other methods like setInt() let you enter values of other types. Sticking values into your database queries in this way neatly sidesteps the character escaping issues that often come into play with other languages, and that are often the cause of security vulnerabilities.

Here's the complete code for addItem() and deleteItem(), thus completing our ToDoList class:

 public void addItem(String item) {
   try {
     if (conn == null) {
       conn = DriverManager.getConnection(jdbcConnectionString);
     }
     PreparedStatement stmt = conn.prepareStatement(
         "INSERT INTO todo (todo) VALUES (?)");
     stmt.setString(1, item);
     stmt.executeUpdate();
   }
   catch (SQLException ex) {
     System.err.println(
         "Error adding a to-do list item to the database:\n" +
         ex.getMessage());
   }
   staleList = true;
 }

 public void deleteItem(int id) {
   try {
     if (conn == null) {
       conn = DriverManager.getConnection(jdbcConnectionString);
     }
     PreparedStatement stmt = conn.prepareStatement(
         "DELETE FROM todo WHERE todoid=?");
     stmt.setInt(1, id);
     stmt.executeUpdate();
   }
   catch (SQLException ex) {
     System.err.println(
         "Error deleting a to-do list item from the database:\n" +
         ex.getMessage());
   }
   staleList = true;
 }

Notice that each of these methods sets staleList to true once it's done its job, so that the next attept to read the to-do list will cause refreshList to fetch it from the database again.

All we need now is a class to test the work we've done so far. Here's a class called ToDoTest that'll do the trick. Put ToDoTest.java in with your other files:

package com.sitepoint;

import java.util.*;

public class ToDoTest {
 public static void main(String[] args) {
   ToDoList list = new ToDoList("com.mysql.jdbc.Driver",
       "jdbc:mysql://localhost/todo?user=root&password=password");

   System.out.println("The to-do list contains " + list.getItemCount() +
                      "items:");
   Iterator it = list.getToDoItems();
   while (it.hasNext()) {
     System.out.println(" - " + it.next());
   }

   list.addItem("Another todo item.");
   list.addItem("And yet another.");

   System.out.println("The to-do list contains " + list.getItemCount() +
                      " items:");
   it = list.getToDoItems();
   while (it.hasNext()) {
     System.out.println(" - " + it.next());
   }
 }
}

You'll need to substitute your MySQL database name, user name, and password into the JDBC connection string near the top of this file.

Compile your three classes from the top-level working directory:

javac com/sitepoint/ToDoList.java com/sitepoint/ToDoItem.java
   com/sitepoint/ToDoTest.java

Then run ToDoTest, with the MySQL JDBC driver added to the classpath:

java -classpath .;mysql-connector-java-3.0.15-ga-bin.jar
   com.sitepoint.ToDoTest

You should see a list of the to-do list items before and after the two new items are added to the list, something like this:

The to-do list contains 2 items:
- Another todo item.
- And yet another.
The to-do list contains 4 items:
- Another todo item.
- And yet another.
- Another todo item.
- And yet another.

Download the source code. (5KB)

That's it! We're ready to build a web application around these classes.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links