Mkyong 中文博客翻译(五十八)

原文:Mkyong

协议:CC BY-NC-SA 4.0

Spring MVC 表单错误标签示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-errors-tag-example/

在 Spring MVC 中,字段错误消息由与控制器相关联的验证器生成,您可以使用 < form:errors / > 标签在默认的 HTML“span”标签中呈现这些字段错误消息。举个例子,

1.验证器

验证器检查“用户名字段,如果为空,从资源包向控制器返回“必需.用户名错误消息。

 //...
public class TextBoxValidator implements Validator{
    
    
	@Override
	public void validate(Object target, Errors errors) {
    
    
		ValidationUtils.rejectIfEmptyOrWhitespace(
			errors, "username", "required.username");
	}
}
/*** required.username = username is required! ***/ 

2.显示字段错误

然后,您可以使用 <表单:errors / > 来呈现与“用户名字段相关联的错误消息。

 <form:errors path="userName" cssClass="error" /> 

它将使用一个默认的“ span ”元素来呈现和封装错误消息,该元素包含一个 CSS 类“ error ”。

 <span id="username.errors" class="error">username is required!</span> 

Note

  1. path = " * "–显示与任何字段相关的所有错误消息。
  2. path = " username "–仅显示与“username”字段相关的错误消息。

3.自定义输出元素

出于某些原因,比如 CSS 格式化的目的,您可能需要用不同的元素来包含错误消息,而不是默认的“ span 标签。为此,只需在“元素属性中指定 prefer 元素:

 <form:errors path="userName" cssClass="error" element="div" /> 

现在,它用一个“ div ”元素呈现并封装错误消息,该元素包含一个“错误”的 CSS 类。

 <div id="username.errors" class="error">username is required!</div> 

4.演示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下载源代码

Download it – SpringMVCForm-TextBox-Example.zip (9KB)form handling spring mvc

Spring MVC 表单处理注释示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-handling-annotation-example/

在本教程中,我们将向您展示如何在 Spring MVC web 应用程序中使用注释进行表单处理。

Note
This annotation-based example is converted from the last Spring MVC form handling XML-based example. So, please compare and spots the different.

1.简单表单控制器与@控制器

在基于 XML 的 Spring MVC web 应用程序中,您通过扩展SimpleFormController类来创建表单控制器。

在基于注释的情况下,可以使用*@控制器*来代替。

简单表单控制器

 public class CustomerController extends SimpleFormController{
    
    
      //...
} 

标注

 @Controller
@RequestMapping("/customer.htm")
public class CustomerController{
    
    
      //...
} 

2.formBackingObject()vs request method。得到

在 SimpleFormController 中,可以在 formBackingObject() 方法中初始化命令对象进行绑定。在基于注释的方法中,您可以通过用**@ request mapping(method = request method)注释方法名来做同样的事情。**搞定)。

简单表单控制器

 @Override
	protected Object formBackingObject(HttpServletRequest request)
		throws Exception {
    
    

		Customer cust = new Customer();
		//Make "Spring MVC" as default checked value
		cust.setFavFramework(new String []{
    
    "Spring MVC"});

		return cust;
	} 

标注

 @RequestMapping(method = RequestMethod.GET)
	public String initForm(ModelMap model){
    
    

		Customer cust = new Customer();
		//Make "Spring MVC" as default checked value
		cust.setFavFramework(new String []{
    
    "Spring MVC"});

		//command object
		model.addAttribute("customer", cust);

		//return form view
		return "CustomerForm";
	} 

3. onSubmit()诉 RequestMethod.POST

在 SimpleFormController 中,表单提交由 onSubmit() 方法处理。在基于注释的方法中,您可以通过用**@ request mapping(method = request method)注释方法名来做同样的事情。后)**。

简单表单控制器

 @Override
	protected ModelAndView onSubmit(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors)
		throws Exception {
    
    

		Customer customer = (Customer)command;
		return new ModelAndView("CustomerSuccess");

	} 

标注

 @RequestMapping(method = RequestMethod.POST)
	public String processSubmit(
		@ModelAttribute("customer") Customer customer,
		BindingResult result, SessionStatus status) {
    
    

		//clear the command object from the session
		status.setComplete(); 

		//return form success view
		return "CustomerSuccess";

	} 

4.reference data()vs @ model attribute

在 SimpleFormController 中,通常通过 referenceData() 方法将引用数据放入模型中,以便表单视图可以访问它。在基于注释的方法中,您可以通过用 @ModelAttribute 注释方法名来做同样的事情。

简单表单控制器

 @Override
	protected Map referenceData(HttpServletRequest request) throws Exception {
    
    

		Map referenceData = new HashMap();

		//Data referencing for web framework checkboxes
		List<String> webFrameworkList = new ArrayList<String>();
		webFrameworkList.add("Spring MVC");
		webFrameworkList.add("Struts 1");
		webFrameworkList.add("Struts 2");
		webFrameworkList.add("JSF");
		webFrameworkList.add("Apache Wicket");
		referenceData.put("webFrameworkList", webFrameworkList);

		return referenceData;
	} 

弹簧的形状

 <form:checkboxes items="${webFrameworkList}" path="favFramework" /> 

标注

 @ModelAttribute("webFrameworkList")
	public List<String> populateWebFrameworkList() {
    
    

		//Data referencing for web framework checkboxes
		List<String> webFrameworkList = new ArrayList<String>();
		webFrameworkList.add("Spring MVC");
		webFrameworkList.add("Struts 1");
		webFrameworkList.add("Struts 2");
		webFrameworkList.add("JSF");
		webFrameworkList.add("Apache Wicket");

		return webFrameworkList;
	} 

弹簧的形状

 <form:checkboxes items="${webFrameworkList}" path="favFramework" /> 

5.initBinder()与@InitBinder

在 SimpleFormController 中,通过 initBinder() 方法定义绑定或注册自定义属性编辑器。在基于注释的方法中,您可以通过用 @InitBinder 注释方法名来做同样的事情。

简单表单控制器

 protected void initBinder(HttpServletRequest request,
		ServletRequestDataBinder binder) throws Exception {
    
    

		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    } 

标注

 @InitBinder
	public void initBinder(WebDataBinder binder) {
    
    
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
	} 

来自验证

在 SimpleFormController 中,您必须通过 XML bean 配置文件注册验证器类并将其映射到控制器类,验证检查和工作流将自动执行。

在基于注释的情况下,您必须显式执行验证器,并手动在 @Controller 类中定义验证流。看到不同的:

简单表单控制器

 <bean class="com.mkyong.customer.controller.CustomerController">
                <property name="formView" value="CustomerForm" />
		<property name="successView" value="CustomerSuccess" />

		<!-- Map a validator -->
		<property name="validator">
			<bean class="com.mkyong.customer.validator.CustomerValidator" />
		</property>
	</bean> 

标注

 @Controller
@RequestMapping("/customer.htm")
public class CustomerController{
    
    

	CustomerValidator customerValidator;

	@Autowired
	public CustomerController(CustomerValidator customerValidator){
    
    
		this.customerValidator = customerValidator;
	}

