Reply to comment

Howto write Java Web Application Project

I am going to start a series of articles to create a java based web application. The goal would be to write good quality and maintainable code which can also be unit tested.

We should always think that technology is going to be outdated. The project requirement and even the author will keep changing. We should design an application keeping these points in mind, and write code as loosely coupled as possible. There should be many reusable components which can be easily exported or copy pasted to other projects with minimum hassles. When using a framework, follow its standard convention with minimal configuration (if necessary). Also if a new person sees the code, s/he should be able to easily understand it. Good documentation is also good, but in my experience nobody likes to go through (or even write) a manual. So a good inline documentation and standard code convention with descriptive variables is very helpful.

In this part, my first step would be write a bad web project where every thing is tightly coupled. Business logic, model and presentation layer are all mixed up. This way, we will know what are the disadvantages first hand ^_^

I will be creating a simple book library...

create a folder c:\projects\bookstore\
now create this folders inside bookstore as shown below
src
src\main
src\main\java
src\main\resources
src\main\webapp\META-INF
src\main\webapp\WEB-INF
src\test
src\test\java

now add these blank files (for now)

c:\projects\bookstore\pom.xml
c:\projects\bookstore\src\main\webapp\WEB-INF\web.xml
c:\projects\bookstore\src\main\webapp\index.jsp

pom.xml is for maven what build.xml is for Ant.
For java web applications web.xml works as driver or it works almost as main method. checkout http://en.wikipedia.org/wiki/Deployment_descriptor.
index.jsp is the default file which loads if not already overridden in web.xml

Now add the following text in each file:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http ://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>nyayapati.surya.tutorial</groupId>
  <artifactId>bookstore</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>bookstore</name>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.6</version>
       <scope>compile</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>bookstore</finalName>
  </build>
</project>

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.4//EN"
 "http://java.sun.com/dtd/web-app_2_4.dtd" >
 
<web-app>
  <display-name>Bookstore</display-name>
</web-app>

index.jsp

<html>
<head><title>Hello World!</title></head>
<body>
<h2>Hello World!</h2>
</body>
</html>

now open command prompt and go to c:\projects\bookstore
type
> mvn install
> mvn eclipse:eclipse
Open eclipse with new workspace and do Import... > Existing project into Workspace. Point to c:\projects\bookstore and hit finish. Make sure to define M2_REPO in eclipse to point at your local maven repository. That's it! your eclipse is ready with bookstore project, with out any further configurations, cool huh ^_^.

now in order to run the project
> mvn tomcat:run
you dont have to download tomcat separately, maven takes care of downloading and running it for you, woohoo!! or you can do
>mvn jetty:run
to run jetty instead.

You should now have a basic web app running. open a browser with http://localhost:8080/bookstore you should see hello world.

long ago...people used to write web applications in only servlets (not even jsp), so if you wanted to print a html then you would do something like

old style servlet 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 HelloWorld extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    out.println("<html>\n<head><title>Hello World!</title></head>\n" +
                "<body>\n<h1>Hello World!</h1>\n" +
                "</body></html>");
  }
}

