分享
 
 
 

一个Jsp初学者的学习过程(六)

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一个Jsp初学者的学习过程(六)

TheUnforgiven

第六章 画柱状统计图

在编码学习的过程中,我发现的问题越来越多了,有Java方面的,SQL方面的,Html方面的,JavaScript方面的等等,对这些看似细小的问题的研究使我积累了实战的经验,起码不只是纸上谈兵了。

这个时候我的领导让我做一个东西,实现局域网内部网上计算机故障报修。这其实就是一个留言板的功能,我正好之前做过练习,所以很轻松的就做好了。之后我想我也许应该做一个统计——统计一年内每个月完成的报修任务量,如果用表格显示的话太简单了,不如做一个动态生成的柱状图吧,我突然有了这个想法。

马上开始动手,先是查资料,知道了Java里和画图有关的是java.awt包,由于我构想的图只是由矩形组成,那么用到的方法也就这么几个:fillRect,drawRect,setColor,setFont,drawString。我很快发现一个问题:如何在页面显示这个图,这是个大问题,于是找例子。

在一个学过研究生Java课程的同事的帮助下知道可以这样:写一个类(Picture.class),这个类只负责画图,没有任何关于如何显示的语句,然后在一个页面文件(.htm文件就行)里<body>里写上这段代码:<applet code="Picture" height="400" width="400"></applet>,运行这个文件就可以了。但是这个方法有这两个弊端:1、它是直接从服务器端下载Picture.class,在客户端生成图片,所以客户端必须装有java环境,比如j2re等;2、现在大部分浏览器都或者迫于无奈或者被强行绑架(这里我严重鄙视一下3721和一个叫“天下搜索”的)安装了阻止小窗口、ActiveX控件的插件——就连XP的SP2也集成了这个功能——而这个功能同样对<applet>有效。

放弃第一种方法后我在网上找到了第二个例子,第二个例子让我很奇怪,代码直接写在一个.jsp文件里,打开文件显示图片,一看这个图片的属性竟然就是这个.jsp文件的名。看了一阵子代码发现不是很理解,我开始看第三个例子。

第三个例子符合我的思维:写一个bean(或者说是一个类),把一个代表路径的字符串和一些数据传给它,它根据数据画图但是不返回(从这一点来说它不能叫做bean),而是生成一个如.jpg文件并按照传进来的路径名进行保存。然后显页面通过<img src="……">显示图片。我通过这种方式实现了工作,下面是这个类的代码:

----------------------------------Picture.java------------------------------------

//该bean用于画柱状统计图

package ringz.javabeans;

import java.io.*;

import java.util.*;

import com.sun.image.codec.jpeg.*;

import java.awt.image.*;

import java.awt.*;

public class PictureBean

{

BufferedImage image;

private String fileLocation;

public void setFileLocation(String fileLocation)//fileLocation是图片的路径,如:“D:\\a\\b\\c.jpg”

{

this.fileLocation=fileLocation;

}

public void createImage(String fileLocation)

{

try

{

FileOutputStream fos = new FileOutputStream(fileLocation);

BufferedOutputStream bos = new BufferedOutputStream(fos);

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);

encoder.encode(image);

bos.close();

}

catch(Exception e)

{

e.printStackTrace();

}

}

public void outGraphic(String titles,String sstr,String str[],int datas[])

{

String Title=titles;

String SStr=sstr;

int imageWidth = 400;//图片的宽度 Line

int imageHeight;//不定长

int frameFirstWidth=imageWidth-10;

int frameFirstHeight=25;

int frameSecondWidth=imageWidth-10;

int frameSecondHeight;//不定长

int frameSpace=10;//两框间隔

int columnHeight=18;//柱的粗

int columnMaxWidth=frameSecondWidth-20;//柱的最大长度,也是代表数值最大的那个柱的长度

int sp=30;//柱的间隔

int num=datas.length;//数组的长度

int Datas[]=new int[num];//得到数组的数值

String name[]=new String[num];

for (int i=0;i<num;i++)

{

Datas[i]=datas[i];

name[i]=str[i];

}

//得此数组中的最大值

int max=Datas[0];

for (int j=0;j<num;j++)

{

if(Datas[j]>max)

max=Datas[j];

}

//得到代表数值的柱的各自高度,实际数值*columnMaxHeight/max

int columnWidth[]=new int[num];//不定长,柱的长度

for (int k=0;k<num;k++)

columnWidth[k]=(Datas[k]*columnMaxWidth)/max;//取整

frameSecondHeight=(sp+columnHeight)*num+10;//+10为了留出一块底边

imageHeight=frameSecondHeight+frameFirstHeight+frameSpace+10;//多加10为了画阴影

PictureBean chartGraphics = new PictureBean();

chartGraphics.image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);

Graphics g = chartGraphics.image.getGraphics();

g.setColor(Color.white);

g.fillRect(0,0,imageWidth,imageHeight);//用白色涂整个图

