论坛首页 Java企业应用论坛

WebWork2.2新特性 系列

浏览 19624 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-09-02  
在xwork中,package的定义中增加了global-exception-mappings,action的定义中增加了exception-mapping,要想使用这2个特性,必须使用xwork-1.1.dtd才行.

DTD中,global-exception-mappings是这样定义的,
<!ELEMENT global-exception-mappings (exception-mapping+);>

也就是说如果要使用,就至少包含一个异常映射.

exception-mapping的定义如下:
<!ELEMENT exception-mapping (#PCDATA|param);*>
<!ATTLIST exception-mapping
    name CDATA #IMPLIED
    exception CDATA #REQUIRED
    result CDATA #REQUIRED
>

可以看到有3个属性:名称,异常类型,和结果.


经过一番查看,发现xwork-default.xml中还没有定义相关的拦截器,搜索了一下,发现了ExceptionMappingInterceptor,看来它是把异常翻译为相应的结果的.
(在最后发行版本中,应该会定义的.目前只好我们自己定义了.)

首先我们虚拟一个程序,假设程序会抛出几种程序,例如Action定义如下:
	package com.jscud.ww2test.exceptionmap;
	
	import com.opensymphony.xwork.ActionSupport;
	
	/**
	 * @author scud http://www.jscud.com
	 *
	 */
	public class ExpMappingAction extends ActionSupport
	{
	    private int type;
	
	    public String execute(); throws NoRightException,NotFoundException
	    {
	        if(type==1);
	        {
	            throw new NoRightException();;
	        }
	        else if(type ==99);
	        {
	            throw new NotFoundException();;
	        }
	        else if(type==60); //其他异常
	        {
	            throw new IllegalArgumentException();; 
	        }
	        
	        return SUCCESS;
	    }
	    
	    public int getType();
	    {
	        return type;
	    }
	    
	    public void setType(int type);
	    {
	        this.type = type;
	    }
	}

从Action可以看出,程序至少会抛出3种异常,我们如果使用异常映射,就要考虑到抛出的所有异常.

程序中用到的NoRightException,NotFoundException是为了演示而建立的2个简单异常,无任何特殊代码,继承自Exception.

我们的xwork.xml中的定义如下:
	<package name="exceptionmapping" extends="webwork-default" namespace="/exceptionmap">
	
		<interceptors>
			<interceptor name="exceptionmapping" class="com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor"/>
			
			<interceptor-stack name="myDefaultStack">
			    <interceptor-ref name="defaultStack"/>
			    <interceptor-ref name="exceptionmapping"/>
			</interceptor-stack>
		</interceptors>

		<default-interceptor-ref name="myDefaultStack"/>


		<global-results>
			<result name="noright" type="dispatcher">
				<param name="location">/exceptionmap/noright.jsp</param>
			</result>
			<result name="exception" type="dispatcher">
				<param name="location">/exceptionmap/exception.jsp</param>
			</result>
		</global-results>
	
		<global-exception-mappings>
			<exception-mapping name="noright" exception="com.jscud.ww2test.exceptionmap.NoRightException" result="noright"/>
			<exception-mapping name="exception" exception="java.lang.Exception" result="exception"/>
		</global-exception-mappings>
	
		<action name="index" class="com.jscud.ww2test.exceptionmap.ExpMappingAction">
			<exception-mapping  name="notfound" exception="com.jscud.ww2test.exceptionmap.NotFoundException" result="notfound"/>
			<result name="success" type="dispatcher">
				<param name="location">/exceptionmap/index.jsp</param>
			</result>
			<result name="notfound" type="dispatcher">
				<param name="location">/exceptionmap/notfound.jsp</param>
			</result>
		</action>
		
	</package>

首先定义了一个exceptionmapping拦截器,用来指向ExceptionMappingInterceptor.
然后定义一个拦截器Stack,包含defaultStack和exceptionmapping,注意,exceptionmapping是在Stack的最后面,否则会发生不可预期的结果.

可以看到global-exception-mappings段包含了2个异常映射,一个为NoRight的处理,另外一个为对应java.lang.Exception的映射.

在Action的定义中包含了一个exception-mapping,对应NotFound异常.

没有看到IllegalArgumentException的对应结果?? 拦截器对没有定义的异常会依次找这个异常的父类,一级一级向上查找,例如IllegalArgumentException的最终父节点是Exception,就会转向到Exception对应的结果. 如果一个异常有多个层次关系上的父类,那个关系最近就找谁.


演示页面如下:
	<%@ page contentType="text/html; CHARSET=utf8" %>
	<%@ taglib uri="webwork" prefix="ww" %>
	<html>
	  <head>
	    <title>exception mapping</title>
	  </head>
	<body>
	
	<br>
	Exception 1:
	<a href="index.jspa?type=1">Exception 1</a>
	<br><br>
	
	Exception 99:
	<a href="index.jspa?type=99">Exception 99</a>
	<br><br>
	
	Other Exception:
	
	<a href="index.jspa?type=60">Exception 60</a>
	<br><br>
	
	Normal:
	<a href="index.jspa">No Exception</a>
	<br><br>
	
	</body>
	</html>

notfound.jsp,exception.jsp,noright.jsp是三个最简单的jsp页面,自己编写即可.

运行程序,发现根据异常类型会转向相应的异常页面.

如果你自己的程序中的异常没有在异常映射中得到对应的result,会抛出异常,所以应该定义一个底层Exception的映射.
0 请登录后投票
   发表时间:2005-09-07  
WebWork2.2新特性(八)使用FreeMarker的FTL做装饰页面


其实我不善于写作,有些东西仅仅是写下来.还可以提醒自己.

人生"入"梦,各位一定要保重身体.



注意:FreeMarkerPageFilter是2.2beta发布后才加到CVS上的,所以从CVS获取新的代码才能看到这个filter,同目录下还有一个VelocityPageFilter.

FreeMarkerPageFilter以及VelocityPageFilter都是Sitemesh页面装饰器中PageFilter的扩展,有了它,可以直接使用FreeMarker的ftl作为装饰页面,可以不在使用SiteMesh带的FreemarkerDecoratorServlet了,而且还可以享受Action中的ValueStack了.
不过我不推荐在装饰页面中使用ValueStack中的值,因为装饰页面对应的Action是不确定的,而且也可能修饰的是一个普通页面,不是一个Action.

我们要有一个Action及其结果页面,或者一个简单的页面,这些不在赘述,自己看自己的了.

首先我们有一个装饰页面,示例如下(main.ftl):

	<html>
	<head>
	    <title>JScud Develop:${page.title}</title>
	    ${page.head}
	</head>
	<body>
	${page.body}
	<br><br>
	From: ${base} by <@ww.text name="copyright"/>
	</body>
	</html>


我们可以看到,其中的标记都有page前缀,而不是直接使用body,title等,原因是这个FreeMarkerPageFilter只把page放到了FreeMarker的model中,如果你还是想遵循原来的习惯,那么自己继承一下FreeMarkerPageFilter即可,非常简单,然后把body,title,head放到model中即可.不过我觉得现在也挺好,省得变量太短和别的混淆.

SiteMesh的decorators.xml示例如下:

	<?xml version="1.0" encoding="ISO-8859-1"?>
	<decorators defaultdir="/decorators">
	    <decorator name="main" page="main.ftl">
	        <pattern>/*</pattern>
	    </decorator>
	</decorators>


我们还需要在web.xml中配置过滤器,在这个地方,我走了弯路,因为没有文档,结果没有注意到 ActionContexCleanUp 这个Filter,自己还自作聪明修改了一下FreeMarkerPageFilter,后来才发现ActionContexCleanUp这个Filter的作用,这都是没有仔细看源码(JavaDoc)的后果啊.

在不使用SiteMesh的时候,为了使用WebWork,我们只需要在web.xml配置FilterDispatcher一个过滤器即可,阅读一下FilterDispatcher的JavaDoc和源码,我们可以看到它调用了:
	finally 
	{
	           ActionContextCleanUp.cleanUp(req);;
	}

而且JavaDoc中也提到看ActionContextCleanUp的文档,那我们就去看吧(我没看所以...)

在ActionContextCleanUp中,有这样的代码:
	req.setAttribute(CLEANUP_PRESENT, Boolean.TRUE);;

如果FilterDispatcher检测到这个属性,就不会清除ActionContext中的内容了,而由ActionContextCleanUp后续的代码来清楚,保证了一系列的Filter访问正确的ActionContext.

文档中提到,如果用到SiteMesh的Filter,那么设置顺序是:

ActionContextCleanUp filter
SiteMesh filter
FilterDispatcher

所以最后我们的web.xml应该类似这样:
    <filter>
        <filter-name>ActionContextCleanUp</filter-name>
        <filter-class>com.opensymphony.webwork.dispatcher.ActionContextCleanUp</filter-class>
    </filter>

    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.webwork.sitemesh.FreeMarkerPageFilter</filter-class>
    </filter>

    <filter>
        <filter-name>webwork</filter-name>
        <filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>ActionContextCleanUp</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>webwork</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


发布程序,运行结果正常.在Action改变Locale,装饰页面也获取了正确的Locale,OK,大功告成...嘿嘿

BTW:如果你使用jsp做装饰页面,使用SiteMesh自己的PageFilter即可,不过也要配置ActionContextCleanUp哦.


BTW 2:
其实,我还想写一篇AJAX的,不过总是懒得写那...
文件上传的拦截器有些Bug,而且处理流程必须结合实际才行,所以也不想写了...


后补: ActionContexCleanUp 已经被修正为ActionContextCleanUp
0 请登录后投票
   发表时间:2005-09-07  
AJAX支持是Webwork2.2最大的亮点,我支持你写!
0 请登录后投票
   发表时间:2005-09-14  
在WebWork2.2中,还有很多的新特性,底层结构也发生了很大的变化,对AJAX的支持也是一个很大的亮点,对于我们使用WebWork的用户来说都是一个巨大的鼓舞.

期待更多的人加入到webwork的使用,开发,测试,讨论中来,呵呵.

投入越多,获得越多,只有努力争取,我们才能获得更多.

没有讲到的一些新特性:
AliasInterceptor
ScopeInterceptor
FileUploadInterceptor(增强)
datepicker
multiply submit button
SpringObjectFactory
......
......


阅读WebWork的源码,你会发现更多

如果你希望我对某个方面进行详细介绍,请联系我 我工作时间无法上msn,请原谅

邮件地址:
0 请登录后投票
   发表时间:2005-11-16  
scud 写道

BTW:如果你使用jsp做装饰页面,使用SiteMesh自己的PageFilter即可,不过也要配置ActionContextCleanUp哦.


你好,scud,大作拜读后,发现我昨天才做的sitemesh装饰页面是main.jsp,但是没有配置ActionContextCleanUp,现在页面运行正常,不知道我说得有没有错。:)
0 请登录后投票
   发表时间:2005-11-16  
建议阅读一下ActionContextCleanUp和FilterDispatcher的源码

如果是简单页面,可能无所谓,如果你的装饰页面用到webwork的功能,action里面的变量就有用了。

建议加上,等你有需要的时候可能就有用了 :)
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics