在jsp页面中获取http请求头的代码(转)

转自:http://www.ericgiguere.com/tools/http-header-viewer.html

Header Viewer Source Code

In case you're wondering, here is the code that prints the headers:

<table width="100%" border="0" cellspacing="0"

       cellpadding="8" bgcolor="#EEEEEE">

      

    <tr><td><b>Name</b></td><td><b>Value</b></td></tr>

    <tr><td colspan="2" width="100%" height="2" bgcolor="#000000"></td></tr>

   

    <c:forEach var="hname" items="${pageContext.request.headerNames}">

   

        <c:forEach var="hvalue" items="${headerValues[hname]}">

            <tr><td valign="top"><c:out value="${hname}"/></td>

            <td valign="top"><c:out value="${hvalue}"/></td></tr>

            <tr><td colspan="2" bgcolor="#000000" width="100%" height="1"></td></tr>

   

        </c:forEach>

    </c:forEach>

</table>

 

As you can see, it's very easy to access the HTTP headers using the Java Standard Tag Library (JSTL), a powerful tag library for use with JavaServer Pages (JSP).

If you didn't realize that this page was built using JSP pages, See How This Site Works for the details.

疑问:关于使用Validator框架后,显示错误信息的问题。

 我发现:使用Validator框架后,

只能使用<html:errors/>显示错误信息,

不能使用诸如:<html:errors property="error1"/>显示指定的错误信息。

我现在需要这样显示错误,

比如:用户名没有填写的话,只在用户名旁边显示错误信息;

如果Email填写不符合标准,只在Email旁边显示错误信息。

我不希望把所有错误都一起显示出来。

可以用Validator实现吗?

因为我不知道如何实现那个目的,

所以,只好把验证的部分放到ActionForm的validate方法中,

这样就可以指定每一个不同的错误信息,以便在错误页面按要求显示了。

可是,每个验证逻辑都需要自己来写,

org.apache.struts.validator.FieldChecks这个类是Validator框架使用的验证类,

里面有很多现成的方法,由于我没有使用这个框架,

所以就无法使用这些现成的方法了(也可能是我不知道如何使用)。

我想知道:有没有现成的验证方法可以下载到?

例如必填、合法日期、合法Email等等。

请前辈指点。

cvs中源码的头部信息不能自动更新了

  原来,我用eclipse2.1提交文件时,在源码中的头部信息如:“// $ Id: DispatchPageAction.java,v 1.3 2005/12/18 13:49:06 dashing_meng Exp $”就会自动更新版本和时间,可是,在最近的代码提交中,我发现它不起作用了。

  因为上次是因为文件属性被设置成了kb成了二进制文件不能自动更新,这次我特意看了文件类型,是kkv(文本文件),没错。可是,为什么这种自动更新不起作用了?搞不懂。

java中的protected提供package访问权限

  也就是,从它们的私有性来说,依次是:private,package,protected(也提供给包以外的继承类访问),public

  摘自:Thinking in Java, 3rd ed. Revision 4.0 6: Reusing Classes protected

 It says “This is private as far as the class user is concerned, but available to anyone who inherits from this class or anyone else in the same package.” (In Java, protected also provides package access.)

  另外,因为abstract方法必须被它的继承类实现才有意义,所以它至少要提供package访问,按道理来说,应该提供protected访问,因为这样可以供在包外的继承者来实现它。

开始Struts的日记。

今天终于对《Jakarta Struts编程》看了一个大概,

准备搭建一个环境进行进一步学习。

我将下载的status-1.2.7.tar.gz解压缩后,

把lib目录中的status.jar、jstl.jar和standard.jar拷贝到了WEB-INF的lib目录中,

起动服务器后,竟然一个劲儿的抛出异常,

郁闷死……

最后,把所有的jar文件都拷贝到WEB-INF的lib目录后,

才解决了问题。

回过头再看书,才发现,

书上已经写的很明白了,只怪当时没有注意到。

