第三章 使用Struts 2 Action
3.1 Struts 2 Action简介
Action 的作用:
- Action封装工作单元,或者至少是业务逻辑的入口点(如果业务逻辑很复杂,我们可能会把业务逻辑构建成一个业务组件,再把这个业务组件注入到Action中去)。
- Action为数据转移提供场所,Action只需把每一个期望承载的数据实现为JavaBean属性。除了这些简单的JavaBean属性,还有两种技术可以把Action作为数据转移对象使用(后续会讲到)。
- Action为结果路由选择返回控制字符串。
3.2 打包Action
1. Struts 2的包提供了一种继承机制,让你能够继承框架已经定义的组件。
<package name="packageName" namespace="/packageNamespace" extends="struts-default">
2. 可以为多个不同的包设置相同的命名空间。
3. 如果不设置namespace属性,你的Action就会进入默认命名空间。默认命名空间在所有其他的命名空间之下,用来解决不能与任何显示声明的命名空间匹配的请求。默认命名空间实际上是空字符串” ”。
4. 你也可以定义叫做”/”的根命名空间。根命名空间和其他显示声明的命名空间相同,必须被完全匹配。
5. 大部分智能默认值定义在系统内建的一个叫做struts-default的包中。虽然当你创建自定义的包时不是一定要扩展struts-default,但是省略了继承就等于拒绝了框架的核心功能。
3.3 实现Action
ActionSupport类。它是一个提供了Action接口和其他几个有用接口的默认实现的便利类,提供了诸如数据验证、错误消息本地化等功能。数据验证和文本本地化服务是通过拦截器和接口的协作实现的。拦截器控制服务的执行,Action实现接口提供被拦截器调用的方法。
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { //.... }
1.基本验证
在默认的拦截器栈中我们可以看到params拦截器在workflow拦截器之前定义。params拦截器将请求数据转移到Action对象上。之后,workflow拦截器在这些数据被模型接受之前验证这些数据。
workflow拦截器称为工作流拦截器,因为如果验证出错,它会把请求工作流重新定向到输入页面。
注意:workflow拦截器必须在params拦截器将数据从请求转移到Action对象之后触发。
当workflow拦截器触发时,它首先会在Action上查找要调用的validate()方法。你会把验证逻辑放在validate()方法中。这个方法通过com.opensymphony.xwork2.Validateable公开出来。从技术上讲ActionSupport实现了validate()方法,你只需用特定的验证逻辑覆盖这个空方法。
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { /** * A default implementation that validates nothing. * Subclasses should override this method to provide validations. */ public void validate() { } }
注意validate()方法没有返回值,秘密在于验证过程生成的错误消息。在调用完validate()方法之后,workflow拦截器检查验证逻辑是否生成了错误消息。如果找到了错误消息,workflow拦截器会改变请求的工作流。它会立即终止请求处理,将用户带回到输入表单,并在表单中显示错误消息。
那么错误消息保存到哪里?workflow如何检查是否有错误消息被创建?
com.opensymphony.xwork2.ValidationAware接口定义了存储和获取错误消息的方法。
public interface ValidationAware { /** * Set the Collection of Action-level String error messages. * * @param errorMessages Collection of String error messages */ void setActionErrors(Collection<String> errorMessages); /** * Get the Collection of Action-level error messages for this action. Error messages should not * be added directly here, as implementations are free to return a new Collection or an * Unmodifiable Collection. * * @return Collection of String error messages */ Collection<String> getActionErrors(); /** * Set the Collection of Action-level String messages (not errors). * * @param messages Collection of String messages (not errors). */ void setActionMessages(Collection<String> messages); /** * Get the Collection of Action-level messages for this action. Messages should not be added * directly here, as implementations are free to return a new Collection or an Unmodifiable * Collection. * * @return Collection of String messages */ Collection<String> getActionMessages(); /** * Set the field error map of fieldname (String) to Collection of String error messages. * * @param errorMap field error map */ void setFieldErrors(Map<String, List<String>> errorMap); /** * Get the field specific errors associated with this action. Error messages should not be added * directly here, as implementations are free to return a new Collection or an Unmodifiable * Collection. * * @return Map with errors mapped from fieldname (String) to Collection of String error messages */ Map<String, List<String>> getFieldErrors(); /** * Add an Action-level error message to this Action. * * @param anErrorMessage the error message */ void addActionError(String anErrorMessage); /** * Add an Action-level message to this Action. * * @param aMessage the message */ void addActionMessage(String aMessage); /** * Add an error message for a given field. * * @param fieldName name of field * @param errorMessage the error message */ void addFieldError(String fieldName, String errorMessage); /** * Check whether there are any Action-level error messages. * * @return true if any Action-level error messages have been registered */ boolean hasActionErrors(); /** * Checks whether there are any Action-level messages. * * @return true if any Action-level messages have been registered */ boolean hasActionMessages(); /** * Checks whether there are any action errors or field errors. * <p/> * <b>Note</b>: that this does not have the same meaning as in WW 1.x. * * @return <code>(hasActionErrors() || hasFieldErrors())</code> */ boolean hasErrors(); /** * Check whether there are any field errors associated with this action. * * @return whether there are any field errors */ boolean hasFieldErrors(); }
实现这个重要接口的类必须为每一个可以验证的字段维护一系列错误消息和一系列与action整体相关的通用错误消息。幸运的是ActionSupport替我们做到了这一点。为了使用它们,我们只需调用下面两个方法。
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { //.... public void addActionError(String anErrorMessage) { validationAware.addActionError(anErrorMessage); } public void addFieldError(String fieldName, String errorMessage) { validationAware.addFieldError(fieldName, errorMessage); } //.... }
2.使用资源包处理文本消息
最佳实践是将字符串消息集中放入外部可维护的资源包中。ActionSupport提供了内建的功能可以轻松地管理。ActionSupport实现了两个接口,它们协作提供了本地化消息文本功能。第一个接口com.opensymphony.xwork2.TextProvider提供了对这些消息的访问。这个接口提供了一系列灵活的方法,使用这些方法可以从资源包中取得消息。
public interface TextProvider { /** * Checks if a message key exists. * * @param key message key to check for * @return boolean true if key exists, false otherwise. */ boolean hasKey(String key); /** * Gets a message based on a message key, or null if no message is found. * * @param key the resource bundle key that is to be searched for * @return the message as found in the resource bundle, or null if none is found. */ String getText(String key); /** * Gets a message based on a key, or, if the message is not found, a supplied * default value is returned. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue); /** * Gets a message based on a key using the supplied obj, as defined in * {@link java.text.MessageFormat}, or, if the message is not found, a supplied * default value is returned. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @param obj obj to be used in a {@link java.text.MessageFormat} message * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue, String obj); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or null if no message is found. * * @param key the resource bundle key that is to be searched for * @param args a list args to be used in a {@link java.text.MessageFormat} message * @return the message as found in the resource bundle, or null if none is found. */ String getText(String key, List<?> args); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or null if no message is found. * * @param key the resource bundle key that is to be searched for * @param args an array args to be used in a {@link java.text.MessageFormat} message * @return the message as found in the resource bundle, or null if none is found. */ String getText(String key, String[] args); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or, if the message is not found, a supplied * default value is returned. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @param args a list args to be used in a {@link java.text.MessageFormat} message * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue, List<?> args); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or, if the message is not found, a supplied * default value is returned. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @param args an array args to be used in a {@link java.text.MessageFormat} message * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue, String[] args); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or, if the message is not found, a supplied * default value is returned. Instead of using the value stack in the ActionContext * this version of the getText() method uses the provided value stack. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @param args a list args to be used in a {@link java.text.MessageFormat} message * @param stack the value stack to use for finding the text * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue, List<?> args, ValueStack stack); /** * Gets a message based on a key using the supplied args, as defined in * {@link java.text.MessageFormat}, or, if the message is not found, a supplied * default value is returned. Instead of using the value stack in the ActionContext * this version of the getText() method uses the provided value stack. * * @param key the resource bundle key that is to be searched for * @param defaultValue the default value which will be returned if no message is found * @param args an array args to be used in a {@link java.text.MessageFormat} message * @param stack the value stack to use for finding the text * @return the message as found in the resource bundle, or defaultValue if none is found */ String getText(String key, String defaultValue, String[] args, ValueStack stack); /** * Get the named bundle, such as "com/acme/Foo". * * @param bundleName the name of the resource bundle, such as <code>"com/acme/Foo"</code>. * @return the bundle */ ResourceBundle getTexts(String bundleName); /** * Get the resource bundle associated with the implementing class (usually an action). * * @return the bundle */ ResourceBundle getTexts(); }
ActionSupport实现了这些方法,使你可以通过关键字引用资源包中的对应的消息。
第二个接口com.opensymphony.xwork2.LocaleProvider只提供了一个方法getLocale()。
public interface LocaleProvider { /** * Gets the provided locale. * * @return the locale. */ Locale getLocale(); }
ActionSupport也为本地化消息文本提供了一个基本的国际化解决方案。ActionSupport实现了这个接口,根据浏览器发送来的地域设置取得用户所在的地域。
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { public Locale getLocale() { ActionContext ctx = ActionContext.getContext(); if (ctx != null) { return ctx.getLocale(); } else { if (LOG.isDebugEnabled()) { LOG.debug("Action context not initialized"); } return null; } } }
你还是用以前的方式取得消息文本。甚至我们还没有使用它的时候,ActionSupport的TextProvider实现已经开始在每次为我们取得文本消息的时候通过调用LocalProvider接口的getLocale()方法检查地域。使用得到的地域,TextProvider(也就是ActionSupport)会尝试为这个地域定位属性文件。
3.4 向Action传递数据
1. 前面的内容,Action把从请求接收到的所有数据放在简单的JavaBean属性上。另外还有两种方式来传递数据。
- 第一种选择也是基于JavaBean。可以公开一个复杂对象作为JavaBean属性,让数据直接传输到这个对象上。
- 另一种选择是使用被称为ModelDriven的Action。
2. 使用域对象做数据转移存在危险。如果请求中的参数与域对象属性匹配,那么数据会被移动到这些属性上。但是域对象可能会包含一些敏感数据(如ID),我们不想把它们公开给自动数据转移机制。这个问题现在并没有很好地解决方案。
3.5 案例研究:文件上传
fileUpload拦截器创建了我们之前看到过的数据自动转移机制的一种特别版本。在默认拦截器栈defaultStack中可以看到fileUpload拦截器在params拦截器之前。当fileUpload拦截器执行时,它处理一个多重请求(multipart request)并且将文件与其他一些元数据一起转换到请求参数中(params拦截器会自动将数据转移到Action上)。在后加工阶段fileUpload拦截器再次出发时,用来消除上传文件的临时版本。
相关推荐
**Struts2实战——《Struts2 In Action中文版》** 《Struts2 In Action》是一本专为Java开发者设计的实战指南,旨在深入解析Struts2框架的使用与实践。Struts2作为一款强大的MVC(Model-View-Controller)框架,极...
根据提供的信息,我们可以推断出这是一本关于Struts 2框架的书籍——《Struts 2实战 Struts 2 in action 的中文版》。本书主要介绍了Struts 2框架的相关概念、工作原理以及实际应用案例等内容。接下来,我们将根据...
《Struts 2实战 Struts2 in Action》这本书不仅介绍了Struts 2的基本概念和技术细节,更重要的是,它通过丰富的实战案例帮助读者深入理解框架的工作原理,并掌握了如何高效地利用Struts 2来解决实际问题。...
"Struts2 in Action" 是一本深入探讨Struts2框架的专业书籍,旨在帮助开发者掌握这一框架的核心概念和实践技巧。这本书的中文版不仅提供了理论知识,还附带有配套的源代码,方便读者进行实践操作,加深理解。 ...
总之,《Struts2技术内幕——深入解析Struts2架构设计与实现原理》配合《struts2基础.chm》,将帮助读者全面掌握Struts2的架构设计、核心组件、配置方式、插件使用以及源码解读,对于想要在Java Web领域深入发展的...
本文将深入探讨Struts2的核心概念,包括Action、Result、配置文件、OGNL与ValueStack、Tags以及项目中的关键实践。 **一、Action** Action是Struts2中处理业务逻辑的核心组件,它是实现了`...
通过阅读《Struts2 in action》这本书,你可以深入学习Struts2的各个方面,包括最佳实践、高级特性和案例分析,从而在实际项目中更加熟练地运用这个框架。无论你是初学者还是经验丰富的开发者,这本书都将为你的Java...
MVC设计模式是Struts2的核心概念之一。模型(Model)负责处理数据和业务逻辑;视图(View)负责展示数据,即用户界面;控制器(Controller)则作为模型和视图之间的桥梁,处理用户请求并将请求分发给适当的模型组件...
总的来说,《Struts2 in Action》中文版是Java Web开发者必备的参考书籍之一,它不仅提供了全面的技术解析,还强调了实际开发中的问题解决和性能优化。通过学习这本书,开发者可以提升自己在Struts2框架上的专业技能...
第二部分 核心概念:动作、拦截器和类型转换 第3章 使用Struts 2动作 36 3.1 Struts 2动作简介 36 3.2 打包动作 39 3.2.1 Struts 2公文包示例应用程序 39 3.2.2 组织你的包 39 3.2.3 使用struts-default包中的组件 ...
中文版的《Struts2 in Action》为中文阅读者提供了方便,使得理解复杂的框架概念变得更加容易。书中详细介绍了Struts2的核心组件、配置、拦截器、结果类型、插件等,以及如何将它们整合到实际项目中。同时,书中还...
struts2 in action 源码
这篇自学笔记将深入探讨Struts2的文件上传机制。 1. **文件上传原理** 文件上传是基于HTTP协议的POST请求实现的。在HTML表单中,通过`<input type="file" />`元素让用户选择本地文件。当用户提交表单时,浏览器会...
要深入学习和掌握Struts2,建议阅读官方文档,参与实际项目实践,也可以参考相关的技术书籍和教程,例如《Struts2技术内幕——深入解析Struts2架构设计与实现原理》等资源,来提升对Struts2框架的全面理解。
在Struts2框架中,Action类是业务逻辑的核心,它接收用户的请求,处理数据,并返回结果到视图。在"struts2+hibernate整合例子"中,Action类可能会包含对新闻的添加、删除、修改和查询方法。这些方法通过调用...
struts2 in actionstruts2 in actionstruts2 in actionstruts2 in actionstruts2 in actionstruts2 in actionstruts2 in action
学习Struts2第三天笔记
Struts2的运行离不开一系列的库文件,也就是Jar文件,这些文件包含了框架的核心组件和必要的支持库。如果项目中缺少Jar文件,可能会导致编译错误或者运行时异常。 首先,我们需要创建一个新的Maven或Ant项目,并在...