刘文涛

Flex3,Struts2,Hibernate3,Spring2,UML,Oracle,mysql,tomcat,compass,lucene

   :: 首页 ::  ::  ::  :: 管理 ::

2006年8月20日 #

     摘要: DisplayTag是一个非常好用的表格显示标签,适合MVC模式,其主页在http://displaytag.sourceforge.net一、最简单的情况,未使用<display:column/>标签1<%request.setAttribute( "test", new ReportList(6) );%>2<display:table name="test" /...  阅读全文
posted @ 2006-08-20 15:22 刘文涛| 编辑 收藏

Display tag 是一个功能强大,易于使用的Jsp tag库
在MVC模式中充当表现层的可重用UI组件,计划支持

1Table
2Tabs
3Tree

等,但目前只实现了Table功能。即使这样,使用DisplayTag仍然可以大大减少Web界面的开发工作量,因为它支持 :

1样式(客户要求修改界面从此变得稍微容易了!)
2动态连接
3分页显示
4显示数据的排序
5将表格数据输出成XLS等格式
6嵌套表格等常用的功能

这些功能以前只能通过Ctr+C加Ctr+V来重用,逻辑相当复杂,搞得页面混乱不堪。
posted @ 2006-08-20 15:18 刘文涛| 编辑 收藏

应用中集成struts menu有三种方式:
1 如果应用中使用了struts,可以把struts menu做为一个struts插件,如下:

1 < plug - in className = " net.sf.navigator.menu.MenuPlugIn " >
2        < set - property property = " menuConfig "  value = " /WEB-INF/menu- config.xml " />
3 </ plug - in >

2 在web.xml中配置监听器, (在appfuse中使用的就是此种方式) 如下:

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

3 如果项目中使用到了spring,可以定义一个bean,如下:

1 < bean id = " menu "   class = " net.sf.navigator.menu.MenuLoader " >
2        < property name = " menuConfig " >
3              < value >/ WEB - INF / menu - config.xml </ value >
4        </ property >
5 </ bean >

然后在/WEB-INF/下定义了menu-config.xml文件,内容如下:

 

 1 < MenuConfig >
 2      < Displayers >
 3          < Displayer name = " CoolMenu "  type = " net.sf.navigator.displayer.CoolMenuDisplayer4 " />
 4          < Displayer name = " ListMenu "  type = "  net.sf.navigator.displayer.ListMenuDisplayer " />
 5      </ Displayers >
 6      < Menus >
 7          < Menu name = " MainMenu "  title = " mainMenu.title "  page = " /mainMenu.html "  width = " 90 " />  
 8          < Menu name = " UserMenu "  title = " menu.user "  description = " User Menu "  page = " /editProfile.html " />
 9          < Menu name = " FileUpload "  title = " menu.selectFile "  description = " File Upload "  page = " /selectFile.html " />
10
11          < Menu name = " AdminMenu "  title = " menu.admin "  description = " Admin Menu "  roles = " admin "  width = " 120 " >
12              < Item name = " ViewUsers "  title = " menu.admin.users "  page = " /users.html " />
13              < Item name = " ReloadContext "  title = " menu.admin.reload  "  page = " /reload.html " />
14              < Item name = " FlushCache "  title = " menu.flushCache "  page = " /flushCache.html "  roles = " admin " />
15              < Item name = " Clickstream "  title = " menu.clickstream "  page = " /clickstreams.jsp "  roles = " admin " />
16          </ Menu >
17      </ Menus >
18 </ MenuConfig >

Displayers中的displayer 定义了菜单的显示方式. CoolMenu和ListMenu.
Menus 下的Menu定义了具体的菜单,.title是菜单的显示名字(是国际化配置文件中的key).
page是与此菜单 项对应的url请求路径.
roles表示显示此菜单用户应该具有的角色.上例表示只有admin这种角色的用户登 陆才会显示AdminMenu菜单.

在taglibs.jsp定义了struts menu 的tag:
<%@ taglib uri="http://struts-menu.sf.net/tag-el" prefix="menu" %>
在menu.jsp中是tag的具体使用,如下:

1 < menu:useMenuDisplayer name = " CoolMenu "  permissions = " rolesAdapter " >  
2      < menu:displayMenu name = " MainMenu " />
3      < menu:displayMenu name = " UserMenu " />
4      < menu:displayMenu name = " FileUpload " />
5      < menu:displayMenu name = " AdminMenu " />  
6 </ menu:useMenuDisplayer >