Color frameFirstColor = new Color(20,50,100);

Color columnColor = new Color(153,19,19);

Color shadowColor = new Color(200,200,200);

g.setColor(shadowColor);

g.fillRect(0+7,0+7,frameFirstWidth,frameFirstHeight);//阴影在原框基础上移7

g.setColor(Color.white);

g.drawRect(0,0,frameFirstWidth,frameFirstHeight);//画第一个框

g.setColor(frameFirstColor);

g.fillRect(0+1,0+1,frameFirstWidth-1,frameFirstHeight-1);

g.setFont(new Font("仿体", 0 , 14));

g.setColor(Color.white);

g.drawString(Title,10,18);//写字

g.drawString(SStr,300,18);

int frameSecondY=1+frameFirstHeight+frameSpace;

g.setColor(shadowColor);

g.fillRect(0+7,frameSecondY+7,frameSecondWidth,frameSecondHeight);//阴影在原框基础上移7

g.setColor(Color.black);

g.drawRect(0,frameSecondY,frameSecondWidth,frameSecondHeight);//画第二个框

g.setColor(Color.yellow);

g.fillRect(0+1,frameSecondY+1,frameSecondWidth-1,frameSecondHeight-1);//填充第二个框

for(int l=0;l<num;l++)

{

g.setColor(Color.black);

int textY=frameSecondY+20+(sp+columnHeight)*l;

g.drawString(name[l]+"("+datas[l]+")",0+10,textY);//写文字

if (columnWidth[l]!=0)

{

g.setColor(columnColor);

g.drawRect(10,textY+5,columnWidth[l],columnHeight);//画柱的外框//框的上边离文字的底边为5

g.fillRect(10+2,textY+5+2,columnWidth[l]-3,columnHeight-3);//画柱

}

}

chartGraphics.createImage(fileLocation);

}

}

--------------------------------------------------------------------------------

但是接下来出现了一个让我难以忍受的事:自做聪明的浏览器缓存使得页面无法在短时间内更新图片——输入2004,显示了2004的图片,马上再输入2005,可是显示的仍然是2004的图片,但这时硬盘目录下的图片已经是2005的图片了,一般来说两次操作时间间隔大约少于3秒,则总是显示缓存里的那张图。这个问题困扰我很长时间,问了很多人试了很多方法都没有解决了。

很显然上面提到的第二个方法不存在此问题,我决定采用这种方法,所以我不得不回头研究它的代码,之后我发现这几句代码是显示图片的关键,而最下面的三句是和显示图有关的:

---------------------------------------------------------

response.setContentType("image/jpeg");

BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

Graphics2D biContext = bi.createGraphics();

……

OutputStream output = response.getOutputStream();

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);

encoder.encode(bi);

---------------------------------------------------------

我手头仅有一本电子版的《java2参考大全》,而令我苦恼的是在里边我竟然找不到BufferedImage、Graphics2D、JPEGImageEncoder这些字样;另外,上一个例子里是Graphics,它和Graphics2D有什么差别呢?这也让我很困惑。但是我终于决定要试一试,把两个例子综合一下,最终得到了下面这个worklord.jsp文件:

-----------------------------------worklord.jsp----------------------------------

<%@ include file="include.inc"%>

<%@ page contentType="text/html;charset=gb2312"%>

<%@ page import="java.io.OutputStream" %>

<%@ page import="java.util.*"%>

<%@ page import="java.awt.image.BufferedImage" %>

<%@ page import="java.awt.*" %>

<%@ page import="com.sun.image.codec.jpeg.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>工作量统计</title>

<style type="text/css">

<!--

body {

margin-left: 10%;

margin-right: 10%;

}

.style2 {font-size: 24px}

-->

</style></head>

<body>

<%

//得到当前的年

java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy");

java.util.Date currentTime_1 = new java.util.Date();//得到当前系统时间

String yearNow = formatter.format(currentTime_1);

String year=null;

try

{

year=request.getParameter("select");

}

catch(Exception e){}

if (year==null)

year=yearNow;

//String y=Integer.toString(year);

int sum=0;

String mon[]=new String[12];

mon[0]=year+"-01";

mon[1]=year+"-02";

mon[2]=year+"-03";

mon[3]=year+"-04";

mon[4]=year+"-05";

mon[5]=year+"-06";

mon[6]=year+"-07";

mon[7]=year+"-08";

mon[8]=year+"-09";

mon[9]=year+"-10";

mon[10]=year+"-11";

mon[11]=year+"-12";

int Datas[]=new int[12];

Connection con = null;

Statement stmt = null;

ResultSet rs = null;

try

{

Class.forName(CLASSFORNAME);//载入驱动程式类别

con=DriverManager.getConnection(SERVANDDB);//建立数据库连接

stmt=con.createStatement();

String sql="select count(*) from record where com_time like '"+year+"%"+"'";

rs=stmt.executeQuery(sql);

if (rs.next())

sum=rs.getInt("count(*)");

for (int i=0;i<12;i++)

{

sql="select count(*) from record where com_time like '"+mon[i]+"%"+"'";

rs=stmt.executeQuery(sql);

if (rs.next())

Datas[i]=rs.getInt("count(*)");

else

Datas[i]=0;

}

rs.close();

stmt.close();

con.close();

}

