13.2. Writing Programs to Generate HTMLHTML is not a programming language. HTML can't specify loops, conditionals, variables, data types, or anything else we've learned about specifying process. HTML is used to describe structure, not process. That said, we can easily write programs to generate HTML. Remember that to have quotes inside of a String object in Java we need to use '\"'. Program 116. Generating a Simple HTML Page |
import java.io.*; /** * Class used to write web (HTML) pages * @author Barb Ericson */ public class WebPageWriter { /** * Method to write an example web (HTML) page */ public void writeExamplePage(String fileName) { // try the following try { // open a file for writing BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); |
That works, but it's really boring. Why would you write a program to write a file that you can easily create with a text editor? You write programs in order to have reusable parts, communicate process, and allow for tailoring. Let's write a method that creates a homepage.
/** * Method that will write out a homepage for a person * with the passed name |
We can modify the main to test this as well:
public static void main(String[] args) { WebPageWriter writer = new WebPageWriter(); writer.writeExamplePage("simple.html"); writer.writeHomepage("Mark", "reading"); }
By executing the main we get:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transition//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Mark's Homepage</title></head> <body> <h1>Welcome to Mark's Homepage</h1> <p>I am interested in reading</p> </body> </html>
|
Modifying this program is painful, though. There is so much detail in the HTML, and all that quoting is confusing. We're better off creating helper methods to break up the program into pieces that are easier to manipulate. This is an example of using procedural abstraction. In procedural abstraction we try to break a task down into subtasks. We can create a method for each subtask. This makes the top level method easier to read and understand.
If we break writing things to the HTML page into smaller methods, we have the problem of what to do with exceptions. Each time we write to a file we could get an IOException. We could add a try and catch block to every small method but that would make them bigger and would mean repeating a fair amount of code. Another approach is to let the small methods throw the IOException and only catch them and handle them in the larger method that calls the smaller methods.
To allow a method to throw an exception, all we have to do is add the tHRows ExceptionClass to the method declaration after the parameter list. This is the keyword throws followed by the class name of the exception that it is throwing.
Here's another version of the method that creates helper (private) methods to do most of the work. Each private method can throw an IOException. This means that the method that calls this method either has to also throw this exception or must catch it.
/** * Method to write the doctype and html tags * @param writer the writer to use * @throws IOException */ private void writeStart(BufferedWriter writer) throws IOException { // write the document type writer.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD " + "HTML 4.01 Transition//EN\""); writer.newLine(); writer.write("\"http://www.w3.org/TR/html4/loose.dtd\">"); writer.newLine(); // start the html page writer.write("<html>"); writer.newLine(); } /** * Method to write the title out * @param writer the writer to use * @param title the title to use * @throws IOException */ private void writeHead(BufferedWriter writer, String title) throws IOException { writer.write("<head><title>" + title + "</title></head>"); writer.newLine(); } /** * Method to write the body of the page * @param writer the writer to use * @param body the body to write * @throws IOException */ private void writeBody(BufferedWriter writer, String body) throws IOException { writer.write("<body>" + body + "</body>"); writer.newLine(); } |
Notice that we now have helper methods that are easy to reuse. We can use the new helper methods to write out different pages.
|
We can grab content for our Web pages from anywhere we want. Here is a recipe that can pull information out of a directory provided as input and generate an index page of those images (Figure 13.7). We're not going to show the code for the writeStart() and other helper methods herewe'll just focus on the part we care about. And that is how we should think about itjust the part we care about, and we write writeStart() once and then forget about it!
Up to now we have been using the newLine() method of the BufferedWriter class to force a new line. But if we are writing lots of text out together, we may want to add a special character to force a new line to our String. The problem is that the special character is different on different operating systems. The best way to handle this is to use the System class to find out the right special characters to use for the current operating system. We can do this by using
String endOfLine = System.getProperty("line.separator");
The method getProperty will return the value of the specified property on the current system. You can use this method to get other information about the current system, such as the directory separator and the version of Java being run.
Here is a method that you can add to the WegPageWriter class to generate a Web page with thumbnails of the images in a directory, as seen in Figure 13.7.
/** * Method to create a page with thumbnails of all the images * in a directory * @param directory the directory to create the page for */ public void createImagePage(String directory) { String name = null; String body = ""; String endOfLine = System.getProperty("line.separator"); // try the following try { // create the File object File dir = new File(directory); // get the full path name of the directory String pathName = directory + dir.getName() + ".html"; BufferedWriter writer = new BufferedWriter(new FileWriter(pathName)); // write the start writeStart(writer); // write the head writeHead(writer,"Thumbnails from " + directory); // get the array of items in the directory String[] items = dir.list(); // loop through the array for (int i = 0; i < items.length; i++) { name = items[i]; if (name.indexOf(".jpg") >= 0) { body = body + "<p>Filename: " + name + "<img src='/books/1/79/1/html/2/" + name + "' height='150'/></p>" + endOfLine; } } // write the body writeBody(writer,body); // write the end writeEnd(writer); |
We can modify the main method of WebPageWriter to test this method. We can comment out the other tests that we did in the main method. Commenting code out means that it won't be executed but it is still around if we want to use it again.
public static void main(String[] args) { WebPageWriter writer = new WebPageWriter(); // writer.writeExamplePage("simple.html"); // writer.writeHomepage("Mark", "reading"); // writer.writeHomepageV2("Barb", "horseback riding"); String dir = "c:/intro-prog-java/mediasources/students/"; writer.createImagePage(dir); }
Executing this main will result in the creation of the Web page shown in Figure 13.7.
We can pull information off of the Web to create new Web content. That's how sites like Google News[1] work. Here's a version of our homepage creator that gathers the temperature live (designed especially for Atlanta).
[1] http://news.google.com
/** * Method for writing a homepage for the passed * name that displays the current weather * @param name the person's name * @param interests a list of the person's interests */ public void writeHomepageV3(String name, String interests) { // get the current temperature TempFinder tempFinder = new TempFinder(); String urlString = "http://www.ajc.com/"; String currTemp = tempFinder.getTempFromNetwork(urlString); // try the following try { |
This method can be tested by the following main method:
public static void main(String[] args) { WebPageWriter writer = new WebPageWriter(); writer.writeHomepageV3("Letisha","flying planes"); }
|
Notice that we can reuse classes that we wrote, too. We just used an object of the class TempFinder in the method writeHomepageWithWeather. This is one of the great things about object-oriented programming: creating classes that you can reuse. We didn't need to import anything to use this class. We didn't have to use an import statement because the classes are in the same package. If you don't have a package statement in your code as the first executable line in the file, then your class is automatically put in the "unnamed" package. Since we didn't have a package statement in either TempFinder or in WebPageWriter, they are both in the "unnamed" package.
Remember the random sentence generator? We can add that, too.
/** * Method for writing a homepage for the passed * name that displays the current weather and a * random sentence * @param name the person's name * @param interests a list of the person's interests */ public void writeHomepageV4(String name, String interests) { // get the current temperature TempFinder tempFinder = new TempFinder(); String urlString = "http://www.ajc.com/"; String currTemp = tempFinder.getTempFromNetwork(urlString); // get the random sentence SentenceGenerator sentenceGen = new SentenceGenerator(); String sentence = sentenceGen.generateRandomSentence(); // try the following try { // open a file for writing BufferedWriter writer = new BufferedWriter(new FileWriter(name + ".html")); // write the start writeStart(writer); // write the header writeHead(writer,name + "'s Homepage"); // write the body writeBody(writer,"<h1>Welcome to " + name + "'s Homepage</h1>" + "<p> I am interested in " + interests + ".</p><p>Right now it is " + currTemp + " degrees.</p>" + "<p>The random thought for the day is: " + sentence + "</p>"); // end the page writeEnd(writer); // close the writer writer.close(); |
We can test this method with the following main method:
public static void main(String[] args) { WebPageWriter writer = new WebPageWriter(); writer.writeHomepageV4("Matthew","playing video games"); }
Let's walk through the whole large example.
Execution will start in the main method, which first creates an object of the class WebPageWriter, and then invokes the method writeHomepageV4.
The method writeHomepageV4 starts executing with the name parameter referring to "Matthew" and the interests parameter referring to "playing video games".
An object of the class TempFinder is created and getTempFromNetwork is used to get the current temperature from http://www.ajc.com/.
An object of the class SentenceGenerator is created and a random sentence is generated by the method generateRandomSentence().
Execution continues in the try block. We try to create a BufferedWriter object using a FileWriter object with a file name of the passed name followed by ".html".
We invoke the method writeStart to write out the beginning of the HTML file.
We invoke the method writeHead to write out the head of the HTML file.
We invoke the method writeBody to write out the body of the HTML file. This includes the passed name, interests, current temperature, and the random sentence.
We invoke the method writeEnd which writes out the end of the HTML file.
We close the BufferedWriter which finishes writing out the buffered data and closes the file.
If an exception occurs during the execution of code in the try block, execution will jump to the catch block. The stack trace (call stack) will be printed.
Where do you think large Web sites get all their information? There are so many pages in those Web sites. Where do they get it all? Where do they store it all?