読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

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

JavaEE
<スポンサーリンク>

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入門