怎么样处理异常?

  处理异常有两种基本的方式:在程序内部捕获它并处理

    try{}

   catch(){}

   或者:在方法的异常规范中声明,告诉上一层的程序,本代码会掷出异常,请处理

  throws Exception{}

   但是,怎么样选择这两种方法呢?

  我看了一下thinking in java 3rd

  里面有一段关于处理方法的选择的话附于后:

  我觉得可以理解下面一些原则:

  1、目的:把处理异常的部分和功能部分分开,使系统易于理解和维护;

  2、原则:你如果不知道怎么处理一个异常就不要捕获它(而把它交给上级处理);

  3、但是具体的处理方式仍是灵活多变的,In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them.

所以,我现在只有在利用原则2的情况下使代码尽可能的简单。

  4、最后那段话不大明白,好像是说从原来C风格的异常处理转过来的人会感到有很大的利益的改变,但是作者感到当它使用起来不大方便的时候又有点迷惑了。最后写了一句什么:“所以的模型都是错的,一些是有用的”。是什么意思?世上没有十全十美的方法吗?

Alternative approaches

An exception-handling system is a trap door that allows your program to abandon execution of the normal sequence of statements. The trap door is used when an “exceptional condition” occurs, such that normal execution is no longer possible or desirable. Exceptions represent conditions that the current method is unable to handle. The reason exception handling systems were developed is because the approach of dealing with each possible error condition produced by each function call was too onerous, and programmers simply weren’t doing it. As a result, they were ignoring the errors. It’s worth observing that the issue of programmer convenience in handling errors was a prime motivation for exceptions in the first place. Feedback

One of the important guidelines in exception handling is “don’t catch an exception unless you know what to do with it.” In fact, one of the important goals of exception handling is to move the error-handling code away from the point where the errors occur. This allows you to focus on what you want to accomplish in one section of your code, and how you’re going to deal with problems in a distinct separate section of your code. As a result, your mainline code is not cluttered with error-handling logic, and it’s much easier to understand and maintain. Feedback

Checked exceptions complicate this scenario a bit, because they force you to add catch clauses in places where you may not be ready to handle an error. This results in the “harmful if swallowed” problem:

try {

  // ... to do something useful

} catch(ObligatoryException e) {} // Gulp!

Programmers (myself included, in the first edition of this book) would just do the simplest thing, and swallow the exception—often unintentionally, but once you do it, the compiler has been satisfied, so unless you remember to revisit and correct the code, the exception will be lost. The exception happens, but it vanishes completely when swallowed. Because the compiler forces you to write code right away to handle the exception, this seems like the easiest solution even though it’s probably the worst thing you can do. Feedback

Horrified upon realizing that I had done this, in the second edition I “fixed” the problem by printing the stack trace inside the handler (as is still seen—appropriately—in a number of examples in this chapter). While this is useful to trace the behavior of exceptions, it still indicates that you don’t really know what to do with the exception at that point in your code. In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them. Feedback

This topic seems simple. But it is not only complicated, it is also an issue of some volatility. There are people who are staunchly rooted on either side of the fence and who feel that the correct answer (theirs) is blatantly obvious. I believe the reason for one of these positions is the distinct benefit seen in going from a poorly-typed language like pre-ANSI C to a strong, statically-typed language (that is, checked at compile-time) like C++ or Java. When you make that transition (as I did), the benefits are so dramatic that it can seem like strong static type checking is always the best answer to most problems. My hope is to relate a little bit of my own evolution, that has brought the absolute value of strong static type checking into question; clearly, it’s very helpful much of the time, but there’s a fuzzy line we cross when it begins to get in the way and become a hindrance (one of my favorite quotes is: “All models are wrong. Some are useful.”). Feedback

(转)[提问] 这样的需求测试用例该怎么设计?(junit答案)

转自:http://www.cntesting.com/bbs/read.php?tid=623&fpage=1

[提问] 这样的需求测试用例该怎么设计?