看来,看书还是要仔细一些。

又或是,水平不够,所以注意不到书上说的内容的重要性。

(转帖)Struts-menu源码分析

(转自:http://champion.ewuxi.com/old/opensource/struts-new/strutsmenu.htm)

Struts-menu源码分析

        好的代码读起来让人如饮醍醐,读完以后神清气爽。如果你想提高你的编程水平,如果你想提高你的设计能力,如果你也想成为大师,那么就去阅读代码吧。以本人十几年来的编程经验,阅读代码能让你得到的比阅读文章(那怕是大师的文章)得到的更多。优秀而且实用的代码有很多,比如Junit,比如Jive,比如petStore,甚至是tomcat的Example、Log4j的Example。

        一段广告完毕,下面就为大家分析一下struts-menu的源码,作为送给大家的圣诞礼物吧。Struts-Menu也来自一位大师的作品, Matt Raible。有很多优秀的作品,比如使用struts和hibernate的struts-resume。官方网站是http://raibledesigns.com/wiki/Wiki.jsp?page=Main。Struts-Menu的最新版本是2.1。功能是使用struts技术,构建树形菜单。应该说是一个非常实用的技术,极大的方便了广大的开发人员。与此同时,个人认为它的作用还不止于些。比如,同时它也是一个使用Maven和velocity的一个很好的例子。

        首先,我们去看一下它的效果。http://www.raibledesigns.com/struts-menu/。可以看到,如此丰富多彩的菜单效果,都是在演示一个配置文件里的内容。这是一个非常好的数据与表示相分离的实现。我们打开它的源码来看。首先看一下它的包图

共有五个包,其中menu自然是完成数据组织功能,是核心之一,displayer是显示方式包,完成数据显示大部分功能。也是核心之一。taglib意义明显。example自然是一些example。util是读取资源文件的包。因些,我们重点研究的包只有三个menu,displayer和taglib。

首先我们来看menu包的类图

首先是MenuPlugIn这个类。这个类的功能很明显,就是一个struts的plug-in。可以看到,它只有一个参数menuConfig,就是menu的配置文件路径。果然,在struts-conf文件中有这么一段

  <!-- ========== Plug Ins Configuration ================================== -->

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

<set-property property="menuConfig" value="/WEB-INF/menu-config.xml"/>

</plug-in>

 

 

说明配置文件来自于/WEB-INF/menu-config.xml,当然,我们可以找到相应路径下找到这个文件。如果你以前没有做过struts的plug-in,现在该知道怎么做了吧,就这么简单。通过阅读初始化函数,知道它的功能就是调用MenuRepository来建立菜单。因此。我们知道MenuRepository必然是一个组织管理管理菜单的组织类。

public void init(ActionServlet servlet, ModuleConfig config)

throws ServletException {

if (log.isDebugEnabled()) {

log.debug("Starting struts-menu initialization");

}

this.servlet = servlet;

repository = new MenuRepository();

repository.setLoadParam(menuConfig);

repository.setServlet(servlet);

try {

repository.load();

servlet.getServletContext().setAttribute(

MenuRepository.MENU_REPOSITORY_KEY,

repository);

if (log.isDebugEnabled()) {

log.debug("struts-menu initialization successfull");

}

} catch (LoadableResourceException lre) {

throw new ServletException(

"Failure initializing struts-menu: " + lre.getMessage());

}

}

 

打开MenuRepository类,我们可以看到这个类也很简单,不过已经有少可以学习的了。首先是FastHashMap,可以看到,这个类里有三个FastHashMap。顾名思议,是快速HashMap了,再看一下,它来自org.apache.commons.collections.FastHashMap;。看到org.apache.commons这个著名的包了?如果你以前从没使用过它,那么建议你花上一段时间去研究使用它,我保证物有所值。

protected FastHashMap menus = new FastHashMap();

protected FastHashMap displayers = new FastHashMap();

protected FastHashMap templates = new FastHashMap();

接下来我们看到log的定义。对了,log,调试的核心之一。而下面这一句则是commons log的最常用的使用方法。快快让你的程序使用上commons log吧,第一,它功能强大,第二,它使用简单,就是这么简单。

private Log log = LogFactory.getLog(getClass().getName());

下面看一个的函数

 protected Digester initDigester() {

        Digester digester = new Digester();

        digester.setClassLoader(Thread.currentThread().getContextClassLoader());

        digester.push(this);

        //digester.setDebug(getDebug());

        // 1

        digester.addObjectCreate("MenuConfig/Menus/Menu",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu");

        digester.addSetNext("MenuConfig/Menus/Menu", "addMenu");

        // 2

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item", "addMenuComponent",

            "net.sf.navigator.menu.MenuComponent");

        // 3       

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item/Item",

            "addMenuComponent", "net.sf.navigator.menu.MenuComponent");

        // 4

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item",

            "addMenuComponent", "net.sf.navigator.menu.MenuComponent");

        // 5

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "addMenuComponent", "net.sf.navigator.menu.MenuComponent");

        // 6

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "addMenuComponent", "net.sf.navigator.menu.MenuComponent");

        // 7

        digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "net.sf.navigator.menu.MenuComponent", "type");

        digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");

        digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item",

            "addMenuComponent", "net.sf.navigator.menu.MenuComponent");

        digester.addObjectCreate("MenuConfig/Displayers/Displayer",

            "net.sf.navigator.displayer.MenuDisplayerMapping", "mapping");

        digester.addSetProperties("MenuConfig/Displayers/Displayer");

        digester.addSetNext("MenuConfig/Displayers/Displayer",

            "addMenuDisplayerMapping",

            "net.sf.navigator.displayer.MenuDisplayerMapping");

        digester.addSetProperty("MenuConfig/Displayers/Displayer/SetProperty",

            "property", "value");

           

        return digester;

    }

 

