- 浏览: 79933 次
- 性别:
- 来自: 重庆
最新评论
-
禀圣含华:
怎么弄空格呢?___________然后我固定这些空格,怎么弄 ...
第18章. iText PDF 生成 -
super0555:
managed
第13章 Seam 应用程序框架 -
Javakeith:
代码呢?共享下代码呗!
第18章. iText PDF 生成 -
tonyshen277:
同感啊。还在做Win32下的开发,楼主所说的一个都不能少啊。
转自baidu wqqq 给软件开发初学者 -
kdboy:
的确,把人放在宇宙中去看,从上帝的眼中去看,人的确是非常渺小, ...
人生是什么
第6章 事件、拦截器和异常处理
为弥补上下文组件模式,有两个更深一层的基础概念,其增进了Seam应用程序极度松耦合的特色。第一个,是强壮的事件模式,通过JSF的捆绑表达式方法事件能被映射到事件侦听器。第二个,是注释和拦截器的普遍深入的使用,利用“横切”关系到实现业务逻辑的组件。
6.1. Seam 事件
Seam组件模式是用来开发事件驱动应用程序的,尤其在一个细粒度事件模式下能开发细粒度、松耦合组件。在Seam的事件中流行的几种类型,大部分我们已经看见过:
* JSF events——JSF事件
* jBPM transition events——jBPM转换事件
* Seam page actions——Seam页面动作
* Seam component-driven events——Seam组件驱动事件
* Seam contextual events——Seam上下文事件
所有这些各种类型的事件通过捆绑表达式的JSF EL方法映射到Seam组件。对一个JFS事件,它是被定义在JSF模板:
<h:commandButton value="Click me!" action="#{helloWorld.sayHello}"/>
对一个jBPM转换事件,它是被定义在jBPM处理定义或页面流定义:
<start-page name="hello" view-id="/hello.jsp">
<transition to="hello">
<action expression="#{helloWorld.sayHello}"/>
</transition>
</start-page>
在另处,你能找到有关JSF事件和jBPM事件信息。现在让我们专心于Seam的两个额外的事件定义类型。
6.2. 页面动作
一个Seam页面动作是一个事件,它发生在我们渲染一个页面前。我们在WEB-INF/pages.xml中声明页面动作。我们能为任意一个特殊的JSF视窗id定义一个页面动作:
<pages>
<page view-id="/hello.jsp" action="#{helloWorld.sayHello}"/>
</pages>
或者我们能使用*通配符作为一个视窗id的后缀指定一个动作,其应用到所有相匹配模式的视窗id :
<pages>
<page view-id="/hello/*" action="#{helloWorld.sayHello}"/>
</pages>
如果多通配符页面动作匹配当前视窗id,Seam会调用所有动作,以最少细节到最多细节的顺序方式。
一个页面动作方法能返回一个JSF结果。如果结果是非空,Seam会使用定义的导航控制导航到一个视窗。
此外,在<page>元素提及的视窗id不必符合一个真的JSP或Facelets页面!所以,我们能再现一个传统的面向动作框架如Struts 或 WebWork使用页面动作的功能。例如:
TODO:转化struts动作成页面动作
这是十分有用的,如果你想响应非页面请求做复杂的事情(如,HTTP GET请求)
多个或条件页面动作可能使用<action>标签指定:
<pages>
<page view-id="/hello.jsp">
<action execute="#{helloWorld.sayHello}" if="#{not validation.failed}"/>
<action execute="#{hitCount.increment}"/>
</page>
</pages>
6.3. 页面参数
一个JSF faces请求(一个表单提交)封装了一个“动作“(捆绑方法)和一个“参数”(捆绑输入值)。一个动作也可以需要参数。
因为GET请求是可标记的,页面参数作为人可读的参数被传递(不象JSF表单输入,其根本不是的)
你能使用页面带有或不带有动作方法的参数。
6.3.1. 映射请求参数到模型
Seam允许我们提供一个捆绑值,映射一个命名请求参数到一个模型对象的一个属性。
<pages>
<page view-id="/hello.jsp" action="#{helloWorld.sayHello}">
<param name="firstName" value="#{person.firstName}"/>
<param name="lastName" value="#{person.lastName}"/>
</page>
</pages>
<param>声明是双向的,就象一个JSF输入的一个捆绑值。
* 当一个对视窗id的非faces(GET)请求发生,在执行适当类型的对话后,Seam设置命名请求参数的值进入模型对象。
* 任何<s:link>或<s:button>明显包括请求参数。在渲染解析期间(当<s:link>被渲染)求得捆绑值决定参数的值。
* 对视窗id的任何带有一个<redirect/>的导航控制,明显包括请求参数。在调用应用程序结束时求得捆绑值决定参数的值。
*对有给定视窗id的页面,值用任何JSF表单提交被明显传播。
所有这些后面的本质是无论如何我们从任何其它页面达到/hello.jsp(或者从/hello.jsp返回到/hello.jsp),模型属性的值引用了捆绑记忆的值,不需要一个对话(或者其它的服务边状态)。
6.4. 传播请求参数
如果仅仅命名属性被指定,则使用PAGE上下文传播请求参数(模型属性不被映射)
<pages>
<page view-id="/hello.jsp" action="#{helloWorld.sayHello}">
<param name="firstName" />
<param name="lastName" />
</page>
</pages>
页面参数传播尤其有用,如果你想构建多层详细控制CRUD 页面。你能用它来记着你先前察看的内容(如,按了Save按钮),和你已编辑过的实体。
* 任何<s:link>或<s:button>明显包括请求参数,如果那些参数被列表作为一个视窗的页面参数。
*对有给定视窗id的页面,值用任何JSF表单提交被明显传播(这意味着视窗参数的行为象对faces请求的PAGE范围上下文变量)。
这所有听起来相当复杂,并且你可能疑惑一个外部结构是否真值得去努力。实事上,一旦你“得到它”,想法就十分自然了。花时间理解这些东西显然是值得的。页面参数是越过一个非faces请求传播状态的相当优雅的方法。对于象用可标记结果页面来搜索屏幕这种难题,它们是特别“酷”的,在那儿我们愿意使用同样的代码书写我们的应用程序代码处理POST 和 GET请求。页面参数排除了在视窗定义的重复请求参数例表,并且使编码重定向更容易。
6.5. 转换和校验
你能为复杂的模型属性指定一个JSF转换器:
<pages>
<page view-id="/calculator.jsp" action="#{calculator.calculate}">
<param name="x" value="#{calculator.lhs}"/>
<param name="y" value="#{calculator.rhs}"/>
<param name="op" converterId="com.my.calculator.OperatorConverter"
value="#{calculator.op}"/>
</page>
</pages>
做为选择:
<pages>
<page view-id="/calculator.jsp" action="#{calculator.calculate}">
<param name="x" value="#{calculator.lhs}"/>
<param name="y" value="#{calculator.rhs}"/>
<param name="op" converter="#{operatorConverter}" value="#{calculator.op}"/>
</page>
</pages>
JSF 校验器,required="true"也可以被使用:
<pages>
<page view-id="/blog.xhtml">
<param name="date"
value="#{blog.date}"
validatorId="com.my.blog.PastDate"
required="true"/>
</page>
</pages>
做为选择:
<pages>
<page view-id="/blog.xhtml">
<param name="date"
value="#{blog.date}"
validator="#{pastDateValidator}"
required="true"/>
</page>
</pages>
甚至更好,基于模型的Hibernate 校验器注释是被自动识别和校验的。当类型转换或校验失败,一个全局的FacesMessage被增加到FacesContext。
6.6. 导航
在一个Seam应用程序中你能在faces-config.xml文件定义标准的导航控制。
可是,JSF导航控制有大量的讨厌的限制:
* 当重定向时,使用指定请求参数是不可能的。
* 从一个控制开始或结束对话是不可能的。
* 控制通过求得的动作方法的返回值工作;求得一个任意的EL表达式是不可能的。
深一层的问题是在pages.xml和faces-config.xml中"安排"逻辑变得松散。统一逻辑在pages.xml是最好的:
<navigation-rule>
<from-view-id>/editDocument.xhtml</from-view-id>
<navigation-case>
<from-action>#{documentEditor.update}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/viewDocument.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
能象下面这样被重写:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<rule if-outcome="success">
<redirect view-id="/viewDocument.xhtml"/>
</rule>
</navigation>
</page>
如果我们没有用字符值返回值(JSF结果)弄脏我们的文体编辑器组件是更好的。这样,Seam让我们写:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}"
evaluate="#{documentEditor.errors.size}">
<rule if-outcome="0">
<redirect view-id="/viewDocument.xhtml"/>
</rule>
</navigation>
</page>
或者,甚至:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<rule if="#{documentEditor.errors.empty}">
<redirect view-id="/viewDocument.xhtml"/>
</rule>
</navigation>
</page>
第一个形式求得一个捆绑值决定子控制使用的结果值。第二个方法忽略结果并为每一个可能的控制求得一个捆绑值。
当然,当一个更新成功,我们或许想结束当前对话。我们象这样做:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<rule if="#{documentEditor.errors.empty}">
<end-conversation/>
<redirect view-id="/viewDocument.xhtml"/>
</rule>
</navigation>
</page>
当我们结束对话,所有的子请求并不知道我们感兴趣的文档。我们能传递文档id作为一个参数,其也产生视图书签:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<rule if="#{documentEditor.errors.empty}">
<end-conversation/>
<redirect view-id="/viewDocument.xhtml">
<param name="documentId" value="#{documentEditor.documentId}"/>
</redirect>
</rule>
</navigation>
</page>
在JSF中空结果是一个特殊情况。空结果被解释为意谓“重新显示这页”。下列导航控制匹配所有非空结果,但不是空结果:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<rule>
<render view-id="/viewDocument.xhtml"/>
</rule>
</navigation>
</page>
如果当一个空结果发生,你想处理导航,使用下列格式:
<page view-id="/editDocument.xhtml">
<navigation from-action="#{documentEditor.update}">
<render view-id="/viewDocument.xhtml"/>
</navigation>
</page>
视窗id 可能用一个EL表达式给出:
<page view-id="/editDocument.xhtml">
<navigation>
<rule if-outcome="success">
<redirect view-id="/#{userAgent}/displayDocument.xhtml"/>
</rule>
</navigation>
</page>
6.7.处理导航、页面动作和参数的细粒度文件
如果你有大量不同的页面动作和页面参数,或者甚至只有大量的导航控制,你可能的确想分割声明成多个文件。你能在一个资源名calc/calculator.page.xml的文件中为一个视窗id /calc/calculator.jsp页面定义动作和参数。在这种情况下,根元素是<page>元素,并且视窗id是暗藏的:
<page action="#{calculator.calculate}">
<param name="x" value="#{calculator.lhs}"/>
<param name="y" value="#{calculator.rhs}"/>
<param name="op" converter="#{operatorConverter}" value="#{calculator.op}"/>
</page>
6.8. 组件驱动事件
Seam组件通过简单地调用彼此的方法就能相互作用。有状态组件甚至能实现观察者/可观察模式。但是,当组件直接调用彼此的方法时,为了能使组件尽可能以松藕合地方法相互作用,
Seam提供了组件驱动事件。
我们指定事件侦听器(观察者)在components.xml.文件中。
<components>
<event type="hello">
<action execute="#{helloListener.sayHelloBack}"/>
<action execute="#{logger.logHello}"/>
</event>
</components>
事件类型只是一个任意的字符串。
当一个事件发生,为那个事件注册的动作将会按在components.xml出现的顺序被调用。组件怎么激活一个事件?Seam为这个提供了一个内建的组件。
@Name("helloWorld")
public class HelloWorld {
public void sayHello() {
FacesMessages.instance().add("Hello World!");
Events.instance().raiseEvent("hello");
}
}
或者你能用一个注释。
@Name("helloWorld")
public class HelloWorld {
@RaiseEvent("hello")
public void sayHello() {
FacesMessages.instance().add("Hello World!");
}
}
注意,那个事件产生者不依赖事件消费者。事件侦听器现在可以完全实现与产生者无关:
@Name("helloListener")
public class HelloListener {
public void sayHelloBack() {
FacesMessages.instance().add("Hello to you too!");
}
}
在上面定义在components.xml文件中的捆绑方法照顾了映射事件到消费者。如果你不喜欢混在components.xml文件中,你能使用一个注释代替:
@Name("helloListener")
public class HelloListener {
@Observer("hello")
public void sayHelloBack() {
FacesMessages.instance().add("Hello to you too!");
}
}
你可能惊奇在这个讨论中没有提及任何有关事件对象事。在Seam中,不需要有事件对象在事件产生者和侦听器之间传播状态。状态被维持在Seam上下文中,并被组件共享。然而,如果你真想传一个事件对象,你能:
@Name("helloWorld")
public class HelloWorld {
private String name;
public void sayHello() {
FacesMessages.instance().add("Hello World, my name is #0.", name);
Events.instance().raiseEvent("hello", name);
}
}
@Name("helloListener")
public class HelloListener {
@Observer("hello")
public void sayHelloBack(String name) {
FacesMessages.instance().add("Hello #0!", name);
}
}
6.9. 上下文事件
Seam定义了许多内建事件,应用程序能用它来处理特殊类型的框架集成。事件有:
* org.jboss.seam.validationFailed — 当JSF校验失败的时候调用
* org.jboss.seam.noConversation —没有一个长运行对话和一个长运行对话是必需的时候调用
* org.jboss.seam.preSetVariable.<name> — 当上下文变量<name>被设置的时候调用
* org.jboss.seam.postSetVariable.<name> —当上下文变量<name>被设置的时候调用
* org.jboss.seam.preRemoveVariable.<name> —当上下文变量<name>被不安装的时候调用
* org.jboss.seam.postRemoveVariable.<name> —当上下文变量<name>被不安装的时候调用
* org.jboss.seam.preDestroyContext.<SCOPE> — 在 <SCOPE>上下文被摧毁前调用
* org.jboss.seam.postDestroyContext.<SCOPE> —在 <SCOPE>上下文被摧毁后调用
* org.jboss.seam.beginConversation — 每当一个长运行对话开始时调用
* org.jboss.seam.endConversation —每当一个长运行对话结束时调用
* org.jboss.seam.conversationTimeout—当一个对话中止联接发生时调用。对话id作为一个参数被传递。
* org.jboss.seam.beginPageflow —当一个页面流开始时调用
* org.jboss.seam.beginPageflow.<name> — 当一个页面流 <name> 开始时调用
* org.jboss.seam.endPageflow —当一个页面流结束时调用
* org.jboss.seam.endPageflow.<name> —当一个页面流 <name> 结束时调用
* org.jboss.seam.createProcess.<name> — 当进程<name>被创建时调用
* org.jboss.seam.endProcess.<name> — 当进程<name>结束时
* org.jboss.seam.initProcess.<name> —当进程<name>关联到对话时调用
* org.jboss.seam.initTask.<name> —当任务<name>关联到对话时调用
* org.jboss.seam.startTask.<name> — 当一个任务<name> 启动时调用
* org.jboss.seam.endTask.<name> —当一个任务<name> 结束时调用
* org.jboss.seam.postCreate.<name> — 当组件<name>被创建时调用
* org.jboss.seam.preDestroy.<name> —当组件<name>被摧毁时调用
* org.jboss.seam.beforePhase — 在一个JSF阶段开始之前调用
* org.jboss.seam.afterPhase —在一个JSF阶段结束之后调用
* org.jboss.seam.postInitialization —在Seam初始化和启动所有组件时调用
* org.jboss.seam.postAuthenticate.<name> — 在一个用户被验证之后调用
* org.jboss.seam.preAuthenticate.<name> — 在企图验证一个用户前调用
* org.jboss.seam.notLoggedIn — 没有验证用户和验证是必要的时候调用
* org.jboss.seam.rememberMe —当Seam安全侦听到用户名在一个cookie中时发生
* org.jboss.seam.exceptionHandled.<type> — 当一个未捕获异常被Seam处理时调用
* org.jboss.seam.exceptionHandled —当一个未捕获异常被Seam处理时调用
* org.jboss.seam.exceptionNotHandled —当一个未捕获异常没有处理时调用
* org.jboss.seam.afterTransactionSuccess — 在Seam应用框架中事务取得成功时调用
* org.jboss.seam.afterTransactionSuccess.<name> —在Seam应用框架中管理一个<name>实例事务取得成功时调用
Seam组件能观察这些事件的任何一个,仅用同样的方法他们能观察任何其它组件驱动事件。
6.10. Seam拦截器
EJB 3.0为会话bean引入一个标准的拦截器模型。为给一个bean增加一个拦截器,你需要写带一个注释@AroundInvoke方法的类,和注释一个带@Interceptors注释指定拦截器类的名字的bean。例如,下面的拦截器检查用户被注册了,才允许调用一个动作侦听器方法:
public class LoggedInInterceptor {
@AroundInvoke
public Object checkLoggedIn(InvocationContext invocation) throws Exception {
boolean isLoggedIn = Contexts.getSessionContext().get("loggedIn")!=null;
if (isLoggedIn) {
//the user is already logged in
return invocation.proceed();
}
else {
//the user is not logged in, fwd to login page
return "login";
}
}
}
为应用这个拦截器到一个其行为如一个动作侦听器的会话bean,我们必须注释会话bean为@Interceptors(LoggedInInterceptor.class)。 这是一个有些丑陋的注释。Seam用EJB3构建拦截器框架,允许你对类级使用@Interceptors作为一个元注释 (那些有注释的@Target(TYPE))。在我们的例子中,我们会创建一个 @LoggedIn注释,如下列:
@Target(TYPE)
@Retention(RUNTIME)
@Interceptors(LoggedInInterceptor.class)
public @interface LoggedIn {}
现在我们能简单注释我们的动作侦听器bean来应用拦截器,用@LoggedIn注释。
@Stateless
@Name("changePasswordAction")
@LoggedIn
@Interceptors(SeamInterceptor.class)
public class ChangePasswordAction implements ChangePassword {
...
public String changePassword() { ... }
}
如果拦截器的顺序重要(通常是),你能增加@Interceptor注释到你的拦截器类,指定一个偏爱的拦截器顺序。
@Interceptor(around={BijectionInterceptor.class,
ValidationInterceptor.class,
ConversationInterceptor.class},
within=RemoveInterceptor.class)
public class LoggedInInterceptor
{
...
}
你甚至能有一个“客户边”拦截器,运行在EJB3的内建功能的任何一个的周围:
@Interceptor(type=CLIENT)
public class LoggedInInterceptor
{
...
}
EJB拦截器是有状态的,有一个如它们拦截的组件一样的生命周期。因为拦截器不需要维持状态,Seam能通过指定@Interceptor(stateless=true)让你获得一个性能优化。
大部分Seam 功能作为一组内建的Seam 拦截器被实现,包括在前面例子中指定的拦截器。你不必通过注释你的组件明确指定这些拦截器;它们对所有可拦截的Seam 组件都存在。你甚至能对JavaBean组件使用Seam拦截器,不仅是EJB3 baen!EJB不仅仅对商业方法(使用@AroundInvoke)定义拦截器,而且也对生命周期方法@PostConstruct, @PreDestroy, @PrePassivate and @PostActive定义。Seam不仅仅支持EJB3 bean组件和拦截器的所有这些生命周期方法,而且也支持JavaBean组件(除@PreDestroy,其不是一个专为JavaBean组件的)
6.11. 管理异常
当JSF达到异常处理时,其令人吃惊地被限制。作为对这个问题的一个局部工作区,Seam让你通过注释异常类来定义一个特殊的异常类如何被处理,或者在XML 文件中声明异常类。这种方法意谓着与EJB 3.0标准 @ApplicationException注释相结合,指定是否异常会引起一个事务回滚。
6.11.1. 异常和事务
EJB指定细粒度控制,当bean的一个商业方法抛出异常时,让我们控制是否一个异常立即标记当前事务为回滚:系统异常总是引起一个事务回滚,缺省时应用程序异常不会引起一个回滚,除非你使用了@ApplicationException(rollback=true)(一个应用程序异常是任一的受检异常,或者被@ApplicationException注释的任一的非受检异常。一个系统异常是没有被@ApplicationException注释的任一的非受检异常)。
注意标记一个事务为回滚和确实回滚事务是有区别的。一个异常控制只是说事务被标记为回滚,除非在异常被抛出后事务可能仍然是活动的。
对Seam JavaBean组件Seam也应用EJB3.0异常回滚控制。
但是这些控制仅应用在Seam组件层。一个异常没有被捕获并在Seam组件层外和JSF层外传播又怎样呢?确实,丢下一个悬而未定的开着的事务总是错误的,所以,当一个异常发生并没有被Seam组件层捕获时,Seam回滚任何活动的事务。
6.11.2. 使Seam 异常处理运作
为使Seam 异常处理运作,我们需要确信我们在web.xml文件中声明了servlet过滤器:
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>*.seam</url-pattern>
</filter-mapping>
如果你想要异常处理被激活,你需要在在web.xml中不用Facelets开发模式和在components.xml不用Seam调试模式。
6.11.3. 使用注释对异常处理
只要异常传播在Seam组件层外,下面的异常会导致HTTP 404错误。当异常抛出时它不会马上回滚当前事务,如果异常没有被其它Seam组件捕获,事务才会被回滚。
@HttpError(errorCode=404)
public class ApplicationException extends Exception { ... }
只要异常传播在Seam组件层外,这个异常会导致浏览器重定向。它也结束当前对话。它马上引起当前事务回滚。
@Redirect(viewId="/failure.xhtml", end=true)
@ApplicationException(rollback=true)
public class UnrecoverableApplicationException extends RuntimeException { ... }
注意,@Redirect不为在JSF生命周期的渲染阶段发生的异常工作。
你也能用EL指定的重定向的视窗id
异常导致一个重定向,同时发一个消息给用户,当它传播在Seam组件层外时。它也马上回滚当前事务
@Redirect(viewId="/error.xhtml", message="Unexpected error")
public class SystemException extends RuntimeException { ... }
6.11.4. 使用XML对异常处理
因为我们不能增加注释到我们感兴趣的所有异常类,Seam也让我们用pages.xml指定这些功能 。
<pages>
<exception class="javax.persistence.EntityNotFoundException">
<http-error error-code="404"/>
</exception>
<exception class="javax.persistence.PersistenceException">
<end-conversation/>
<redirect view-id="/error.xhtml">
<message>Database access failed</message>
</redirect>
</exception>
<exception>
<end-conversation/>
<redirect view-id="/error.xhtml">
<message>Unexpected failure</message>
</redirect>
</exception>
</pages>
最后的<exception>声明没有指定一个类,并且对没有另外通过注释或在指定pages.xml处理的所有异常全捕获。
你也能使用EL指定重定向视窗id.
你也能通过EL访问处理异常实例,Seam放它在对话上下文中,例如访问异常信息。
...
throw new AuthorizationException("You are not allowed to do this!");
<pages>
<exception class="org.jboss.seam.security.AuthorizationException">
<end-conversation/>
<redirect view-id="/error.xhtml">
<message severity="WARN">#{org.jboss.seam.handledException.message}</message>
</redirect>
</exception>
</pages>
org.jboss.seam.handledException拥有被一个异常处理者实际处理的嵌套异常。最外面(包裹者)异常也是可用的,作为org.jboss.seam.caughtException。
6.11.4.1.抑制异常日志操作
对定义在pages.xml中的异常操作者,声明个在哪个异常会被日志的日志级是可能的,或者甚至完全地抑制异常被日志操作。属性日志和日志级能被用来控制异常的日志操作。通过设置log="false"作为下列每一个例子,那么当指定异常产生时没有日志消息会被产生:
<exception class="org.jboss.seam.security.NotLoggedInException" log="false">
<redirect view-id="/register.xhtml">
<message severity="warn">You must be a member to use this feature</message>
</redirect>
</exception>
如果日志属性没有被指定,那么缺省为true(也就是异常会被日志)。
做为选择,你能指定日志级来控制在哪个日志级异常会被日志操作:
<exception class="org.jboss.seam.security.NotLoggedInException" logLevel="info">
<redirect view-id="/register.xhtml">
<message severity="warn">You must be a member to use this feature</message>
</redirect>
</exception>
logLevel 可访问的值有:fatal, error, warn, info, debug 或 trace。如果日志级没有指定,或者如果无效的值被设置,那么它为设为缺省值为error。
6.11.5.一些普通异常
如果正使用JPA:
<exception class="javax.persistence.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message>Not found</message>
</redirect>
</exception>
<exception class="javax.persistence.OptimisticLockException">
<end-conversation/>
<redirect view-id="/error.xhtml">
<message>Another user changed the same data, please try again</message>
</redirect>
</exception>
如果你正在使用Seam应用程序框架:
<exception class="org.jboss.seam.framework.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message>Not found</message>
</redirect>
</exception>
如果你正在使用Seam安全:
<exception class="org.jboss.seam.security.AuthorizationException">
<redirect>
<message>You don't have permission to do this</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.NotLoggedInException">
<redirect view-id="/login.xhtml">
发表评论
-
第31章. Seam内建组件
2009-05-28 11:51 1462第31章. Seam内建组件 本章描述Seam内建组件 ... -
第30章. Seam注释
2009-05-26 20:21 1597第30章. Seam注释 在你编写一个Seam应用程 ... -
第31章. Seam内建组件
2009-05-26 20:21 1424第31章. Seam内建组件 本章描述Seam内建组件 ... -
第29章. 配置Seam和打包Seam应用程序
2009-05-26 20:19 1540第29章. 配置Seam和打包Seam应用程序 配置 ... -
第28章. Hibernate搜索
2009-05-26 20:17 152028.1. 介绍 如Apache Lucen ... -
第27章. Spring框架集成
2009-05-26 20:16 1398第27章. Spring框架集成 Spring集成 ... -
第26章. Seam和Google网页工具
2009-05-26 20:15 1216第26章. Seam和Google网页工具 ... -
第25章. 远程
2009-05-26 20:15 1269第25章. 远程 Seam 提供了一个从网页远程访 ... -
第24章. Web服务
2009-05-26 20:15 1677第24章. Web服务 Seam 集成了JBossWS, ... -
第23章. 缓存
2009-05-26 20:14 1416第23章. 缓存 在 ... -
第22章. 异步和消息
2009-05-26 20:12 2125第22章. 异步和消息 Seam 使异步执行来自网页请 ... -
第21章. Email
2009-05-26 20:11 1311现在Seam包含一个用于模板和发送邮件的可选组件。 Emai ... -
第 20章. RSS支持
2009-05-26 20:10 820第 20章. RSS支持 20.1. 安装 20.2. ... -
第19章. 微软的Excel 电子表格应用程序支持
2009-05-26 20:07 1822第19章. 微软的Excel 电子表格应用程序支持 S ... -
第18章. iText PDF 生成
2009-05-26 20:01 6474第18章. iText PDF 生成 18.1. 使用PDF ... -
第17章. Seam文本
2009-05-26 19:59 1024第17章. Seam文本 面向协作站点需要一种更有友好的 ... -
第16章. 国际化、本地化和主题
2009-05-26 19:57 1388第16章. 国际化、本地化和主题 Seam使构建国际化应用程 ... -
第15章 安全(2)
2009-05-26 19:56 932第15章 安全(2) 15.5. 错误消息 安全 ... -
第15章 安全(1)
2009-05-26 19:53 98215.1. 概述 Seam安全API为你基于Seam的 ... -
第14章 Seam 和 JBoss 规则
2009-05-26 19:50 1431第14章 Seam 和 JBoss 规则 Seam使从 ...
相关推荐
6. **第六章:动态方法调用(Dynamic Method Invocation,DMI)** - 动态方法调用的含义和应用场景 - 如何配置和使用DMI,处理动态Action方法的调用 7. **第七章:Struts 2标签库** - Struts 2提供的丰富标签库,...
完整版 Java开发实训课程系列-SpringMVC框架技术教程 第6章 异常处理 (共12页).pptx 完整版 Java开发实训课程系列-SpringMVC框架技术教程 第7章 文件上传和json数据交互 (共30页).pptx 完整版 Java开发实训课程...
以上只是对Struts2权威指南第六章6.1、6.3、6.4三个部分的基础介绍,实际应用中涉及的知识点更为广泛。例如,ActionContext的理解与使用,它封装了请求、session、应用上下文等信息;还有OGNL(Object-Graph ...
6. **异常处理(Exception Handling)**:Struts2提供了一套优雅的异常处理机制,包括全局异常映射和动作级别的异常处理。这部分可能详细阐述如何配置和实现自定义的异常处理器。 7. **国际化...
在第6章的源码中,开发者可能会看到如何创建Action类、配置Action、定义结果类型、使用拦截器以及如何与视图层进行交互的示例。通过深入研究这些源码,你可以更好地理解Struts2框架的内部工作机制,提升你的Web开发...
本章可能深入解析拦截器的工作原理,以及如何自定义和配置拦截器链。 3. **结果类型(Result Types):** 结果类型决定了Action执行后如何呈现结果。默认的结果类型如“dispatcher”用于转发到JSP页面,而“stream...
4. **异常处理**:Struts2提供了一套完善的异常处理机制,包括全局和局部的异常映射。这部分可能会介绍如何处理和显示应用程序中的错误和异常。 5. **国际化与本地化**:Struts2支持多语言环境,通过资源包...
在本项目"struts第5章"中,我们探讨的是Struts框架的高级特性和应用场景,这通常涉及到MVC(Model-View-Controller)设计模式的深入应用、Action类的定制、国际化与本地化处理、异常处理、以及与数据库的交互等方面...
2. **异常处理**:Struts 2提供了一种优雅的异常处理机制,可能包括如何配置全局异常映射,以及自定义错误页面。 3. **文件上传与下载**:Struts 2支持处理文件上传请求,这一章可能详细介绍了如何实现文件上传功能...
综上所述,"Struts2权威指南第6章第6.2节"主要涵盖了Struts2框架中动作的配置、参数传递、结果类型、拦截器、数据绑定等方面的知识,这些都是构建高效、可维护的Struts2应用的基础。通过深入理解和实践这些概念,...
6. **异常处理**:Struts2提供了一种优雅的方式来捕获和处理应用程序中的异常,避免了在每个Action中编写相同的异常处理代码。 7. **模型驱动(ModelDriven)**:这是一种Action模式,它自动将请求参数绑定到一个...
7. ** strut2的异常处理**:Struts2提供了一套全面的异常处理机制,包括全局和局部的异常映射,以优雅地处理运行时错误。 8. **插件和第三方扩展**:Struts2拥有丰富的插件库,如Tiles、Freemarker、i18n等,用于...
6. **异常处理**:Struts2提供了一套完整的异常处理机制,包括全局和局部异常映射。这部分内容可能涵盖如何处理程序中的异常并优雅地向用户展示错误信息。 7. **国际化(Internationalization, i18n)**:Struts2...
它在Struts1的基础上进行了大量的改进和增强,提供了更强大的控制结构、更好的异常处理机制以及更丰富的插件支持。第7章通常会涵盖Struts2框架的核心概念、配置和实际应用开发中的关键点。 在"Struts2.1权威指南...
第13章通常会涵盖特定的主题,可能是框架的某个关键部分,如拦截器、结果类型、插件机制、国际化或异常处理。 1. **拦截器(Interceptors)**:Struts2的核心特性之一是其强大的拦截器机制,它们允许开发者定义和实现...
6. **错误和异常处理**:Struts2允许自定义错误页面和异常处理策略,提升用户体验。这一章可能会讲解如何配置全局和局部的异常映射,以及如何处理自定义的业务异常。 7. **文件上传与下载**:Struts2提供了处理文件...
9. **Struts2的异常处理**:Struts2提供了全局异常处理机制,可以捕获和处理Action执行过程中的所有异常。 10. **表单验证**:Struts2支持基于注解和XML的表单验证,可以对用户输入的数据进行有效性检查。 在第13...
第六章的源代码可能包含了以上知识点对应的示例,通过实际运行和调试这些代码,读者可以更好地掌握Struts2.1的用法和最佳实践。每个子文件可能对应一个特定的示例或概念,例如,一个Action类用于演示业务逻辑,一个...
8. **异常处理**:Struts2提供了一套完善的异常处理机制,包括全局异常配置和Action级别的异常处理。第21章可能会讲解如何捕获和处理异常。 9. **国际化(i18n)**:Struts2支持多语言环境,源码可能包含了资源文件...
10. **异常处理**:Struts2允许自定义异常处理策略,包括全局和Action级别的异常处理器。源码可能涵盖了异常捕获和处理的实现。 通过对第20章源码的学习,开发者能更深入地理解Struts2的工作原理,提高Web应用开发...