在这个菜单中,通过userMenuDisplayer 标签的name制定了菜单的显示样式是"CoolMenu"。
permissions指 定了菜单的显示与否是通过 role来决定的.(在前面的menu-config.xml中指定了AdminMenu菜单只有admin 角色的才显示).struts menu的 role permission 是通过request.isUserInRole来判断是否显示菜 单.appfuse使用了acegi security框架,在用户登陆的时候采用了acegi security的基于form 的认证方式 .在 acegi的org.acegisecurity.wrapper.SecurityContextHolderAwareRequestWrapper 类中有如下方法 :

1 public   boolean  isUserInRole(String role)  {
2          return  isGranted(role);
3     }
 
4

所以使用了它就可以完成这项工作,acegi security 提供了对struts menu的 role permission的支持.

posted @ 2006-08-20 13:08 刘文涛| 编辑 收藏

appfuse中使用Clickstream来跟踪用户的页面操作。它通过监听器来开始一次会话跟踪过程。 用户的每一条点击信息是通过一个servlet filter来捕捉的。当用户的session结束后把整个跟踪 记录保存在一个文件里或打印输出。可以发现用户是不是一个“人”。并且进行过滤(可以发现 252中机器人)。可以通过jsp或servlet显示用户的当前的点击信息。 先在web.xml中定义了filter和listener.

1<filter>
2    <filter-name>clickstreamFilter</filter-name>
3    <filter-class>com.opensymphony.clickstream.ClickstreamFilter</filter-class>
4</filter>

1<filter-mapping>
2    <filter-name>clickstreamFilter</filter-name>
3    <url-pattern>*.html</url-pattern>
4</filter-mapping>

1<listener>
2    <listener-class>com.opensymphony.clickstream.ClickstreamListener</listener-class>
3</listener>


listener开始一次跟踪,filter捕捉每一次请求,在这里捕捉以html结尾的请求。
在 项目主页http://www.opensymphony.com/clickstream/提供了显示当前在线信息的jsp和servlet
clickstream.jsp,viewstream.jsp 以及ActiveStreamServlet.

appfuse直接使用了上诉的两个jsp文件
几乎没有做任何改动。

   如果希望和自己的权限管理系统结合起来,获得用户的名称,可以为clickStream类加一个属性,然后修改一下addRequest()方法.
   
    ClickStream的用途:记录并显示当前在线的用户, IP, 登陆时间, 登陆时长, 访问纪录列表, 和最后一次点击的时间. 还可以配置common-log把这一切记录下来.
posted @ 2006-08-20 12:37 刘文涛| 编辑 收藏

spring中的提供了一个名为org.springframework.web.util.IntrospectorCleanupListener的监听器。它主要负责处理由 
JavaBeans  Introspector的使用而引起的缓冲泄露。spring中对它的描述如下:
 
它是一个在web应用关闭的时候,清除JavaBeans Introspector的监听器.在web.xml中注册这个listener.可以保证在web 应用关闭的时候释放与掉这个web 应用相关的class loader 和由它管理的类
 
如果你使用了JavaBeans Introspector来分析应用中的类,Introspector 缓冲中会保留这些类的引用.结果在你的应用关闭的时候,这些类以及web 应用相关的class loader没有被垃圾回收.
 
不幸的是,清除Introspector的唯一方式是刷新整个缓冲.这是因为我们没法判断哪些是属于你的应用的引用.所以删除被缓冲的introspection会导致把这台电脑上的所有应用的introspection都删掉.
 
需要注意的是,spring 托管的bean不需要使用这个监听器.因为spring它自己的introspection所使用的缓冲在分析完一个类之后会被马上从javaBeans Introspector缓冲中清除掉.
 
应用程序中的类从来不直接使用JavaBeans Introspector.所以他们一般不会导致内部查看资源泄露.但是一些类库和框架往往会产生这个问题.例如:Struts 和Quartz.
 
单个的内部查看泄漏会导致整个的web应用的类加载器不能进行垃圾回收.在web应用关闭之后,你会看到此应用的所有静态类资源(例如单例).这个错误当然不是由这个类自身引起的.


这个listener的源代码 :

package  org.springframework.web.util;

import  java.beans.Introspector;
import  javax.servlet.ServletContextEvent;
import  javax.servlet.ServletContextListener;

public   class  IntrospectorCleanupListener  implements  ServletContextListener  {
    
public   void  contextInitialized(ServletContextEvent event)  {
    }


    
public   void  contextDestroyed(ServletContextEvent event)  {
        Introspector.flushCaches();
    }

}
posted @ 2006-08-20 12:36 刘文涛| 编辑 收藏

appfuse中使用了UrlRewrite.实现了url的重写,这样有什么用处呢?上网搜了一把,大体上有以下好处:

1、满足搜索引擎的要求
某些搜索引擎不能支持动态页面的抓取,大量的信息就不能被潜在用户搜索到。用UrlRewrite技术你可以把 http://server/news.asp?id=111 变成 http://server/news/111.htm 这样他们就会被搜索引擎收录了。google虽然可以抓取动态页面,但是google对动态页面的评分一般低于静态页面。所以,对大量信息发布的网站,把网站地址改变成静态的绝对是值得的。
 
2、隐藏技术实现,提高网站的移植性
每个页面都挂着鲜明的.asp/.jsp这种开发语言的标记,可以一眼让人看出你的网站使用什么语言做的。而且在改变网站的语言的时候,你需要改动大量的链接。而且,一个页面修改了扩展名,他的pagerank也会随之消失,从头开始。我们可以用UrlRewrite技术隐藏我们的实现细节,这样修改移植都很方便,而且完全不损失pagerank。

3、满足美感的要求
对于追求完美主义的网站设计师,即使是网页的地址也要看起来简洁明快。形如 http://server/news.asp?channel=3&id=111 的网页地址,肯定是上不了完美主义者的法眼的,用UrlRewrite技术,你可以把他变成 http://server/news/3/111.htm
在应用中怎样集成它呢?看看appfuse中的实现方式。
首先在web.xml中配置一个过滤器:

1<filter>
2    <filter-name>rewriteFilter</filter-name>
3    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
4    <init-param>
5        <param-name>logLevel</param-name>
6        <param-value>commons</param-value>
7    </init-param>
8</filter>

1<filter-mapping>
2    <filter-name>rewriteFilter</filter-name>
3    <url-pattern>/*</url-pattern>
4    <!--dispatcher>REQUEST</dispatcher>
5    <dispatcher>FORWARD</dispatcher-->
6</filter-mapping>

然后在WEB-INF目录下有一个配置文件urlrewrite.xml内容如下:

 1<?xml version="1.0" encoding="utf-8"?>
 2<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
 3    "http://tuckey.org/res/dtds/urlrewrite3.0.dtd">
 4
 5<!-- https://urlrewrite.dev.java.net/manual/3.0 -->
 6<urlrewrite>
 7    <rule>
 8        <from>^/user/(.*).html$</from>
 9        <to type="forward">/editUser.html\?username=$1</to>
10    </rule>
11
12    <!-- Override default validation.js from WebWork -->
13    <rule>
14        <from>^/webwork/css_xhtml/validation.js$</from>
15        <to type="forward">/template/css_xhtml/validation.js</to>
16    </rule>
17</urlrewrite>
posted @ 2006-08-20 12:17 刘文涛| 编辑 收藏

appfuse中使用了缓冲:

applicationContext-service.xml:
 1<bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
 2    <property name="cache">
 3        <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
 4            <property name="cacheManager">
 5                <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
 6            </property>
 7            <property name="cacheName" value="userCache"/>
 8        </bean>
 9    </property>
10</bean>

这里没有给org.springframework.cache.ehcache.EhCacheManagerFactoryBean. 定义属性configLocation. 则EhCache使用默认的配置文件.WEB- INF/classes/ehcache.xml.(当然你也可以通过以下方式指定配置文件)

1<bean id="cacheManager" 
2        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
3    <property name="configLocation">
4        <value>classpath:/ehcache-failsafe.xml</value>
5    </property>
6</bean>

WEB- INF/classes/ehcache.xml文件中的定义如下:

 1<ehcache>
 2    <diskStore path="java.io.tmpdir"/>
 3       <defaultCache
 4        maxElementsInMemory="10000"
 5        eternal="false"
 6        overflowToDisk="true"
 7        timeToIdleSeconds="120"
 8        timeToLiveSeconds="120"
 9        diskPersistent="false"
10        diskExpiryThreadIntervalSeconds="120"/>
11</ehcache>



可以看到
1: acegi security提供的daoAuthenticationProvider 把userDetails对象保存在Cache里.这个Cache在bean "userCache"里进行了定义(cache名为 userCache).

security.xml :
1    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
2         <property name="userDetailsService" ref="userDao"/>
3         <property name="userCache" ref="userCache"/>
4         <property name="passwordEncoder" ref="passwordEncoder"/>
5    </bean>

2同时userSecurityAdvice这个AOP设备也对cache进行了操作.这个类实现了 MethodBeforeAdvice接口的before方法.此方法的作用是不允许非 administrators用户修改自己的角色.它也实现了AfterReturningAdvice接口的 afterReturning方法,此方法的作用是根据当前用户信息更新缓冲中的用户数据 (userDetail).

applicationContext-service.xml:
1<bean id="userSecurityAdvice" class="org.appfuse.service.UserSecurityAdvice">
2    <property name="userCache" ref="userCache"/>
3</bean>


posted @ 2006-08-20 11:14 刘文涛| 编辑 收藏