So far you have learned how to write Java servlets that generate dynamic HTML text. Java servlets are not limited to sending text to a browser. They can return images on demand. The images can be stored in files or created from programs.
You can use the HTML <img> tag to send images from files. The syntax for the tag is:
<img src = URL alt = text align = [top middle bottom texttop] >
The attribute src specifies the source of the image. The attribute alt specifies an alternative text to be displayed in case the image cannot be displayed on the browser. The attribute align tells the browser where to place the image.
To demonstrate getting images from a file in a servlet, let us create a servlet that dynamically generates the flag of a country and a text that describes the flag, as shown in Figure 34.21. The flag is stored in an image file, and the text that describes the flag is stored in a text file.
Create the servlet named ImageContent in Listing 34.12. Compile it into c:\jakarta-tomcat-5.5.9\webapps\liangweb\WEB-INF\classes . Run the servlet using the URL
http://localhost:8080/liangweb/ImageContent?country=ca
1 import javax.servlet.*; 2 import javax.servlet.http.*; 3 import java.io.*; 4 5 public class ImageContent extends HttpServlet { 6 /** Process the HTTP Get request */ 7 public void doGet(HttpServletRequest request, HttpServletResponse 8 response) throws ServletException, IOException { 9 response.setContentType( "text/html" ); 10 PrintWriter out = response.getWriter(); 11 12 String country = request.getParameter( "country" ); 13 14 out.println( "<img src = \"/liangweb/images/" + country + ".gif" 15 + "\" align=left> " ); 16 17 // Read description from a file and send it to the browser 18 java.util.Scanner in = new java.util.Scanner( 19 new File( "c:\\book\\" + country + ".txt" )); 20 21 // Text line from the text file for flag description 22 String line; 23 24 // Read a line from the text file and send it to the browser 25 while (in.hasNext()) { 26 out.println(in.nextLine()); 27 } 28 29 out.close(); 30 } 31 } |
You should store the image files in c:\jakarta-tomcat-5.5.9\webapps\liangweb\images .
The country parameter determines which image file and text file are displayed. The servlet sends the HTML contents to the browser. The contents contain an <img> tag (lines 14 “15) that references to the image file.
The servlet reads the characters from the text file and sends them to the browser (lines 18 “27).
The preceding example displays an image stored in an image file. You can also send an image dynamically created in the program.
Before the image is sent to a browser, it must be encoded into a format acceptable to the browser. Image encoders are not part of Java API, but several free encoders are available. One of them is the GifEncoder class ( http://www.acme.com/java/software/Acme.JPM.Encoders.GifEncoder.html ), which is included in \book\acme.jar . Use the following statement to encode and send the image to the browser:
new GifEncoder(image, out , true ).encode();
where out is a binary output stream from the servlet to the browser, which can be obtained using the following statement:
OutputStream out = response.getOutputStream();
To demonstrate dynamically generating images from a servlet, let us create a servlet that displays a clock to show the current time, as shown in Figure 34.22.
Create the servlet named ImageContentWithDrawing in Listing 34.13. Place acme.jar in c:\jarkata-tomcat-5.5.9\common\lib directory to ensure that GifEncoder and its supporting classes are available at runtime for the server. You also need to add acme.jar to the classpath to be able to compile the servlet. Compile ImageContentWithDrawing into c:\jakarta-tomcat-5.5.9\webapps\liangweb\WEB-INF\classes . Run the servlet using the URL
http://localhost:8080/liangweb/ImageContentWithDrawing
1 import javax.servlet.*; 2 import javax.servlet.http.*; 3 import java.io.*; 4 import java.util.*; 5 import java.text.*; 6 import java.awt.*; 7 import java.awt.image.BufferedImage; 8 import Acme.JPM.Encoders.GifEncoder; 9 10 public class ImageContentWithDrawing extends HttpServlet { 11 /** Initialize variables */ 12 private final static int width = 300 ; 13 private final static int height = 300 ; 14 15 /** Process the HTTP Get request */ 16 public void doGet(HttpServletRequest request, HttpServletResponse 17 response) throws ServletException, IOException { 18 response.setContentType( "image/gif" ); 19 OutputStream out = response.getOutputStream(); 20 21 // Create image 22 Image image = new BufferedImage(width, height, 23 BufferedImage.TYPE_INT_ARGB); 24 25 // Get Graphics context of the image 26 Graphics g = image.getGraphics(); 27 28 drawClock(g); // Draw a clock on graphics 29 30 // Encode the image and send to the output stream 31 new GifEncoder(image, out, true ).encode(); 32 33 out.close(); // Close stream 34 } 35 36 private void drawClock(Graphics g) { 37 // Initialize clock parameters 38 int clockRadius = 39 ( int )(Math.min(width, height) * 0.7 * 0.5 ); 40 int xCenter = (width) / 2 ; 41 int yCenter = (height) / 2 ; 42 43 // Draw circle 44 g.setColor(Color.black); 45 g.drawOval(xCenter - clockRadius, yCenter - clockRadius, 46 2 * clockRadius, 2 * clockRadius); 47 g.drawString( "12" , xCenter - 5 , yCenter “ clockRadius + 12 ); 48 g.drawString( "9" , xCenter “ clockRadius + 3 , yCenter + 5 ); 49 g.drawString( "3" , xCenter + clockRadius - 10 , yCenter + 3 ); 50 g.drawString( "6" , xCenter - 3 , yCenter + clockRadius - 3 ); 51 52 // Get current time using GregorianCalendar 53 TimeZone timeZone = TimeZone.getDefault(); 54 GregorianCalendar cal = new GregorianCalendar(timeZone); 55 56 // Draw second hand 57 int second = ( int )cal.get(GregorianCalendar.SECOND); 58 int sLength = ( int )(clockRadius * 0.9 ); 59 int xSecond = ( int )(xCenter + sLength * Math.sin(second * 60 ( 2 * Math.PI / 60 ))); 61 int ySecond = ( int )(yCenter “ sLength * Math.cos(second * 62 ( 2 * Math.PI / 60 ))); 63 g.setColor(Color.red); 64 g.drawLine(xCenter, yCenter, xSecond, ySecond); 65 66 // Draw minute hand 67 int minute = ( int )cal.get(GregorianCalendar.MINUTE); 68 int mLength = ( int )(clockRadius * 0.75 ); 69 int xMinute = ( int )(xCenter + mLength * Math.sin(minute * 70 ( 2 * Math.PI / 60 ))); 71 int yMinute = ( int )(yCenter “ mLength * Math.cos(minute * 72 ( 2 * Math.PI / 60 ))); 73 g.setColor(Color.blue); 74 g.drawLine(xCenter, yCenter, xMinute, yMinute); 75 76 // Draw hour hand 77 int hour = ( int )cal.get(GregorianCalendar.HOUR_OF_DAY); 78 int hLength = ( int )(clockRadius * 0.6 ); 79 int xHour = ( int )(xCenter + hLength * Math.sin((hour + minute 80 / 60.0 ) * ( 2 * Math.PI / 12 ))); 81 int yHour = ( int )(yCenter “ hLength * Math.cos((hour + minute 82 / 60.0 ) * ( 2 * Math.PI / 12 ))); 83 g.setColor(Color.green); 84 g.drawLine(xCenter, yCenter, xHour, yHour); 85 86 // Set display format in specified style, locale and timezone 87 DateFormat formatter = DateFormat.getDateTimeInstance 88 (DateFormat.MEDIUM, DateFormat.LONG); 89 90 // Display current date 91 g.setColor(Color.red); 92 String today = formatter.format(cal.getTime()); 93 FontMetrics fm = g.getFontMetrics(); 94 g.drawString(today, (width - 95 fm.stringWidth(today)) / 2 , yCenter + clockRadius + 30 ); 96 } 97 } |
Since the image is sent to the browser as binary data, the content type of the response is set to image/gif (line 18). The GifEncoder class is used to encode the image into content understood by the browser (line 31). The content is sent to the OutputStream object out .
The program creates an image with the specified width, height, and image type, using the BufferedImage class (lines 22 “23):
Image image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
To draw things on the image, you need to get its graphics context using the getGraphics method (line 26):
Graphics g = image.getGraphics();
You can use various drawing methods in the Graphics class to draw simple shapes , or you can use Java 2D to draw more sophisticated graphics. This example uses simple drawing methods to draw a clock that displays the current time.
The servlets in the preceding example return images. Often images are mixed with other contents. In this case, you have to set the content type to "image/gif" before sending images, and set the content type to "text/html" before sending the text. However, the content type cannot be changed in one request. To circumvent this restriction, you may embed a GET request for displaying the image in an <img> tag in the HTML content. When the HTML content is displayed, a separate GET request for retrieving the image is then sent to the server. Thus text and image are obtained through two separate GET requests .
To demonstrate mixing images and texts , let us create a servlet that mixes the clock image created in the preceding example with some text, as shown in Figure 34.23.
Create the servlet named MixedContent in Listing 34.14 and compile it into c:\jakarta-tomcat-5.5.9\webapps\liangweb\WEB-INF\classes . Run the servlet using the URL
http://localhost:8080/liangweb/MixedContent
1 import javax.servlet.*; 2 import javax.servlet.http.*; 3 import java.io.*; 4 5 public class MixedContent extends HttpServlet { 6 /** Process the HTTP Get request */ 7 public void doGet(HttpServletRequest request, HttpServletResponse 8 response) throws ServletException, IOException { 9 response.setContentType( "text/html" ); 10 PrintWriter out = response.getWriter(); 11 12 String country = ; request.getParameter( "country" ) 13 14 out.println( "<img src = \"/liangweb/" + 15 "ImageContentWithDrawing\" align=right >" ); 16 17 out.println( "This is a clock created using a Java program " + 18 "and sent to the browser by a servlet." ); 19 20 out.close(); 21 } 22 } |
The servlet generates an HTML file with the image tag
<img src = "/liangweb/ImageContentWithDrawing" align = "right" >
The HTML file is rendered by the browser. When the browser sees the image tag, it sends the request to the server. ImageContentWithDrawing , created in Listing 34.13, is invoked to send the image to the browser.