The New
Servlet Tutorial - Part One, A Different MVC
Well it's been three years since my last servlet tutorial, which were primarily written for my students at the time. Time passes and we get older and wiser so I felt
it was time to redo
the whole series. Over the next 6 or 7 tutorials we will look at a home-made MVC (Model View Controller) system built especially
for the website and web application coder. Were going to take a complete relook
at the whole idea of servlets and how to use them with a website, how to secure
a website with sessions and how to build these applications to use the least amount of server resources while giving your clients a rocket fast web application. Stick around
for the whole series, I think you'll enjoy it.
The Model View Controller Concept
Before we start looking at how to build our MVC we need to take a few moments to explain exactly what it is and why we would want to use it in out web applications. The MVC concept is a design pattern where you separate your application into three pieces, the model which stores the data (anything from flat files to a large scale relational database), the View which displays it (your layout-design the customer interacts with), and the Controller which handles data moving back and forth between the model and the view. It what's commonly known as a 3 tier programming platform. The primary advantage of this system is creating a buffer (the controller) between your client, their actions and your data. As any good programmer knows data integrity is paramount. So now that we have an explanation of what we are trying to create lets start working out the details.
Building A Different MVC
While most Java MVC tutorials around today use a JSP for the front end I don't. Even though many of these other programmers feel the JSP / Servlet model allows them a complete separation of display content from their application code I constantly find a massive amount of lines of java code embedded in these JSPs, which of course contain all (or most) of their HTML. I take a slightly different approach that I feel allows almost the same separation of html from java while adding a massive amount of functionality to a web application. Do I have HTML within java files? Yes but my HTML is contained with 2 or 3 class files that are created exactly for this purpose, but we will get to that soon enough. Now before I go any further I must say I do use ONE JSP on every website, the index page BUT it only consists of two lines of code:
<%@ page session="false"%>
<jsp:include page="/servlet/Controller?page=Main" />
If you notice this code does nothing more than include my controller servlet, which handles all of the processing throughout the website. This allows me to control ALL the design graphics and functionality from one set of files including the index page. You may ask why I just don't redirect into a servlet from an HTML file. The answer lies in the fact that html redirects reek havoc on search engine rankings, something else any good web developer should always consider. So we have waited to long to get started, lets get to some code.
We are going to start out with our main controller class, which we will call (surprisingly) Controller.java. I'll start from the basics again even though my old tutorial did this I feel its worth repeating. So here's our HTTP Servlet Skeleton, really nothing special but we'll cover the basics of it. Notice I have both a doPost and a doGet coded with the doGet doing nothing more than passing everything to my doPost. This eliminates the need to worry about how the data might come in from a form, link or whatnot. Next you will notice I've created a StringBuffer object within the doPost. This handles all of my HTML output back to the client, and provides us an easy to use object for adding and removing that html. Lastly you will notice I have created a PrintWriter object (java.io.PrintWriter) for our final send back to the client, I pass the now filled StringBuffer to it and print it, then close it. One important thing to notice here (as I mentioned in my first tutorial) is that only one printing is done here. This avoids many, many problem with browsers and can mean the life or death or your servlet-based application. Multiple out.print statements will slow a servlet down to a crawl and should be avoided at all costs! Also note the res.setContentType("text/html"); line. This is the one line that's I've seen more beginners screw up than any other. Without this line several Mozilla-based browsers will actually output your code into the browser, NOT the finished page! OK, That's the absolute basics needed, now let's attack our different page's content.
I've added two new lines of code in this next example. First is a test for the incoming page name parameter, appropriately called page. This is done with a ternary operator which I use more than any other test condition. The second is a call to a class I call ContentReader which, as we we'll see shortly, handles all of our different pages and adding them to the final output. So here's the next step of our servlet. But before we go into too much detail I feel it's probably a good idea to address the ternary operator, since you will be seeing a lot of them in this tutorial.
Ternary Operators are Fun and FAST
A lot of beginning (and even some more seasoned) Java programmers have literally thousands of lines of if-else statements or multiple if statements one after another. I'm sorry but if you want lightning fast webapps (or any application for that fact) you MUST learn how to use ternaries to your advantage. A ternary replaces those nasty old mulitline if-else statements with a single rocket fast check condition. You can also replace those simple one lined if statements with them! So let's look at the code and make some sense of it.
String page = (req.getParameter("page") != null && req.getParameter("page").trim().length() != 0) ? req.getParameter("page").trim() : "None":
The first part of the ternary is what the data will be assigned to based on the return of the check condition. In this case its the String, page. Next is the check condition itself, which is enclosed in the parens. This condition tests whether the variable we are looking for actually exists AND its not an empty string. Note: You MUST check for null before attempting to check for the empty string to avoid throwing a NullPointerException from the call to trim() and you MUST use the && shortcut operator so if the parameter is null the trim is never called. After the check condition is a ? (question mark) This separates the check condition from the two available assignments. The first statement after the ? is what will be assigned to the String page IF the check condition returns true. After that statement is a : that separates the true return from the false return which of course follows the colon. So in plain language the ternary above says this:
If the request parameter "page" exists and is NOT an empty String assign its trimmed value to the String page, ELSE assign "None" to it.
They really are simple to use once you get the hang of them and will increase the speed of all your apps 10 fold. Even better they can be nested within other statements (more on this later). Keep these in mind because you will see them used in many of the following examples in a multitude of different ways.
Back to the Servlet
OK, so now we understand the first of the two new lines in our example servlet, now lets look at the call to our ContentReader. It's this line: sb = new ContentReader().getPageContent(sb, page); Now here's another way to save some server resources, which always makes things run smoother and faster. You'll notice I didn't create a variable here, in other words I didn't do: ContentReader cr = new ContentReader(); and then call the method cr.getPageContent(sb, page); There is no reason to create an instance of ContentReader since we are only using it once within the scope of this servlet. Now does it save a ton of memory, no its probably a minute amount that would never even register with this servlet running ..... until you have 100,000 people all hitting it at the same time. You see IF I made an instance it's life span would be the whole doPost where as the nanosecond the method returns this way makes the ContentReader object eligible for garbage collection. I'll grant you its not a huge savings but every little bit helps and secondly it's one line I code we don't need to write. Now as I said before our ContentReader object handles reading in our page content. I still use (for you old time readers) flat .txt files for my websites content. Why? They are simple for a non HTML enabled customer to edit and they are small and memory friendly.
Reading Content from files
Now as I mentioned before I store all of site's content in flat .txt files. Many people throw their content into databases but I have found that the whole process of connecting
to the database, running the query, iterating through the ResultSet and THEN adding it to your output extremely wasteful of server resources. This is especially true when the site you build has to grow
into millions of user. Personally I don't go to a database unless I have to! Now our call to ContentReader passes the name of the page, the StringBuffer to add the page's content to AND the servlet context
which is essential for being able to locate the content files. Here's our ContentReader example. Let's run through
the code quickly just in case there is anything you may not understand. The first line of the getPageContent method locks into our content file by use of the URL object. Note it uses the ServletContext object
we passed to the method from the servlet. What is the ServletContext, why couldn't we get it here and why did we have to pass it? The ServletContext can only be grabbed
from within a servlet,
what it does, in simple terms, is tell your app where on the server you are. Without it and it's method sc.getResource we'll never be able to locate where your application is actually running and how to access files and folders without the entire
path from the root. I should also mention I could have used the getRealPath method, which returns a String that includes the whole path but I just find this method easier.
Notice after we have the URL object everything is contained within a try / catch block. This gives us protection from those nasty NullPointerExceptions when someone types the wrong URL
into the browser or we delete a page. You'll notice I've caught both a NullPointer and a FileNotFound Exception for this very reason. Both of these catch blocks add our pageNotFoundError HTML code in place
of the page that isn't there. This is a cleaned up handled 404
page that gives them a nice Sorry you page wasn't found
error page ... not a blank white page or exception stack trace.
Our first line of code opens the stream from the file we locked into with our URL object via an InputStream. You will also notice I then test that InputStream object just to make sure its really there. I
consider these type redundant checks as insurance
because I don't like my clients getting errors! Once we know we have our stream we then create a BufferedReader object to start the read.
Finally we run though the file line by line assigning the lines content to the String s and adding it to our StringBuffer, along with a new line character for easier source code reading. Finally we MUST close the
BuffferedReader and the InputStream objects to prevent those nasty memory leaks. Very fast, very low overhead while allowing us to let clients edit their own page content, either through a CMS or just plain
notepad. Of course any formatting they want in those files is truly their option but I always keep it to header tags <h1> etc. and paragraph tags.
Next, adding design and functionality to our servlet driven site
Lissa Lee, bathandbodycare.com | More Testimonials >>