お天気情報をJSONでくれるWebAPIがあるので、それを利用してお天気アプリを作成しよう。
WebAPI確認
1.まずはWebAPIから吐き出されるJSONを確認しよう。
今回はlivedoorから提供されているWeather Hacks
のAPIを使用する。まずは東京のお天気情報のリクエストURLを叩いてレスポンスを確認しよう。
http://weather.livedoor.com/forecast/webservice/json/v1?city=130010

まるっとコピーしてJSON整形サイトで確認してもよいが、吐き出す内容が多いのでChromeにプラグインとしてインストールしたJSON formatterで確認してみる。

要素を折りたたむことができるので全体像をつかむのに便利だ。
2.アプリの仕様を決める。
すべての要素を盛り込んでアプリを作ってもいいが、今回は送信されるデータのうち、title,description,forecastsを利用することとする。
アプリ作成
下準備
1.エクリプス、新規動的Webプロジェクトから[joytas13]アプリを作成する。
2.GsonでJsonパースを行いたいので以下のファイルをWEB-INF/libの中に貼り付ける。
model
1.Jsonデータとにらめっこしながらmodelを作成する。今回は以下のような3つのクラスを作成した。
●model.Image.java(forecastがもっている画像情報クラス)
package model;
import java.io.Serializable;
public class Image implements Serializable{
/*
"width": 50,
"url": "http://weather.livedoor.com/img/icon/15.gif",
"title": "雨",
"height": 31
*/
private int width;
private String url;
private String title;
private int height;
public Image(){}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
●model.Forecast.java(1日分のお天気データクラス)
(Jsonにあるtemperatureは今回不使用)
package model;
import java.io.Serializable;
/*
* {
"dateLabel": "今日",
"telop": "雨",
"date": "2017-09-17",
"temperature": {
"min": null,
"max": null
},
"image": {
"width": 50,
"url": "http://weather.livedoor.com/img/icon/15.gif",
"title": "雨",
"height": 31
}
}
*/
public class Forecast implements Serializable{
private String dateLabel;
private String telop;
private String date;
private Image image;
public Forecast(){}
public String getDateLabel() {
return dateLabel;
}
public void setDateLabel(String dateLabel) {
this.dateLabel = dateLabel;
}
public String getTelop() {
return telop;
}
public void setTelop(String telop) {
this.telop = telop;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
●model.Weather.java(本体となるクラス、3日分の天気などをhas-aで持つ)
(使いたい部分を抽出してクラスのフィールドとする)
package model;
import java.io.Serializable;
/*
* "pinpointLocations": [],
"link": "http://weather.livedoor.com/area/forecast/130010",
"forecasts": [],
"location": {},
"publicTime": "2017-09-17T17:00:00+0900",
"copyright": {},
"title": "東京都 東京 の天気",
"description": {
"text": " 前線が日本の南に停滞しています。また、大型の台風第18号が四国の南\n西海上にあって、北東へ進んでいます。\n\n【関東甲信地方】\n 関東甲信地方は、おおむね雨となっています。\n\n 17日は、前線や台風の影響によりおおむね雨となり、雷を伴い非常に激\nしく降る所がある見込みです。\n\n 18日は、前線や台風の影響により、はじめは雨で雷を伴い非常に激しく\n降る所がありますが、次第に晴れるでしょう。\n\n 関東近海では、18日にかけて、うねりを伴い大しけとなる見込みです。\n船舶は高波に警戒してください。\n\n【東京地方】\n 17日は、雨で夜は雷を伴い激しく降る所があるでしょう。\n 18日は、曇り後晴れで、明け方まで雨で雷を伴い激しく降る所がある見\n込みです。",
"publicTime": "2017-09-17T16:55:00+0900"
}
*/
public class Weather implements Serializable{
private String title;
private String description;
private Forecast[] forecasts;
public Weather(){}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Forecast[] getForecasts() {
return forecasts;
}
public void setForecasts(Forecast[] forecasts) {
this.forecasts = forecasts;
}
}
controller
1.リクエストを処理するコントローラーを以下のように作成する。
[処理の流れ]
WebAPIにHttpリクエストを投げて、その結果(Json)をInputStreamで取得。
取得したデータをGsonでパースしてWeatherオブジェクトを生成し、リクエストスコープに詰めている。
なお、Jsonに含まれる改行コードの部分をbrタグに変換するメソッドを別メソッドにしている。
(こうすることで改行コード部分をHtml上で改行させることができる)
●controller.Main.java(Servlet)
package controller;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.RequestDispatcher;
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 com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import model.Forecast;
import model.Image;
import model.Weather;
/**
* Servlet implementation class Main
*/
@WebServlet("/Main")
public class Main extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//webAPIのurlからURLインスタンスを作成
URL url=new URL("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010");
//GETでの通信処理
HttpURLConnection con=(HttpURLConnection)url.openConnection();
con.setRequestMethod("GET");
//InputStreamで結果を取得
InputStream is=con.getInputStream();
//スプーンからスコップ
InputStreamReader isr=new InputStreamReader(is,"UTF-8");
//ファイル読み込み時にはBufferedReaderだがここではJsonReaderインスタンスを取得する。
JsonReader reader=new JsonReader(isr);
//ルートが{}なのでオブジェクトとして取得
JsonObject root=new Gson().fromJson(reader,JsonObject.class);
//結果として必要となるWeatherインスタンスをnew(フィールドの値はすべてnull)
Weather w=new Weather();
//Jsonからプロパティがtitleの項目を探してきてそれをStringに変換してwにセットする。
w.setTitle(root.get("title").getAsString());
//descriptionはオブジェクトを値として持っているのでまずはそれを取得し、その中にあるtextを取得(メソッドチェーン)
//結果の文字列に改行文字が含まれているのでそれを<br>という文字列に変換しておく。(メソッドは下部にある)
w.setDescription(nl2br(root.get("description").getAsJsonObject().get("text").getAsString()));
//forecastsは配列なので配列として取得
JsonArray fArray=root.get("forecasts").getAsJsonArray();
//Forecast型のインスタンスを格納する配列を準備
Forecast[] forecasts=new Forecast[fArray.size()];
//配列とforは刺身と醤油の相性。JsonArrayの要素数はsize()で求められる
for(int i=0;i<fArray.size();i++) {
//配列の要素一つ一つはオブジェクトなのでそれを取得
JsonObject fObj=fArray.get(i).getAsJsonObject();
//取得した情報をもとにインスタンスを生成したいのでまずはフィールドがnullの状態でnew
Forecast f=new Forecast();
//JSONから情報を取得し、fにセットしていく
f.setTelop(fObj.get("telop").getAsString());
f.setDateLabel(fObj.get("dateLabel").getAsString());
f.setDate(fObj.get("date").getAsString());
//パラメータimageはオブジェクトなのでJsonオブジェクトとして取得
JsonObject iObj=fObj.get("image").getAsJsonObject();
//その情報をもとにインスタンスを作りたいのでまずはnew
Image image=new Image();
//情報をもとにimageに詰める
image.setHeight(iObj.get("height").getAsInt());
image.setTitle(iObj.get("title").getAsString());
image.setUrl(iObj.get("url").getAsString());
image.setWidth(iObj.get("width").getAsInt());
//image要素ができたのでfにセットする
f.setImage(image);
//fが一つできたので配列にセットする
forecasts[i]=f;
}
//for文が回り終わるとすべてのforecastインスタンスが詰まっているのでおおもとのwにセット
w.setForecasts(forecasts);
//完成したw(Weater)インスタンスをリクエストスコープに詰める
request.setAttribute("weather", w);
//フォワード処理
RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/main.jsp");
rd.forward(request,response);
}
//文字列に含まれる改行コードを<br>タグに置き換えるメソッド
public static String nl2br(String str) {
if (str == null || str.equals("")) {
return "";
}
str = str.replace("\n", "<br>");
return str;
}
}
view
1.modelとcontrollerの連携により欲しいデータが作れたので後はviewで表示するだけだ。
いつものように/WEB-INF/の中にviewフォルダを作ってmain.jspを配置しよう。
●/WEB-INF/view/main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="model.*"%>
<%
Weather w=(Weather)request.getAttribute("weather");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title><%=w.getTitle() %></title>
</head>
<body>
<h1><%=w.getTitle() %></h1>
<p><%=w.getDescription() %></p>
<table border="1">
<%for(Forecast f:w.getForecasts()) {%>
<tr>
<td><%=f.getDateLabel() %></td>
<td><%=f.getTelop() %></td>
<td><%=f.getDate() %></td>
<%Image image=f.getImage(); %>
<td><img src="<%=image.getUrl()%>" width="<%=image.getWidth() %>" height="<%=image.getHeight() %>" alt="<%=image.getTitle()%>"></td>
</tr>
<%} %>
</table>
</body>
</html>
完成品
1.以下のように東京の3日分(時間帯によっては2日分)のお天気情報が表示されれば成功だ。

コメント