	@RequestMapping(method = RequestMethod.POST)
	public String processSubmit(
		@ModelAttribute("customer") Customer customer,
		BindingResult result, SessionStatus status) {
    
    

		customerValidator.validate(customer, result);

		if (result.hasErrors()) {
    
    
			//if validator failed
			return "CustomerForm";
		} else {
    
    
			status.setComplete();
			//form success
			return "CustomerSuccess";
		}
	}
	//... 

完整示例

查看完整的@Controller 示例。

 package com.mkyong.customer.controller;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;

import com.mkyong.customer.model.Customer;
import com.mkyong.customer.validator.CustomerValidator;

@Controller
@RequestMapping("/customer.htm")
public class CustomerController{
    
    

	CustomerValidator customerValidator;

	@Autowired
	public CustomerController(CustomerValidator customerValidator){
    
    
		this.customerValidator = customerValidator;
	}

	@RequestMapping(method = RequestMethod.POST)
	public String processSubmit(
		@ModelAttribute("customer") Customer customer,
		BindingResult result, SessionStatus status) {
    
    

		customerValidator.validate(customer, result);

		if (result.hasErrors()) {
    
    
			//if validator failed
			return "CustomerForm";
		} else {
    
    
			status.setComplete();
			//form success
			return "CustomerSuccess";
		}
	}

	@RequestMapping(method = RequestMethod.GET)
	public String initForm(ModelMap model){
    
    

		Customer cust = new Customer();
		//Make "Spring MVC" as default checked value
		cust.setFavFramework(new String []{
    
    "Spring MVC"});

		//Make "Make" as default radio button selected value
		cust.setSex("M");

		//make "Hibernate" as the default java skills selection
		cust.setJavaSkills("Hibernate");

		//initilize a hidden value
		cust.setSecretValue("I'm hidden value");

		//command object
		model.addAttribute("customer", cust);

		//return form view
		return "CustomerForm";
	}

	@ModelAttribute("webFrameworkList")
	public List<String> populateWebFrameworkList() {
    
    

		//Data referencing for web framework checkboxes
		List<String> webFrameworkList = new ArrayList<String>();
		webFrameworkList.add("Spring MVC");
		webFrameworkList.add("Struts 1");
		webFrameworkList.add("Struts 2");
		webFrameworkList.add("JSF");
		webFrameworkList.add("Apache Wicket");

		return webFrameworkList;
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) {
    
    
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));

	}

	@ModelAttribute("numberList")
	public List<String> populateNumberList() {
    
    

		//Data referencing for number radiobuttons
		List<String> numberList = new ArrayList<String>();
		numberList.add("Number 1");
		numberList.add("Number 2");
		numberList.add("Number 3");
		numberList.add("Number 4");
		numberList.add("Number 5");

		return numberList;
	}

	@ModelAttribute("javaSkillsList")
	public Map<String,String> populateJavaSkillList() {
    
    

		//Data referencing for java skills list box
		Map<String,String> javaSkill = new LinkedHashMap<String,String>();
		javaSkill.put("Hibernate", "Hibernate");
		javaSkill.put("Spring", "Spring");
		javaSkill.put("Apache Wicket", "Apache Wicket");
		javaSkill.put("Struts", "Struts");

		return javaSkill;
	}

	@ModelAttribute("countryList")
	public Map<String,String> populateCountryList() {
    
    

		//Data referencing for java skills list box
		Map<String,String> country = new LinkedHashMap<String,String>();
		country.put("US", "United Stated");
		country.put("CHINA", "China");
		country.put("SG", "Singapore");
		country.put("MY", "Malaysia");

		return country;
	}
} 

要使注释工作,您必须在 Spring 中启用组件自动扫描特性。

 <beans 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<context:component-scan base-package="com.mkyong.customer.controller" />

	<bean class="com.mkyong.customer.validator.CustomerValidator" />

 	<!-- Register the Customer.properties -->
	<bean id="messageSource"
		class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="com/mkyong/customer/properties/Customer" />
	</bean>

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

下载源代码

Download it – SpringMVC-Form-Handling-Annotation-Example.zip (12KB)

参考

  1. spring 2.5 中带注释的 web mvc 控制器
  2. Spring MVC 表单处理示例–XML 版本
  3. Spring MVC hello world 注释示例
  4. Spring MVC multi action controller 注释示例

Tags : annotation form spring mvc

Spring MVC 表单处理示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-handling-example/

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本教程中,我们将向您展示一个 Spring MVC 表单处理项目来完成以下工作:

  1. 表单值绑定 JSP 和模型。
  2. 表单验证并显示错误消息。
  3. 形成 POST/REDIRECT/GET 模式,并将消息添加到 flash 属性。
  4. CRUD 操作,用一个 HTML 表单添加、获取、更新和删除。

使用的技术:

  1. 弹簧 4.1.6 释放
  2. maven3
  3. 自举 3
  4. HSQLDB 驱动程序 2.3.2
  5. 回溯 1.1.3
  6. JDK 1.7
  7. JSTL 1.2
  8. Eclipse IDE

一个简单的用户管理项目,你可以通过 HTML 表单列出、创建、更新和删除一个用户。您还将看到如何执行表单验证并有条件地显示错误消息。该项目使用 Bootstrap 3 进行设计,数据存储在 HSQL 嵌入式数据库中。

URI 结构:

| 上呼吸道感染 | 方法 | 行动 |
| /用户 | 得到 | 列表,显示所有用户 |
| /用户 | 邮政 | 保存或更新用户 |
| /users/{id} | 得到 | 显示用户{id} |
| /用户/添加 | 得到 | 显示添加用户表单 |
| /users/{id}/update | 得到 | 显示{id}的更新用户表单 |
| /users/{id}/delete | 邮政 | 删除用户{id} |