catch(Exception e)

{

out.print(e);

}

if (sum!=0)

{

String Title=year+"年度工作量统计图";

String SStr="总和:"+sum;

String name[]={"一月份","二月份","三月份","四月份","五月份","六月份","七月份","八月份","九月份","十月份","十一月份","十二月份"};

int num=Datas.length;//数组的长度

//得此数组中的最大值

int max=Datas[0];

for (int j=0;j<num;j++)

{

if(Datas[j]>max)

max=Datas[j];

}

int imageWidth = 400;//图片的宽度 Line

int imageHeight;//不定长

int frameFirstWidth=imageWidth-10;

int frameFirstHeight=25;

int frameSecondWidth=imageWidth-10;

int frameSecondHeight;//不定长

int frameSpace=10;//两框间隔

int columnHeight=18;//柱的粗

int columnMaxWidth=frameSecondWidth-20;//柱的最大长度,也是代表数值最大的那个柱的长度

int sp=30;//柱的间隔

//得到代表数值的柱的各自高度,实际数值*columnMaxHeight/max

int columnWidth[]=new int[num];//不定长,柱的长度

for (int k=0;k<num;k++)

columnWidth[k]=(Datas[k]*columnMaxWidth)/max;//取整

frameSecondHeight=(sp+columnHeight)*num+10;//+10为了留出一块底边

imageHeight=frameSecondHeight+frameFirstHeight+frameSpace+10;//多加10为了画阴影

//开始画图

response.setContentType("image/jpeg");

BufferedImage image = new BufferedImage(imageWidth,imageHeight,BufferedImage.TYPE_INT_RGB);

Graphics g = image.createGraphics();

g.setColor(Color.white);

g.fillRect(0,0,imageWidth,imageHeight);//用白色涂整个图

Color frameFirstColor = new Color(20,50,100);

Color columnColor = new Color(153,19,19);

Color shadowColor = new Color(200,200,200);

g.setColor(shadowColor);

g.fillRect(0+7,0+7,frameFirstWidth,frameFirstHeight);//阴影在原框基础上移7

g.setColor(Color.white);

g.drawRect(0,0,frameFirstWidth,frameFirstHeight);//画第一个框

g.setColor(frameFirstColor);

g.fillRect(0+1,0+1,frameFirstWidth-1,frameFirstHeight-1);

g.setFont(new Font("仿体", 0 , 14));

g.setColor(Color.white);

g.drawString(Title,10,18);//写字

g.drawString(SStr,300,18);

int frameSecondY=1+frameFirstHeight+frameSpace;

g.setColor(shadowColor);

g.fillRect(0+7,frameSecondY+7,frameSecondWidth,frameSecondHeight);//阴影在原框基础上移7

g.setColor(Color.black);

g.drawRect(0,frameSecondY,frameSecondWidth,frameSecondHeight);//画第二个框

g.setColor(Color.yellow);

g.fillRect(0+1,frameSecondY+1,frameSecondWidth-1,frameSecondHeight-1);//填充第二个框

for(int l=0;l<num;l++)

{

g.setColor(Color.black);

int textY=frameSecondY+20+(sp+columnHeight)*l;

g.drawString(name[l]+"("+Datas[l]+")",0+10,textY);//写文字

if (columnWidth[l]!=0)

{

g.setColor(columnColor);

g.drawRect(10,textY+5,columnWidth[l],columnHeight);//画柱的外框//框的上边离文字的底边为5

g.fillRect(10+2,textY+5+2,columnWidth[l]-3,columnHeight-3);//画柱

}

}

try

{

//输出图

OutputStream output = response.getOutputStream();

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);

encoder.encode(image);

output.close();

}

catch(Exception e)

{

e.printStackTrace();

}

}//if

else

{%>

<table width="100%">

<tr>

<td width="407">

<span class="style2"><font color="#FF0000">没有<%=year%>年的记录!</font></span>

</td>

</tr>

</table>

<%

}

%>

</body>

</html>

----------------------------------------------------------------------------------

现在任务是完成了,其中的最关键的部分代码是实现什么功能的也大概知道了,可是还是没有掌握其中的知识,不能不说是遗憾。

另外,worklord.jsp这样的页面很特殊,就是因为这部分代码引起的:

OutputStream output = response.getOutputStream();

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);

encoder.encode(image);

这导致了这个页面没法再干别的了,也就是说,假如你要在<body>里干点别的,像写几个字,放一个<form>什么的,页面显示不出来。

本章最后,感谢那两个例子的作者,而且图的风格都是抄袭第二个例子那位仁兄的:),但是没有记住你们的名字很遗憾。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有