Model-View Architecture using Servlets, JavaBeans and JSP (Principle and Implementation)

Struts is based on MVC Architecture. As a prelude to Struts, the author explains how MVC can be implemented without using the Struts framework, so that in the sequel, the Struts framework’s working and merits can be better appreciated.

Knowledge and experience in using the Struts Framework, is a highly valued skill at present for Java programmers. Admittedly, Struts Framework is a bit difficult to follow, except for coders with sufficient exposure to the recent versions of Servlet and JSP specifications and also to Tomcat-4.

First of all, let us list the usual requirements in complex applications. JSP was developed, and to hide the business-logic, JavaBeans were used along with JSP. As a further simplification, custom-tags were developed and used in JSP, so that the JSP page will be free from scriptlets.
However, Plain-Old-Javabeans (POJ) can be of two types. The first type is known as ‘utility bean’ and such a bean is an encapsulation of some functionality. We can also think of it as ‘function-bean’. For example, let us consider a ‘greeter’ bean. This is a function-bean (Code-1). In this bean, there is only one ‘function’ i.e. the bean is a class for carrying out some job (‘greetme’ function). In such beans, there is no attribute or property.

Code 1

//greeterbean.java

package ourbeans;

public class greeterbean
{
public greeterbean()

public String greetme(String s)
{
return “how are you?...” + s;
}
}

Let us now consider the other type of Javabeans, known as ‘value-bean’, which we can think of as property-bean’. See Code-2.

 

Code 2

package ourbeans;

public class playerbean
{
String name;
String game;

public playerbean()
{
name=””;
game=””;
}

public void setName(String a)
{    name=a;       }

public void setGame(String c)
{    game=c;       }

public String getName()
{    return name;  }

public String getGame()
{    return game;  }
}

It will be noticed that the above class (Code-2) has a public ‘no-args’ constructor and setter and getter methods for all the specified properties. Thus it follows the pattern stipulated for Javabeans. If this pattern is strictly followed, it is guaranteed that the properties could be read and written in a standard container, by introspection. This concept is a recurring theme in Java and is very important in understanding Entity type of EJB also (both Container-managed persistence and Bean-managed persistence types. The only additional point is that Entity beans are also persisted to a database in hard-disk.) There are two jsp-tags known as ‘jsp:getProperty’ and ‘jsp:setProperty’. Using these tags, we can read and write the required properties without using scriptlets.

Coming now to the topic of MVC, in MVC Architecture, M stands for Model, V stands for View and C stands for Controller. Controller is a servlet, Model is a bean and View is a JSP.

Though, the Struts Framework has become a favoured implementation of MVC, the learning curve for Struts is rather steep and for medium-level projects, working under time-constraints, it may not be the right choice, as it takes time to train the staff to the required level of competence and reliability. In such cases, rolling out our own implementation of MVC may not be a bad idea at all. (This is the opinion of a famous author of books on Servlets & JSP, named Marty Hall, endorsed by Sun MicroSystems. The tutorials can be accessed on the web from www.coreservlets.com & www.moreservlets.com).

The standard procedure for getting things done, in the MVC way, is as listed below.

  1. It is required that all requests should pass through the controller servlet.
  2. The controller servlet will then pass the data to a suitable function-bean through an action-servlet.
  3. The function-bean will carry out the business-logic and return the result to the action-servlet. The action-servlet then creates an instance of the value-bean and populates its fields. Strictly speaking, it is this value-bean that is known as Model in MVC approach.
  4. The action-servlet will then forward this instance of value-bean to the JSP as an object with session-scope.
  5. The JSP will then gather the property from this specific bean instance that has been forwarded to it.
  6. The JSP page should display the result using tags only and should not contain any scriptlets.

These are the requirements for designing an MVC application without using Struts. Let us now see how we can implement these requirements by the usual Java Servlet API methods rather than by using the Struts Framework. We are having all the typical components in this illustration, such as HTML form, calling servlet, control servlet, action-servlet, function bean for business logic, value bean loaded with the datafields of the result and JSP with tags only for displaying the result.