Note
In the old days, before Spring 3.0, we use [SimpleFormController](http://web.archive.org/web/20190303052227/http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/portlet/mvc/SimpleFormController.html) to do the form handling. As Spring 3.0, this class is deprecated in favor of Spring annotated @Controller.

Spring MVC 表单绑定

在开始本教程之前,您需要了解 Spring MVC 表单绑定是如何工作的。

1.1 在 controller 中,将对象添加到模型属性中。

 @RequestMapping(value = "/users/add", method = RequestMethod.GET)
	public String showAddUserForm(Model model) {
    
    

		User user = new User();
		model.addAttribute("userForm", user);
		//...
	} 

1.2 在 HTML 表单中,你使用spring:form标签,通过modelAttribute绑定控制器对象。

 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

	<form:form method="post" modelAttribute="userForm" action="${userActionUrl}">
		<form:input path="name" type="text" /> <!-- bind to user.name-->
		<form:errors path="name" />
	</form:form> 

1.3 当 HTML 表单为“POST”时,通过@ModelAttribute获取值。

 @RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(@ModelAttribute("userForm") User user,
		BindingResult result, Model model) {
    
    
	//...
} 

完成了。让我们开始教程。

1.项目目录

这是最终的项目目录结构。标准的 Maven 项目。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 ## 2.项目相关性

开发一个 Spring MVC 项目,需要spring-webmvc

pom.xml

 <project  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mkyong.form</groupId>
	<artifactId>spring-mvc-form</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>SpringMVC + Form Handling Example</name>

	<properties>
		<jdk.version>1.7</jdk.version>
		<spring.version>4.1.6.RELEASE</spring.version>
		<hsqldb.version>2.3.2</hsqldb.version>
		<logback.version>1.1.3</logback.version>
		<jcl.slf4j.version>1.7.12</jcl.slf4j.version>
		<jstl.version>1.2</jstl.version>
		<servletapi.version>3.1.0</servletapi.version>
	</properties>

	<dependencies>

		<!-- Spring Core -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${
    
    spring.version}</version>
			<exclusions>
			   <exclusion>
				<groupId>commons-logging</groupId>
				<artifactId>commons-logging</artifactId>
			    </exclusion>
			</exclusions>
		</dependency>

		<!-- Spring Web -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${
    
    spring.version}</version>
		</dependency>

		<!-- Spring JDBC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${
    
    spring.version}</version>
		</dependency>

		<!-- HyperSQL DB -->
		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>${
    
    hsqldb.version}</version>
		</dependency>

		<!-- logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${
    
    jcl.slf4j.version}</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${
    
    logback.version}</version>
		</dependency>

		<!-- jstl -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${
    
    jstl.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${
    
    servletapi.version}</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>
		<plugins>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.3</version>
				<configuration>
					<source>${
    
    jdk.version}</source>
					<target>${
    
    jdk.version}</target>
				</configuration>
			</plugin>

			<!-- embedded Jetty server, for testing -->
			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.2.11.v20150529</version>
				<configuration>
				  <scanIntervalSeconds>10</scanIntervalSeconds>
				  <webApp>
					<contextPath>/spring-mvc-form</contextPath>
				  </webApp>
				</configuration>
			</plugin>

			<!-- configure Eclipse workspace -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.9</version>
				<configuration>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
					<wtpversion>2.0</wtpversion>
					<wtpContextName>spring-mvc-form</wtpContextName>
				</configuration>
			</plugin>

		</plugins>
	</build>
</project> 

3.控制器

Spring @Controller类向你展示如何通过@ModelAttribute绑定表单值,添加表单验证器,将消息添加到 flash 属性中,填充下拉列表和复选框的值等等。阅读评论,不言自明。

UserController.java

 package com.mkyong.form.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.mkyong.form.model.User;
import com.mkyong.form.service.UserService;
import com.mkyong.form.validator.UserFormValidator;

@Controller
public class UserController {
    
    

	private final Logger logger = LoggerFactory.getLogger(UserController.class);

	@Autowired
	private UserService userService;

	@Autowired
	UserFormValidator userFormValidator;

	//Set a form validator
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
    
    
		binder.setValidator(userFormValidator);
	}

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String index(Model model) {
    
    
		logger.debug("index()");
		return "redirect:/users";
	}

	// list page
	@RequestMapping(value = "/users", method = RequestMethod.GET)
	public String showAllUsers(Model model) {
    
    

		logger.debug("showAllUsers()");
		model.addAttribute("users", userService.findAll());
		return "users/list";

	}

	// save or update user
	// 1\. @ModelAttribute bind form value
	// 2\. @Validated form validator
	// 3\. RedirectAttributes for flash value
	@RequestMapping(value = "/users", method = RequestMethod.POST)
	public String saveOrUpdateUser(@ModelAttribute("userForm") @Validated User user,
			BindingResult result, Model model, 
			final RedirectAttributes redirectAttributes) {
    
    

		logger.debug("saveOrUpdateUser() : {}", user);

		if (result.hasErrors()) {
    
    
			populateDefaultModel(model);
			return "users/userform";
		} else {
    
    

			// Add message to flash scope
			redirectAttributes.addFlashAttribute("css", "success");
			if(user.isNew()){
    
    
			  redirectAttributes.addFlashAttribute("msg", "User added successfully!");
			}else{
    
    
			  redirectAttributes.addFlashAttribute("msg", "User updated successfully!");
			}

			userService.saveOrUpdate(user);

			// POST/REDIRECT/GET
			return "redirect:/users/" + user.getId();

			// POST/FORWARD/GET
			// return "user/list";

		}

	}

	// show add user form
	@RequestMapping(value = "/users/add", method = RequestMethod.GET)
	public String showAddUserForm(Model model) {
    
    

		logger.debug("showAddUserForm()");

		User user = new User();

		// set default value
		user.setName("mkyong123");
		user.setEmail("[email protected]");
		user.setAddress("abc 88");
		user.setNewsletter(true);
		user.setSex("M");
		user.setFramework(new ArrayList<String>(Arrays.asList("Spring MVC", "GWT")));
		user.setSkill(new ArrayList<String>(Arrays.asList("Spring", "Grails", "Groovy")));
		user.setCountry("SG");
		user.setNumber(2);
		model.addAttribute("userForm", user);

		populateDefaultModel(model);

		return "users/userform";

	}

	// show update form
	@RequestMapping(value = "/users/{id}/update", method = RequestMethod.GET)
	public String showUpdateUserForm(@PathVariable("id") int id, Model model) {
    
    

		logger.debug("showUpdateUserForm() : {}", id);

		User user = userService.findById(id);
		model.addAttribute("userForm", user);

		populateDefaultModel(model);

		return "users/userform";

	}

	// delete user
	@RequestMapping(value = "/users/{id}/delete", method = RequestMethod.POST)
	public String deleteUser(@PathVariable("id") int id, 
		final RedirectAttributes redirectAttributes) {
    
    

		logger.debug("deleteUser() : {}", id);

		userService.delete(id);

		redirectAttributes.addFlashAttribute("css", "success");
		redirectAttributes.addFlashAttribute("msg", "User is deleted!");

		return "redirect:/users";

	}

	// show user
	@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
	public String showUser(@PathVariable("id") int id, Model model) {
    
    

		logger.debug("showUser() id: {}", id);

		User user = userService.findById(id);
		if (user == null) {
    
    
			model.addAttribute("css", "danger");
			model.addAttribute("msg", "User not found");
		}
		model.addAttribute("user", user);

		return "users/show";

	}

	private void populateDefaultModel(Model model) {
    
    

		List<String> frameworksList = new ArrayList<String>();
		frameworksList.add("Spring MVC");
		frameworksList.add("Struts 2");
		frameworksList.add("JSF 2");
		frameworksList.add("GWT");
		frameworksList.add("Play");
		frameworksList.add("Apache Wicket");
		model.addAttribute("frameworkList", frameworksList);

		Map<String, String> skill = new LinkedHashMap<String, String>();
		skill.put("Hibernate", "Hibernate");
		skill.put("Spring", "Spring");
		skill.put("Struts", "Struts");
		skill.put("Groovy", "Groovy");
		skill.put("Grails", "Grails");
		model.addAttribute("javaSkillList", skill);

		List<Integer> numbers = new ArrayList<Integer>();
		numbers.add(1);
		numbers.add(2);
		numbers.add(3);
		numbers.add(4);
		numbers.add(5);
		model.addAttribute("numberList", numbers);

		Map<String, String> country = new LinkedHashMap<String, String>();
		country.put("US", "United Stated");
		country.put("CN", "China");
		country.put("SG", "Singapore");
		country.put("MY", "Malaysia");
		model.addAttribute("countryList", country);

	}

} 

4.表单验证器

4.1 Spring 验证器示例。

UserFormValidator.java

 package com.mkyong.form.validator;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.mkyong.form.model.User;
import com.mkyong.form.service.UserService;

@Component
public class UserFormValidator implements Validator {
    
    

	@Autowired
	@Qualifier("emailValidator")
	EmailValidator emailValidator;

	@Autowired
	UserService userService;

	@Override
	public boolean supports(Class<?> clazz) {
    
    
		return User.class.equals(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {
    
    

		User user = (User) target;

		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.userForm.name");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "NotEmpty.userForm.email");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "address", "NotEmpty.userForm.address");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty.userForm.password");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword","NotEmpty.userForm.confirmPassword");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "sex", "NotEmpty.userForm.sex");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "country", "NotEmpty.userForm.country");

		if(!emailValidator.valid(user.getEmail())){
    
    
			errors.rejectValue("email", "Pattern.userForm.email");
		}

		if(user.getNumber()==null || user.getNumber()<=0){
    
    
			errors.rejectValue("number", "NotEmpty.userForm.number");
		}

		if(user.getCountry().equalsIgnoreCase("none")){
    
    
			errors.rejectValue("country", "NotEmpty.userForm.country");
		}

		if (!user.getPassword().equals(user.getConfirmPassword())) {
    
    
			errors.rejectValue("confirmPassword", "Diff.userform.confirmPassword");
		}

		if (user.getFramework() == null || user.getFramework().size() < 2) {
    
    
			errors.rejectValue("framework", "Valid.userForm.framework");
		}

		if (user.getSkill() == null || user.getSkill().size() < 3) {
    
    
			errors.rejectValue("skill", "Valid.userForm.skill");
		}

	}

} 

validation.properties

 NotEmpty.userForm.name = Name is required!
NotEmpty.userForm.email = Email is required!
NotEmpty.userForm.address = Address is required!
NotEmpty.userForm.password = Password is required!
NotEmpty.userForm.confirmPassword = Confirm password is required!
NotEmpty.userForm.sex = Sex is required!
NotEmpty.userForm.number = Number is required!
NotEmpty.userForm.country = Country is required!
Valid.userForm.framework = Please select at least two frameworks!
Valid.userForm.skill = Please select at least three skills!
Diff.userform.confirmPassword = Passwords do not match, please retype!
Pattern.userForm.email = Invalid Email format! 

要运行 Spring 验证器,通过@InitBinder添加验证器,并用@Validated注释模型

 @InitBinder
protected void initBinder(WebDataBinder binder) {
    
    
	binder.setValidator(userFormValidator);
}

@RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(... @Validated User user,
		...) {
    
    

	//...

} 

或者手动运行。

 @RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(... User user,
		...) {
    
    
	userFormValidator.validate(user, result);	
	//...
} 

5.HTML 表单

所有的 HTML 表单都是 css 样式,使用 Bootstrap 框架,并使用 Spring form 标签进行显示和表单绑定。
5.1 用户列表。

list.jsp

 <%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html lang="en">

<jsp:include page="../fragments/header.jsp" />

<body>

	<div class="container">

		<c:if test="${not empty msg}">
		    <div class="alert alert-${css} alert-dismissible" role="alert">
			<button type="button" class="close" data-dismiss="alert" 
                                aria-label="Close">
				<span aria-hidden="true">×</span>
			</button>
			<strong>${
    
    msg}</strong>
		    </div>
		</c:if>

		<h1>All Users</h1>

		<table class="table table-striped">
			<thead>
				<tr>
					<th>#ID</th>
					<th>Name</th>
					<th>Email</th>
					<th>framework</th>
					<th>Action</th>
				</tr>
			</thead>

			<c:forEach var="user" items="${users}">
			    <tr>
				<td>
					${
    
    user.id}
				</td>
				<td>${
    
    user.name}</td>
				<td>${
    
    user.email}</td>
				<td>
                                  <c:forEach var="framework" items="${user.framework}" 
                                                             varStatus="loop">
					${
    
    framework}
    				        <c:if test="${not loop.last}">,</c:if>
				  </c:forEach>
                                </td>
				<td>
				  <spring:url value="/users/${user.id}" var="userUrl" />
				  <spring:url value="/users/${user.id}/delete" var="deleteUrl" /> 
				  <spring:url value="/users/${user.id}/update" var="updateUrl" />

				  <button class="btn btn-info" 
                                          onclick="location.href='${userUrl}'">Query</button>
				  <button class="btn btn-primary" 
                                          onclick="location.href='${updateUrl}'">Update</button>
				  <button class="btn btn-danger" 
                                          onclick="this.disabled=true;post('${deleteUrl}')">Delete</button>
                                </td>
			    </tr>
			</c:forEach>
		</table>

	</div>

	<jsp:include page="../fragments/footer.jsp" />

</body>
</html> 

show.jsp

 <%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html lang="en">

<jsp:include page="../fragments/header.jsp" />

<div class="container">

	<c:if test="${not empty msg}">
		<div class="alert alert-${css} alert-dismissible" role="alert">
			<button type="button" class="close" data-dismiss="alert" 
                                aria-label="Close">
				<span aria-hidden="true">×</span>
			</button>
			<strong>${
    
    msg}</strong>
		</div>
	</c:if>

	<h1>User Detail</h1>
	<br />

	<div class="row">
		<label class="col-sm-2">ID</label>
		<div class="col-sm-10">${
    
    user.id}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Name</label>
		<div class="col-sm-10">${
    
    user.name}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Email</label>
		<div class="col-sm-10">${
    
    user.email}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Address</label>
		<div class="col-sm-10">${
    
    user.address}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Newsletter</label>
		<div class="col-sm-10">${
    
    user.newsletter}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Web Frameworks</label>
		<div class="col-sm-10">${
    
    user.framework}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Sex</label>
		<div class="col-sm-10">${
    
    user.sex}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Number</label>
		<div class="col-sm-10">${
    
    user.number}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Country</label>
		<div class="col-sm-10">${
    
    user.country}</div>
	</div>

	<div class="row">
		<label class="col-sm-2">Skill</label>
		<div class="col-sm-10">${
    
    user.skill}</div>
	</div>

</div>

<jsp:include page="../fragments/footer.jsp" />

</body>
</html> 

userform.jsp

 <%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html lang="en">

<jsp:include page="../fragments/header.jsp" />

<div class="container">

	<c:choose>
		<c:when test="${userForm['new']}">
			<h1>Add User</h1>
		</c:when>
		<c:otherwise>
			<h1>Update User</h1>
		</c:otherwise>
	</c:choose>
	<br />

	<spring:url value="/users" var="userActionUrl" />

	<form:form class="form-horizontal" method="post" 
                modelAttribute="userForm" action="${userActionUrl}">

		<form:hidden path="id" />

		<spring:bind path="name">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Name</label>
			<div class="col-sm-10">
				<form:input path="name" type="text" class="form-control" 
                                id="name" placeholder="Name" />
				<form:errors path="name" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="email">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Email</label>
			<div class="col-sm-10">
				<form:input path="email" class="form-control" 
                                id="email" placeholder="Email" />
				<form:errors path="email" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="password">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Password</label>
			<div class="col-sm-10">
				<form:password path="password" class="form-control" 
                                id="password" placeholder="password" />
				<form:errors path="password" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="confirmPassword">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">confirm Password</label>
			<div class="col-sm-10">
				<form:password path="confirmPassword" class="form-control" 
                                id="password" placeholder="password" />
				<form:errors path="confirmPassword" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="address">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Address</label>
			<div class="col-sm-10">
				<form:textarea path="address" rows="5" class="form-control" 
                                id="address" placeholder="address" />
				<form:errors path="address" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="newsletter">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Newsletter</label>
			<div class="col-sm-10">
				<div class="checkbox">
				  <label> 
                                     <form:checkbox path="newsletter" id="newsletter" />
				  </label>
				     <form:errors path="newsletter" class="control-label" />
				</div>
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="framework">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Web Frameworks</label>
			<div class="col-sm-10">
				<form:checkboxes path="framework" items="${frameworkList}" 
                                 element="label class='checkbox-inline'" />
				<br />
				<form:errors path="framework" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="sex">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Sex</label>
			<div class="col-sm-10">
				<label class="radio-inline"> 
                                  <form:radiobutton path="sex" value="M" /> Male
				</label> 
                                <label class="radio-inline"> 
                                  <form:radiobutton path="sex" value="F" /> Female
				</label> <br />
				<form:errors path="sex" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="number">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Number</label>
			<div class="col-sm-10">
				<form:radiobuttons path="number" items="${numberList}" 
                                element="label class='radio-inline'" />
				<br />
				<form:errors path="number" class="control-label" />
			</div>
		  </div>
		</spring:bind>

		<spring:bind path="country">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Country</label>
			<div class="col-sm-5">
				<form:select path="country" class="form-control">
					<form:option value="NONE" label="--- Select ---" />
					<form:options items="${countryList}" />
				</form:select>
				<form:errors path="country" class="control-label" />
			</div>
			<div class="col-sm-5"></div>
		  </div>
		</spring:bind>

		<spring:bind path="skill">
		  <div class="form-group ${status.error ? 'has-error' : ''}">
			<label class="col-sm-2 control-label">Java Skills</label>
			<div class="col-sm-5">
				<form:select path="skill" items="${javaSkillList}" 
                                 multiple="true" size="5" class="form-control" />
				<form:errors path="skill" class="control-label" />
			</div>
			<div class="col-sm-5"></div>
		  </div>
		</spring:bind>

		<div class="form-group">
		  <div class="col-sm-offset-2 col-sm-10">
			<c:choose>
			  <c:when test="${userForm['new']}">
			     <button type="submit" class="btn-lg btn-primary pull-right">Add
                             </button>
			  </c:when>
			  <c:otherwise>
			     <button type="submit" class="btn-lg btn-primary pull-right">Update
                             </button>
			  </c:otherwise>
			</c:choose>
		  </div>
		</div>
	</form:form>

</div>

<jsp:include page="../fragments/footer.jsp" />

</body>
</html> 

6.数据库的东西

6.1 创建一个表,并插入一些测试数据。

create-db.sql

 CREATE TABLE users (
  id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 100, INCREMENT BY 1) PRIMARY KEY,
  name VARCHAR(30),
  email  VARCHAR(50),
  address VARCHAR(255),
  password VARCHAR(20),
  newsletter BOOLEAN,
  framework VARCHAR(500),
  sex VARCHAR(1),
  NUMBER INTEGER,
  COUNTRY VARCHAR(10),
  SKILL VARCHAR(500)
); 

insert-data.sql

 INSERT INTO users (name, email, framework) VALUES ('mkyong', '[email protected]', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('alex', '[email protected]', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('joel', '[email protected]', 'Spring MVC, GWT'); 

6.2 启动一个 HSQLDB 嵌入式数据库,创建一个数据源和 jdbcTemplate。

SpringDBConfig.java

 package com.mkyong.form.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

@Configuration
public class SpringDBConfig {
    
    

	@Autowired
	DataSource dataSource;

	@Bean
	public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
    
    
		return new NamedParameterJdbcTemplate(dataSource);
	}

	@Bean
	public DataSource getDataSource() {
    
    
		EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
		EmbeddedDatabase db = builder.setName("testdb")
                        .setType(EmbeddedDatabaseType.HSQL)
			.addScript("db/sql/create-db.sql")
                        .addScript("db/sql/insert-data.sql").build();
		return db;
	}

} 

6.3 用户对象。

user.java

 package com.mkyong.form.model;

import java.util.List;

public class User {
    
    
	// form:hidden - hidden value
	Integer id;

	// form:input - textbox
	String name;

	// form:input - textbox
	String email;

	// form:textarea - textarea
	String address;

	// form:input - password
	String password;

	// form:input - password
	String confirmPassword;

	// form:checkbox - single checkbox
	boolean newsletter;

	// form:checkboxes - multiple checkboxes
	List<String> framework;

	// form:radiobutton - radio button
	String sex;

	// form:radiobuttons - radio button
	Integer number;

	// form:select - form:option - dropdown - single select
	String country;

	// form:select - multiple=true - dropdown - multiple select
	List<String> skill;

	//Check if this is for New of Update
	public boolean isNew() {
    
    
		return (this.id == null);
	}

	//...

} 

7.服务和一体行动

UserService.java

 package com.mkyong.form.service;

import java.util.List;
import com.mkyong.form.model.User;

public interface UserService {
    
    

	User findById(Integer id);

	List<User> findAll();

	void saveOrUpdate(User user);

	void delete(int id);

} 

UserServiceImpl.java

 package com.mkyong.form.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mkyong.form.dao.UserDao;
import com.mkyong.form.model.User;

@Service("userService")
public class UserServiceImpl implements UserService {
    
    

	UserDao userDao;

	@Autowired
	public void setUserDao(UserDao userDao) {
    
    
		this.userDao = userDao;
	}

	@Override
	public User findById(Integer id) {
    
    
		return userDao.findById(id);
	}

	@Override
	public List<User> findAll() {
    
    
		return userDao.findAll();
	}

	@Override
	public void saveOrUpdate(User user) {
    
    

		if (findById(user.getId())==null) {
    
    
			userDao.save(user);
		} else {
    
    
			userDao.update(user);
		}

	}

	@Override
	public void delete(int id) {
    
    
		userDao.delete(id);
	}

} 

UserDao.java

 package com.mkyong.form.dao;

import java.util.List;

import com.mkyong.form.model.User;

public interface UserDao {
    
    

	User findById(Integer id);

	List<User> findAll();

	void save(User user);

	void update(User user);

	void delete(Integer id);

} 

UserDaoImpl.java

 package com.mkyong.form.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.mkyong.form.model.User;

@Repository
public class UserDaoImpl implements UserDao {
    
    

	NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	@Autowired
	public void setNamedParameterJdbcTemplate(
		NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
    
    
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}

	@Override
	public User findById(Integer id) {
    
    

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);

		String sql = "SELECT * FROM users WHERE id=:id";

		User result = null;
		try {
    
    
			result = namedParameterJdbcTemplate
                          .queryForObject(sql, params, new UserMapper());
		} catch (EmptyResultDataAccessException e) {
    
    
			// do nothing, return null
		}

		return result;

	}

	@Override
	public List<User> findAll() {
    
    

		String sql = "SELECT * FROM users";
		List<User> result = namedParameterJdbcTemplate.query(sql, new UserMapper());
		return result;

	}

	@Override
	public void save(User user) {
    
    

		KeyHolder keyHolder = new GeneratedKeyHolder();

		String sql = "INSERT INTO USERS(NAME, EMAIL, ADDRESS, PASSWORD, NEWSLETTER, FRAMEWORK, SEX, NUMBER, COUNTRY, SKILL) "
				+ "VALUES ( :name, :email, :address, :password, :newsletter, :framework, :sex, :number, :country, :skill)";

		namedParameterJdbcTemplate.update(sql, getSqlParameterByModel(user), keyHolder);
		user.setId(keyHolder.getKey().intValue());

	}

	@Override
	public void update(User user) {
    
    

		String sql = "UPDATE USERS SET NAME=:name, EMAIL=:email, ADDRESS=:address, " 
			+ "PASSWORD=:password, NEWSLETTER=:newsletter, FRAMEWORK=:framework, "
			+ "SEX=:sex, NUMBER=:number, COUNTRY=:country, SKILL=:skill WHERE id=:id";

		namedParameterJdbcTemplate.update(sql, getSqlParameterByModel(user));

	}

	@Override
	public void delete(Integer id) {
    
    

		String sql = "DELETE FROM USERS WHERE id= :id";
		namedParameterJdbcTemplate.update(sql, new MapSqlParameterSource("id", id));

	}

	private SqlParameterSource getSqlParameterByModel(User user) {
    
    

		MapSqlParameterSource paramSource = new MapSqlParameterSource();
		paramSource.addValue("id", user.getId());
		paramSource.addValue("name", user.getName());
		paramSource.addValue("email", user.getEmail());
		paramSource.addValue("address", user.getAddress());
		paramSource.addValue("password", user.getPassword());
		paramSource.addValue("newsletter", user.isNewsletter());

		// join String
		paramSource.addValue("framework", convertListToDelimitedString(user.getFramework()));
		paramSource.addValue("sex", user.getSex());
		paramSource.addValue("number", user.getNumber());
		paramSource.addValue("country", user.getCountry());
		paramSource.addValue("skill", convertListToDelimitedString(user.getSkill()));

		return paramSource;
	}

	private static final class UserMapper implements RowMapper<User> {
    
    

		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
    
    
			User user = new User();
			user.setId(rs.getInt("id"));
			user.setName(rs.getString("name"));
			user.setEmail(rs.getString("email"));
			user.setFramework(convertDelimitedStringToList(rs.getString("framework")));
			user.setAddress(rs.getString("address"));
			user.setCountry(rs.getString("country"));
			user.setNewsletter(rs.getBoolean("newsletter"));
			user.setNumber(rs.getInt("number"));
			user.setPassword(rs.getString("password"));
			user.setSex(rs.getString("sex"));
			user.setSkill(convertDelimitedStringToList(rs.getString("skill")));
			return user;
		}
	}

	private static List<String> convertDelimitedStringToList(String delimitedString) {
    
    

		List<String> result = new ArrayList<String>();

		if (!StringUtils.isEmpty(delimitedString)) {
    
    
			result = Arrays.asList(StringUtils.delimitedListToStringArray(delimitedString, ","));
		}
		return result;

	}

	private String convertListToDelimitedString(List<String> list) {
    
    

		String result = "";
		if (list != null) {
    
    
			result = StringUtils.arrayToCommaDelimitedString(list.toArray());
		}
		return result;

	}

} 

