Creating the Forecaster JSP


In this project, the first task is to get the user's ZIP Code. You're going to need the ZIP Code in order to get the National Weather Service's high and low temperature forecasts, so that's the first order of business. After getting that ZIP Code, the code will concentrate on getting the forecast and graphing it.

Getting the ZIP Code

In the JSP, there are two ways to get the ZIP Code. First, you can supply a ZIP Code as part of the URL encoded as ?zip=nnnnn, this way, which sets the URL to 94707:

http://www.yourjsphost/username/forecast.jsp?zip=94707

This way is handy in case you want to embed the JPEG image this JSP creates in a web page, as you see in Figure 10.1. You can use the URL to the JSP, with the encoded ZIP Code, in an HTML <IMG> tag's SRC attribute to display the forecast in a web page like this (this is the page you see displayed in Figure 10.1forecast.jsp just sends a JPEG back to the browser, but by using an HTML <IMG> tag, you can neatly embed that JEPG in a web page):

 <HTML> tag;SRC attribute>;SRC attribute> tag> tag>     <HEAD>         <TITLE>             The Forecaster         </TITLE>     </HEAD>     <BODY>         <CENTER>             <H1>                 Forecasting the weather             </H1>             <IMG src="/books/1/263/1/html/2/forecast.jsp?zip=94707">         </CENTER>     </BODY> </HTML> <IMG src="/books/1/263/1/html/2/" /> 

Here's the second way the code can get the ZIP Code: If you don't supply a URL this way, forecast.jsp will ask you for your URL with an HTML text field, and it'll store that URL in a cookie on your machine.

NOTE

If you want to use the Forecast.java standalone application, on the other hand, it'll ask you the first time you run it what your ZIP Code is and then store it in a file named zip.txt, which it uses from then on.


The forecast.jsp page begins with the JSP page directive, which it uses both to import the needed Java classes and to set the type of the content it will send back to the browser. Setting the content type is particularly important, because this is how you tell the browser that you're not sending it HTML, but a JPEG image instead.

Here is the syntax for the JSP page directive:

 <%@ page           [ language="java" ]           [ extends="package.class" ]           [ import="{package.class | package.*}, ..." ]           [ session="true | false" ]           [ buffer="none | 8kb | sizekb" ]           [ autoFlush="true | false" ]           [ isThreadSafe="true | false" ]           [ info="text" ]           [ errorPage="relativeURL" ]           [ contentType="mimeType [ ;charset=characterSet ]"               |   "text/html ; charset=ISO-8859-1" ]           [ isErrorPage="true | false" ]  %> 

Here are the attributes that are important in this case:

  • import="{package.class | package.* }, ..." You assign this attribute a comma-separated list of Java packages that you want to import. Once imported, the packages, and their contents, will be available to scriptlets, expressions, and declarations in the JSP.

  • contentType="mimeType [ ;charset=characterSet ]" | "text/html;charset=ISO-8859-1" You assign this attribute the MIME type (including, if you want to, the character encoding) the JSP code will use in the response it sends to the browser. Note that the default MIME type is "text/html," and the default character encoding is "ISO-8859-1."

In this case, the code needs to import the java.io.*, java.awt.*, java.awt.image.*, java.net.*, and com.sun.image.codec.jpeg.* packages, which looks like this in the page directive:

[View full width]

<%@ page import="java.io.*, java.awt.*, java.awt.image.*,java.net.*,com.sun.image.codec .jpeg.*" %> . . .

To tell the browser that you're sending back a binary image in JPEG format, you can set the contentType attribute to the "image/jpeg" MIME type:

[View full width]

<%@ page contentType="image/jpeg" import="java.io.*, java.awt.*, java.awt.image.*,java.net .*,com.sun.image.codec.jpeg.*" %> . . .

How do you recover the ZIP Code if the user has supplied one? He might have URL-encoded a ZIP Code, like this:

http://www.yourjsphost/username/forecast.jsp?zip=94707.com

Encoding data this way is often how the data in HTML controls is sent back to the server, so you can recover the ZIP Code by pretending that it was entered by the user into an HTML control named "zip." To recover that data, you'd use this code in forecast.jsp:

[View full width]

<%@ page contentType="image/jpeg" import="java.io.*, java.awt.*, java.awt.image.*,java.net .*,com.sun.image.codec.jpeg.*" %> <% String zip = ""; if(request.getParameter("zip") != null){ zip = request.getParameter("zip"); . . . } . . . }

