表格提交_处理表格提交

表格提交

本文是由三部分组成的文章系列的第二篇文章,该系列文章“开发在IBM WebSphere Portal中使用的Spring Portlet MVC Framework应用程序”。 这是一篇高级文章; 尽管不需要任何高级知识,但您应该熟悉开发JSR-168 Portlet的基础知识,并且对Spring框架有基本的了解。

在本系列的第一篇文章“ Spring Portlet MVC框架简介”中,我们讨论了如何使用Spring Portlet MVC Framework开发简单的HelloWorld Portlet。 在本文中,我们介绍了如何处理表单提交以及如何生成动态内容,这是大多数实际Portlet应用程序中的常见要求。

例如,开发一个示例联系人管理应用程序,使您可以在基础数据源中创建,检索,更新和删除(CRUD)联系人。 我们还将研究Spring Portlet MVC Framework收到表单提交请求时发生的事件顺序。

处理表格提交

您在本系列的第一部分中开发的HelloWorld Portlet有一个重要的限制:它不支持动作处理,这是大多数实际Portlet应用程序的基本要求。 在这里,我们开发了一个示例联系人管理应用程序,该应用程序允许用户列出,添加,更新和删除联系人。 为了简化开发环境,我们将联系信息存储在Hashmap中,而不是存储在基础数据库中的CONTACT表中。 请按照以下步骤来构建联系人管理应用程序。

第一步是在IBM Rational Application Developer for WebSphere Software中将ContactManagPortlet创建为动态Web应用程序。 使用/ src / main / java作为Java源目录,使用/ src / main / webapp作为Web内容目录。

然后将pom.xml构建脚本从本文的示例代码复制到新项目的根目录。 复制构建脚本后,执行mvn integration-test命令,该命令将下载ContactManagPortlet的所有必需依赖项。

下载所有依赖项之后,执行mvn eclipse:eclipse命令以将所有依赖项JAR文件添加到项目的类路径文件中。 右键单击ContactManagPortlet项目并刷新它时,您会看到在项目的构建路径中添加的所有依赖项JAR文件。

开发ContactDAO.java

在开发方面,第一步是定义联系人管理应用程序的所有数据访问操作。 创建ContactDAO.java接口,如清单1所示。

清单1. ContactDAO.java的代码清单
public interface ContactDAO {
	public ArrayList getContactList();
	public Contact getContact(String contactId);
	public int insertContact(Contact contact);
	public int updateContact(Contact contact);
	public int deleteContact(String contactId);
}

如您所见,ContactDAO界面定义了联系人管理应用程序的创建,检索,删除和更新(CRUD)操作。

开发Contact.java

接下来,创建Contact类,它是DTO对象,用于在Web部件和数据访问层之间传递数据,如清单2所示。

清单2. Contact.java的代码清单
public class Contact {
	private String contactId;
	private String firstName;
	private String lastName;
	private String email;
	private String phoneNumber;
	
public String getContactId() {
		return contactId;
	}
	public void setContactId(String contactId) {
		this.contactId = contactId;
	}
}

在示例应用程序中,每个联系人记录都有五个字段:contactId,firstName,lastName,phoneNumber和email。 为所有其他字段添加getter和setter方法,或直接从本文的示例代码复制Contact.java。

接下来,从本文的“ 下载”部分中包含的样本代码中复制com.ibm.developerworks.contact.service.HashmapContact.java和com.ibm.developerworks.contact.service.ContactDAOImpl.java。 ContactDAOImpl类实现ContactDAO接口,并将控制委托给HashmapContact对象,以实际存储联系人记录。 HashmapContact对象将联系信息存储在Hashmap中,因此当应用程序重新启动时,您的联系信息会丢失。 您可以创建ContactDAORDBMS.java类,以将联系信息存储在实际数据库中。

开发applicationContext.xml

下一步是在/ WEB-INF /文件夹中创建applicationContext.xml文件,如清单3所示。

清单3.更改applicationContext.xml的代码清单
<bean id="contactDAO"
	class="com.ibm.developerworks.contact.service.ContactDAOImpl">
	<property name="hashMapContact" ref="hashMapContact"/>
</bean>
<bean id="hashMapContact"
	class="com.ibm.developerworks.contact.service.HashmapContact" />

这是applicationContext.xml文件的部分列表。 查看完整清单的示例代码。 我们已将以下两个bean定义添加到applicationContext.xml中:

  • contactDAO。 contactDAO是ContactDAOImpl类的对象,并具有hashMapContact属性。
  • hashMapContact。 hashMapContact bean是HashmapContact类的对象。 这是联系人表的基于Hashmap的实现。