8.弹簧配置

混合 Spring XML 和 JavaConfig。

SpringWebConfig.java

 package com.mkyong.form.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({
    
     "com.mkyong.form.web", "com.mkyong.form.service", "com.mkyong.form.dao",
		"com.mkyong.form.exception", "com.mkyong.form.validator" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
    
    

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

	@Bean
	public InternalResourceViewResolver viewResolver() {
    
    
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/jsp/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}

	@Bean
	public ResourceBundleMessageSource messageSource() {
    
    
		ResourceBundleMessageSource rb = new ResourceBundleMessageSource();
		rb.setBasenames(new String[] {
    
     "messages/messages", "messages/validation" });
		return rb;
	}

} 

spring-web-servlet.xml

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Scan the JavaConfig -->
	<context:component-scan base-package="com.mkyong.form.config" />

</beans> 

web.xml

 <web-app  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">

	<display-name>Spring3 MVC Application</display-name>

	<servlet>
		<servlet-name>spring-web</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>spring-web</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/jsp/error.jsp</location>
	</error-page>

	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/jsp/error.jsp</location>
	</error-page>

	<error-page>
		<location>/WEB-INF/views/jsp/error.jsp</location>
	</error-page>

</web-app> 

9.演示

下载项目并键入mvn jetty:run

 $ mvn jetty:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building SpringMVC + Form Handling Example 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
//...
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds. 

**9.1 列出所有用户。**http://localhost:8080/spring-MVC-form/users

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**9.2 添加用户。**http://localhost:8080/spring-MVC-form/users/add

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.3 表单验证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**9.4 新增用户。**http://localhost:8080/spring-MVC-form/users

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**9.5 删除用户。**http://localhost:8080/spring-MVC-form/users/104/delete

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下载源代码

Download it - spring4-form-handle-example.zip (80 kb)Github - TBD

参考

  1. 使用 Spring 的表单标签库
  2. Spring MVC 3 验证
  3. RedirectAttributes JavaDoc

form handling spring mvc

Spring MVC 处理程序拦截器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/

Spring MVC 允许您通过处理程序拦截器来拦截 web 请求。处理程序拦截器必须实现 HandlerInterceptor 接口,该接口包含三个方法:

  1. preHandle()–在处理程序执行前调用,返回一个布尔值,“true”:继续处理程序执行链;“false”,停止执行链并返回。
  2. post handle()–在处理程序执行后调用,允许在将 ModelAndView 对象呈现到视图页面之前对其进行操作。
  3. after completion()–在完成请求完成后调用。很少使用,找不到任何用例。

在本教程中,您将创建两个处理程序拦截器来展示 HandlerInterceptor 的用法。

  1. execute time interceptor–拦截 web 请求,记录控制器执行时间。
  2. 维护拦截器–拦截 web 请求,检查当前时间是否在维护时间之间,如果是,则重定向到维护页面。

Note
It’s recommended to extend the HandlerInterceptorAdapter for the convenient default implementations.

1.ExecuteTimeInterceptor

截取控制器执行前后的时间,记录执行的开始和结束时间,保存到已有的截取控制器的 modelAndView 中,以便以后显示。

文件:ExecuteTimeInterceptor.java

 package com.mkyong.common.interceptor;

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

import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{
    
    

	private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);

	//before the actual handler will be executed
	public boolean preHandle(HttpServletRequest request, 
		HttpServletResponse response, Object handler)
	    throws Exception {
    
    

		long startTime = System.currentTimeMillis();
		request.setAttribute("startTime", startTime);

		return true;
	}

	//after the handler is executed
	public void postHandle(
		HttpServletRequest request, HttpServletResponse response, 
		Object handler, ModelAndView modelAndView)
		throws Exception {
    
    

		long startTime = (Long)request.getAttribute("startTime");

		long endTime = System.currentTimeMillis();

		long executeTime = endTime - startTime;

		//modified the exisitng modelAndView
		modelAndView.addObject("executeTime",executeTime);

		//log it
		if(logger.isDebugEnabled()){
    
    
		   logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");
		}
	}
} 

