How do I separate presentation (HTML) from business logic (Java) when using servlets?

Joe Morse

Almost anybody who has ever written a servlet can identify with this one. We all know it's bad for to embed HTML code in our java source; it's lame to have to recompile and re-deploy every time you want an HTML element to look a bit different. But what are our choices here? There are two basic options;

1. Use JSP: Java Server Pages allows you to embed Java code or the results of a servlet into your HTML. You could, for instance, define a servlet that gives a stock quote, then use the <servlet> tag in a JSP page to embed the output. But then, this brings up the same problem; without discipline, your content/presentation and program logic are again meshed. I think the ideal here is to completely separate the two.

2. Use a templating/parsing system: Hmm...I know you're about to rant about re-inventing the wheel, but it's not that bad (see below). Plus, it really does pay to take this approach; you can have a group of programmers working on the Java code, and a group of HTML producers maintaining the interface. So now you probably want to know how to do it...so read on.

Use SSI!
Remember SSI? It hasn't gotten much attention in recent years because of embeddable scripting languages like ASP and JSP, but it still remains a viable option. To leverage it in the servlet world, I believe the best way is to use an API called SSI for Java from Areane. This API will let you emulate SSI commands from a templating system, and much more. It will let you execute any command on any system, including executing java classes! It also comes with several utility classes for creating stateful HTML form elements, tables for use with iteration, and much more. It's also open source, so it's free and you can tweak it to your heart's content! You can read the SSI for Java documentation for detailed info, but the following is an example of its use.
Here's the servlet:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import com.areane.www.ssi.*;

public class SSITemplatingServlet extends HttpServlet {
	private String	templateFilesDirectory = "d:projectsidemo	emplates"; //Holds path to template files

	/**Handles GET requests; defers every request to the POST processor*/
	public void doGet(HttpServletRequest req, HttpServletResponse res) 
		throws ServletException, IOException, FileNotFoundException {doPost(req, res);}

	/**Handles all requests. Processes the request, 
	  *saves the values, parses the file, then feeds the file to the out stream*/
	public void doPost(HttpServletRequest req, HttpServletResponse res) 
		throws ServletException, IOException, FileNotFoundException {
		HttpSession	ses		= req.getSession(true);
		Properties context 	= null;
		if((context = (Properties)ses.getValue("user.context")) == null) { //if properties doesn't already exist, create it.
			context	= new Properties();
		//Write parameters to Properties object
		Enumeration paramNames	= req.getParameterNames();
		String curName, curVal;
		while(paramNames.hasMoreElements()) {
			curName	= (String)paramNames.nextElement();
			curVal	= req.getParameter(curName);
			context.setProperty(curName, curVal);

		//Save the values to the session
		ses.putValue("user.context", context);

		//Parse the page and stream to the client
		String templateName	= req.getParameter("template"); // Get the file name of the template to use
		SsiPage	page	= SsiParser.parse(this.templateFilesDirectory + templateName); //Parsing occurs here
		page.write(res.getWriter(), context); //Stream to the client
		page = null; //clean up

Now, just create a template file, pass the servlet the template file name, and have at it!