`
zhkac
  • 浏览: 53945 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

用 Spring MVC 来处理向导式复杂表单

阅读更多

一. 定义好需求

为了使我们尽快掌握 AbstractWizardFormController 的使用,而不至让具体业务所纠缠。故而,这里要对 CSDN 的简历向导大大的简化,简化后的向导页和每页的填写内容如下:

1. 求职意向(期望工作地点-必填,期望月薪)
2. 基本信息(姓名-必填、手机号码-必填)
3. 工作经历(单个文本框录入)
4. 项目经验(单个文本框录入)
5. 完成页,Congratulations

每页操作完之后,点击“下一步”按钮进到下一页面,同时要对标识为必填项进行非空验证。用户也可以点“上一步”按钮重填上一页面的信息。用户可以中途点击“取消”按钮取消向导。最后在项目经验向导页面,点击“完成”按钮处理表单数据,成功后显示 Congratulations 页。

二. 定义接收表单数据的 Command 类(Resume)

这里我们定义为 com.unmi.bean.Resume,代码如下:

package com.unmi.bean;

public class Resume {
	private String workPlace;   //期望工作地点
	private int salary;         //期望薪水
	private String name;        //姓名
	private String mobile;     //手机号码
	private String experience;  //工作经历
	private String projects;    //项目此验
	
	//...... 相应的 getter/setter 方法此处略去
}

 

三. 创建向导控制器(ResumeWizardController)

package com.unmi.webapp.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;

import com.unmi.bean.Resume;

/**
 * 处理简单向导表单的控制类
 * @author Unmi
 */
public class ResumeWiardController extends AbstractWizardFormController {
	
	public ResumeWiardController(){
		setCommandClass(Resume.class);  //设置命令类
	}

	//处理表单数据
	protected ModelAndView processFinish(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {
		
		//完成表单时获取到所有填写数据,调用业务类来处理
		Resume resume = (Resume)command;
		//resumeService.submitResume(resume);
		
		return new ModelAndView("congratulations"); //完了后,转到祝贺页面
	}

	/**
	 * 向导中每一页面都要调用的验证方法,用 page 识别当前面
	 */
	protected void validatePage(Object command, Errors errors, int page) {
		ResumeValidator validator = (ResumeValidator)getValidator();
		
		if(page == 0){//验证求职意向页面
			validator.validateWorkplace("workPlace", errors);
		}
		else if(page == 1){//验证档基本信息页面
			validator.validateName("name", errors);
			validator.validateMobile("mobile", errors);
		}
	}
}

 

四. 还是提一下 web.xml 的配置

在 web.xml 增加了 Spring 的 DispatchServlet 来处理 /*.html 的 URL,Servlet Name 为 resume

<servlet>
	<servlet-name>resume</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>resume</servlet-name>
	<url-pattern>*.html</url-pattern>
</servlet-mapping>

 

 五. Spring 配置文件(resume-servlet.xml)

因为上面的 Servlet Name 为 resume,所以可以直接在 WEB-INF 目录中直接配置一个文件名为 resume-servlet.xml 的 Spring 配置文件。这是默认行为,当然,你也可以为 DispatcherServlet 用 contextConfigLocation 属性来指定配置文件。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
	
	<bean name="/createResume.html" class="com.unmi.webapp.controller.ResumeWiardController">
		<property name="resumeService">
			<ref bean="resumeService"/>
		</property>
		<property name="pages">
			<list>
				<value>intention</value>
				<value>baseinfo</value>
				<value>experience</value>
				<value>projects</value>
				<value>congratulations</value>
			</list>
		</property>
		<property name="validator">
			<bean class="com.unmi.webapp.validator.ResumeValidator"></bean>
		</property>
	</bean>

	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/resume/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
</beans>

 上面对 ResumeWizardController  用 pages 指定了一系列的逻辑视图名,他们依序有一个索引号(以 0 为基数),后面会用到。这些逻辑面在运行时会依据 InternalResourceViewResolver 解析成对应的 jsp 文件名,例如,intention -> /resume/intention.jsp,其余类同。

 六. 分步显示向导中的表单页面

任何向导控制器显示的第一个页面都是 pages 属性中列表的第一个页面。其后为了判断接下来的是哪个页面, AbstractWizardFormController 询问它的 getTargetPage() 方法。这个方法返回一个整数,它就是 pages 和中设置页面列表的索引值。

getTargetPage() 方法的缺省实现是根据请求中的一个参数来决定下一步是哪个页面的,这个参数以 "_target" 开头,以数结尾。getTargetPage() 只取这个数字作为页面列表的索引。一般我们会把该参数命名给相应的提交按钮。例如我们在第二个页面 /resume/baseinfo.jsp 中的“上一步”,“下一步” 按钮的 html 代码这样写:

<form action="/createResume.html" method="post">
  ......
  <input type="submit" value="上一步" name="_target0">
  <input type="submit" value="下一步" name="_target2">
</form>

 七. 完成或取消向导

那么 AbstractWizardFormController 又是如何知道你点击的是完成按钮,要调用 processFinish() 方法处理表单数据,或是点了取消按钮,要调用 processCancel() 来作些清理工作或作部分数据处理呢?它也是依据于特殊的请求参数,它们分别是 “_finish” 和 “_cancel”。因此,相应的 html 代码就要写成:

<form action="/createResume.html" method="post">
  ......
  <input type="submit" value="完成" name="_finish">
  <input type="submit" value="取消" name="_cancel">
</form>

 

八. 每次验证一个向导表单

对于这种向导式页面,如果你仍是在最后点完成按钮来验证所有表单数据的话,一旦某个数据有问题,你将很难定位是在哪个向导页输入的,并且转向到哪个出错页面也麻烦。所以我们需要在每填完一个表单,点击 “下一步” 或“完成” 按钮时立即就对当前表单数据进行验证。

AbstractWizardFormController 在每次页面跳转时会调用它的 validatePage() 方法。而 validatePage() 方法缺省实现是空的,这要留给你来实现。AbstractWizardFormController  中有两个重载的 validatePage() 方法,代码分别如下:

protected void validatePage(Object command, Errors errors, int page) {
}

protected void validatePage(Object command, Errors errors, int page, boolean finish) {
	validatePage(command, errors, page);
}

 

你可以选择实现其中一个方法来对表单进行验证。如果你希望在点击“完成” 按钮时,能作一些特别的验证,例如,如多个表单的相关联数据进行一致性检查,那你就应该实现带有 boolean finish 参数的 validatePage() 方法。

最好是把验证逻辑单独写在一个实现了 Validator 接口的验证类中,通过 validator 属性配置给你的 ResumeWizardFormController,然后在 validatePage() 方法中取到这个 validator,再调用其中的验证方法 validateXXX()。例如我们前面配置在 resume-servlet.xml 中的 com.unmi.webapp.validator.ResumeValidator。

注意,对于 AbstractWizardFormController,它不会调用配置给它的 validator 的标准的 validate() 方法。在点击“下一步”按钮,即向导正向走时,若验证不通过,则停留在当前页,等待重新输入。然而,当点击“上一步”按钮时,也就是页面索引号递减,向导逆向走时,同样会要求对当前页面输入进行验证,只不过这种情况下验证即使不能通过也不会停留在当前页,仍会转向到上一页面。

这时候,我们在 ResumeWizardController 的 validatePage(Object command, Errors errors, int page) 就可以参照这么写了:

protected void validatePage(Object command, Errors errors, int page) {
	Resume resume = (Resume) command;
	ResumeValidator validator = (ResumeValidator)getValidator();
	
	if(page == 1){//判断所在的页面来调用相应的验证方法
		validator.validateName("name", errors);
	}
}

 

对于另一个版本的 validatePage(Object command, Errors errors, int page, boolean finish) 方法,那就是:

protected void validatePage(Object command, Errors errors, int page,
		boolean finish) {
	Resume resume = (Resume) command;
	ResumeValidator validator = (ResumeValidator)getValidator();
	
	if(page == 1){//判断所在的页面来调用相应的验证方法
		validator.validateName("name", errors);
	}
	
	if(finish){//如果是完成向导时,进行自己的验证,这里直接调用了标准的 validate() 方法
		validator.validate(command,errors);
	}
}

 

九. 完整的工程代码

下载地址:http://www.blogjava.net/Files/Unmi/SpringWizardForm.rar

本工程未去处理有请求参数 _cancel 时,执行 ResumeWizardController.processCancel() 方法的情形,如果你有这样的需求的话可自己去完善。对 ResumeWizardController,也是只实现了 validatePage(Object command, Errors errors, int page) 这个版本的方法。

解压到 Tomcat 下即能运行,浏览 http://localhost:8080/SpringWizardForm 点链接进到向导。包含源代码和所需的 jar 文件。使用的是 Spring 2.0,jsp 页面中用 spring-form 标签。支持国际化,从资历源文件中获取验证错误信息在输入框下方显示。

十. 运行效果

把整个操作过程做成了一个 Gif 动画来展示,能使你一目了然。只恐怕这精彩的部分放在后头,可能鲜有人有此等耐心把滚动条拉至此处。

SpringWizardForm.gif 说明:

1. 浏览 http://localhost:8080/SpringWizardForm,点链接进到向导页

2. 操作中测试到了每一个验证的效果,期望工作地点、姓名和手机号码不能为空

3. 验证不通过时,从资源文件中取出错误信息,显示在相应输入框之下。并且页面仍留在当前页

4. 在向导的进行中,点“上一步”,“下一步”按钮时,只要填写提交过的数据一直保留

5. 所有数据填完后,点击“完成”按钮,业务类处理整个表单数据(后台会打印出 resume 信息),页面显示恭喜.



参考资料:1. 《Spring in Action》 第一版,第八章
             2. spring标签介绍 -- 说的是 Spring 中的 spring.tld 中的标签
             3. 使用Spring MVC表单标签 -- 说的是 Spring 2.0 开始的 spring-form.tld 中的标签
             4. Spring MVC国际化配置

分享到:
评论
1 楼 kakaluyi 2010-04-09  
写的很不错 最后的效果做的很好

相关推荐

    Spring MVC学习(四)-------Controller接口控制器详解3

    在Spring MVC框架中,`AbstractWizardFormController` 是一个重要的抽象类,它提供了多步骤表单(通常称为向导式表单)的支持。这对于实现复杂的用户交互流程非常有用,比如注册过程中的多步骤验证、个人资料完善等...

    Java框架Bootstrap、HTML5、jQuery、Spring MVC、Hibernate、向导、验证、UI组件、日历、相册、时间轴

    4. **用户管理**:同样使用jQuery jqGrid处理用户数据,支持日期选择。 5. **角色权限管理**:利用jQuery jqGrid和Bootstrap FuelUX Tree组件处理角色权限数据。 6. **菜单管理**:jQuery jqGrid用于菜单数据的展示...

    SPRING WEB-FLOW入门教程

    总的来说,Spring Web Flow为开发者提供了一种强大且灵活的工具,使得处理复杂的Web交互变得更加简单,提高了代码的可读性和可重用性,降低了维护成本。无论是在构建大型的多步骤表单还是需要精细控制用户导航的应用...

    Spring in Action(第二版 中文高清版).part2

    13.3.3 用向导处理复杂表单 13.3.4 使用一次性控制器 13.4 处理异常 13.5 小结 第14章 渲染Web视图 14.1 视图解析 14.1.1 使用模板视图 14.1.2 解析视图Bean 14.1.3 选择视图解析器 14.2 使用Spring模板...

    Spring_Web_Flow

    3. **集成 Spring MVC**:配置 DispatcherServlet 使其能够处理流程相关的请求。 4. **注册 FlowExecutor**:通过 FlowExecutor 来管理和执行流程。 5. **定义视图解析器**:配置视图解析器以支持不同类型的视图技术...

    Spring in Action(第二版 中文高清版).part1

    13.3.3 用向导处理复杂表单 13.3.4 使用一次性控制器 13.4 处理异常 13.5 小结 第14章 渲染Web视图 14.1 视图解析 14.1.1 使用模板视图 14.1.2 解析视图Bean 14.1.3 选择视图解析器 14.2 使用Spring模板...

    Spring攻略(第二版 中文高清版).part1

    8.11 用向导表单控制器处理多页表单 331 8.11.1 问题 331 8.11.2 解决方案 331 8.11.3 工作原理 332 8.12 使用注解(JSR-303)的Bean校验 341 8.12.1 问题 341 8.12.2 解决方案 342 8.12.3 工作原理 ...

    Spring攻略(第二版 中文高清版).part2

    8.11 用向导表单控制器处理多页表单 331 8.11.1 问题 331 8.11.2 解决方案 331 8.11.3 工作原理 332 8.12 使用注解(JSR-303)的Bean校验 341 8.12.1 问题 341 8.12.2 解决方案 342 8.12.3 工作原理 ...

    Spring WebFlow

    Spring Web Flow适用于需要复杂导航控制的场景,如多步骤的表单提交、向导式用户界面等。它鼓励服务导向架构(SOA)的设计原则,促进代码的低耦合和高可维护性,同时提供高度的可扩展性,使得开发者能够专注于业务...

    spring web flow 小项目

    SWF的主要目的是解决Web应用中复杂导航控制的问题,比如向导式操作,通过一系列步骤来引导用户完成一个大型事务。 在传统的Web页面流程中,如Struts,页面流程的定义往往不够直观,而Spring MVC虽然提供了轻量级的...

    Spring Web Flow 介绍.ppt ppt

    而Spring MVC虽然提供了高层次的表单控制器功能,但在处理复杂的流程时仍然显得力不从心。SWF弥补了这一空白,它允许开发者以简洁明了的方式定义页面流程,并且这些流程可以被复用,提高了代码的可维护性和可重用性...

    Struts 2,Spring 2,Hibernate S2SH 整合例子

    它允许开发人员使用面向对象的方式来处理数据库,而无需编写大量的SQL语句。在S2SH整合中,Hibernate负责将Java对象持久化到数据库,通过Spring的数据访问抽象层(DAO)进行管理。 **整合过程**: 1. 创建一个Java ...

    Spring Layout-开源

    Spring Layout是Spring MVC扩展和标记库,可简化以数据为中心的Web应用程序的开发。 它通过标签集成,页面/字段级别的安全性以及多面板/向导样式的控制器和表单来提供丰富的声明式验证。

    hotel-reservation-springmvc:使用弹簧靴和百里香的酒店预订系统

    该项目实现了一个复杂的域模型,该模型为基于会话的向导表单流提供了预订酒店房间的动力。 该流程通过具有各种预订选项和业务规则来模拟现实世界的应用程序。 主要功能包括 Thymeleaf Ajax片段+ JavaScript ...

Global site tag (gtag.js) - Google Analytics