The most important point to be noted is that a value-bean is being shared between a servlet and a JSP. It is obligatory to use package for bean used in JSP. If we thus declare the package for bean, we will run into trouble when we try to compile the servlet. The servlet class also should then be placed in the same package as the bean. Hence, note the exact procedure to be followed. Otherwise, we will have lot of problems in getting things executed correctly. We will be using a package named ‘lesson’. (Among the scores of tutorials on Servlets & JSP, it is only the one from Marty Hall, which pinpoints this problem and suggests the correct method).

The fact that we are using this package for holding the servlets’ class-files and the bean class-files, which are also referenced by JSP, makes it necessary to follow a systematic procedure for editing and compiling the files, as given below.

We are now in the folder – ‘c:\sam’. We create a subfolder named ‘lesson’ under ‘sam’. 'C:\sam\lesson' will be our working folder. We create all the files here. First, we set the path as below:

set path=c:\windows\command;d:\jdk1.4\bin

Then, we set the classpath to ‘c:\sam’ only and NOT TO ‘c:\sam\lesson’!

set classpath=c:\sam;c:\tomcat32\lib\servlet.jar

We are now ready to create the files. To begin with we have two HTML files, namely, ‘demo1.htm’ and ‘demo2.htm’. ‘demo1.htm’ invokes the ‘demo1’ servlet and ‘demo2.htm’ invokes the ‘demo2’ servlet. demo1 and demo2 are ‘calling servlets’. They just collect the data entered by the user in the form and pass it on to the control servlet. Carefully note that the action-field in the HTML form should be given as:

action=”/servlet/lesson.demo1”

Thus we are accounting for the package. When we submit the username through ‘demo1.htm’, demo1 servlet accepts the data and passes it on to control servlet. How does demo1 servlet pass data to control servlet? What is the syntax?  For this, we have ‘setAttribute’ function. Let us consider the code in demo1 servlet, step by step.

String s = request.getParameter(“text1”);

After getting the visitor’s name, demo1 sets the attribute accordingly.

request.setAttribute(“visitor”, s);

The next step is to pass it on to control servlet.

RequestDispatcher dispatcher=request.getRequestDispatcher(“/servlet/lesson.control”);
dispatcher.forward(request, response);

Once again, note carefully that we have referred to control servlet’s class within ‘lesson’ package. So, this is the method of passing data from one servlet to another. The ‘RequestDispatcher’ class is the workhorse in Servlet API, which tackles the problem of servlet-chaining, inter-servlet communication, servlet-JSP data chaining and JSP-servlet chaining too! However, in MVC, there is no necessity for passing data from a JSP to servlet.

Now that the control servlet (control.java) has been invoked by demo1 servlet, it accepts data by the following syntax:

String a = (String)request.getAttribute(“visitor”);

Note that we have to cast it to String object.

But, how does the control servlet know which action-servlet/bean to invoke? That depends on the servlet from which the data was obtained. In our example, if the data came from demo1 servlet, the control servlet sends the data to demo3 servlet. On the other hand, if the data came from demo2 servlet, it will pass data to demo4 servlet. Just as demo1 and demo2 were the calling servlets, demo3 and demo4 are the respective ‘action-servlets’.

String path=request.getServletPath();

