JSP/Servlet(郵便番号検索)

Java

郵便番号APIを利用して、郵便番号から住所を検索するアプリを作成してみよう。

作るもの

郵便番号を入れるフォームがあるので、調べたい郵便番号を入れて送信ボタンをおす。

結果が表示される

一つの郵便番号に複数の住所が割り振られている場合がある。
989-2351
をいれると20件の住所が表示される。

作成

WebAPI

まずは大前提となるWebAPIを確認する。
zipcloudさんが提供してくれている郵便番号APIを利用させていただく。

これはリクエストパラメーターに調べたい郵便番号を含めると、その結果をJSONデータでレスポンスしてくれるサービスだ。以下のURLを入力してサンプルレスポンスを確認してもらいたい。
https://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060

今回はこのAPIを使ってアプリを作成していく。

作成

  • エクリプス新規動的Webプロジェクトよりzipappを作成
  • 新規クラスからAddressクラスを以下のように作成する。パッケージはmodelとする。
package model;

import java.io.Serializable;

public class Address implements Serializable{
	private String zipcode;
	private String prefcode;
	private String address1;
	private String address2;
	private String address3;
	private String kana1;
	private String kana2;
	private String kana3;
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getPrefcode() {
		return prefcode;
	}
	public void setPrefcode(String prefcode) {
		this.prefcode = prefcode;
	}
	public String getAddress1() {
		return address1;
	}
	public void setAddress1(String address1) {
		this.address1 = address1;
	}
	public String getAddress2() {
		return address2;
	}
	public void setAddress2(String address2) {
		this.address2 = address2;
	}
	public String getAddress3() {
		return address3;
	}
	public void setAddress3(String address3) {
		this.address3 = address3;
	}
	public String getKana1() {
		return kana1;
	}
	public void setKana1(String kana1) {
		this.kana1 = kana1;
	}
	public String getKana2() {
		return kana2;
	}
	public void setKana2(String kana2) {
		this.kana2 = kana2;
	}
	public String getKana3() {
		return kana3;
	}
	public void setKana3(String kana3) {
		this.kana3 = kana3;
	}
	
}

ポイント

返却されるjsonデータのキーの名前と合わせてフィールド名を設定しておくと後で楽にパースすることができる。スコープに詰めるのでjavabeansの書式を守ること。

ダウンロードしたgson-2.8.2.jarファイルを以下のlibフォルダに配置する。
webapp/WEB-INF/lib/

  • modelパッケージの中に以下のように一般クラスとしてAddressParser.javaを作成する。
package model;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;

