JSP/Servletアプリでvalidatorの機能を使う

Servlet/JSPの環境で、入力値のチェックを行ってみます。
ここでは、バリデーションという仕組みを利用します。

この記事では、バリデーションの他に、DispatcherServletパターン、setAttributeでインスタンスを設定して、JSPで表示する方法のサンプルとしても使えます。

さて、今回の例では、名前、年齢、身長を入力して、その入力値をチェックします。

フォームはこんなイメージです。

f:id:sho322:20140517173628j:plain

ここにチェックした入力値が空だったり、数値を入れるべきところに変な文字列が入っていたりすると、以下のようにエラーメッセージを表示します。

f:id:sho322:20140517173442j:plain

サンプルのフォルダ構成は以下のようになっています。
こちらがソースの構成です。
f:id:sho322:20140517173538j:plain

こちらが、WEB-INF周りの構成。
f:id:sho322:20140517173429j:plain

それでは、ソースを見てきましょう。
まずはコントローラーです。
■Controller(インターフェース)

package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Controller {
String handleRequest(HttpServletRequest request, HttpServletResponse response);
}

■InputFriendController

package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class InputFriendController implements Controller {
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
return "/WEB-INF/jsp/FriendForm.jsp";
}
}

■SaveFriendController

package controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import domain.Friend;
import validator.FriendValidator;
import form.FriendForm;
public class SaveFriendController implements Controller {
public String handleRequest(HttpServletRequest request,
HttpServletResponse response) {
FriendForm friendForm = new FriendForm();
friendForm.setName(request.getParameter("name"));
friendForm.setAge(request.getParameter("age"));
friendForm.setHeight(request.getParameter("height"));
FriendValidator friendValidator = new FriendValidator();
List<String> errors = friendValidator.validate(friendForm);
if(errors.isEmpty()) {
Friend friend = new Friend();
friend.setName(friendForm.getName());
friend.setAge(Integer.parseInt(friendForm.getAge()));
friend.setHeight(Float.parseFloat(friendForm.getHeight()));
request.setAttribute("friend", friend);
return "/WEB-INF/jsp/FriendDetails.jsp";
} else {
request.setAttribute("errors", errors);
request.setAttribute("form", friendForm);
return "/WEB-INF/jsp/FriendForm.jsp";
}
}
}

これらのコントローラーは、ブラウザからリクエストされたHTTPを処理する役割を果たします。
各コントローラーに、入力値の保存や、入力フォームの表示などの役割を割り当てて、分離しています。

そうすることで、以下のようなDispatcherServletによって、各コントローラーに振り分けることができます。
DispatcherControllerパターンは、JavaEEの古くからのデザインパターンで、リクエストを最初に受け付けるコントローラーの役割を果たします。

最初に受け付けて、担当者に振り分けるわけです。

■DispatcherServlet

package servlet;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import controller.InputFriendController;
import controller.SaveFriendController;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 38749L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
public void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String uri = request.getRequestURI();
int lastIndex = uri.lastIndexOf("/");
String action = uri.substring(lastIndex + 1);
String dispatchUrl = null;
if (action.equals("friend_input.action")) {
InputFriendController controller = new InputFriendController();
dispatchUrl = controller.handleRequest(request, response);
} else if (action.equals("friend_save.action")) {
SaveFriendController controller = new SaveFriendController();
dispatchUrl = controller.handleRequest(request, response);
}
if (dispatchUrl != null) {
RequestDispatcher rd = request.getRequestDispatcher(dispatchUrl);
rd.forward(request, response);
}
}
}

このDispatcherServletでは、リクエストを受けたURLを解析して、そのアクション(どんな処理をしたいのか)を取り出します。
そのアクションに応じたコントローラーに処理を振り分けるわけです。

DispatcherServletに振り分けるためのweb.xmlの設定は以下のとおりです。

■web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
<display-name>springweb</display-name>
<!--
		- Location of the XML file that defines the root application context.
		- Applied by ContextLoaderListener.
	-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/application-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--
		- Servlet that dispatches request to registered handlers (Controller implementations).
	-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>servlet.DispatcherServlet</servlet-class>
<!--  
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        -->
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>

STS(Spring Tool Suite)のSpring Web Mavenプロジェクトを使っているので、余計な記述も含まれています。

次に、今回のメインである、Validatorについて見てみます。

■FriendValidator

package validator;
import java.util.ArrayList;
import java.util.List;
import form.FriendForm;
public class FriendValidator {
public List<String> validate(FriendForm friendForm) {
List<String> errors = new ArrayList<String>();
String name = friendForm.getName();
if (name == null || name.trim().isEmpty()) {
errors.add("名前は必ず入力してください");
}
String age = friendForm.getAge();
if (age == null || age.trim().isEmpty()) {
errors.add("年齢は必ず入力してください");
} else {
try {
Integer.parseInt(age);
} catch (NumberFormatException e) {
errors.add("年齢に変な値を入れてませんか?");
}
}
String height = friendForm.getHeight();
if (height == null || height.trim().isEmpty()) {
errors.add("身長を入れてね");
} else {
try {
Float.parseFloat(height);
} catch (NumberFormatException e) {
errors.add("身長におかしな値を入れてませんか?");
}
}
return errors;
}
}

ここで出てくるFriendFormとはなんでしょうか。
■FriendForm

package form;
public class FriendForm {
private String name;
private String age;
private String height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
}

■Friend

package domain;
public class Friend {
private String name;
private int age;
private float height;
public Friend() {
}
public Friend(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}

最後に、これらを表示するJSPを見てみます。

■FriendForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>友達入力</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>
<div id="global">
<c:if test="${requestScope.errors != null}">
<p id="errors">
おねがい
<ul>
<c:forEach var="error" items="${requestScope.errors}">
<li>${error}</li>
</c:forEach>
</ul>
</p>
</c:if>
<form action="friend_save.action" method="post">
<fieldset>
<legend>友達を追加します</legend>
<p>
<label for="name">おなまえ:</label>
<input type="text" id="name" name="name" tabindex="1">
</p>
<p>
<label for="age">年齢:</label>
<input type="text" id="age" name="age" tabindex="2">
</p>
<p>
<label for="height">身長:</label>
<input type="text" id="height" name="height" tabindex="3">
</p>
<p id="buttons">
<input id="reset" type="reset" tabindex="4">
<input id="submit" type="submit" tabindex="5" 
                    value="友達を追加">
</p>
</fieldset>
</form>
</div>
</body>
</html>

■FriendDetails.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>Save Product</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>
<div id="global">
<h4>友達を登録しました</h4>
<p>
<h5>詳細は以下のとおりです:</h5>
名前: ${friend.name}<br/>
年齢: ${friend.age}<br/>
身長: $${friend.height}
</p>
</div>
</body>
</html>

スッキリわかるサーブレット&JSP入門

スッキリわかるサーブレット&JSP入門



お金があるかないかで人生の楽しさは全く変わってきます。

お金があっても幸せになれるとは限りませんが、お金がない人生は不幸です。

お金がなかった私が、転職して年収1000万を超えるまでにお世話になったブログを紹介します。

エンジニア転職のリアル

今の時代は、お金を稼げるかどうかは能力の有無よりも触れた情報の質によるものが大きいです。
ぜひ皆さんも良質な情報に触れて、お金持ちになって人生を充実させてください。