分享
 
 
 

一个java的web日历实现

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

相信大家都看到很多blog站点都有一些本月的日历功能,可以在上面选择有blog的那天来查看那天的作者的日志!有很多方式来实现这个日历功能,可以用javascript,也可以用web语言的支持来写,比如asp,jsp的支持。下面我们就来以www.seerlog.net这个站点(也就是我的啦)的日历模块功能的实现为例子来讲解使用java跟DHTML结合实现这个日历。

一,分析模块的组成,功能

这个日历模块主要的功能包括 显示当月的日历表,当日特殊显示,有blog的那天特殊显示并支持链接到那天的blog列表。

功能分析清楚了,我们来看看这个功能的具体设计: 首先肯定有一个 DayStatus 类,用来描述当天是否有blog,是否是查看的当天。其他的还需要一个DateUtil 类来生成 当月所有的DayStatus对象数组。另外还需要一个haveBlogDay,haveBlogMonth对象来保存拥有blog的日期。

二,预备知识

1.从jdk1.4开始 sun 提供了一个java.util.Calendar 抽象类,用来取代部分Date的功能并提供更强大的日期处理能力。我们先来看看这个类的说明(具体请查看jdk文档 API)

Calendar 是一个抽象的基类,用于在一个 Date 对象和一个诸如 YEAR 、 MONTH 、 DAY 、 HOUR 等整数字段集合之间转换。 ( Date 对象代表一个时间精度为毫秒达到特定实例。 关于 Date 类的信息请参见 java.util.Date 。)

Calendar 的子类根据一个特定的日历系统解释一个 Date 。 JDK 提供了 Calendar 的一个具体的子类: GregorianCalendar 。 将来的子类将代表世界上大部分地区使用的各种类型的阴历。

同其它国别敏感的类一样, Calendar 提供了一个类方法 getInstance ,以获得该类型的一个通用的对象。 Calendar 的 getInstance 方法返回一个 GregorianCalendar 对象,该对象的时间域由当前的日期和时间初始化: Calendar rightNow = Calendar.getInstance();

Calendar 对象能够产生为特定语言和日历风格格式化所需实现的日期_时间的所有时间域值。( 例如,日语-格里高里日历,日语-传统日历 ) 。

当从时间域中计算 Date 时,可能会出现两种情况:或者没有足够的信息计算 Date ( 例如只有年和月但没有日 ) 或者有矛盾的信息 ( 例如 "Tuesday, July 15, 1996" -- 实际上,1996 年 7 月 15 日是星期一 )。

没有足够的信息。 日历将使用缺省信息指定缺少的域。 这将根据不同日历有所不同;对于格里高里日历,域的缺省值等于开始时间: 例如,YEAR = 1970,MONTH = JANUARY,DATE = 1 等等。

矛盾的信息。 如果域值有冲突,日历将参考最近设置的域值。 例如,当确定日时,日历将参考下列域的组合之一。将使用由最近设置的单个域确定的最近的组合。 MONTH + DAY_OF_MONTH MONTH + WEEK_OF_MONTH + DAY_OF_WEEK MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK DAY_OF_YEAR DAY_OF_WEEK + WEEK_OF_YEAR 对于一天内的时间: HOUR_OF_DAY AM_PM + HOUR

注意: 对于非格里高里日历,为了保证完全没有歧义,可能会需要不同的域。 例如,关于阿拉伯宇宙日历的完整的规格说明有时需要年、月、一月中的日期 和 一周中的日期。

注意: 对于某些特别的时间的解释可能会有一定的歧义,这可以用下列方式解决:

24:00:00 “属于”下一天。即,1969 年 11 月 31 日 23:59 < 1970 年 1 月 1 日 24:00 < 1970 年 1 月 1 日 24:01:00。

尽管历史的来看不精确,午夜也属于“上午”,中午属于“下午”,所以在同一天,12:00 am ( 午夜 ) < 12:01 am,12:00 pm ( 中午 ) < 12:01 pm。

日期或时间格式字符串不是日历定义的一部分,因为在运行时,它们必须能够由用户修改或重写。使用 java.text.DateFormat 格式化日期。

Calendar 为域的“滚动”提供了一个 API,域可以被加一或减一,但是循环滚动。 例如,将日期 "September 12, 1996" 向上滚动一个月结果是 "October 12, 1996"。

Calendar 也为将指定 ( 带符号的 ) 数量的时间添加到特定的时间域中提供了一个日期计算功能。 例如,将日期 "September 12, 1996" 减 5 天得到 "September 7, 1996"。

2.java.text.DateFormat 类 (具体请查看jdk文档 API)