2.维护拦截器

在控制器执行前拦截,检查当前时间是否在维护时间之间,如果是则重定向到维护页面;否则继续执行链。

文件:MaintenanceInterceptor.java

 package com.mkyong.common.interceptor;

import java.util.Calendar;

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

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class MaintenanceInterceptor extends HandlerInterceptorAdapter{
    
    

	private int maintenanceStartTime;
	private int maintenanceEndTime;
	private String maintenanceMapping;

	public void setMaintenanceMapping(String maintenanceMapping) {
    
    
		this.maintenanceMapping = maintenanceMapping;
	}

	public void setMaintenanceStartTime(int maintenanceStartTime) {
    
    
		this.maintenanceStartTime = maintenanceStartTime;
	}

	public void setMaintenanceEndTime(int maintenanceEndTime) {
    
    
		this.maintenanceEndTime = maintenanceEndTime;
	}

	//before the actual handler will be executed
	public boolean preHandle(HttpServletRequest request, 
			HttpServletResponse response, Object handler)
	    throws Exception {
    
    

		Calendar cal = Calendar.getInstance();
		int hour = cal.get(cal.HOUR_OF_DAY);

		if (hour >= maintenanceStartTime && hour <= maintenanceEndTime) {
    
    
			//maintenance time, send to maintenance page
			response.sendRedirect(maintenanceMapping);
			return false;
		} else {
    
    
			return true;
		}

	}
} 