If the ZIP Code was found this way, the code only needs to call the drawImage method (covered in a few pages) that will perform the data gathering and drawing:

[View full width]

<%@ page contentType="image/jpeg" import="java.io.*, java.awt.*, java.awt.image.*,java.net .*,com.sun.image.codec.jpeg.*" %> <% if(request.getParameter("zip") != null){ zip = request.getParameter("zip"); drawImage(zip, response); return; } . . . }

So far, so good. But what if the ZIP Code hasn't been URL-encoded? In that case, perhaps it was already encoded in a cookie set by forecast.jsp earlier. The cookie that forecast.jsp sets is called zipCookie, and the code checks if it already exists and sets a Boolean variable named foundCookie to true if it does.

Here's how that works. First, the code uses the request object's getCookies method to get the current cookies passed to the code by the browser as an array of Cookie objects:

[View full width]

<%@ page contentType="image/jpeg" import="java.io.*, java.awt.*, java.awt.image.*,java.net .*,com.sun.image.codec.jpeg.*" %> <% Cookie[] cookies = request.getCookies(); boolean foundCookie = false; String zip = ""; . . . }

This is the first time code in this book has worked with cookies, and you can find the significant methods of the Java Cookie class in Table 10.1. Being able to use cookies is a powerful technique, and JSP is up to the task.

Table 10.1. Significant Methods of the javax.servlet.http.Cookie Class

Method

Does This

java.lang.String getComment()

Returns a comment that describes the purpose of this cookie

java.lang.String getDomain()

Returns the domain name for the cookie

int getMaxAge()

Returns the maximum age of the cookie (given in seconds). The default value is -1, which means the cookie should be deleted when the browser is closed

java.lang.String getName()

Returns the name of the cookie as text

boolean getSecure()

Returns a value of true if the browser is sending cookies using only a secure protocol

java.lang.String getValue()

Returns the value of the cookie as text

int getVersion()

Returns the version of the protocol this cookie uses

void setComment (java.lang.String purpose)

Sets a comment that describes this cookie and/or its purpose

void setDomain

(java.lang.String pattern)

Sets the domain associated with this cookie

void setMaxAge(int expiry)

Sets the maximum age of the cookie (given in seconds)

void setSecure(boolean flag)

Specifies to the browser whether or not the cookie should only be returned to the server using a secure protocol

void setValue

Assigns a text value to the cookie (java.lang.String newValue)

void setVersion(int v)

Sets the version of the cookie protocol this cookie uses


Now the code loops over the cookie array in order to search for the cookie named zipCookie:

[View full width]

<%@ page contentType="image/jpeg" import="java.io.*, java.awt.*, java.awt.image.*,java.net .*,com.sun.image.codec.jpeg.*" %> <% Cookie[] cookies = request.getCookies(); boolean foundCookie = false; String zip = ""; if(request.getParameter("zip") != null){ zip = request.getParameter("zip"); drawImage(zip, response); return; } if(cookies != null){ for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) { . . . } } . . . }

It can determine if the current cookie in the loop is named zipCookie by using the cookie's getName method:

     if(cookies != null){         for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++)         {             Cookie cookie1 = cookies[loopIndex];             if (cookie1.getName().equals("zipCookie")) {                 .                 .                 .             }         }     }     .     .     . } 

If the zipCookie object was found, you can get the ZIP Code from it with the Cookie object's getValue method, and you can also set the foundCookie Boolean to true:

     if(cookies != null){         for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++)         {             Cookie cookie1 = cookies[loopIndex];             if (cookie1.getName().equals("zipCookie")) {                 zip = cookie1.getValue();                 foundCookie = true;             }         }     }     .     .     . } 

If you've found the cookie, you've also got the ZIP Code, so you're ready to go. But what if the cookie didn't exist? In that case, you've got to ask the user for his ZIP Code and store it in the cookie. The Forecaster project does that with the web page you see in Figure 10.3.

Figure 10.3. Asking for the user's ZIP Code.