这里又是一个经典,digester,Digester的使用,如果你需要读一个XML配置文件,并且不想与DOM直接打交道的话,Digester将是一个很好的选择。实际上我们看到load函数调用一句 digester.parse(input);就已经把menu-config.xml建立到内存里了,就这么简单。如果你想要初始化你的系统,这种方法是不是可以学习呢?"工欲善其事,必先利其器"。我们可以看到Raible是怎么样利用现有的工具来减轻开发量的。

由于MenuRepository举重若轻的初始化过程,甚至都没有让我们看到树形结构是怎么建立到内存里去的。不过不要着急,类图给我们了明示。

看到MenuBase类了吗?对了,看名字就知道是一个Menu的基类。可以看到,它是一个简单的JavaBean。而且相信它的每个属性大家根据名字也能猜出来。所以重点讲解是MenuComponent,一个简化的 "Composite"模式。

如上图所示。由于此处的Leaf没有任何方法,只有属性。因此Leaf和Composite收缩成了一个MenuComponent类。大家都知道,Composite模式是实现树形结构最好的方法。如果你以前没有机会实现或者没有从Composite模式得到好处,那么,从这里看一下用Composite模式得到的好处。首先看它的简单,MenuComponet的实际代码很少,加起来不到十行。

public void addMenuComponent(MenuComponent menuComponent) {

        menuComponents.add(menuComponent);

        menuComponent.setParent(this);

        if ((menuComponent.getName() == null) ||

                (menuComponent.getName().equals(""))) {

            menuComponent.setName(this.name + menuComponents.size());

        }

    }

    public MenuComponent[] getMenuComponents() {

        MenuComponent[] menus =

            (MenuComponent[]) menuComponents.toArray(_menuComponent);

        return menus;

    }

 

如果你用十行来实现一个树型结构(并且还是通用的),你愿不愿意?就是通过简单的这么一些代码,实现的在内存中建立树型结构的目标。