3.启用处理程序拦截器

要启用它,请将您的处理程序拦截器类放入处理程序映射“拦截器”属性中。

 <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.5.xsd">

	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/welcome.htm">welcomeController</prop>
			</props>
		</property>
		<property name="interceptors">
			<list>
				<ref bean="maintenanceInterceptor" />
				<ref bean="executeTimeInterceptor" />
			</list>
		</property>
	</bean>

	<bean
	class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
		<property name="interceptors">
			<list>
				<ref bean="executeTimeInterceptor" />
			</list>
		</property>
	</bean>

	<bean id="welcomeController" 
                  class="com.mkyong.common.controller.WelcomeController" />
	<bean class="com.mkyong.common.controller.MaintenanceController" />

	<bean id="executeTimeInterceptor" 
                 class="com.mkyong.common.interceptor.ExecuteTimeInterceptor" />

	<bean id="maintenanceInterceptor" 
                class="com.mkyong.common.interceptor.MaintenanceInterceptor">
		<property name="maintenanceStartTime" value="23" />
		<property name="maintenanceEndTime" value="24" />
		<property name="maintenanceMapping" value="/SpringMVC/maintenance.htm" />
	</bean>

	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

</beans> 

下载源代码

Download it –SpringMVC-HandlerInterceptor-Example.zip (8 KB)

