
このチュートリアルでは、次のことを行うSpring MVCフォーム処理プロジェクトを紹介します:
-
フォームバリューバインディング – JSPとモデル.
-
フォームの検証とエラーメッセージの表示
-
POST POST/REDIRECT/GETパターンを作成し、フラッシュ属性にメッセージを追加します.
-
CRUD操作、HTMLフォームによる追加、取得、更新、削除
-
Spring 4.1.6.RELEASE
-
Maven 3
-
ブートストラップ3
-
HSQLDBドライバ2.3.2
-
ログバック1.1.3
-
JDK 1.7
-
JSTL 1.2
-
Eclipse IDE
-
あなたが構築するもの:** +簡単なユーザー管理プロジェクトでは、HTMLフォームを使用して、ユーザーの一覧表示、作成、更新、および削除を行うことができます。フォームの検証を実行し、エラーメッセージを条件付きで表示する方法もわかります。このプロジェクトはBootstrap 3でスタイリングし、データはHSQL組み込みデータベースに格納されます。
-
URI構造:**
-
| =========================================== =========== | URI |メソッド|アクション|/users | GET |リスト表示、すべてのユーザーの表示|/users | POST |ユーザーの保存または更新ユーザー\ {id} |/users/add | GET |ユーザーフォームの追加を表示する/ユーザー/\ {id}/update | GET | \ {id} |/users/\ {id}/deleteの更新ユーザーフォームを表示する| POST |ユーザーを削除\ {id} | =============================== =================
-
注意** Spring 3.0以前は、フォーム処理を行うために `SimpleFormController`を使用していました。 Spring 3.0として、このクラスはSpring注釈付き@Controllerを使用して非推奨になりました。
Spring MVCフォームバインディング
チュートリアルを始める前に、Spring MVCフォームバインディングがどのように機能するかを理解する必要があります。
1.1コントローラでは、オブジェクトをモデル属性に追加します。
@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プロジェクト。
リンク://wp-content/uploads/2010/08/spring-mvc-form-handling-directory.png[
]
プロジェクトの依存関係
Spring MVCプロジェクトを開発するには、 `spring-webmvc`が必要です。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
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.コントローラー
@ ModelAttribute`を介してフォーム値をバインドする方法、フォームバリデーターを追加する方法、フラッシュ属性にメッセージを追加する方法、ドロップダウンやチェックボックスの値を入力する方法などを示すSpring
@ Controller`クラスです。
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("test@gmail.com");
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 Validatorを実行するには、
@ 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フォームは、BootstrapフレームワークでCSSスタイルを設定し、Springフォームタグを使用して表示とフォームのバインドを行います。 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', 'mkyong@gmail.com', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('alex', 'alex@yahoo.com', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('joel', 'joel@gmail.com', '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.サービスとDAO
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="http://www.springframework.org/schema/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="http://java.sun.com/xml/ns/javaee"
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
リンク://wp-content/uploads/2010/08/spring-mvc-form-handling-demo-add.png[
]
-
9.3フォーム検証。**
リンク://wp-content/uploads/2010/08/spring-mvc-form-handling-demo-add-error.png[
]
-
9.4新しいユーザーが追加されました。**
http://localhost:8080/spring-mvc-form/users
リンク://wp-content/uploads/2010/08/spring-mvc-form-handling-demo-add-done.png[
]
-
9.5ユーザーを削除する**
http://localhost:8080/spring-mvc-form/users/104/delete
リンク://wp-content/uploads/2010/08/spring-mvc-form-handling-demo-delete.png[
]
参考文献
春のフォームタグライブラリ]。
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#validation-mvc
[Spring
MVC 3検証]。
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/support/RedirectAttributes.html
[RedirectAttributes
JavaDoc]