Using the Builder Design Pattern to output HTML on Servlets

I am fortunate, in a way, to be working on a website where the technology is dated and the code was not shown any “love and care” for a number of years. So why would anybody feel fortunate to be working on a website like this, well it is just so easy to make improvements and to feel the sense of achievement when you improve something.

I recently had an example where I was refactoring some of our servlets. As I was going through and tidying I noticed a number of similar pieces of code and html. To eliminate the duplication I moved the duplicated code into methods. Once I was complete with the refactoring, I was still not happy. A page needs to be built in a certain order and all our servlet pages should be built in the same manner.

As a result, this ended up being a neat example to utilise the Builder Design Pattern. I am not going to go into any detail about the pattern itself because there are a number of posts, for example this tutorial on the Builder Design Pattern and books, such as Design Patterns: Elements of Reusable Object-Oriented Software by the GOF. I simply want to provide an example of how this has simplified our building of servlets into a standard manner.

So essentially we would have required nearly 80 lines of code to generate the very simple example page below.

An example of the outputted html screen

An example of the outputted html screen

The code to create this page using our traditional coding style for servlets would have looked as per below.

package com.servlet.presentation;

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

public class ServletWithHTML extends HttpServlet {

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

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html> ");
 out.println("<head>");
 out.println("<title>An example using a builder pattern to make the servlet code prettier</title>");
 out.println("<link rel=\"stylesheet\" href=\"css\\reset.css\">");
 out.println("<link rel=\"stylesheet\" href=\"css\\style.css\">");
 out.println("</head> ");

out.println("<body>");

out.println("<form>");

out.println("<div class=\"title\">Builder pattern to make servlet html creation easier to read</div> ");

out.println("<div class=\"paragraph\">An example using a builder pattern to make the servlet code prettier</div>");

out.println("<dl>");

out.println("<dt class=\"twocolumn\"><label>");
 out.println("Label text 1");
 out.println("</label></dt>");
 out.println("<dd class=\"twocolumn\"><p>");
 out.println("Value text 1");
 out.println("</p></dd>");

out.println("<dt class=\"twocolumn\"><label>");
 out.println("Label text 2");
 out.println("</label></dt>");
 out.println("<dd class=\"twocolumn\"><p>");
 out.println("Value text 2");
 out.println("</p></dd>");

out.println("<dt class=\"twocolumn\"><label>");
 out.println("Label text 3");
 out.println("</label></dt>");
 out.println("<dd class=\"twocolumn\"><p>");
 out.println("Value text 3");
 out.println("</p></dd>");

out.println("<dt class=\"twocolumn\"><label>");
 out.println("Label text 4");
 out.println("</label></dt>");
 out.println("<dd class=\"twocolumn\"><p>");
 out.println("Value text 4");
 out.println("</p></dd>");

out.println("</dl>");

out.println("<div class=\"paragraph\">This is really hard to read</div>");

out.println("</form>");

out.println("</body>");
 out.println("</html>");
 }
 }

Even though this is a very simple example, reading the page is very difficult with all the html references and quotes. It is also not very descriptive in describing what the developer is trying to do.

So first off a FormBuilder was created to build the page and generate the associated html.

package com.servlet.builder;

import java.io.PrintWriter;

public class FormBuilder {

private StringBuilder stringBuilder = new StringBuilder();

public FormBuilder() {
 stringBuilder.append("<form>");
 }

public FormBuilder title(String text) {
 div("title",text);
 return this;
 }

public FormBuilder paragraph(String text) {
 div("paragraph",text);
 return this;
 }

public FormBuilder twoColumnTable(TwoColumnTable twoColumnTable) {
 stringBuilder.append(twoColumnTable.toString());
 return this;
 }

public void toString(PrintWriter printWriter) {
 endForm();
 printWriter.println(stringBuilder.toString());
 }

public String toString() {
 endForm();
 return stringBuilder.toString();
 }

private void endForm() {
 stringBuilder.append("</form>");
 }

private void div(String style,String text){
 stringBuilder.append("<div class=\"").append(style).append("\">");
 stringBuilder.append(text);
 stringBuilder.append("</div>");
 }
}

To create the two column table in the example page a TwoColumnTable builder was created.

package com.servlet.builder;

public class TwoColumnTable {
 StringBuilder stringBuilder = new StringBuilder();

public TwoColumnTable() {
 stringBuilder.append("<dl>");
 }

public TwoColumnTable row(String label, String text) {
 stringBuilder.append("<dt class=\"twocolumn\"><label>");
 stringBuilder.append(label);
 stringBuilder.append("</label></dt>");
 stringBuilder.append("<dd class=\"twocolumn\"><p>");
 stringBuilder.append(text);
 stringBuilder.append("</p></dd>");

return this;
 }

public String toString() {
 stringBuilder.append("</dl>");
 return stringBuilder.toString();
 }
}

The nice thing with this is that some relationship is maintained between the html elements. In this example only a form can have a TwoColumnTable and row can only be contained in the TwoColumnTable.

Now with the FormBuilder and TwoColumnTableBuilder in place, our java code for the servlet would look like below.


package com.servlet.presentation;

import com.servlet.builder.FormBuilder;
import com.servlet.builder.TwoColumnTable;

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

public class ServletUsingBuilder extends HttpServlet {

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

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html> ");
 out.println("<head>");
 out.println("<title>An example using a builder pattern to make the servlet code prettier</title>");
 out.println("<link rel=\"stylesheet\" href=\"css\\reset.css\">");
 out.println("<link rel=\"stylesheet\" href=\"css\\style.css\">");
 out.println("</head> ");

out.println("<body>");

new FormBuilder()
 .title("Builder pattern to make servlet html creation easier to read")
 .paragraph("An example using a builder pattern to make the servlet code prettier")
 .twoColumnTable(new TwoColumnTable()
    .row("Label text 1", "Value text 1")
    .row("Label text 2", "Value text 2")
    .row("Label text 3", "Value text 3")
    .row("Label text 4", "Value text 4"))
 .paragraph("This is really much easier to read")
 .toString(out);

 out.println("</body>");
 out.println("</html>");
 }
}

So 26 fewer lines of code to output exactly the same html. That is nearly a 40% line count improvement on a very simple example.

Writing code to output standard html that is repeated throughout the site in this fashion provides the following benefits:

  • Firstly, the code is a lot cleaner and easier to read.
  • The code is more descriptive.
  • A lot less code needs to be written.
  • The html is generated consistently. We don’t have to remember all the html and css tags.
  • The code becomes testable – for example we can write tests for the builder and if we make any changes to the html we can validate it is correct.
  • Changes to the html we want to generate are made in a single location.
  • The compiler provides support in ensuring tags are contained only within allowed elements.

The full source for this example is available at https://github.com/craigew/HtmlBuilder. In the near future I will add tests to the project to illustrate how this can aid with testability.

Advertisements

About craigew

I am a technologist at heart and enjoy working with like minded people who show a passion for what they do. Craftsmanship is important to me and each day I am honing my skills as a software developer on a journey to one day becoming a master software craftsman.
This entry was posted in Design Patterns, Software development and tagged , , , , , , , , , . Bookmark the permalink.

2 Responses to Using the Builder Design Pattern to output HTML on Servlets

  1. Bill says:

    I am doing something similar but first I created an XML builder, I have a Node create another node object and so on and the builder generates the correct or depending on if it has content. I also added AddAttribute to the Node object. The HTML Builder uses the XML builder.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s