public class AddressParser {
	public List<Address> getList(String urlString){
		List<Address> list = new ArrayList<>();
		JsonReader reader=null;
		HttpURLConnection con = null;
		try {
			URL url = new URL(urlString);
			con=(HttpURLConnection)url.openConnection();
			con.setRequestMethod("GET");
			InputStream is = con.getInputStream();
			InputStreamReader isr= new InputStreamReader(is,"UTF-8");
			reader = new JsonReader(isr);
			Gson gson=new Gson();
			JsonObject root=gson.fromJson(reader,JsonObject.class);
			//resultsの値のnullチェック
			if(!root.get("results").isJsonNull()) {
				JsonArray results=root.get("results").getAsJsonArray();
				//ArrayListにパースするときにはTypeTokenを使う必要がある
				list=gson.fromJson(results, new TypeToken<ArrayList<Address>>() {}.getType());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(con != null) {
				con.disconnect();
			}
		}
		return list;
	}
}

ポイント解説

AddressクラスをJSONデータのキーの名前を一致して作成したので,JsonArrayオブジェクトからループを回すことなくArrayListを作成することができる。

list=gson.fromJson(results, new TypeToken<ArrayList<Address>>() {}.getType());
  • 続いて新規サーブレットからMain.javaを作成する。このときパッケージはcontrollerとすること。doGet内に以下を記述する。(doPostは空にしておく)
package controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Main")
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("msg", "郵便番号を入力してください");
		request.getRequestDispatcher("/WEB-INF/view/main.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}
}
  • WEB-INF内にviewフォルダを作成し、その中にmain.jspを以下のように作成する。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String msg=(String)request.getAttribute("msg");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>住所検索</title>
</head>
<body>
<div id="container">
<p><%=msg %></p>
<form action="Main" method="post">
<input type="text" name="zip" placeholder="000-0000" required>
<button type="submit">送信する</button>
</form>
</div><!-- container -->
</body>
</html>
  • controller.Main.javaをサーバーで実行してみよう。以下のようにフォームが表示されれば成功だ。
  • 郵便番号を入れて、送信ボタンを押したら作動するdoPostをcontroller.Main.javaを以下のように追記する。
package controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Address;
import model.AddressParser;
@WebServlet("/Main")
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("msg", "郵便番号を入力してください");
		request.getRequestDispatcher("/WEB-INF/view/main.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String zip = request.getParameter("zip");
		String msg=null;
		if(zip == null || !zip.matches("[0-9]{3}-?[0-9]{4}")) {
			msg="不正な郵便番号です";
		}
		if(msg == null) {
			msg="通信結果";
			String zipcode = zip.replace("-","");
			String url =
					String.format("https://zipcloud.ibsnet.co.jp/api/search?zipcode=%s",zipcode);
			AddressParser parser = new AddressParser();
			List<Address> list = parser.getList(url);
			if(list.size() == 0) {
				msg="実在しない郵便番号です";
			}else {
				request.setAttribute("list", list);
			}
		}
		request.setAttribute("zip", zip);
		request.setAttribute("msg",msg);
		request.getRequestDispatcher("/WEB-INF/view/main.jsp").forward(request, response);
		
	}
}

  • WEB-INF/view/main.jspを以下のように追記
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.*,java.util.*"%>
<%
String zip = (String)request.getAttribute("zip");
zip = zip == null ? "":zip;
String msg=(String)request.getAttribute("msg");
List<Address> list = (List<Address>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>住所検索</title>

</head>
<body>
<div id="container">
<p><%=msg %></p>
<form action="Main" method="post">
<input type="text" name="zip" placeholder="000-0000" value="<%=zip %>" required>
<button type="submit">送信する</button>
</form>
<% if(list != null && list.size() > 0){ %>
<div id="result">
<% for(Address a:list){ %>
<table>
<tr><td>郵便番号</td><td><%=a.getZipcode() %></td></tr>
<tr><td>都道府県コード</td><td><%=a.getPrefcode() %></td></tr>
<tr><td>都道府県名</td><td><%=a.getAddress1() %></td></tr>
<tr><td>市区町村名</td><td><%=a.getAddress2() %></td></tr>
<tr><td>町域名</td><td><%=a.getAddress3() %></td></tr>
<tr><td>都道府県名カナ</td><td><%=a.getKana1() %></td></tr>
<tr><td>市区町村名カナ</td><td><%=a.getKana2() %></td></tr>
<tr><td>町域名カナ</td><td><%=a.getKana3() %></td></tr>
</table>
<%} %>
</div><!-- result -->
<%} %>
</div><!-- container -->
</body>
</html>
  • 入力が終わったら、controller.Main.javaをサーバーで起動して自分の郵便番号を入力してみよう。正しく表示されればうまくいっている。

スタイルの追加

  • スタイルをあてよう。WEB-INF/view/main.jspに以下の1行を追記する。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model.*,java.util.*" %>
<%
String msg=(String)request.getAttribute("msg");
String zip = (String)request.getAttribute("zip");
zip = zip == null ? "":zip;
List<Address> list = (List<Address>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>住所検索</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="container">
<p><%=msg %></p>
<form action="Main" method="post">
<input type="text" name="zip" placeholder="000-0000" value="<%=zip %>" required>
<button type="submit">送信する</button>
</form>
<% if(list != null && list.size() > 0){ %>
<div id="result">
<% for(Address a:list){ %>
<table>
<tr><td>郵便番号</td><td><%=a.getZipcode() %></td></tr>
<tr><td>都道府県コード</td><td><%=a.getPrefcode() %></td></tr>
<tr><td>都道府県名</td><td><%=a.getAddress1() %></td></tr>
<tr><td>市区町村名</td><td><%=a.getAddress2() %></td></tr>
<tr><td>町域名</td><td><%=a.getAddress3() %></td></tr>
<tr><td>都道府県名カナ</td><td><%=a.getKana1() %></td></tr>
<tr><td>市区町村名カナ</td><td><%=a.getKana2() %></td></tr>
<tr><td>町域名カナ</td><td><%=a.getKana3() %></td></tr>
</table>
<%} %>
</div><!-- result -->
<%} %>
</div><!-- container -->
</body>
</html>
  • cssファイルを作成していこう。webappsの直下にcssフォルダを作成し,main.cssファイルを作成する。
#container {
  width: 96%;
  margin: 20px auto;
}

#result {
  display: grid;
  grid-template-columns: repeat(auto-fill, 300px);
  gap: 20px;
}

table {
  border-collapse: collapse;
  margin-top: 20px;
}

td {
  padding: 5px 10px;
  border: 1px solid #333;
}
  • 実行してみよう。結果のテーブルに罫線があたっていれば成功だ。
    989-2351
    などの複数住所が存在している郵便番号もいれてみよう。

仕上げ

カスタムタグを使ってjspからプログラム要素を排除していこう。以下のリンクを参考に2つのjarファイルをWEB-INF/libの中にコピペで貼り付ける

JSTL (1.2) のインストール手順
JSTLをインストールするには、2つの異なるJARをダウンロードし、クラスパスにコピーする必要があります。 step1JSTL API(インタフェース)のダウンロード Maven Repository
  • main.jspを以下のように変更する。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model.*,java.util.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- スクリプトレット削除 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>住所検索</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="container">
<p>${msg}</p>
<form action="Main" method="post">
<input type="text" name="zip" placeholder="000-0000" value="${zip}" required>
<button type="submit">送信する</button>
</form>
<c:if test="${not empty list}">
<div id="result">
<c:forEach var="add" items="${list}">
<table>
<tr><td>郵便番号</td><td>${add.zipcode}</td></tr>
<tr><td>都道府県コード</td><td>${add.prefcode}</td></tr>
<tr><td>都道府県名</td><td>${add.address1}</td></tr>
<tr><td>市区町村名</td><td>${add.address2}</td></tr>
<tr><td>町域名</td><td>${add.address3}</td></tr>
<tr><td>都道府県名カナ</td><td>${add.kana1}</td></tr>
<tr><td>市区町村名カナ</td><td>${add.kana2}</td></tr>
<tr><td>町域名カナ</td><td>${add.kana3}</td></tr>
</table>
</c:forEach>
</div><!-- result -->
</c:if>
</div><!-- container -->
</body>
</html>

コメント

タイトルとURLをコピーしました