So how do you handle the case where the user enters his ZIP Code this way? The text field you see in Figure 10.3 is named "textField," and you can check if the user has filled his ZIP Code in that text field this way, if the cookie doesn't exist:

     if(cookies != null){         for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++)         {             Cookie cookie1 = cookies[loopIndex];             if (cookie1.getName().equals("zipCookie")) {                 zip = cookie1.getValue();                 foundCookie = true;             }         }     }     if (!foundCookie) {         if(request.getParameter("textField") != null){         .         .         .         }         .         .         . } 

If there's text waiting for you in the textField parameter, that text is the user's ZIP Code. The code stores that ZIP Code in the zipCookie cookie first:

 if (!foundCookie) {     if(request.getParameter("textField") != null){         Cookie cookie1 = new Cookie("zipCookie",             request.getParameter("textField"));             .             .             .         .         .         .     } 

Then you can set the maximum age of the cookiein this case, the code sets it to 365 * 24 * 60 * 60 seconds, or one year, before it expires. To set that cookie in the user's machine, you can use the response object's addCookie method this way:

 if (!foundCookie) {     if(request.getParameter("textField") != null){         Cookie cookie1 = new Cookie("zipCookie",             request.getParameter("textField"));         cookie1.setMaxAge(365 * 24 * 60 * 60);         response.addCookie(cookie1);         .         .         .     } 

At this point, you can also display the forecast using the ZIP Code the user has entered into the text field in Figure 10.3 by using the drawImage method, which will be created in a few pages:

 if (!foundCookie) {     if(request.getParameter("textField") != null){         Cookie cookie1 = new Cookie("zipCookie",             request.getParameter("textField"));         cookie1.setMaxAge(365 * 24 * 60 * 60);         response.addCookie(cookie1);         drawImage(request.getParameter("textField"), response);     }     .     .     . } 

On the other hand, what if there is no text waiting for you in the textField parameter? In that case, the user hasn't seen the input page that appears in Figure 10.3 yet, and you should display it. Here's how that looks: (Note that this is where the input text field named "textField" is created.)

     if (!foundCookie) {         if(request.getParameter("textField") != null){             Cookie cookie1 = new Cookie("zipCookie",                 request.getParameter("textField"));             cookie1.setMaxAge(365 * 24 * 60 * 60);             response.addCookie(cookie1);             drawImage(request.getParameter("textField"), response);         }         else{ %>     <HTML>         <HEAD>             <META HTTP-EQUIV="Expires" CONTENT="-1">             <TITLE>                 Forecaster             </TITLE>         </HEAD>         <BODY>             <H1>                 Forecaster             </H1>             <FORM NAME="form1" METHOD="POST">                 Please enter your five-digit zip code:                 <INPUT TYPE="TEXT" NAME="textField"></INPUT>                 <BR>                 <BR>                 <INPUT TYPE="SUBMIT" VALUE="Submit">             </FORM>         </BODY>     </HTML>         .         .         . 

If the user doesn't need to see the input page, you already have his ZIP Code at this point, so you're ready to call the method that does all the work, drawImage:

     if (!foundCookie) {         if(request.getParameter("textField") != null){         .         .         .         }         else{ %>     <HTML>         <HEAD>             <META HTTP-EQUIV="Expires" CONTENT="-1">             <TITLE>                 Forecaster             </TITLE>         </HEAD>         .         .         .     </HTML> <%         }     }     else{         drawImage(zip, response);     } %> 

Excellent, you've gotten the user's ZIP Code, whether it's from URL-encoding, a cookie, or the text field. Now it's time to start the real business of the Forecast projectdisplaying the forecast.

Gathering the Weather Data

Next on the list is writing the drawImage method, which does the actual work, now that you have the user's ZIP Code at hand. You pass this method the ZIP Code and response object (you need the response object so the code can send the JPEG back to the browser). Because this is a new method, you need to declare it in a JSP declaration (not a scriplet, which can't support method declarations). This is created with the markup <%! and %>:

 <%! public void drawImage(String zip, HttpServletResponse response)  {     .     .     . } %> 

The drawImage method starts by getting the weather data from the National Weather Service. The National Weather Service has a web page at http://www.srh.noaa.gov that allows you to enter the ZIP Code you're interested in. By taking a look at the web page, you find that the ZIP Code is sent to a PHP file named zipcity.php and that the text field containing the ZIP Code is called "inputstring." To automate the submission process to include the user's ZIP Code, then, you can create a Java URL object like this:

 public void drawImage(String zip, HttpServletResponse response) {     try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         .         .         . } 

To connect to the National Weather Service's website, you can use a URLConnection object this way:

 public void drawImage(String zip, HttpServletResponse response) {     try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         URLConnection urlconnection = url.openConnection();         .         .         . } 

You can find the significant methods of the Java URLConnection class, which is terrific for downloading web pages in code, in Table 10.2.

Table 10.2. Significant Methods of the java.net.URLConnection Class

Method

Does This

void addRequestProperty (String key, String value)

Sets a request property as given by this key-value pair

abstract void connect()

Connects to the resource referenced by this URL

int getConnectTimeout()

Returns the value of the connection timeout (given in seconds)

Object getContent()

Returns the contents of this URL connection as an object

String getContentEncoding()

Returns the current value of the content-encoding header

int getContentLength()

Returns the current value of the content-length header

String getContentType()

Returns the current value of the content-type header

long getDate()

Returns the current value of the date header

boolean getDoInput()

Returns the current value of this URLConnection object's doInput setting

boolean getDoOutput()

Returns the current value of this URLConnection object's doOutput setting

long getExpiration()

Returns the current value of the expires header field

String getHeaderField(int n)

Returns the value for a given header

String getHeaderField (String name)

Returns the value of a header specified by name

long getHeaderFieldDate (String name, long Default)

Returns the value of the named field treated as a date

int getHeaderFieldInt (String name, int Default)

Returns the value of the named field treated as an int

String getHeaderFieldKey(int n)

Returns the key for a given header field

Map<String,List<String>> getHeaderFields()

Returns a Java map containing the headers

InputStream getInputStream()

Returns an input stream that lets you read from this connection

long getLastModified()

Returns the value of the last-modified header

OutputStream getOutputStream()

Returns an output stream that you can use to write to this URL connection

Permission getPermission()

Returns an object giving the permission you need to connect using this object

int getReadTimeout()

Returns the current setting for the timeout length (given in milliseconds)

Map<String,List<String>> getRequestProperties()

Returns a Java map containing request properties for this connection

String getRequestProperty (String key)

Returns the value of the named request property

URL getURL()

Returns the value of this URLConnection object's URL

void setConnectTimeout (int timeout)

Sets a timeout value, in milliseconds, used when opening a connection

void setDoInput(boolean doinput)

Sets the value of the doInput setting for this URLConnection object to the given value

void setDoOutput (boolean dooutput)

Sets the value of the doOutput setting for this URLConnection object to the given value

static void setFileNameMap (FileNameMap map)

Sets the FileNameMap setting for this connection

void setReadTimeout(int timeout)

Sets the timeout for reading operations to the given value (given in milliseconds)

void setRequestProperty (String key, String value)

Sets a request property to the given value


How do you read the National Weather Service page that's returned by this URL, letting you recover the weather data? You can open an InputStream object to the URL using the URLConnection class's getInputStream method this way in the code:

 public void drawImage(String zip, HttpServletResponse response) {     try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         URLConnection urlconnection = url.openConnection();         InputStream in = urlconnection.getInputStream();         .         .         . } 

So far, so good. Now that you have an InputStream object connected to the National Weather Service's web server, you can read in the target web page to a temporary buffer, which in this case is a String object named input:

 public void drawImage(String zip, HttpServletResponse response) {     try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         URLConnection urlconnection = url.openConnection();         InputStream in = urlconnection.getInputStream();         String input = "";         String inchar;         char[] cc = new char[1];         while ((character = in.read()) != -1) {             char z = (char)character;             cc[0] = z;             inchar = new String(cc);             input += inchar;         }         in.close();         .         .         . } 

At this point, you've got the weather data, and you can start searching it for high and low temperature predictions. You can see a representative National Weather Service forecast in Figure 10.4; notice the "Hi" numbers (these are displayed in red) and the "Lo" numbers (these are displayed in blue) at the bottom of the page. These numbers give the forecast.

Figure 10.4. A representative National Weather Service forecast.


To retrieve the high temperature forecasts for the next four days, you can search for the formatting text that immediately precedes the high temperatures. The National Weather Service pages use either the HTML Hi <font color="#FF0000"> or Hi: <span > right in front of the high temperature forecast values. You can determine which HTML is used in the page you've retrieved by searching for these HTML strings and then storing named hiSearch:

 public void drawImage(String zip, HttpServletResponse response) {     try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         URLConnection urlconnection = url.openConnection();         .         .         .         in.close();         if(input.indexOf("Hi <font color=\"#FF0000\">") >= 0){             hiSearch = "Hi <font color=\"#FF0000\">";         }         else{             hiSearch= "Hi: <span class=\"red\">";         }         .         .         . } 

Now that you know what HTML to search for, you can retrieve the four-day high temperature forecasts and store them in an array named hiTemperature this way:

 public void drawImage(String zip, HttpServletResponse response) {     String hiTemperature[] = new String[4];      try {         URL url = new URL             ("http://www.srh.noaa.gov/zipcity.php?inputstring="             + zip);         URLConnection urlconnection = url.openConnection();         .         .         .         if(input.indexOf("Hi <font color=\"#FF0000\">") >= 0){             hiSearch = "Hi <font color=\"#FF0000\">";         }         else{             hiSearch= "Hi: <span class=\"red\">";         }         int currentPosition = 0;         for(int loopIndex = 0; loopIndex < 4; loopIndex++){             int location = input.indexOf(hiSearch,                 currentPosition);             int end = input.indexOf("&deg;", location);             hiTemperature[loopIndex] = input.substring(location +                 hiSearch.length(), end);             currentPosition = end + 1;          }     .     .     . } 

That fills the hiTemperature array with the highs. Now what about the lows? The National Weather Service pages use either Lo <font color="#0033CC"> or Lo: <span > as the HTML to format the low temperature forecasts, so you can determine which format the current page uses and fill an array named loTemperature with the forecasted low temperatures this way:

 public void drawImage(String zip, HttpServletResponse response)  {     String hiTemperature[] = new String[4];     String loTemperature[] = new String[4];         .         .         .         if(input.indexOf("Lo <font color=\"#0033CC\">") >= 0){             loSearch = "Lo <font color=\"#0033CC\">";         }         else{             loSearch= "Lo: <span class=\"blue\">";         }         currentPosition = 0;         for(int loopIndex = 0; loopIndex < 4; loopIndex++){             int location = input.indexOf(loSearch,                 currentPosition);             int end = input.indexOf("&deg;", location);             loTemperature[loopIndex] = input.substring(location +                 loSearch.length(), end);             currentPosition = end + 1;          }         .         .         . } 

Excellent. You've now stored the high temperature forecasts in the hiTemperature array and the low temperature forecasts in the loTemperature array. You've got your datathe next step is to graph that data and send it back to the user.

Graphing the Data

The problem now breaks down to graphing the data in the hiTemperature and loTemperature arrays and then sending it back to the browser.

The code in the drawImage method continues by drawing the image that will be sent back to the browser, using a BufferedImage object, and creating a Graphics2D object, called g, to draw in that image:

 BufferedImage image = new BufferedImage(225, 201,       BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); . . . 

You can start by filling the image with a white background (when first created, it's black):

 g.setColor(Color.white); g.fillRect(0, 0, 224, 200); . . . 

Here's how to draw the grid lines you see in Figure 10.1, in gray:

 g.setColor(Color.gray); for(int loopIndex = 0; loopIndex < 21; loopIndex++){     g.drawLine(25, loopIndex * 10, 224, loopIndex * 10);     g.drawLine(loopIndex * 10 + 25, 0, loopIndex * 10         + 25, 199); } . . . 

Next come the temperature labels, 10 to 90 degrees, you see along the left in Figure 10.1. Here's how to draw them in blue:

 g.setColor(Color.blue);  Font font = new Font("Courier", Font.PLAIN, 18); g.setFont(font); for(int loopIndex = 20; loopIndex < 200; loopIndex += 20){     g.drawString(String.valueOf(100 - loopIndex / 2), 0,         loopIndex + 5); } . . . 

Okay, what about drawing the high and low temperature forecasts? First the highs, which are displayed in red. As you can see in Figure 10.1, each temperature forecast is drawn with a circle, and then the circles are connected. In the evening, the National Weather Service's forecasts omit the day's high, starting instead with the evening's low. For that reason, the code determines if it's evening by checking whether the low or high forecast appears first:

 boolean evening = false; if(input.indexOf(loSearch) < input.indexOf(hiSearch)){     evening = true;     hiTemperature[3] = hiTemperature[2];     hiTemperature[2] = hiTemperature[1];     hiTemperature[1] = hiTemperature[0]; } . . . 

After you determine whether this is the evening, here's how to draw those circles, each corresponding to a high temperature forecast (note that the code checks if it's evening in order to determine whether today's high value is no longer available):

 g.setColor(Color.red); if(!evening){     g.drawOval(65 - 4, 200 - (Integer.parseInt(         hiTemperature[0]) * 2) - 4, 8, 8); } g.drawOval(105 - 4, 200 - (Integer.parseInt(hiTemperature[1]) *     2) - 4, 8, 8); g.drawOval(145 - 4, 200 - (Integer.parseInt(hiTemperature[2]) *     2) - 4, 8, 8); g.drawOval(185 - 4, 200 - (Integer.parseInt(hiTemperature[3]) *     2) - 4, 8, 8); . . . 

Then you connect those circles with lines to get the upper figure you see in Figure 10.1:

 if(!evening){     g.drawLine(65, 200 - (Integer.parseInt(         hiTemperature[0]) * 2), 105, 200 -         (Integer.parseInt(hiTemperature[1]) * 2)); } g.drawLine(105, 200 - (Integer.parseInt(hiTemperature[1]) * 2),     145, 200 - (Integer.parseInt(hiTemperature[2]) * 2)); g.drawLine(145, 200 - (Integer.parseInt(hiTemperature[2]) * 2),     185, 200 - (Integer.parseInt(hiTemperature[3]) * 2)); . . . 

Okay, now what about the low temperature forecasts? Here's how that works:

 g.setColor(Color.blue); g.drawOval(65 - 4, 200 - (Integer.parseInt(loTemperature[0]) *     2) - 4, 8, 8); g.drawOval(105 - 4, 200 - (Integer.parseInt(loTemperature[1]) *     2) - 4, 8, 8); g.drawOval(145 - 4, 200 - (Integer.parseInt(loTemperature[2]) *     2) - 4, 8, 8); g.drawOval(185 - 4, 200 - (Integer.parseInt(loTemperature[3]) *     2) - 4, 8, 8); g.drawLine(65, 200 - (Integer.parseInt(loTemperature[0]) * 2),     105, 200 - (Integer.parseInt(loTemperature[1]) * 2)); g.drawLine(105, 200 - (Integer.parseInt(loTemperature[1]) * 2),     145, 200 - (Integer.parseInt(loTemperature[2]) * 2)); g.drawLine(145, 200 - (Integer.parseInt(loTemperature[2]) * 2),     185, 200 - (Integer.parseInt(loTemperature[3]) * 2)); . . . 

Finally, here's how to create the label box with the text "Four-Day Forecast" and the attribution "Source: Nat. Weather Srvce." that you see in Figure 10.1:

 g.setColor(Color.white); g.fillRect(55, 160, 140, 30); g.setColor(Color.blue); g.drawRect(55, 160, 140, 30); font = new Font("Courier", Font.PLAIN, 12); g.setFont(font); g.drawString("Four-Day Forecast", 65, 172); font = new Font("Courier", Font.PLAIN, 9); g.setFont(font); g.drawString("Source: Nat. Weather Srvce.", 58, 185); . . . 

That completes the image. However, all this work will have gone for nothing if you can't send the image back to the browser. You've already indicated in the JSP page's page directive that you're going to be sending back a JPEG image, but how do you actually do that?

This turns out to be simpler than you might imagine. You can create a com.sun.image.codec.jpeg.JPEGImageEncoder object that will encode the image and send it back to the browser. To create that object, you use the createJPEGEncoder method of com.sun.image.codec.jpeg.JPEGCodec, passing it the OutputStream object you want to send the data to.

You can get an OutputStream object that will send data back to the browser using the JSP response object's getOutputStream method. Here's what that looks like (note that this code opens a binary output stream to the browser):

         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder             (response.getOutputStream());         .         .         . } 

You can find the significant methods of the Java JPEGCodec class in Table 10.3 and the significant methods of the Java JPEGImageEncoder class in Table 10.4. Both these classes come bundled with Java, no extra downloads needed.

Table 10.3. Significant Methods of the com.sun.image.codec.jpeg.JPEGCodec Class

Method

Does This

static JPEGImageDecoder createJPEGDecoder(InputStream src)

Creates a JPEGImageDecoder object that you can use to decode JPEG data

static JPEGImageDecoder createJPEGDecoder (InputStream src, JPEGDecodeParam jdp)

Creates a parameterized JPEGImageDecoder) object that you can use to decode JPEG data

static JPEGImageEncoder createJPEGEncoder (OutputStream dest)

Creates a JPEGImageEncoder object that you can use to encode image data as JPEG data

static JPEGImageEncoder createJPEGEncoder (OutputStream dest, JPEGEncodeParam jep)

Creates a parameterized JPEGImageEncoder object that you can use to encode image data as JPEG data

static JPEGEncodeParam getDefaultJPEGEncodeParam (BufferedImage bi)

Lets you create JPEGEncodeParam objects given a buffered image to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (int numBands, int colorID)

Lets you create JPEGEncodeParam objects, given the number of bands and a color ID to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (JPEGDecodeParam jdp)

Lets you create JPEGEncodeParam objects, given a JPEGDecodeParam object to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (Raster ras, int colorID)

Lets you create JPEGEncodeParam objects, given raster and color ID to hold parameter settings


Table 10.4. Significant Methods of the com.sun.image.codec.jpeg.JPEGImageEncoder Class

Method

Does This

void encode(BufferedImage bi)

Encodes a buffered image into JPEG data

void encode(BufferedImage bi, JPEGEncodeParam jep)

Encodes a buffered image as JPEG data, using a JPEGEncodeParam object

void encode(Raster ras)

Encodes a Raster object as a JPEG data stream

void encode(Raster ras, JPEGEncodeParam jep)

Encodes a Raster object as a JPEG data stream using a JPEGEncodeParam object

static JPEGEncodeParam getDefaultJPEGEncodeParam (BufferedImage bi)

Lets you create JPEGEncodeParam objects given a buffered image to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (int numBands, int colorID)

Lets you create JPEGEncodeParam objects, given the number of bands and a color ID to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (JPEGDecodeParam jdp)

Lets you create JPEGEncodeParam objects, given a JPEGDecodeParam object to hold parameter settings

static JPEGEncodeParam getDefaultJPEGEncodeParam (Raster ras, int colorID)

Lets you create JPEGEncodeParam objects, given raster and color ID to hold parameter settings

JPEGEncodeParam getJPEGEncodeParam()

Returns a copy of the current JPEGEncodeParam object

OutputStream getOutputStream()

Returns the output stream the encoder is associated with

void setJPEGEncodeParam (JPEGEncodeParam jep)

Sets the JPEGEncodeParam object used for encoding operations


REAL-WORLD SCENARIO: INTERACTIVE ONLINE IMAGES

Creating interactive online images and sending them to the browser in real time is one of the exciting things you can do with Java. But most Java programmers don't know that they can do thislet alone that it's so easy, just two lines of code.

All the functionality you need is packed into the com.sun.image.codec.jpeg packages, and more programmers have been putting this technology to work over the years. However, the fact that these classes are not in the standard Java packages has made adoption of these auxiliary classes slower than it should have been.

On the other hand, developers who know how to make this work know that the potential is great. You can put together real-time stock tickers, financial reports, system resource usage charts, and, as shown in this chapter, up-to-date weather forecasts. You can add your picture to your data or charts, display photos of current users, and even interact with the users if you track their mouse movements using JavaScript event handling to let them draw JPEG images.


Now that you've created a JPEGImageEncoder object, you can encode and send the image to the browser as a JPEG image this way:

         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder             (response.getOutputStream());         encoder.encode(image);         .         .         . } 

That's all it takes. Now you've created the forecast graph and have sent it back to the browser. If you want to embed the image in an HTML page, use an HTML <IMG> element like this (change this to supply your correct ZIP Code):

 <IMG src="/books/1/263/1/html/2/forecast.jsp?zip=94707"> 

Congratulations, you've written your own online daily temperature forecaster in Java, forecast.jsp. This JSP is ready to go. Just store it in the webapps directory of a JSP-enabled Internet server.

What about writing the standalone desktop version? That's coming up next.



    Java After Hours(c) 10 Projects You'll Never Do at Work
    Java After Hours: 10 Projects Youll Never Do at Work
    ISBN: 0672327473
    EAN: 2147483647
    Year: 2006
    Pages: 128

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net