Spring Framework将applicationContext.xml文件加载到应用程序上下文对象中。 请注意,Spring Framework创建了一个应用程序上下文层次结构,其中子对象可以查看父对象,但是父对象不能查看子对象。 在applicationContext.xml文件中定义的bean是在portlet应用程序级别创建的,并且portlet上下文中的bean可以访问在portlet应用程序上下文级别定义的bean。 但是,在portlet应用程序上下文级别定义的bean无法访问portlet上下文中的bean。 在样本代码中,在portlet应用程序级别可以访问contactDAO和hashMapContact bean。

开发InsertController.java

在Spring Portlet MVC Framework中,要处理表单提交,您可以从AbstractFormController或其子类派生Controller类。 SimpleFormController是AbstractFormController的具体实现之一,它提供了用于处理表单提交的简单工作流。 每当SimpleFormController收到请求时,它都会检查以确定您是要访问表单页面还是提交表单。

  • 如果您正在访问表单页面,则它将返回一个formView页面。
  • 如果要提交表单,则它将读取此Controller的commandClass的值,创建一个commandClass对象,并使用用户在表单上提交的值填充其属性。 然后,它允许您执行一些业务逻辑。 之后,它将向用户显示successView页面。

我们将在本文后面详细介绍这些信息。

在联系人管理应用程序中,您既要使用InsertController来向用户显示新的联系人页面,又要处理页面提交,因此您要创建InsertController.java,如清单4所示。

清单4. InsertController.java的代码清单
public class InsertController extends SimpleFormController{
	private ContactDAO contactDAO;
	public ContactDAO getContactDAO() {
		return contactDAO;
	}
	public void setContactDAO(ContactDAO contactDAO) {
		this.contactDAO = contactDAO;
	}
	
protected void onSubmitAction(ActionRequest request, ActionResponse response, 
Object command, BindException errors) throws Exception {
		contactDAO.insertContact((Contact)command);
		response.setRenderParameter("action", "list");
	}
}

如您所见,InsertController的实现非常简单。 首先,我们使用相应的getter和setter方法将contactDAO定义为该bean的属性。 我们决定重写SimpleFormController的onSubmitAction()方法。 在onSubmitAction()方法内部,首先我们调用contactDAO.insertContact(contact)方法,该方法将新的联系人记录插入基础数据源中。 接下来,我们将action设置为render参数,其值等于“插入”。

SimpleFormController还定义了doSubmitAction(command)方法,该方法足以实现您的业务逻辑。 不过,在我们的情况下,我们希望在添加新联系人后将用户重定向到联系人电子表格。 为此,我们在呈现阶段将控件传递给SelectController。 设置action render参数可以解决这一问题。

insertController的Bean定义

Spring Portlet MVC Framework如何知道使用哪个JSP文件来显示“插入新联系人”页面? 如何知道要使用com.ibm.developerworks.contact.domain.Contact作为InsertController的命令类? 这就是insertController bean定义变得重要的地方。 在应用程序的/ WEB-INF /文件夹中创建SpringContactManag-portlet.xml,并添加insertController bean定义,如清单5所示。

请记住,InsertController是Java类的名称,而insertController是在Spring上下文文件中定义的bean的名称。 通常,Java类名称的首字母大写。 在Spring上下文文件中定义的Bean名称中,名称的第一个字母为小写。

清单5. ContactManagPortlet-portlet.xml中insertController bean定义的代码清单
<bean id="insertController" 
class="com.ibm.developerworks.contact.controller.InsertController">
	<property name="contactDAO" ref="contactDAO"></property>
	<property name="commandName" value="contact"/>
<property name="commandClass" value="com.ibm.developerworks.contact.domain.Contact" />
	<property name="formView" value="insert"></property>
	<property name="successView" value="list"></property>
</bean>l

在示例代码中,我们为以下insertController bean属性设置值:

  • contactDAO。 我们将引用传递给contactDAO bean,后者是负责实际联系人插入的服务类。 记住,我们在applicationContext.xml文件中声明了contactDAO bean。
  • commandClass。 在示例代码中,我们使用Contact类作为命令类,其中填充了用户在表单上提交的值。
  • commandName。 在此表单的模型中设置commandClass对象时,将使用commandName的值。
  • formView。 formView参数的值用于确定应向用户显示哪个视图以进行输入。 在我们的示例代码中,当用户单击“添加联系人”链接时,我们要显示insert.jsp页面,因此formView属性的值是insert。 (我们将InternalResourceViewResolver用于ViewResolution,它将插入值映射到/WEB-INF/jsp/insert.jsp文件。)
  • successView。 successView参数的值用于确定添加新联系人是否成功时要显示给用户的视图。 在这种情况下,如果添加成功,我们希望显示list.jsp文件,因此此属性的值为list。