心力背单词 [traffic /'træfik/ n. 交通(量) ]

到某论坛上逛了一圈,看到了这个提问正好是我的本行,所以特别拿出来秀以下,如果这个朋友到了我们这里可以直接问我。

原贴:

本地写卡功能:

界面:

号码、产品、副号、空SIM卡

号码和空卡为可输入框

1、号码不能是一卡双号的副号,可以是:全球通普通号码,全球通一卡双号主号(若有副号,直接把副号赋给副号输入框处)、神州行、动感地带

2、号码状态必须是正使用状态

3、SIM卡状态是可用状态

4、动感地带号码只能用“28动感地带空白SIM卡”,神州行只能用“29 神州行空白SIM卡”,全球通用“26全球通空白SIM卡”和“27 一卡双号空白SIM卡”;如果输入该号码有副号则只允许写“27 一卡双号空白SIM卡”;

符合1、2、3、4 写卡成功

若号码状态不对, 提示请用正使用的号码

若卡状态不对,提示请用可用状态的卡

若不符合1,提示副号不能写卡

若不符合4,提示卡类型不正确

 

 

测试是非常古老的传统行业,据说地球起源来自于一场非常糟糕的实验。根据我最新考证,上帝创造的亚当夏娃就没有经过很好的测试,不然怎么会因为一个APPLE_BUG就导致了整个世界的崩溃?! 

[楼 主] | Posted:2005-11-03 22:53|  

 

 

smile_xunn

 

 

级别: 测试新手

精华: 0

发帖: 2

测试威望: 2 点

测试币: 6 CSB

测试贡献值: 0 点

在线时间:5(小时)

注册时间:2005-11-08

最后登陆:2005-12-12       

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

心力背单词 [sail /seil/ n. 帆,航行;vi. 航行,启航,翱游,飘;vt. 航行,飘过 ]

准备一些定义,如下:

全球通普通号码 commonCode

全球通一卡双号主号 doubleCode

神州行 allGo

动感地带 dyArea

号码状态 codeState

SIM卡状态 simState

28动感地带空白SIM卡 dyArea28

29 神州行空白SIM卡 allGo29

26 全球通空白SIM卡 doubleCode26

27 一卡双号空白SIM卡(无副号) doubleCode27

27 一卡双号空白SIM卡(有副号) doubleCode27Fu

测试java伪代码如下:

/**

* 定义一个Product Bean,由它来定义卡的类型,如下:

* 28动感地带空白SIM卡 dyArea28

* 29 神州行空白SIM卡 allGo29

* 26 全球通空白SIM卡 doubleCode26

* 27 一卡双号空白SIM卡(无副号) doubleCode27

* 27 一卡双号空白SIM卡(有副号) doubleCode27Fu

*/

public class Product{

  private String _productId = "commonCode";//产品编码,默认为全球通编码

  private String _productName = "全球通普通号码";//产品名称,默认为全球通描述

  public Product(String productId,String productName){

        this._productId = productId;

        this._productName = productName;

  }

  public Product(){

  }

 

}

/**

* 定义一个Card JavaBean.

*/

public class Card{

  private String _startCode = null;//号码

  private Product _product = null;//产品

  private String _endCode = null;//副号

  private boolean _isState = false;//卡状态

  public Card(String startCode ,Product product,String endCode,boolean isState ){

      this._startCode = startCode;

      this._product = product;

      this._endCode = endCode;

      this._isState = isState;

  }

  public void setStartCode(String startCode){

      this._startCode = startCode;

  }

  public String getStartCode(){

      return _startCode ;

  }

 

  public void setEndCode(String endCode){

      this._endCode = endCode;

  }

  public String getEndCode(){

      return _endCode;

  }

  public void setProduct(Product product){

    this. _product = product;

  }

  public Product getProduct(){

    return _product;

  }

  public void setIsState(boolean isState){

    this._isState = isState;

  }

  public boolean getIsState(){

    return _isState;

  }

  /* *

  * 对_startCode,_endCode进行代码检查,

  */

  public boolean isRightCode(){

    return false;//没有作代码实现,返回值为false;

  }

  /**

  * 得到代码范围,通过判断主号和辅号,判断该号码属于哪种卡,如“28动感地带    

  * 空白SIM卡”

  */

  pubic String getCodeType(){

    //未作实现代码返回值为空

    return null;

  }

}

/**

* 使用继承junit TestCase 的 CardTest类进行测试

*/

public Class CardTest extends TestCase{

  public void testWriteCard(Card card){

    //如果号码状态不对,提示请用正使用的号码

    assertTrue(card.getIsState(),"请用正使用的号码");

    //若卡状态不对,提示请用可用状态的卡

    assertTrue(card.isRightCode(),"请用可用状态的卡");

    // 如果输入该号码有副号则只允许写“27 一卡双号空白SIM卡”;

    if(card.getEndCode()!=null &&!card.getEndCode().trim().equals("")){

    card.getCodeType().equals("27 一卡双号空白SIM卡");

    }

    //1、号码不能是一卡双号的副号,可以是:全球通普通号码,全球通一卡双号主号     //(若有副号,直接把副号赋给副号输入框处)、神州行、动感地带

    String productName = card.getProduct().getProductName().;

   

    if(productName .equals("全球通普通号码")){

        //全球通用“26全球通空白SIM卡”和“27 一卡双号空白SIM卡”        

      if(!(card.getCodeType().equals("26全球通空白SIM卡")||

        card.getCodeType().equals("27 一卡双号空白SIM卡"))){

            assetFalse(true,"卡类型不正确");

      }

    } else if(productName.equals("全球通一卡双号主号")){

        //ok;

    }else if(prodcutName.equals("神州行")){

        //神州行只能用“29 神州行空SIM卡”          

        if(!card.getCodeType().equals("29 神州行空白SIM卡")){

            assetFalse(true,"卡类型不正确");

        }

    }else if(prodcutName.equals("动感地带")){

        //动感地带号码只能用“28动感地带空白SIM卡”

      if(!card.getCodeType().equals("28动感地带空白SIM卡")){

            assetFalse(true,"卡类型不正确");

      }

             

    }else{

        assertTrue(false,"副号不能写卡");

    }

    asserTrue(true,"写卡成功");

   

}

 

 

[转帖] 利用StrutsTestCase测试Struts应用程序

转自:http://www.cntesting.com/bbs/read.php?tid=1239

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

[转帖] 利用StrutsTestCase测试Struts应用程序

心力背单词 [partly /'pa:tli/ ad. 部分地,在一定程度上 ]

作者:叶枫(http://blog.matrix.org.cn/page/叶枫)

关键字:Struts StrutsTestCase

一、Struts测试概述

 

  一个具有良好系统架构的J2EE应用程序至少有三层组成,即表现层,商业层和系统

集成层(包括数据存取以及和其他系统集成),目前,Struts是应用比较广泛,实现MVC2模式应用于表现层的一种技术. 在这里面,Struts Action主要用来完成一些简单的数据校验,转换,以及流程转发控制(注意:这里流程不是业务规则). 因此在对整个应用程序进行测试时,我们同时也要测试Struts Action.

  但是,测试Struts Action相对测试简单的JavaBean是比较困难,因为Struts是运行在Web服务器中, 因此要测试Struts Action就必须发布应用程序然后才能测试. 我们想象一下,对于一个拥有上千个JSP page和数百甚至数千Java Classes的大规模应用程序,要把他们发布到诸如Weblogic之类的应用服务器再测试,需要多少的时间和硬件资源? 所以这种模式的测试是非常费时费力的.

  所以,如果有一种办法能够不用发布应用程序,不需要Web服务器就能象测试普通Java Class一样测试Struts Action,那就能极大地加强Struts的可测试性能,使应用程序测试更为容易,简单快速. 现在这个工具来了,这就是StrutsTestCase.

二、StrutsTestCase 概述

  StrutsTestCase 是一个功能强大且容易使用的Struts Action开源测试工具,

它本身就是在大名鼎鼎的JUnit基础上发展起来的。因此通过和JUnit结合

使用能极大加强应用程序的测试并加快应用程序的开发.

 

  StrutsTestCase提供了两者测试方式,模仿方式和容器测试方式. 所谓模仿方式就是有StrutsTestCase本身来模拟Web服务器. 而容器测试方式则需要Web服务器. 本文要讨论的是前者,原因很简单,不需要Web服务器就能象测试普通的Java Class一样测试Struts Action.

三、准备StrutsTestCase和Struts Action/ActionForm/Config

  StrutsTestCase是一个开源工具,可以到http://strutstestcase.sourceforge.net下载. 目前最新版本是2.1.3,

如果你使用Servlet2.3就下载StrutsTestCase213-2.3.jar,使用Servlet2.4的就下载StrutsTestCase213-2.4.jar.

另外StrutsTestCase本身就是从JUnit继承的,所以你还需要下载JUnit3.8.1.

  在本文中,我们用一个简单的例子来做测试. 假设我们有一张表Hotline(country varchar2(50),pno varchar2(50)),

我们要做的是根据输入条件从这张表检索相应的记录.检索条件是country.

Value Object: 

package sample;            public class HotlineDTO implements Serializable{        private String country = "";       private String pno = "";                /**         * Method HotlineActionForm         *         *         */        public HotlineDTO () {             super();      }                public void setCountry(String country) {                this.country = country;         }        public void setPno(String pno) {                this.pno = pno;         }        public String getCountry() {                return (this.country);         }        public String getPno() {                return (this.pno);         }              }

ActionForm:

     

package sample;      import org.apache.struts.action.ActionForm;      public class HotlineActionForm extends ActionForm{        private String country = "";        private String pno = "";                /**         * Method HotlineActionForm         *         *         */        public HotlineActionForm() {                super();        }                public void setCountry(String country) {                this.country = country;         }        public void setPno(String pno) {                this.pno = pno;         }        public String getCountry() {                return (this.country);         }        public String getPno() {                return (this.pno);         }              } 

Action Class:

     public class SearchHotlineAction extends Action {     public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,      HttpServletResponse response) throws Exception {        String target = "";        try{         //调用HotlineDAO检索hotline         String country=((HotlineActionForm)form).getCountry();         List hotlineList = HotlineDAO.getHotlineList(country);         if(hotlineList!=null && hotlineList.size()>0){            request.setAttribute("hotlineList",hotlineList);            target = "hotlineList";         }else{            target = "notfound";         }        }catch(Exception ex){           ....        }                             }

Struts Config:

 

<struts-config>      <form-beans>     <form-bean name="hotlineActionForm" type="sample.HotlineActionForm" />       .......   </form-beans>  <action-mappings>     <action path="/SearchHotline"           name="hotlineActionForm"           type="sample.SearchHotlineAction "                     scope="request"                                                      validate="false">       <forward name="hotlineList" path="/hotlineList.jsp"/>              <forward name="notfound" path="/searchHotline.jsp"/>   </action>    .....  <action-mappings>   ........ <struts-config>

四、初试StrutsTestCase

    当采用模拟方式时,所有的StrutsTestCase测试Class都是从MockStrutsTestCase继承下来的.

    下面我们就创建一个最简单的测试Class.

   

public class SearchHotlineAction extends MockStrutsTestCase {     public void setUp()throws Exception{     }     public void tearDown()throws Exception{     }    public void testSearchHotline() throws Exception{    setRequestPathInfo("/SearchHotline.do");    addRequestParameter("country", "CN");    actionPerform();    }    }

   上面的Class相信用过JUnit的朋友都很熟悉.

    好了,一个简单的测试例子就完成了,如果你用的是Eclipse就选择Run-Run...-JUnit-New就可以直接运行.不需要发布你的程序,不需要任何的Web服务器支持,就可以测试Struts Action,这就是StrutsTestCase带来的好处.下面简单地介绍一下它是怎么工作的.

    在上面的例子中,我们调用setRequestPathInfo()告诉StrutsTestCase我们要模拟JSP调用SearchHotline.do这个Action,并且调用addRequestParameter()增加了一个参数country.最后调用actionPerform()运行.

看到这里,大家发现一个问题没有? 在上面Action的源代码里我们是通过

String country=((HotlineActionForm)form).getCountry();

也就是ActionForm来取得输入的参数值,可我们在testSearchHotline()方法里并没有设置ActionForm?

那么它是怎么出来的呢? 其实大家如果熟悉Struts的运行流程的话就知道,JSP接受用户的输入并发请求时

都是类似这样的http://hostname/servletName?param1=value1¶m2=value2. 只是Struts接受到这些

参数后再根据Struts Config里的Action和ActionForm的映射把他们转为ActionForm后传给Action的.

   在上面的例子,我们只是简单地运行了Action,那么Action是否正确执行以及返回的结果是不是我们想要的呢?

我们继续完善一下testSearchHotline()这个Method.

public void testSearchHotline() throws Exception{

    setRequestPathInfo("/SearchHotline.do");

    addRequestParameter("country", "CN");

    actionPerform();

    verifyNoActionErrors();

    verifyForward("hotlineList");

    assertNotNull(request.getAttribute("hotlineList"));

    List hotlineList = (List) request.getAttribute("hotlineList");

    for (Iterator it = hotlineList.iterator();it.hasNext();){

     ....

    }

    }

我们在actionPerform()后增加了几行语句来断定Struts Action是否正确执行.

   verifyNoActionErrors() -- 判断Action里没有任何的Action;

   verifyForward("hotlineList") -- 判断Action确实转发到hotlineList;     

   assertNotNull(request.getAttribute("hotlineList")) -- 判断Action确实返回了hotlineList并且不为空

到这里,我们已经基本上讨论完了StrutsTestCase的核心部分. 从头到尾,我们没有发布应用程序,也不需要Web服务器,对我们来讲,Struts Action就象普通的Java Class一样容易调试测试.这就是StrutsTestCase给我们带来的方便.

五、深入StrutsTestCase

  除了以上我们用到的几个断定和校验方法外,StrutsTestCase还提供了其他几个方法便于我们测试Struts Action. 下面我一一讲述,具体的大家可以参考文档.

verifyActionErrors/Messages --  校验ActionActionServlet controller 是否发送了ActionError或ActionMessage.   参数为ActionError/Message Key

verifyNoActionErrors/Messages --校验ActionActionServlet controller 没有发送ActionError或ActionMessage

VerifyForward -- 校验Action是否正确转发到指定的ActionForward.

VerifyForwardPath -- 校验Action是否正确转发到指定的URL

verifyInputForward -- 校验Action是否转发到Action Mapping里的input属性

verifyTilesForward/verifyInputTilesForward--和以上类似,应用程序使用到tiles时用的

六、关于Web.xml和Struts-Config.xml

  缺省情况下,StrutsTestCase认为你的Web.xml和struts-config.xml的路径分别是:

  /WEB-INF/web.xml和/WEB-INF/struts-config.xml

  1. 假如你的web.xml/struts-config.xml的路径是

  d:/app/web/WEB-INF/web.xml(struts-config.xml)的话,就需要把d:/app/web加到classpath.

 

  2. 假如你的struts config是strust-config-module.xml,

  那么必须调用setConfigFile()设置你的struts config文件

 

七、结束语

  J2EE应用程序的测试在开发过程中占有相当重要的位置,利用StrutsTestCase能极大方便你测试基于Struts的应用程序.

关于作者:

叶枫:热爱Java和Oracle. 在软件开发有近10年, 目前在国外一家美国大公司担任SA, 负责技术研究。

ant building 报找不到com.sun.tools.javac.Main

今天,在eclipse2.1中用run ant运行ppig写的ant脚本编译学习日记文档时,发现通不过,报找不到com.sun.tools.javac.main;但不在eclipse2.1环境中在dos命令行窗口中执行能通过。最后,在windows->preferences->ant->Runtime->Classpath->Add Jars中,添加了jdk下面的\lib\tools.jar后,编译通过。原来com.sun.tools.javac.Main在这个tools.jar中。

(转帖)如何在Web工程中实现任务计划调度

转自:http://www.javaresearch.org/article/showarticle.jsp?column=2&thread=12337

 首页 » 研究文集 » J2EE综合   搜索标题相关文章      发表评论     开始监控     加入收藏夹 

如何在Web工程中实现任务计划调度

nbDeveloper 原创  (参与分:4690,专家分:120)   发表:2004-02-23 22:53   更新:2004-02-26 08:19   版本:1.0   阅读:4263次 

 

    好多朋友用过Windows的任务计划,也有不少程序迷自己曾写过时钟报警、系统自动关机等趣味程序,可却很少有朋友在Web工程中实现过类似功能。今天有空把笔者先前曾在Tomcat上实现的类似功能,搬出来与大家共享。

    早在几年前,我公司跟某市财政局合作项目开发,为加强财政局对所属单位财务状况的有效监管,开发、实施了财政局数据中心项目。此项目采用B/S加C/S混合结构模式。财政局Web服务器上架设数据同步接收装置,由市属单位每天下班前把财务信息通过HTTP协议上传至财政局中心服务器,与Web服务器上的接收装置对接。财政局内部各部门需要查阅大量财务信息,获取完备的市属单位当前财务状况信息,各部门按职能划分,需要准确的获取各部门各自所关注的汇总信息,以财政报表的形式提供。

    因财政数据量大,实时计算财政报表速度较慢,当初就考虑用报表缓存来减轻服务器的负担,但用缓存需要一个合理的缓存更新机制。考虑到各市属单位每天下班前才把财务数据上传,财政局每天所查看到的财务信息其实并不包括当天(除非有某位领导等到所属单位全部上传完之后才来查看信息,应该已经下班了),所以要是能实现任务计划调度,在每晚深夜把当天及历史财务信息汇总,更新缓存,速度瓶颈不就解决了吗。

    当时由于系统核心是基于Web部署的,报表计算引擎也相应的部署在Tomcat容器上,因此如果想要借用Windows的任务计划来实现定时计算,就需要额外编写普通桌面应用程序接口,稍显复杂。于是就琢磨着想在Web上实现,经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

    下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

    我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):

    private java.util.Timer timer = null;

    public void contextInitialized(ServletContextEvent event) {

        timer = new java.util.Timer(true);

        event.getServletContext().log("定时器已启动");        

         timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);

        event.getServletContext().log("已经添加任务调度表");

    }

    public void contextDestroyed(ServletContextEvent event) {

        timer.cancel();

        event.getServletContext().log("定时器销毁");

    }

    以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

   下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:

    private static final int C_SCHEDULE_HOUR   = 0;

    private static boolean isRunning = false;

         private ServletContext context = null;

    public MyTask(ServletContext context) {

        this.context = context;

    }

    public void run() {

        Calendar cal = Calendar.getInstance();        

        if (!isRunning)  {           

            if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {            

                    isRunning = true;                

                context.log("开始执行指定任务");

                

                //TODO 添加自定义的详细任务,以下只是示例

                int i = 0;

                while (i++ < 10) {

                    context.log("已完成任务的" + i + "/" + 10);

                }

                isRunning = false;

                context.log("指定任务执行结束");               

            }            

        } else {

            context.log("上一次任务执行还未结束");

        }

    }

    上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:

    <listener>

        <listener-class>com.test.ContextListener</listener-class>

    </listener>

    当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

2003-12-05 0:21:39 开始执行指定任务

2003-12-05 0:21:39 已完成任务的1/10

    ……

2003-12-05 0:21:39 已完成任务的10/10

2003-12-05 0:21:39 指定任务执行结束

    以上代码在Tomcat 4.1.29以及Tomcat 5.0.16上调试通过。如果您需要完整代码,请通过nbDeveloper@hotmail.com与我联系。

 

 

 

(转帖)servlet 相关的Listener应用(内含web程序的定时器)

转自:http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/07/2268.aspx

servlet 相关的Listener应用

ZhangLiHai.Com Blog

servlet 相关的Listener应用

 

张利海 于 2004年11月22日 23:27 发表 

关键词 : servlet listener timer 定时器

从作用域范围来说,Servlet的作用域有ServletContext,HttpSession,ServletRequest.

Context范围:

   

ServletContextListener:

对一个应用进行全局监听.随应用启动而启动,随应用消失而消失主要有两个方法:

contextDestroyed(ServletContextEvent event)

 在应用关闭的时候调用

contextInitialized(ServletContextEvent event)

在应用启动的时候调用

这个监听器主要用于一些随着应用启动而要完成的工作,也就是很多人说的我想在容器

启动的时候干..........

一般来说对"全局变量"初始化,如

public void contextInitialized(ServletContextEvent event){

    ServletContex sc = event.getServletContext();

    sc.setAttribute(name,value);

}

以后你就可以在任何servlet中getServletContext().getAttribute(name);

我最喜欢用它来做守护性工作,就是在contextInitialized(ServletContextEvent event)

方法中实现一个Timer,然后就让应用在每次启动的时候让这个Timer工作:

public void contextInitialized(ServletContextEvent event){

    timer = new Timer();

    timer.schedule(new TimerTask(){

        public void run(){

            //do any things

        }

    },0,时间间隔);

}

    有人说Timer只能规定从现在开始的多长时间后,每隔多久做一次事或在什么时间做

一次事,那我想在每月1号或每天12点做一项工作如何做呢?

你只要设一个间隔,然后每次判断一下当时是不是那个时间段就行了啊,比如每月一号做,那你

时间间隔设为天,即24小时一个循环,然后在run方法中判断当时日期new Date().getDate()==1

就行了啊.如果是每天的12点,那你时间间隔设为小时,然后在run中判断new Date().getHour()

==12,再做某事就行了.

ServletContextAttributeListener:

这个监听器主要监听ServletContex对象在setAttribute()和removeAttribute()的事件,注意

也就是一个"全局变量"在被Add(第一次set),replace(对已有的变量重新赋值)和remove的时候.

分别调用下面三个方法:

public void attributeAdded(ServletContextAttributeEvent scab)这个方法不仅可以知道

哪些全局变量被加进来,而且可获取容器在启动时自动设置了哪些context变量:

public void attributeAdded(ServletContextAttributeEvent scab){

    System.out.println(scab.getName());

}

  public void attributeRemoved(ServletContextAttributeEvent scab)

  public void attributeReplaced(ServletContextAttributeEvent scab)

 

 

Session范围:

HttpSessionListener:

这个监听器主要监听一个Session对象被生成和销毁时发生的事件.对应有两个方法:

  public void sessionCreated(HttpSessionEvent se)

  public void sessionDestroyed(HttpSessionEvent se)

  一般来说,一个session对象被create时,可以说明有一个新客端进入.可以用来粗略统计在线人

数,注意这不是精确的,因为这个客户端可能立即就关闭了,但sessionDestroyed方法却会按一定

的策略很久以后才会发生.

HttpSessionAttributeListener:

和ServletContextAttributeListener一样,它监听一个session对象的Attribut被Add(一个特定

名称的Attribute每一次被设置),replace(已有名称的Attribute的值被重设)和remove时的事件.

对就的有三个方法.

  public void attributeAdded(HttpSessionBindingEvent se)

  public void attributeRemoved(HttpSessionBindingEvent se)

  public void attributeReplaced(HttpSessionBindingEvent se)

  上面的几个监听器的方法,都是在监听应用逻辑中servlet逻辑中发生了什么事,一般的来说.

我们只要完成逻辑功能,比如session.setAttribute("aaa","111");我只要把一个名为aaa的变量

放在session中以便以后我能获取它,我并不关心当session.setAttribute("aaa","111");发生时

我还要干什么.(当然有些时候要利用的),但对于下面这个监听器,你应该好好发解一下:

HttpSessionBindingListener:

上面的监听器都是作为一个独立的Listener在容器中控制事件的.而HttpSessionBindingListener

对在一对象中监听该对象的状态,实现了该接口的对象如果被作为value被add到一个session中或从

session中remove,它就会知道自己已经作为一个session对象或已经从session删除,这对于一些非

纯JAVA对象,生命周期长于session的对象,以及其它需要释放资源或改变状态的对象非常重要.

比如:

session.setAttribute("abcd","1111");

以后session.removeAttribute("abcd");因为abcd是一个字符中,你从session中remove后,它就会

自动被垃圾回收器回收,而如果是一个connection:(只是举例,你千万不要加connection往session

中加入)

session.setAttribute("abcd",conn);

以后session.removeAttribute("abcd");这时这个conn被从session中remove了,你已经无法获取它

的句柄,所以你根本没法关闭它.而在没有remove之前你根本不知道什么时候要被remove,你又无法

close(),那么这个connection对象就死了.另外还有一些对象可以在被加入一个session时要锁定

还要被remove时要解锁,应因你在程序中无法判断什么时候被remove(),add还好操作,我可以先加锁

再add,但remove就后你就找不到它的句柄了,根本没法解锁,所以这些操作只能在对象自身中实现.

也就是在对象被add时或remove时通知对象自己回调相应的方法:

MyConn extends Connection implements HttpSessionBindingListener{

  public void valueBound(HttpSessionBindingEvent se){

    this.initXXX();

  }

  public void valueUnbound(HttpSessionBindingEvent se){

    this.close();

  }

}

session.setAttribute("aaa",new MyConn());

这时如果调用session.removeAttribute("aaa"),则触发valueUnbound方法,就会自动关闭自己.

而其它的需要改变状态的对象了是一样.

另外还有一个HttpSessionActivationListener监听器是实现分布式应用中session同步的.不作

多介绍,如果有要实现该功能的朋友可以和我联系.

在servlet2.4中,对于request范围已经实现对应的监听器:

ServletRequestListener,ServletRequestAttributeListener

但没有找到好的容器的支持所以没有做过多的测试.虽然从API可以掌握99%,但没有经过真正的

测试我是不会仅把API抄出来的.以后我会补齐这方面的内容

原作者:Axman

 

 

(转帖)一个实现MD5的简洁的java类

来自:http://www.javaresearch.org/article/showarticle.jsp?column=33&thread=10461

×××××××××××××××××××××××××××××××××××××××××××××××××××××

                         正文

一个实现MD5的简洁的java类

Jagie 原创  (参与分:100322,专家分:3090)   发表:2003-11-18 17:14   更新:2003-11-19 08:34   版本:1.0   阅读:6307次 

 

关键词:md5

由于消息摘要唯一性和不可逆性的特点,所以不失为一种简单的常用的加密手段,比如你可以用md5来加密你的应用中的用户口令。

package test;

import java.security.MessageDigest;

/**

 * <p>Title: </p>

 * <p>Description: </p>

 * <p>Copyright: Copyright (c) 2003</p>

 * <p>Company: </p>

 * @author unascribed

 * @version 1.0

 */

public class StringUtil {

  private final static String[] hexDigits = {

      "0", "1", "2", "3", "4", "5", "6", "7",

      "8", "9", "a", "b", "c", "d", "e", "f"};

  /**

   * 转换字节数组为16进制字串

   * @param b 字节数组

   * @return 16进制字串

   */

  public static String byteArrayToHexString(byte[] b) {

    StringBuffer resultSb = new StringBuffer();

    for (int i = 0; i < b.length; i++) {

      resultSb.append(byteToHexString(b[i]));

    }

    return resultSb.toString();

  }

  private static String byteToHexString(byte b) {

    int n = b;

    if (n < 0)

      n = 256 + n;

    int d1 = n / 16;

    int d2 = n % 16;

    return hexDigits[d1] + hexDigits[d2];

  }

  public static String MD5Encode(String origin) {

    String resultString = null;

    try {

      resultString=new String(origin);

      MessageDigest md = MessageDigest.getInstance("MD5");

      resultString=byteArrayToHexString(md.digest(resultString.getBytes()));

    }

    catch (Exception ex) {

    }

    return resultString;

  }

  public static void main(String[] args){

    System.err.println(MD5Encode("a"));

  }

}

在RFC 1321中,给出了Test suite用来检验你的实现是否正确:

MD5 ("") = d41d8cd98f00b204e9800998ecf8427e

MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661

MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72

MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0

MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b

参考资料:《java security handbook》 jamie jaworski

版权声明   给作者写信  本篇文章对您是否有帮助?  投票: 是    否     投票结果:     24       1

 

 

 

作者其它文章:

在MIDP2.0中操作图片像素

用MMAPI拍照

如何在Swing中实现文件路径选择的TableCellEditor

MIDP中一个简单的折行文本绘制办法

在MIDP1.0下实现图片翻转

作者全部文章 

 

 

  评论人:yipsilon    参与分: 15609    专家分: 290    来自: Dalian

 发表时间: 2003-11-20 19:29 

使用这种方式的前提是必需有JCE支持。如果在J2SDK 1.3中,则必需下载额外的jce包。 

 

  评论人:Jagie    参与分: 100322    专家分: 3090    来自: 北京

 发表时间: 2003-11-21 11:11 

java.security.MessageDigest是jdk自带的,无需使用javax.crypto包,所以无需下载jce.

至少我在运行这个例子的时候就没有下载jce

 

 

  评论人:rower    参与分: 167    专家分: 0  发表时间: 2004-04-10 17:10 

实际测试,在J2SDK 1.3中无需下载额外的jce包,运行良好。 

 

  评论人:huangyafei    参与分: 80    专家分: 0  发表时间: 2005-03-06 13:41 

怎么我在运行上面的程序的时候出错了:出错信息为:

D:\works\java\MD5Encode.java:12: class StringUtil is public, should be declared in a file named StringUtil.java

public class StringUtil {

       ^

1 error

 

 

  评论人:yifenggege    参与分: 259    专家分: 70  发表时间: 2005-07-13 14:12 

好! 

 

  评论人:keli    参与分: 34262    专家分: 1320  发表时间: 2005-11-16 17:24 

加密是可以的,但是解密就难了。呵呵。

我看第5个答复想笑,哈哈哈哈。 

 

  评论人:gui_jq    参与分: 73813    专家分: 1070    来自: 广州天河

 发表时间: 2005-12-01 18:28 

写得不错,我最近要写个radius协议分析的工具想用java来编写,所以第一得弄java下面的MD5实现,没有想到如此简单,jdk原来就带有了,最坏的打算我还想用c的代码改一个呢。呵呵。在这里我补充一下:

1,MD5本来就是不可逆的,加密只是保证在网络传输中内容不被修改,可以通过md5来检查,防止有人修改包内容进行模仿发包,所以服务端在受到包写更加对方的算法来md5一次然后在处理包内容,如果不通过则直接丢弃包。另外就是用来验证下载的重要文件是否正确和完整。

2,程序中的打印16进制方法有点欠妥,在c里面可以通过printf("%02x",buf[])就可以,但是java对byte的处理没有这个。所以我推荐下面的方法:

private static String dumpBytes(byte[] bytes) {

    int i;

    StringBuffer sb = new StringBuffer();

    for (i = 0; i < bytes.length; i++) {

      if (i % 32 == 0 && i != 0) {

        sb.append("\n");

      }

      String s = Integer.toHexString(bytes[i]);

      if (s.length() < 2) {

        s = "0" + s;

      }

      if (s.length() > 2) {

        s = s.substring(s.length() - 2);

      }

      sb.append(s);

    }

    return sb.toString();

  }

这个更加灵活高效。

补充结束。谢谢大家。呵呵。 

 

 

(转帖)webwork并入struts团队了!

对学习Struts的朋友是一个利好的消息,正文如下:

webwork并入struts团队了!

来源:http://www.javaeye.com/viewtopic.php?t=17242&postdays=0&postorder=asc&start   发表时间:2005-11-29 09:29 

 

WebWork joining Struts

Yes, it's true. The WebWork development team (Jason and I) have been working with the Struts development team (Don Brown and Ted Husted) and have come to the conclusion that the best thing for Java community would be to merge WebWork in to Struts.

Read Ted's email here, but the gist of it is this: WebWork is a great technology, and Struts is a great community. It's a perfect match and bringing the two together will only be better for WebWork and Struts users alike. The only down side for me is that I'll be working less with OpenSymphony, but I believe that is a small price for all the great benefits that come from this merger.

Just to be clear, WebWork is not going away. WebWork 2.2 is still coming out any day now, and there may even be a WebWork 2.3. But new minor/major versions won't be coming out under the WebWork name for much longer. Instead, they will be released under the Struts incubator program with the intent to eventually become Struts Action Framework 2.0.

So don't worry, WebWork 2.1.8, 2.2.1, and other bug fix releases will continue to come out and we will support the WebWork community as long as needed. In addition, we'll make compatibility with both Struts and WebWork a high priority, so future releases may help with that. To be clear: no one is leaving WebWork and it will continue to be supported for a very long time.

With this renewed energy, larger development team, and larger community, the combined efforts of Struts and WebWork will surely make the Struts platform the easiest, fastest, and most powerful Java web framework available. We hope that all the WebWork users and developers are as excited about this as we are and are ready to take WebWork to the next level

原文:http://www.opensymphony.com/webwork/

 

阅读:321次  〔lanxing〕 

版权声明 

 

评论人:lanxing    参与分: 6527  专家分: 181  发表时间: 2005-11-29 09:42     评论 

 

一下文字来自javaeye的管理员 robbin

==========================================================

看到了这个消息以后感觉非常吃惊,所以跟踪相关的link仔细阅读了一下相关的网页,看完以后我认为对于webwork和struts来说这都是一个重大利好的消息。从整个事件来看,并不是单纯的webwork开发团队合并struts团队这么简单,事实上struts1.3和webwork2.2仍然按照原定roadmap继续发展,而两个团队核心开发人员发起一个新的项目Struts Ti,它的readmap是:

引用:

* Ti phase 1 = WebWork 2.2 + Struts 1.x compatibility library and migration tools

* Ti phase 2 = phase 1 + Commons Chain integration + Beehive's Page Flow + simplified annotations + quick development mode

从这个roadmap可以看出来,新项目Struts Ti是以webwork的整体架构为基础,辅以Struts的一些库,并且该项目的四个发起人联名的声明中这样说:

引用:

As some of you know, the underlying idea behind Ti was to use WebWork as the core of Struts Action Framework 2.x. Conceptually, WebWork and Struts 1.x are very similar. We've often said, without embarrassment, that WebWork does many things better than Struts 1.x. Meanwhile, WebWork has the ability to provide a layer of almost full backwards-compatibility for Struts 1.x, and we have already demonstrated we can integrate Beehive's (very cool) Page Flow with WebWork.

这段话明白无误的指明新框架是以webwork为core的,并且webwork可以提供一个抽象层,以完全向后兼容Struts1.x,并且struts还可以集成Apache Beehive的Page Flow。

因此,我想那些担心webwork从此消失的人可以打消顾虑了,消失的只是webwork这个名字,和com.opensymphony的package前缀,而webwork的程序架构却不会消失。

对于Struts的使用者来说,Struts虽然拥有一个庞大的使用群体,但是Struts在技术上已经非常落伍,再不进行重大的架构革新,势必要被淘汰。因此,这个事情是Struts开发团队的一次自救的革命,从Struts1.3到Struts Ti的改变如同EJB2到EJB3的改变,旧的Struts1.3的架构被完全抛弃,吸收了更加先进的开源软件和架构之后,推出的新东西。

对于Webwork的使用者来说,获得了更加广泛的用户群体和接受度。并且核心开发团队也得到了壮大,相信未来的新版本推出速度可以更快了,而不是现在这样,对webwork2.2都望穿秋水了。

另外非常值得注意的是,Struts Ti的目标可不止集成Webwork这么简单,看看它的phase 2,集成Beehive的Page Flow,JDK1.5的annotations,目标是Ruby on Rails般的快速开发模式,多么诱人的前景!

============================================================

 

 

 

JAVA开发者应该去的20个英文网站-转贴

JAVA开发者应该去的20个英文网站-转贴  发表时间: 2005-05-16 17:52  

 

[http://www.javaalmanac.com] - Java开发者年鉴一书的在线版本. 要想快速查到某种Java技巧的用法及示例代码, 这是一个不错的去处.

[http://www.onjava.com] - O'Reilly的Java网站. 每周都有新文章.

[http://java.sun.com] - 官方的Java开发者网站 - 每周都有新文章发表.

[http://www.developer.com/java] - 由Gamelan.com 维护的Java技术文章网站.

[http://www.java.net] - Sun公司维护的一个Java社区网站.

[http://www.builder.com] - Cnet的Builder.com网站 - 所有的技术文章, 以Java为主.

[http://www.ibm.com/developerworks/java] - IBM的Developerworks技术网站; 这是其中的Java技术主页.

[http://www.javaworld.com] - 最早的一个Java站点. 每周更新Java技术文章.

[http://www.devx.com/java] - DevX维护的一个Java技术文章网站.

[http://www.fawcette.com/javapro] - JavaPro在线杂志网站.

[http://www.sys-con.com/java] - Java Developers Journal的在线杂志网站.

[http://www.javadesktop.org] - 位于Java.net的一个Java桌面技术社区网站.

[http://www.theserverside.com] - 这是一个讨论所有Java服务器端技术的网站.

[http://www.jars.com] - 提供Java评论服务. 包括各种framework和应用程序.

[http://www.jguru.com] - 一个非常棒的采用Q&A形式的Java技术资源社区.

[http://www.javaranch.com] - 一个论坛,得到Java问题答案的地方,初学者的好去处。

[http://www.ibiblio.org/javafaq/javafaq.html] - comp.lang.java的FAQ站点 - 收集了来自comp.lang.java新闻组的问题和答案的分类目录.

http://java.sun.com/docs/books/tutorial/] - 来自SUN公司的官方Java指南 - 对于了解几乎所有的java技术特性非常有帮助.

http://www.javablogs.com] - 互联网上最活跃的一个Java Blog网站.

http://java.about.com/] - 来自About.com的Java新闻和技术文章网站.

 

(转帖)[译]Struts Menu开发向导

  哈,网络真是一个好东东,早就想在我们站使用菜单技术,可是我对此不熟悉,这里又有一个现存的东西可以拿来用了。

  转自:http://kb.csdn.net/java/Articles/200511/3af84c4b-0aba-47ad-9060-58f81c7592ab.html

  正文:

   您的位置:CSDN 首页 -> 知识库 -> 文章摘要

[译]Struts Menu开发向导

作者: ∣来源:BlogJava∣原文地址∣2005-11-28

 官方英文版向导(http://struts-menu.sourceforge.net/userguide.html)

一、从1.X升级到2.X需要做以下事情:

1、改变你的taglib声明中的URI。

 <% at taglib uri="http://struts-menu.sf.net/tag" prefix="menu" %>

2、改变<plug-in>,使用新的包名"net.sf.navigator." 。

 <plug-in className="net.sf.navigator.menu.MenuPlugIn">

3、改变你的menu-config.xml文件,使用新的包名"net.sf.navigator." 。

 <Displayer name="Simple"

   type="net.sf.navigator.displayer.SimpleMenuDisplayer"/>

二、快速开始:

1、下载最新的struts-menu版本;

2、解包到本地目录;

3、下载Tomcat或者其它Servlet容器;

4、把struts-menu.war包放入Tomcat安装目录的wabapps目录下,并重启Tomcat服务。

5、打开htpp://localhost:8080/struts-menu/

三、把Struts Menu整合到你的应用程序中:

Struts Menu能够被轻易的整合到你的Struts应用程序中,它也可以整合到一个非Struts的应用程序中,但是我不喜欢这样做,所以在此没有提供相应的教程。这里将一步步的带你整合这个标签库。

你需要把struts-menu.jar放到你的WEB-INF/lib目录下。然后使用URI标签声明你的JSP文件中想使用的这个标签库。

如果使用Struts Menu 2.1,你还需要 Jakarta's Standard Tag Library JAR包放入你的WEB-INF/lib目录下。下载地址:http://ibiblio.org/maven/taglibs/jars/standard-1.0.4.jar,这个文件包括例程WAR包文件和二进制发布包。

1、放入struts-menu.jar包到你的应用程序的WEB-INF/lib目录中。

2、在你的struts-config.xml文件中加入plug-in设置。

 <plug-in className="net.sf.navigator.menu.MenuPlugIn">

   <set-property property="menuConfig"

     value="/WEB-INF/menu-config.xml"/>

 </plug-in>

3、你将需要在你的应用程序的/WEB-INF/menu-config.xml文件中定义你的菜单,这里提供一个简单的片断:

 <Menu name="contactMenu" title="Contact" location="?Contact">

   <Item name="email" title="E-Mail" location="?EMail"/>

   <Item name="phone" title="Phone" location="?Phone"/>

 </Menu>

  更多全面的例程,请查看应用程序的web/WEB-INF目录中的menu-config.xml文件,你可以截取一段作为你需要的菜单。完整的属性列表,可以查看MenuBase class's javadocs(http://struts-menu.source......avigator/menu/MenuBase.html)。

4、在你的JSP文件的顶部加入taglib声明:

 <% at taglib uri="http://struts-menu.sf.net/tag" prefix="menu" %>

5、在你的JSP文件中要放置菜单的位置加入taglib代码:

 <menu:useMenuDisplayer name="TabbedMenu"

   bundle="org.apache.struts.action.MESSAGE">

   <menu:displayMenu name="Home"/>

   <menu:displayMenu name="About"/>

 </menu:useMenuDisplayer>

  属性name="TabbedMenu"被定义在menu-config.xml文件的顶部:

 <Displayer name="TabbedMenu"

   type="net.sf.navigator.displayer.TabbedMenuDisplayer"/>

(译注:其实到此步即可在你的JSP文件中添加相应的菜单了,只不过是没有结合Velocity。在menu-config.xml文件的头部可以定义多个Displayer,每个Displayer都有name和type属性,name属性与JSP文件中menu:useMenuDisplayer标签的name属性相对应,即表明使用何种样式,具体的样式定义便在type属性中定义,type属性中是一个class。在menu-config.xml文件中的菜单定义中的name属性则与JSP文件中的menu:displayMenu标签的name属性相对应。)

使用定制的Velocity模版实施你的菜单,你需要整合Velocity到你的WEB应用程序中。如果需要这样做的话,请完成下面的步骤:

1、确定你的menu-config.xml文件有“Velocity”的displayer定义:

 <Displayer name="Velocity"

     type="net.sf.navigator.displayer.VelocityMenuDisplayer"/>

2、加入Velocity的JARs包到你的WEB-INF/lib目录中,下载velocity-1.4-rc1.jar(http://www.ibiblio.org/ma......y/jars/velocity-1.4-rc1.jar)和velocity-tools-view-1.0.jar(http://www.ibiblio.org/ma......velocity-tools-view-1.0.jar)。

3、加入globalMacros.vm(http://cvs.sourceforge.net/viewcvs.py/*checkout*/struts-menu/navigator/web/WEB-INF/classes/globalMacros.vm?content-type=text%2Fplain&rev=1.1(右键另存为))到你的WEB-INF/lib目录中。

4、改变你的JSP文件中displayer的值为“Velocity”,“config”属性指向一个文件(如config="/templates/tabs.html")或者如果tabs.htm在你的WEB-INF/classes目录中的话,则可设config="tabs.html"。

这里提供了一些使用Velocity的displayer例子,可在sample application(http://demo.raibledesigns.com/struts-menu/index.jsp)中查看。它总是在你的菜单需要的时候显示CSS,JavaScript和图像文件。下面有一些在当前的Struts Menu中用到的Velocity模版的例子的链接:

 CoolMenus: Demo(http://demo.raibledesigns......menu/velocity-coolmenu4.jsp),

    Template(http://struts-menu.sourceforge.net/templates/coolmenus.html)

 NiceTabs: Demo, Template

 Tabs: Demo, Template

 XTree: Demo, Template

所有相关的有用的文件如果你需要的话都可以在下面的站点上下载:

 Images (http://struts-menu.sourceforge.net/menu-images/)

 Stylesheets (http://struts-menu.sourceforge.net/styles/)

 Scripts (http://struts-menu.sourceforge.net/scripts/)

 Templates (http://struts-menu.sourceforge.net/templates/)

更多的基于roles的显示/隐藏菜单的信息,请查看FAQs(http://struts-menu.sourceforge.net/faq.html)。

四、在Struts之外使用Struts Menu:

在2.2版中,Menu Repository能够使用MenuContextListener载入:

 <!--

    - Loads the menu-config.xml for struts-menu at startup,

    - by default from "/WEB-INF/menu-config.xml".

    - To override this, add a context-param named "menuConfigLocation"

    - web.xml file.

    -->

 <listener>

     <listener-class>net.sf.navigator.menu.MenuContextListener</listener-class>

 </listener>

或者如果你使用Spring,甚至更容易。仅仅需要加入下面的部分到你的applicationContext.xml文件中:

 <bean id="menu" class="net.sf.navigator.menu.MenuLoader">

   <property name="menuConfig">

     <value>/WEB-INF/menu-config.xml</value>

   </property>

 </bean>

 <!-- The menuConfig property is an optional attribute.  It is set to

     /WEB-INF/menu-config.xml by default. -->

感谢Dan Luputan提供MenuLoader类的源代码。

五、从源文件编译:

要从源文件编译这个项目,执行下面的步骤:

1、下载并安装Maven(http://maven.apache.org/);

2、创建一个环境变量MAVEN_HOME指出你的Maven的安装目录,然后添加$MAVEN_HOME/bin到你的PATH变量中;

3、操纵这个目录你可以扩展源代码,执行“maven.jar”创建target/struts-menu.jar。

要展开struts-menu例程,需要下面的步骤:

1、下载和安装Tomcat;

2、创建一个环境变量CATALINA_HOME指出你的Tomcat的安装目录;

3、执行“maven deploy”把应用程序展开到Tomcat中;

4、打开http://localhost:8080/struts-menu在你喜爱的浏览器中。

如果你喜欢使用Eclipse开发项目,请参考此份开发向导(http://struts-menu.sourceforge.net/devguide.html)。

Robin's Java World 2005-11-28 10:15

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