DateFormat 是日期/时间格式化子类的一个抽象类,这些子类以基于语言的方式格式化和分析日期或时间。 日期/时间格式化子类,如 SimpleDateFormat ,允许格式化 (即 date -> text)、分析 (text -> date) 和标准化。 日期由一个 Date 对象表示,或者用从 GMT 1970 年 1 月 1 日 0 时 0 分 0 秒起的毫秒数表示。

DateFormat 为获得基于缺省的或给定的语言环境和格式化风格的缺省的日期/时间格式化程序提供了许多类方法。格式化风格包括 FULL、LONG、MEDIUM 和 SHORT。方法说明中提供了更详细的说明以及使用这些风格的例子。

DateFormat 帮助格式化和分析任何语言环境的日期。 代码可以独立于语言环境对于月、星期的约定,甚至可以独立于日历格式:lunar 和 solar。

为了格式化当前 Locale 的日期,使用下列静态工厂方法之一: myString = DateFormat.getDateInstance().format(myDate);

如果格式化多个数值,获得格式后多次使用它会更有效率,这样系统就不必多次去取关于本地语言的国家的约定的信息。 DateFormat df = DateFormat.getDateInstance(); for(int i = 0; i < } ?); ?; + output.println(df.format(mydate[i]) { ++i)>

为了格式化一个不同 Locale 的数值,在调用 getDateInstance() 时指明。 DateFormat df = DateFormat.getDateInstance(Locale.FRANCE);

也可以用 DateFormat 来分析。 myDate = df.parse(myString);

使用 getDate 获得该国一般日期格式。也有其它可用的静态工厂方法。 使用 getTime 获得该国一般时间格式。使用 getDateTime 获得一个日期和时间格式。可以给这些工厂方法传入不同的选项控制结果的长度;从 SHORT 到 MEDIUM 到 LONG 到 FULL。确切的结果取决于语言环境,但是通常:

SHORT 完全是数字的,例如 12.13.52 或 3:30pm

MEDIUM 更长一些,例如 Jan 12, 1952

LONG 更长一些,例如 January 12, 1952 或 3:30:32pm

FULL 是全部指定的,例如 Tuesday, April 12, 1952 AD or 3:30:42pm PST。

可以将时区设置为希望的格式。如果希望进一步控制格式化或分析,( 或者希望给用户更多的控制 ),可以尝试将从工厂方法中获得的 DateFormat 变形为 SimpleDateFormat。这将适用于大多数的国家;只需把它放在 try 块中,以防遇到意外的情况。

也可以用 ParsePosition 和 FieldPosition 调用不同形式的分析和格式化的方法,这将允许:

顺次的分析字符串。

调整任何特定的域,或者当在屏幕上选择时找出他的位置。

三,让我们来动手实现这个功能吧

1.首先来实现haveBlogDay,haveBlogMonth对象,两个其实都是一个HashSet。因为我们一开始就要获取它的数据,所以在一个ServletContextListener实现类中来获取。

HashSet haveBlogDay;

HashSet haveBlogMonth;

try{

Session session = Hi.getSession();

Transaction tx= session.beginTransaction();

//haveBlogDay 初始化

String time_sql="select topic.submitTime from Topic as topic";

List timeList = session.find(time_sql);

for(int i=0;i<timeList.size();i++)

{

String tem=(String)timeList.get(i);

timeList.set(i,TextUtil.subString(tem,10));

}

haveBlogDay=new HashSet(timeList);

context.setAttribute("haveBlogDay",haveBlogDay);

Log.info("haveBlogDay 已经存入app 内");

//haveBlogMonth 初始化

for(int i=0;i<timeList.size();i++)

{

String tem=(String)timeList.get(i);

timeList.set(i,TextUtil.subString(tem,7));

}

haveBlogMonth=new HashSet(timeList);

context.setAttribute("haveBlogMonth",haveBlogMonth);

Log.info("haveBlogMonth 已经存入app 内");

上面使用了hibernate来获取数据,这里使用 HashSet 的数据不可重复性来保证日期的唯一。

2.DayStatus的编码设计

public class DayStatus{

private boolean have_blog;

private String day;

public DayStatus(int t){

if(t==0){

this.day="&nbsp;";

this.have_blog=false;

}

else{

this.day=String.valueOf(t);

this.have_blog=false;

}

}

DayStatus(){}

public String getDay(){

return this.day;

}

public String getFullDay(){

Date now=new Date();

String today="";

SimpleDateFormat df=new SimpleDateFormat("yyyy.MM.");

String nowtime=df.format(now).toString();

if(!day.equals("&nbsp;")){

if(Integer.parseInt(day)<10){today=nowtime+"0"+day;}

else{today=nowtime+day;}

}

return today;

}

public boolean haveBlog(HashSet hs){

Date now=new Date();

String today="";

SimpleDateFormat df=new SimpleDateFormat("yyyy.MM.");

String nowtime=df.format(now).toString();

if(!day.equals("&nbsp;")){

if(Integer.parseInt(day)<10){today=nowtime+"0"+day;}

else{today=nowtime+day;}

}

return hs.contains(today);

}

public boolean isToday(){

Date now=new Date();

SimpleDateFormat df=new SimpleDateFormat("dd");

String nowtime=df.format(now).toString();

if(this.day.equals(nowtime)) return true;

else return false;

}

}

3.DateUtil的编码设计

首先要定义几个类变量

private static DayStatus[][] arr=new DayStatus[6][7];

private static int month_count; //一个月的天数

然后定义方法getCalendar() :

public DayStatus[][] getCalendar(int year,int month){

Calendar ca = new GregorianCalendar(year,month,1);

int before=ca.get(Calendar.DAY_OF_WEEK); //得到月历前的空白天数

ca.roll(Calendar.MONTH,true); //滚动一个月后

int next_before=ca.get(Calendar.DAY_OF_WEEK);

int after;

if(next_before==1){after=7;}

else{after=next_before-1;} //得到当前时间

/* 获取月天数 ,考虑闰年的2月*/

if(before<=after){

int temp=after-before+1;

if(temp<7){month_count=temp+28;

}

else{month_count=28;}

}

else{

int temp=8-before+after;

if(temp<7){month_count=temp+28;

}

else{month_count=28;}

}

// System.out.println ("月天数="+month_count); // 检查月天数

// 开始赋值

int temp_day=9-before; //第二行 起始的日期数

// System.out.println ("before="+before); // test

// System.out.println ("after="+after);

//第一行的处理

for(int k=0;k<before-1;k++){

arr[0][k]=new DayStatus(0);} //为前面的几个赋值空格

for(int m=1;m<9-before;m++){

arr[0][before-2+m]=new DayStatus(m);

}

/*检查第一行 完成 无误*/

//接下来的处理

for(int i=1;i<6;i++){

for(int j=0;j<7;j++){

if(temp_day<=month_count){

arr[i][j]=new DayStatus(temp_day);

temp_day++;

}

else{arr[i][j]=new DayStatus(0);}

}

}

/*

System.out.println ("检查全部数组");

for(int t=0;t<6;t++){

for(int i=0;i<7;i++){

DayStatus d=arr[t][i];

System.out.println (d.getDay());

}

}

*/

return arr; //返回 日历数组

}

四,前台web页面的显示

<table width="100%" border="0" cellpadding="0" cellspacing="0" class="calendarBigBorder" id="caltable">

<thead>

<tr align="center" valign="middle">

<td class="calendarTd">日</td>

<td class="calendarTd">一</td>

<td class="calendarTd">二</td>

<td class="calendarTd">三</td>

<td class="calendarTd">四</td>

<td class="calendarTd">五</td>

<td class="calendarTd">六</td>

</tr>

</thead>

<TBODY border=1 cellspacing="0" cellpadding="0" ID="calendar" ALIGN=CENTER >

<%

HashSet hs=(HashSet)getServletContext().getAttribute("haveBlogDay");

DayStatus[][] thisMonth=DateUtil.getThisCalendar();

for(int i=0;i<6;i++){

out.print("<TR style='cursor:hand'>");

for(int j=0;j<7;j++){

DayStatus ds=thisMonth[i][j];

if(ds.isToday()){

%>

<TD class="calendarNow" onMouseover="this.className='calendarHover'" onMouseOut="this.className='calendarNow'">

<%=ds.getDay()%>

</td>

<%

}

else{

if(ds.haveBlog(hs)){

%>

<TD class="calendarTd" onMouseover="this.className='calendarHover'" onMouseOut="this.className='calendarTd'">

<a href="/topic.do?time=<%=ds.getFullDay()%>" class="a"><%=ds.getDay()%> </a>

</td>

<%

}else{%>

<TD class="calendarTd" onMouseover="this.className='calendarHover'" onMouseOut="this.className='calendarTd'">

<%=ds.getDay()%>

</td>

<%}}

}

out.print("</tr>");

}

%>

</tbody>

</table>

这里有一些scripts,的确很难看哦,当然你可以通过自定义标签来消除这些难看的代码,怎么样,重构一下吧!

五,总结

看了上面差不多能明白是如何来实现的吧,其实这里还可以更好的设计的,也就是有badsmell,可以重构一下。比如说可以让DayStatus这个设计成单纯的一个bean,把功能都转移出去。这样DayStatus可以作为一个VO直接用在前台界面的显示上。

好了,都看的能理解了吧,有什么问题联系我吧yujiebo025@hotmail.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有