as you can see this is a nightmare! you have to be java programmer and also be web designer (of course having both skills is a plus, but there aren't many). It becomes a pain to maintain such code. if a new guy, comes in, he would not know where to begin.
So that's why we have JSP. We can totally use jsp instead of servlets, because in the end jsp is converted in to servlets at runtime. you can also see this in you tomcats work folder. Generally its a good practice or norm to keep the presentation code in jsp and other stuff in servlet classes which ultimately becomes MVC pattern ^_^. (if you want to know more about servlets go to http://en.wikipedia.org/wiki/Java_Servlet and http://java.sun.com/products/servlet/articles/tutorial/)

Any way lets create some database tables. i will be using MySQL since its free.

Bookstore SQL

This could have been more complicated. however, I wanted a basic book library so this should be sufficient.

-- --------------------------------------------------------
-- 
-- Table structure for table authors
--
 
CREATE TABLE IF NOT EXISTS authors (
  id int NOT NULL auto_increment,
  fname varchar(50) NOT NULL,
  lname varchar(50) NOT NULL,
  created datetime default NULL,
  modified datetime default NULL,
  PRIMARY KEY  (id),
  UNIQUE KEY names (fname, lname)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin ;
 
-- --------------------------------------------------------
 
--
-- Table structure for table publisher
--
 
CREATE TABLE IF NOT EXISTS publishers (
  id int NOT NULL auto_increment,
  company varchar(100) NOT NULL,
  created datetime default NULL,
  modified datetime default NULL,
  PRIMARY KEY  (id),
  UNIQUE KEY names (company)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin ;
 
-- --------------------------------------------------------
--
-- Table structure for table books
--
 
CREATE TABLE IF NOT EXISTS books (
  id int NOT NULL auto_increment,
  title varchar(100) NOT NULL,
  isbn CHAR(13),
  year int NOT NULL,
  price DECIMAL (6,2) NOT NULL,
  description text default NULL,
  quantity INTEGER DEFAULT 0, 
  publisher_id int NOT NULL,
  created datetime default NULL,
  modified datetime default NULL,   
  PRIMARY KEY  (id),
  UNIQUE KEY isbn_number (isbn),
  INDEX (title),
  INDEX publisher_id (publisher_id),
  FOREIGN KEY (publisher_id) REFERENCES publishers (id)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin ;
 
-- --------------------------------------------------------
--
-- Table structure for authors_books, relationship between authors and books
--
CREATE TABLE IF NOT EXISTS authors_books (
 id int NOT NULL auto_increment,
 author_id int NOT NULL,
 book_id int NOT NULL,
 INDEX athr_id (author_id),
 INDEX bok_id (book_id),
 PRIMARY KEY  (id),
 FOREIGN KEY (author_id) REFERENCES authors (id),
 FOREIGN KEY (book_id) REFERENCES books (id)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin ;
 
-- --------------------------------------------------------
INSERT INTO authors (id, fname ,lname, created, modified) VALUES
(1, 'Surya','Nyayapati', '2009-05-11 19:02:19', '2009-05-11 19:02:22'),
(2, 'Srini','Nyayapati', '2009-05-11 19:02:19', '2009-05-11 19:02:22');
 
INSERT INTO publishers (id, company, created, modified) VALUES
(1,'Nyayapati Inc', '2009-05-11 19:02:19', '2009-05-11 19:02:22');
 
INSERT INTO books (id, title, isbn, year, price,description,quantity,publisher_id, created, modified) VALUES
(1,'Surya\'s Sandbox', '12-3456-789-0', 2009, 10.00, 'Blah blah!!',5, 1,
  '2009-05-11 19:02:19', '2009-05-11 19:02:22');
 
INSERT INTO authors_books (id, author_id, book_id) VALUES
(1,1,1),
(2,2,1);

modify index.jsp with following code

<%@ page import="java.sql.*"%>
<%@ page import="java.io.*"%>
<html>
<body>
<h2>Hello World!</h2>
<%	
	String strConn = "jdbc:mysql://localhost:3306/bookstore";
	Connection connection = null;
	ResultSet resultSetBooks = null;
	ResultSet resultSetAuthors = null;
	PreparedStatement prepStmntBooks = null;
	PreparedStatement prepStmntAuthors = null;
 
	try {		
		Class.forName("com.mysql.jdbc.Driver").newInstance();		
		connection = DriverManager.getConnection(strConn, "bookstore_user",	"bookstore123");
		prepStmntBooks = connection.prepareStatement("SELECT books.id, title, isbn, year, "+
                     "price, company, description FROM books,publishers WHERE "+
                     "books.publisher_id=publishers.id");	
	    prepStmntAuthors = connection.prepareStatement("SELECT fname,lname FROM books, authors,"
                    "publishers,authors_books WHERE authors.id=authors_books.author_id AND "+ 
                  "books.id=authors_books.book_id AND books.publisher_id=publishers.id AND books.id=?");				
%>
<table>
<thead>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>ISBN</th>
<th>YEAR</th>
<th>PRICE</th>
<th>PUBLISHER</th>
<th>AUTHOR</th>
<th>DESCRIPTION</th>
</tr>
</thead>
<tbody>
<%		
		resultSetBooks = prepStmntBooks.executeQuery();	
		while (resultSetBooks.next()) {
%>
<tr>
<td><%= resultSetBooks.getInt("id") %></td>
<td><%= resultSetBooks.getString("title") %></td>
<td><%= resultSetBooks.getString("isbn") %></td>
<td><%= resultSetBooks.getInt("year") %></td>
<td>$<%= resultSetBooks.getBigDecimal("price") %></td>
<td><%= resultSetBooks.getString("company") %></td>
<td><%
		prepStmntAuthors.setInt(1, resultSetBooks.getInt("id")); 
		resultSetAuthors = prepStmntAuthors.executeQuery();
		while (resultSetAuthors.next()) {			
			out.println(resultSetAuthors.getString("fname") + " " +
                              resultSetAuthors.getString("lname")+"<br/>");
		}
%></td>
<td><%= resultSetBooks.getString("description") %></td>
</tr>
<%			
		}
	} catch (Exception ex) {
		out.println("error :" + ex);
	} finally {
		// close all the connections.
		if(resultSetBooks!=null){
			resultSetBooks.close();
		}
		if(resultSetAuthors!=null){
			resultSetAuthors.close();
		}
		if(prepStmntBooks!=null){
			prepStmntBooks.close();
		}
		if(prepStmntAuthors!=null){
			prepStmntAuthors.close();
		}
		if(connection!=null){
			connection.close();	
		}		
	}
%>
</tbody>
</table>
</body>
</html>

again open command prompt goto projects root folder and type
> mvn clean install tomcat:run
open brower and goto http://localhost:8080/bookstore you should see hello world and a table with content from database.

So in Conclusion, this is not a good practice. Even though you wont see any problem initially, but in the long run when you have many jsp files with many lines of code, you would see lot of repeated code and/or logic, which would require a lot of refactoring. Also if you want to change the database, say from MySql to Oracle you have to make changes in lot of jsp files again! All these changes can be error-pron.
To add more to your woes, unit testing becomes extreemly difficult (writing unit test prevents runtime errors and a lot of future frustrations). Now lets say you have to write a webservice (SOAP) you also have to duplicate business logic.
Finally it would be tough for the designer, to only concentrate on style/layout using only html, css, javascript. Sounds like a lot of work, time, money and headache O_O.

In the next part i am going to fix the problem by separating code/logic as much as possible within limit (too much is also not good, you have find a right balance). I will also talk about debugging and testing.

Reply

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.