参考

  1. HandlerInterceptorAdapter 文档
  2. 处理接收器文档
  3. ControllerClassNameHandlerMapping 示例
  4. SimpleUrlHandlerMapping 示例

Tags : interceptor spring mvc

用 AbstractWizardFormController 处理多页表单

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-handling-multipage-forms-with-abstractwizardformcontroller/

在上一个 Spring MVC 表单处理示例中,我们将向您介绍如何使用 SimpleFormController 来处理单页表单提交,这非常简单明了。

但是,有时,您可能需要处理"向导表单,这需要将表单处理成多页,并要求用户逐页填写表单。在这种向导表单情况下,主要关心的是如何存储模型数据(由用户填写的数据)并将其带到多个页面上?

SAbstractWizardFormController

幸运的是,Spring MVC 自带了AbstractWizardFormController类来轻松处理这个向导表单。在本教程中,我们将向您展示如何使用AbstractWizardFormController类来跨多个页面存储和携带表单数据,应用验证并在最后一页显示表单数据。

1.向导表单页面

本演示共 5 页,按以下顺序进行:

 [User] --> WelcomePage --> Page1 --> Page2 --> Page3 --> ResultPage 

使用AbstractWizardFormController,页面顺序由提交按钮的“名称”决定:

  1. _finish:完成向导表单。
  2. _cancel:取消向导表单。
  3. _targetx:移动到目标页面,其中 x 是从零开始的页面索引。例如 _target0_target1 等。

1。WelcomePage.jsp
一个欢迎页面,带有一个超链接来启动向导表单过程。

 <html>
<body>
	<h2>Handling multipage forms in Spring MVC</h2>
	Click here to start playing -
	<a href="user.htm">AbstractWizardFormController example</a>
</body>
</html> 

2。Page1Form.jsp
第 1 页,有一个“用户名”文本框,显示错误信息(如果有的话),并包含 2 个提交按钮,其中:

  1. _ target 1–移至第 2 页。
  2. _ cancel–取消向导表单流程,并将其移至取消页面
 <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
    
    
	color: #ff0000;
}

.errorblock {
    
    
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>

<body>
	<h2>Page1Form.jsp</h2>

	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Username :</td>
				<td><form:input path="userName" />
				</td>
				<td><form:errors path="userName" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Next"
					name="_target1" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>

</body>
</html> 

3。Page2Form.jsp
第 2 页,有一个“密码”字段,显示错误信息(如果有的话),并包含 3 个提交按钮,其中:

  1. _ target 0–移至第 1 页。
  2. _ target 2–移至第 3 页。
  3. _ cancel–取消向导表单流程,并将其移至取消页面
 <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
    
    
	color: #ff0000;
}

.errorblock {
    
    
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>

<body>
	<h2>Page2Form.jsp</h2>

	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Password :</td>
				<td><form:password path="password" />
				</td>
				<td><form:errors path="password" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Previous"
					name="_target0" /> <input type="submit" value="Next"
					name="_target2" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>

</body>
</html> 

4。Page3Form.jsp
第 3 页,有一个“备注”文本框,显示错误信息(如果有),并包含 3 个提交按钮,其中:

  1. _ target 1–移至第 2 页。
  2. _ finish–完成向导表单流程,并将其移至完成页面。
  3. _ cancel–取消向导表单流程,并将其移至取消页面。
 <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
    
    
	color: #ff0000;
}