开发insert.jsp

在定义insertController bean时,我们将insert.jsp配置为formView属性的值。 当您单击联系人电子表格上的“添加联系人”链接时,Spring Portlet MVC框架会尝试查找/WEB-INF/jsp/insert.jsp页面。 下一步是在/WEB-INF/jsp/insert.jsp中创建insert.jsp页面,如清单6所示。

清单6. insert.jsp的代码清单
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<portlet:actionURL var="formAction">
	<portlet:param name="action" value="insert"/>
</portlet:actionURL>
<h3>Add New Contact</h3>
<form:form commandName="contact" method="post" action="${formAction}">
	<table cellpadding="4">
		<tr>
			<td>Contact Id</td>
<td><form:input path="contactId" size="30" maxlength="80"/></td>
		</tr>
		<tr>
<td><input type="submit" name="_finish" value="Save"/></td>
<td><input type="submit" name="_cancel" value="Cancel"/></td>
		</tr>
	</table>
</form:form>

insert.jsp页面具有三个标记库声明。 您已经熟悉其中的两个,jstl标记库和portlet标记库。 此外,我们还定义了表单标签库。 从2.0版开始,Spring Framework提供了表单标签库,Web MVC Framework或Portlet MVC Framework应用程序代码中包含的JSP文件可以使用该表单标签库。

表单标签库与Spring Portlet MVC Framework集成在一起,并提供对命令对象的访问。 在insert.jsp文件中,<form:form>是用于在最终标记中生成HTML <form>标记的第一个标记。 此标记还读取命令对象,并将其设置在JSP文件的pageContext中。 在示例代码中,commandName是联系人,因此<form>标记的commandName属性的值是contact。

表单标签库中的所有其他标签都是<form>标签的嵌套标签。 我们使用的下一个表单标签库标签是<input>,它用于在最终标记中生成<input type =“ text”>元素。 在示例代码中,我们希望将contactId输入绑定到Contact对象中的contactId属性,为此,我们添加了一个路径属性,其值等于contactId。 注意,这是insert.jsp的部分代码清单。 完整的清单在本文的“ 下载”部分列出的示例代码中。

开发SpringContactManagPortlet-portlet.xml

下一步是在SpringContactManagPortlet-portlet.xml中添加几个bean定义,如清单7所示。

清单7. SpringContactManagPortlet-portlet.xml中更改的代码清单
<bean id="parameterMappingInterceptor" 
class= "org.springframework.web.portlet.handler.ParameterMappingInterceptor" />
<bean id="portletModeParameterHandlerMapping" 
class= "org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="parameterMappingInterceptor" />
		</list>
	</property>
	<property name="portletModeParameterMap">
		<map>
			<entry key="view">
				<map>
					<entry key="select">
						<ref bean="selectController" />
					</entry>
					<entry key="insert">
						<ref bean="insertController" />
					</entry>
				</map>
			</entry>
		</map>
	</property>
</bean>

如您所见,我们在SpringContactManagPortlet-portlet.xml文件中定义了另外两个bean定义。

  • parameterMappingInterceptor。 parameterMappingInterceptor用于将动作请求参数的值从ActionRequest转发到RenderRequest,以便Spring Portlet MVC Framework使用相同的控制器来处理动作请求和呈现请求。 我们将在本文后面详细讨论。
  • portletModeParameterHandlerMapping。 portletModeParameterHandlerMapping是HandlerMapping的高级实现,它使用portlet模式以及动作请求参数的值来解析请求的处理程序。 在示例代码中,我们在View模式下有多个处理程序,因此我们使用portletModeParameterHandlerMapping。 portletModeParameterHandlerMapping bean具有portletModeParameterMap属性,该属性是您的portlet支持的所有portlet模式的映射。 该映射将键值对与Portlet模式的名称作为键。 值是另一个映射,它以操作请求参数的值作为键,并以处理其请求的控制器的引用作为其值。

在示例代码中,您只希望支持“查看”模式,以便顶层地图只有一个条目。 但是,第二级映射具有一个等于insert的键,其值引用了insertController bean。 结果,当此Portlet在View模式下获得操作参数等于insert的请求时,它将控制权传递给InsertController进行处理。

构建此示例代码的最后一步是从本文的示例代码中复制其他文件SelectController.java,UpdateController.java,DeleteController.java以及相应的JSP文件list.jsp和update.jsp。 从示例代码复制了所有必需的文件之后,执行mvn package命令来构建portlet应用程序。 准备好WAR文件后,可以在IBM WebSphere Portal上对其进行测试。

动作处理如何工作