下面我们来看DispLay包,这个包的功能也是很清楚的,就是用来显示啦。这个包的类图非常漂亮,遗憾的是也非常大。只能缩小了给大家看了。

从类图中可以看到一个非常极漂亮的面象对象的设计思路。通过一个接口,利用模板方法。最后具体实现树型结构的显示。其主要方法是displayComponents和display这两方法,init方法则实现了初始化的工作,读取javascript和图片等文件。displayComponents是一个迭代函数。从而可以遍历一个MenuCompont树。并将其显示出来。

应该说,Menu包是一个M层,而Dispplya包是一个view层,而加上TagLib包,就实现了MVC的完整结构。

两个Tag类很清楚,首先我们从怎么使用它来看它们实现的功能

<menu:useMenuDisplayer name="ListMenu"

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

        <menu:displayMenu name="ToDoListMenuFile"/>

        <menu:displayMenu name="ToDoListMenuEdit"/>

        <menu:displayMenu name="CaseDetailMenuCase"/>

        <menu:displayMenu name="Standalone"/>

</menu:useMenuDisplayer>

显而易见。useMenuDisplayer这个类是实现使用哪一种显示方式。在menu-config里我们看到ListMenu的定义

<Displayer name="ListMenu"

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

displayMenu则是取得一菜单,并将其显示出来,同样在menu-config也能找到。

<Menu  name="ToDoListMenuEdit"  title="EDIT">         <Item  name="TDLselect" title="SELECT_ALL"       image="images/select-all.png"                    location="index.jsp" width="100" />         <Item  name="TDLprefs"  title="USER_PREFERENCES" image="images/prefs.png"                    location="index.jsp" width="150" />         <Item  title="Action Test" action="setPermissions?displayer=${displayer}"/></Menu>

 

查看 DisplayMenu的代码,可以看到。它完成的功能只是从context里取得MenuComponent对象,然后通过 displayer.display(menu);把它交给一个MenuDisplayer的实例来负责画出来。

因此,Control层很好的完成了控制的功能。

综上所述。通过这样一个优美的设计,把各个功能都他离开来了。如果我们需要增加一种显示方式,只要继承MenuDisplayer或它的一个子类,然后写出我们的方法,而不需要修改系统的其他部分。同样的,如果我们的菜单不准备存放在ServletContext而准备存放在比如Session里了,那么我们也只需要修改control部分和生成部分(即MenuRepository)部分。而不影响Display部分。

OK,对struts-menu的介绍结束了,下一篇文章将是如果使用struts-menu和数据库技术动态生成菜单了。请大家继续关注我的网站。

 

 

紫龙,于12/22/2003 16:45:09

蓝色天空版权所有

 

使用静态常量的注意事项

  两个*.java文件,一个是静态常量,一个是使用静态常量的。含有静态常量的文件在我本地和虚拟空间的内容是不一样的,使用静态常量的文件是一样的。我在本地更新了使用静态常量的那个文件,上传到虚拟空间后发现,这个文件引用的是本地的静态常量。

  反编译使用静态常量的那个*.class文件,发现引用静态常量的变量统统都是本地的静态常量值。

  原来,java中使用的静态常量是编译时就固定了,并不是运行时间的动态调用。看来,有必要学习一下java运行的基本原理。

使用标记的怪现象

       <html:select property="parentID" name="oldAdvice">

         <html:options collection="processGoalsList" property="articleID" labelProperty="articleName"/>

       </html:select>

  上面代码的作用是把一个包含同样对象的List中的对象显示到下拉列表中,其中默认为对象“oldAdvice”,本来这个用法在资料中说得很清楚,我用它却出现了至今也想不通的怪现象两次。就是我按照正确的方法写了代码后,运行中却始终得不到正确的效果。我不知道是eclipse或tomcat的问题。

  以后为了保险起见,遇到自己不熟悉的代码编写后,运行时要:1、删除程序运行的work目录;2、重新编译源程序;3、重新启动tomcat服务器。

  我想,这样总不会再扯拐吧?