.errorblock {
    
    
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>

<body>
	<h2>Page3Form.jsp</h2>

	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Remark :</td>
				<td><form:input path="remark" />
				</td>
				<td><form:errors path="remark" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Previous"
					name="_target1" /> <input type="submit" value="Finish"
					name="_finish" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>

</body>
</html> 

5。ResultForm.jsp
显示前 3 页收集的所有表单数据。

 <html>
<body>
	<h2>ResultForm.jsp</h2>

	<table>
		<tr>
			<td>UserName :</td>
			<td>${
    
    user.userName}</td>
		</tr>
		<tr>
			<td>Password :</td>
			<td>${
    
    user.password}</td>
		</tr>
		<tr>
			<td>Remark :</td>
			<td>${
    
    user.remark}</td>
		</tr>
	</table>

</body>
</html> 

2.模型

创建一个模型类来存储表单数据。

文件:User.java

 package com.mkyong.common.model;

public class User{
    
    

	String userName;
	String password;
	String remark;

	//getter and setter methods
} 

3.AbstractWizardFormController

扩展AbstractWizardFormController,只需覆盖以下方法

  1. process finish–当用户点击名为 _finish 的提交按钮时触发。
  2. process cancel–当用户点击名为 _cancel 的提交按钮时触发。
  3. formBackingObject–使用“User”模型类将所有表单数据存储在多个页面中。

文件:UserController.java

 package com.mkyong.common.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;
import com.mkyong.common.model.User;
import com.mkyong.common.validator.UserValidator;

public class UserController extends AbstractWizardFormController{
    
    

	public UserController(){
    
    
		setCommandName("userForm");
	}

	@Override
	protected Object formBackingObject(HttpServletRequest request)
		throws Exception {
    
    

		return new User();
	}
	@Override
	protected ModelAndView processFinish(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors)
		throws Exception {
    
    

		//Get the data from command object
		User user = (User)command;
		System.out.println(user);

		//where is the finish page?
		return new ModelAndView("ResultForm", "user", user);
	}

	@Override
	protected ModelAndView processCancel(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors)
		throws Exception {
    
    

		//where is the cancel page?
		return new ModelAndView("WelcomePage");
	}
} 

一个简单的控制器返回一个" WelcomePage "视图。

文件:WelcomeController.java

 package com.mkyong.common.controller;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class WelcomeController extends AbstractController{
    
    

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
		HttpServletResponse response) throws Exception {
    
    

		return new ModelAndView("WelcomePage");
	}

} 

4.多页/向导表单验证

SimpleFormController中,创建一个验证器类,将所有的验证逻辑放在 validate() 方法中,并将验证器装饰性地注册到简单表单控制器中。

但是,在AbstractWizardFormController中有点不同。首先,创建一个验证器类,以及每个页面的验证方法,如下所示:

文件:UserValidator.java

 package com.mkyong.common.validator;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.mkyong.common.model.User;

public class UserValidator implements Validator{
    
    

	@Override
	public boolean supports(Class clazz) {
    
    
		//just validate the User instances
		return User.class.isAssignableFrom(clazz);
	}

	//validate page 1, userName
	public void validatePage1Form(Object target, Errors errors) {
    
    
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName",
		        "required.userName", "Field name is required.");
	}

	//validate page 2, password
	public void validatePage2Form(Object target, Errors errors) {
    
    
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",
			"required.password", "Field name is required.");
	}

	//validate page 3, remark
	public void validatePage3Form(Object target, Errors errors) {
    
    
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "remark",
			"required.remark", "Field name is required.");
	}

	@Override
	public void validate(Object target, Errors errors) {
    
    
		validatePage1Form(target, errors);
		validatePage2Form(target, errors);
		validatePage3Form(target, errors);
	}
} 

File:user . Properties–存储错误消息的属性

 required.userName = Username is required!
required.password = Password is required!
required.remark = Remark is required! 

并且,在向导表单控制器(UserController.java)中,通过手动调用验证器来覆盖 validatePage() (不再有像简单表单控制器那样的声明)。

UserController.java的更新版本。

 public class UserController extends AbstractWizardFormController{
    
    
	//other methods, see above

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

		UserValidator validator = (UserValidator) getValidator();

		//page is 0-indexed
		switch (page) {
    
    
		   case 0: //if page 1 , go validate with validatePage1Form
			validator.validatePage1Form(command, errors);
			break;
		   case 1: //if page 2 , go validate with validatePage2Form
			validator.validatePage2Form(command, errors);
			break;
		   case 2: //if page 3 , go validate with validatePage3Form
			validator.validatePage3Form(command, errors);
			break;
		}
	}
} 

validatePage() 方法中,使用一个“开关函数来确定哪个页面正在调用,并将其与相应的验证器相关联。该页面的索引为 0。

5.弹簧配置

声明向导表单控制器(UserController.java),按正确的顺序排列所有页面,并注册一个验证器。

 <bean class="com.mkyong.common.controller.UserController" >
    	   <property name="pages">
		<list>
		<!-- follow sequence -->
		<value>Page1Form</value> <!-- page1, _target0 -->
		<value>Page2Form</value> <!-- page2, _target1 -->
		<value>Page3Form</value> <!-- page3, _target2 -->
		</list>
	   </property>
	   <property name="validator">
		<bean class="com.mkyong.common.validator.UserValidator" />
	   </property>
       </bean> 

Note
In the “pages” property, the order of the list value is used to define the sequence of the page in the wizard form.

查看完整示例:

 <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.5.xsd">

 <bean 
  class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

    <bean class="com.mkyong.common.controller.WelcomeController" />  
    <bean class="com.mkyong.common.controller.UserController" >
    	<property name="pages">
	   <list>
		<!-- follow sequence -->
		<value>Page1Form</value> <!-- page1 -->
		<value>Page2Form</value> <!-- page2 -->
		<value>Page3Form</value> <!-- page3 -->
	   </list>
	   </property>
	   <property name="validator">
		<bean class="com.mkyong.common.validator.UserValidator" />
	   </property>
      </bean>

      <!-- Register User.properties for validation error message -->
      <bean id="messageSource"
           class="org.springframework.context.support.ResourceBundleMessageSource">
	   <property name="basename" value="User" />
      </bean>

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

5.演示

网址:http://localhost:8080/spring MVC/welcome . htm

1。WelcomePage.jsp,点击链接,移动到 Page1Form.jsp**。**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2。Page1Form.jsp,包含一个“用户名”文本框和两个按钮:

  1. “下一步”按钮–移动到 Page2Form.jsp。
  2. “取消”按钮–移至 WelcomePage.jsp

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果提交表单时“用户名”为空,则显示错误消息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。Page2Form.jsp,包含一个“密码”字段和 3 个按钮:

  1. “上一页”按钮–移至 Page1Form.jsp。
  2. “下一步”按钮–移动到 Page3Form.jsp。
  3. “取消”按钮–移至 WelcomePage.jsp。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4。Page3Form.jsp,包含一个“备注”文本框和 3 个按钮:

  1. “上一页”按钮–移至 Page2Form.jsp。
  2. “完成”按钮–移动到 ResultForm.jsp。
  3. “取消”按钮–移至 WelcomePage.jsp。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5。ResultForm.jsp,显示所有表单的数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下载源代码

Download it – SpringMVC-MultiPage-Form-Handling-Example.zip (12KB)

参考

  1. AbstractWizardFormController Javadoc
  2. Spring MVC 表单处理示例

Tags : spring mvc

猜你喜欢

转载自blog.csdn.net/wizardforcel/article/details/143497701