if(path.equals(“/servlet/lesson.demo1”)
{
RequestDispatcher dispatcher=request.getRequestDispatcher(“/servlet/lesson.demo3”);

dispatcher.forward(request, response);
}

if(path.equals(“/servlet/lesson.demo2”)
{
RequestDispatcher dispatcher=request.getRequestDispatcher(“/servlet/lesson.demo4”);

dispatcher.forward(request, response);
}

For the moment, we will concern ourselves with a single stream of execution, where the sequence is:

  1. demo1.htm
  2. demo1 servlet (calling servlet)
  3. control servlet
  4. demo3 servlet (action servlet)
  5. morningbean (function bean)
  6. resultbean (value bean)
  7. result1jsp.jsp

 

All the above files are created in our working folder ‘C:\sam\lesson’. We begin with demo1.htm (Code-3).

Code 3

<html>
<body bgcolor=purple text=yellow>
<form method=post action="/servlet/lesson.demo1">
Enter name
<input type=text name="text1">
<input type=submit>
</form>
</body>
</html>

The above HTML invokes demo1 servlet (Code-4) in ‘lesson’ folder of the tomcat server. (Exact deployment will be seen shortly.)

Code 4

// c:\sam\lesson\demo1.java

package lesson;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class demo1 extends HttpServlet
{
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out=response.getWriter();

System.out.println("now I'm in demo1");

String path=request.getServletPath();

String s=request.getParameter("text1");
out.println(s);

request.setAttribute("visitor",s);

request.setAttribute("path",path);

RequestDispatcher rd=request.getRequestDispatcher("/servlet/lesson.control");
rd.forward(request,response);
}
}

The demo1 servlet, collects the data in ‘text1’ and also the servlet path It then creates two keys, namely, ‘visitor’ and ‘path’ and sets their attributes with the respective values. Then the values are forwarded to control servlet (Code-5).

Code 5

// c:\sam\lesson\control.java

package lesson;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class control extends HttpServlet
{
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out=response.getWriter();

System.out.println("now I'm in control servlet");

String path=(String)request.getAttribute("path");

request.setAttribute("visitor",a);

if(path.equals("/servlet/lesson.demo1"))
{

String a=(String)request.getAttribute("visitor");

RequestDispatcher rd=request.getRequestDispatcher("/servlet/lesson.demo3");
rd.forward(request,response);

}

if(path.equals("/servlet/lesson.demo2"))
{

RequestDispatcher rd=request.getRequestDispatcher("/servlet/lesson.demo4");
rd.forward(request,response);

}
}
}

The control servlet first checks up from where it is being invoked, by using getAttribute(“path”). If it is from demo1, it collects the appropriate data. Finally, it passes the data to the matching action-servlet, in our case, demo3.java (Code-6)

Code 6

// c:\sam\lesson\demo3.java

package lesson;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class demo3 extends HttpServlet
{
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out=response.getWriter();

System.out.println("now I'm in demo3");

System.out.println("invoking Bean & Sending data”);

String s3=(String)request.getAttribute("visitor");

morningbean bean1=new morningbean();
String r1= bean1.sayGoodMorning(s3);

System.out.println("Getting  data from bean1....");
System.out.println(r1);

resultbean result1 = new resultbean();

result1.setresult(r1);

String a=result1.getresult();
System.out.println("verifying data from resultbean");
System.out.println(a);

HttpSession session=request.getSession();

session.setAttribute("bean", result1);

RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/result1jsp.jsp");
System.out.println("forwarding to resultjsp.jsp");

rd.forward(request,response);

}
}

The demo3 servlet first gets the data for the ‘visitor’, by getAttribute(“visitor”). Then, it creates an instance of ‘morningbean’ class. This bean is a function-bean, which will return ‘Good Morning’, appending the name supplied as parameter (this is our ‘business logic!’) See Code-7.

 

Code 7

// c:\sam\lesson\morningbean.java

package lesson;

public class morningbean
{
public morningbean() { }

public String sayGoodMorning(String s)
{
return "Good Morning"+s;
}
}

After this, the demo3 servlet creates an instance of ‘resultbean’ class. This is a value-bean, to hold the particular result. See Code-8.

Code 8

// c:\sam\lesson\resultbean.java

package lesson;

public class resultbean
{
String result;

public resultbean()
{
result="  ";
}

public String getresult()
{
return result;
}

public void setresult(String a)
{
result=a;
}
}