Spring Portlet MVC框架在后台执行许多操作。 从长远来看,在您熟悉该软件之后,这可能是一个很大的优势。 从短期来看,这种方法可能很难理解。 在本节中,我们讨论当DispatcherPortlet收到一个动作请求时,后台会发生什么。 见图1。

图1. DispatcherPortlet收到动作请求时发生的事件序列的序列图
DispatcherPortlet收到动作请求时发生的事件序列的序列图

当DispatcherPortlet获取插入操作请求时,将发生以下事件序列。

  1. DispatcherPortlet检查是否为您的Portlet启用了多部分请求处理。 如果已启用,则DispatcherPortlet将检查请求是否为多部分; 也就是说,HTML <form>元素的enctype属性设置为multipart / form-data。 如果是,则将该请求包装在MultipartActionRequest对象中。
  2. DispatcherPortlet遍历您的Portlet应用程序中配置的所有HandlerMappings的列表,调用其getHandler()方法来获取当前请求的适当处理程序。 在示例代码中,我们仅配置了一个HandlerMapping实现类PortletModeParameterHandlerMapping。 当获得控制权时,它将检查当前请求的Portlet模式(在这种情况下为View模式)以及动作请求参数的值(即insert)。 现在,在SpringContactManagPortlet-portlet.xml中定义portletModeParameterHandlerMapping bean时,插入键被映射到InsertController,因此它返回InsertController的对象。
  3. 在DispatcherPortlet知道InsertController负责处理此请求之后,它将开始遍历此处理程序的所有拦截器,并调用其preHandleAction()方法。 在示例代码中,我们仅配置了一个拦截器类ParameterMappingInterceptor,因此将调用其preHandleAction()方法。
  4. ParameterMappingInterceptor用于将动作请求参数的值从ActionRequest转发到RenderRequest,因此它将渲染参数设置为名称等于action且值等于insert。

    Spring Portlet MVC Framework在操作阶段和呈现阶段都尝试为当前请求解析Handler。 如果希望Spring Portlet MVC Framework在操作和呈现阶段使用相同的Handler,则可以使用ParameterMappingInterceptor。
  5. DispatcherPortlet调用InsertController的handleActionRequest()方法; 这是实际动作处理发生的地方。 在示例代码中,InsertController扩展了SimpleFormController,使其遵循SimpleFormController定义的操作请求生命周期。
  6. SimpleFormController首先读取为InsertController配置的commandClass的名称,即com.ibm.developerworks.contact.domain.Contact,并创建其对象。
  7. 之后,SimpleFormController创建PortletRequestDataBinder的对象,该对象负责使用用户在表单上提交的值填充Contact对象。 例如,它将读取firstName请求参数的值,并将其设置为Contact对象中firstName属性的值。
  8. 如果希望Spring Portlet MVC Framework在将请求参数值转换为命令类属性值时使用某些自定义逻辑,则可以在类中重写initBinder()方法。 例如,您可以指定如何将String转换为Date或将MultiPartFile转换为byte []数组。 我们将在本文后面的示例中显示此示例。
  9. 在使用用户提交的值填充Contact bean之后,SimpleFormController遍历应用程序中的所有Validator,并调用其validate()方法。 在这里,您可以编写服务器端验证逻辑。 例如,您可以检查联系人ID是否为必填字段。 我们将在本文后面详细讨论。
  10. 执行验证后,SimpleFormController检查是否发生任何验证错误。 如果没有发生错误,它将在InsertController中调用onSubmitAction()/ doSubmitAction()。 通常,我们建议您在Controller类中重写doSubmitAction()。 但是,在示例代码中,我们希望在呈现阶段将控件重定向到SelectController,因此我们将覆盖onSubmitAction()阶段。

操作阶段完成后,DispatcherPortlet将检查是否发生任何验证错误。 如果确实发生错误,它将读取formView的值并将用户重定向到该页面。 如果没有验证错误,则它将用户重定向到successView页面。

结论

在本文中,我们介绍了如何使用Spring Portlet MVC Framework开发示例联系人管理应用程序。 我们讨论了如何创建一个覆盖SimpleFormController的类,该类在获得GET请求时将控制转发给formView属性定义的值,并在它获得POST请求并成功执行动作时将控制转发给successView属性定义的值。 我们还讨论了您需要创建的所有配置文件,并介绍了如何使用Spring Portlet MVC Framework定义的自定义标签库。

在本系列的最后一部分中,我们将讨论Spring Portlet MVC Framework中的一些高级主题,例如处理表单验证,优雅地处理异常和国际化。 我们还将演示如何将Apache Tiles框架与Spring Portlet MVC框架集成。


翻译自: https://www.ibm.com/developerworks/websphere/library/techarticles/0802_patil-pt2/0802_patil-pt2.html

表格提交

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值