At this stage, the demo3 servlet creates a ‘key’ named ‘bean’ and sets its attribute as the instance of the value-bean. Finally, the demo3 servlet forwards the details to ‘result1jsp.jsp’ (Code-9).

 

Code 9

// c:\sam\lesson\result1jsp.jsp

<html>
<body bgcolor=yellow>

<jsp:useBean id="bean" scope="session" class="lesson.resultbean" />
<jsp:getProperty name="bean" property="result"  />

</body>
</html>

The remarkable feature to be noted in the JSP file is that the bean that has been passed by the demo3 servlet, is being accessed directly by the simple <jsp:useBean> tag. Normally, for every setAttribute(), there will be a corresponding getAttribute() code. But in this case, it is not necessary. Thus, we are able to access the value bean instance, by simply using a tag, without using scriptlet code. In the next step, the JSP extracts the required data from the instance of value-bean, by using <jsp:getProperty> tag.

We must, however, carefully note the syntax. The ‘id’ is NOT the object name of the bean but the key of the setAttribute function. And, without even saying, ‘out.println’, the result is displayed in the browser! (<getProperty> automatically displays the value.)

That was by way of explanation for the code. It will be noticed that we have not used any XML file etc. anywhere. Of course, things have been hard-coded and the advantage of Struts approach is avoidance of such hard-coded details. However, the approach (Marty Hall suggests that we term this improvised method as ‘Model-View-Architecture’ Approach rather than ‘Model-View-Controller’ Architecture, as a concession to purists) is easy to follow and implement for any coder with knowledge of standard Servlet library only. (With all that din about the Struts framework, it is easy to forget that it is not a ‘standard’ endorsed by JCP).

Much the same procedure is followed in Struts also, and once we get a feel for the flow, it is then just a matter of getting to know the readymade classes provided, which we over-ride for our specific requirements and also good familiarity with the web.xml and Struts-config xml file.

Now for the actual steps for compiling, deploying and testing our lesson. We have already set:

path=c:\windows\command;d:\jdk1.4\bin
classpath=c:\sam;c:\tomcat32\lib\servlet.jar

  1. C:\sam\lesson>javac *.java
  2. Copy *.class to c:\tomcat32\webapps\root\WEB-INF\classes\lesson

(after creating ‘lesson’ folder under ‘classes’ folder).

  1. Copy demo1.htm to c:\tomcat32\webapps\root
  2. Copy result1jsp.jsp to c:\tomcat32\webapps\root\WEB-INF
  3. In another DOS window,

>c:\tomcat32\bin
>set JAVA_HOME=D:\JDK1.4
>startup
(this starts the Tomcat server)

  1. Start the browser and type the URL as: http://localhost:8080/demo1.htm
  2. Type ‘tom’ in text1 and submit. We will get ‘Good Morning tom’.
  3. Now, if we view the console output of Tomcat, we will find a trace of the workflow.

Tomcat console

Starting tomcat. Check logs/tomcat.log for error messages
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /examples )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /admin )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx(  )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /test )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /root )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /jspecho.jsp )
2014-11-15 04:43:27 - ContextManager: Adding context Ctx( /axis )
2014-11-15 04:43:29 - PoolTcpConnector: Starting HttpConnectionHandler on 8080
2014-11-15 04:43:29 - PoolTcpConnector: Starting Ajp12ConnectionHandler on 8007
Now I'm in demo1
Now I'm in control servlet
Now I'm in demo3
Invoking Bean.....Sending data to bean1
Get data from bean1....
Good Morningtom
verifying data from resultbean
Good Morningtom
forwarding to resultjsp.jsp
this is diagnostic code in result1jsp.jsp

Suggested reading

  1. Web-tutorials on Servlets & JSP

www.coreservlets.com
www.moreservlets.com

  1. Java Server Pages (3rd edition), Hans Bergsten, O’Reilly pub.

The author can be reached on ramrsr@rediffmail.com








}