Scoreの順位をJsonで返却するWebAPIを作成しよう。
[作成]
1.MySQLでデータベース[unity]を作成する。
CREATE DATABASE unity DEFAULT CHARACTER SET utf8;
2.データベースunityに[scores]テーブルを作成する。
CREATE TABLE scores( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, score INT, sex INT );
3.https://dev.mysql.com/downloads/connector/j/にアクセスして、MySQLのJDBCをダウンロードする。
遷移したら「No thanks, just start my download.」をクリック
4.エクリプス。新規動的Webプロジェクトを選択し「ScoreAPI」を作成する。
5.WEB-INFフォルダにあるlibフォルダに先程ダウンロードしたJDBCをコピペで貼り付ける。
6.context.xmlを以下のように編集。
<?xml version="1.0" encoding="UTF-8" ?> <Context> <Resource name="jdbc/jsp" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/unity?characterEncoding=UTF-8" connectionProperties="autoReconnect=true;verifyServerCertificate=false;useSSL=false;requireSSL=false" username="root" validationQuery="select 1"/> </Context>
上はrootユーザー、パスワードなしが前提だが、ユーザー、パスワードを設定している場合は以下
<?xml version="1.0" encoding="UTF-8" ?> <Context> <Resource name="jdbc/jsp" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/unity?characterEncoding=UTF-8" connectionProperties="autoReconnect=true;verifyServerCertificate=false;useSSL=false;requireSSL=false" username="ユーザーネーム" password="パスワード" validationQuery="select 1"/> </Context>
7.作成したcontext.xmlをMETA-INFの直下に配置
8.modelの作成。modelパッケージにScoreクラスを以下のように作成
●model.Score.java
package model; import java.io.Serializable; public class Score implements Serializable{ private int id; private String name; private int score; private int sex; public Score(){ } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } }
9.DAOの作成。daoパッケージを作成し、その中にScoreDAO.javaを作成する。まずは1つデータを追加できるinsertOneメソッドを作成する。
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import model.Score; public class ScoreDAO { private Connection db; private PreparedStatement ps; private ResultSet rs; // 接続共通処理 private void connect() throws NamingException, SQLException { Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/jsp"); this.db = ds.getConnection(); } // 切断共通処理 private void disconnect() { try { if (rs != null) { rs.close(); } if (ps != null) { ps.close(); } if (db != null) { db.close(); } } catch (SQLException e) { e.printStackTrace(); } } public void insertOne(Score score){ try { this.connect(); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } }
10.Insertの確認。controllerパッケージを作成し、Insert.java(Servlet)を以下のように作成する。
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; import dao.ScoreDAO; import model.Score; @WebServlet("/Insert") public class Insert extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Score score=new Score(); score.setName("山田太郎"); score.setScore(10000); score.setSex(0); ScoreDAO dao=new ScoreDAO(); dao.insertOne(score); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
11.Insertサーブレットをサーバーで実行してみよう。データが1件挿入されれば成功だ。
ダミーデータの作成
12.以下から名前と性別の50人分のcsvをダウンロードし、WEB-INF/data/の中に配置する。
13.ScoreDAOを以下のように変更する。
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import model.Score; public class ScoreDAO { private Connection db; private PreparedStatement ps; private ResultSet rs; // 接続共通処理 private void connect() throws NamingException, SQLException { Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/jsp"); this.db = ds.getConnection(); } // 切断共通処理 private void disconnect() { try { if (rs != null) { rs.close(); } if (ps != null) { ps.close(); } if (db != null) { db.close(); } } catch (SQLException e) { e.printStackTrace(); } } public void insertOne(Score score){ try { this.connect(); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } //ここを追記 public void insertAll(List<Score> list){ try { this.connect(); db.setAutoCommit(false); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); for(Score score:list){ ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } db.commit(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } }
14.controllerパッケージにCreateRandomData.java(Servlet)を以下のように作成する。
package controller; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.servlet.ServletContext; 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 dao.ScoreDAO; import model.Score; /** * Servlet implementation class CreateRandomData */ @WebServlet("/CreateRandomData") public class CreateRandomData extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext application =this.getServletContext(); String path=application.getRealPath("/WEB-INF/data/data.csv"); FileInputStream fis=new FileInputStream(path); InputStreamReader isr=new InputStreamReader(fis,"UTF-8"); BufferedReader br=new BufferedReader(isr); Random rand=new Random(); List<Score> list=new ArrayList<>(); String line; while((line=br.readLine()) !=null){ String[] vals=line.split(","); Score score=new Score(); score.setName(vals[0]); //0~99999のランダム score.setScore(rand.nextInt(100000)); score.setSex(Integer.parseInt(vals[1])); list.add(score); } ScoreDAO dao=new ScoreDAO(); dao.insertAll(list); br.close(); } }
15.CreateRandomData.javaをサーバーで実行してみよう。以下のよにデータが挿入されれば成功だ。
APIの作成
リクエストに応じて点数降順リストをJSONで返却するAPIを作成する。
16.ScoreDAOを以下のように変更
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import model.Score; public class ScoreDAO { private Connection db; private PreparedStatement ps; private ResultSet rs; // 接続共通処理 private void connect() throws NamingException, SQLException { Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/jsp"); this.db = ds.getConnection(); } // 切断共通処理 private void disconnect() { try { if (rs != null) { rs.close(); } if (ps != null) { ps.close(); } if (db != null) { db.close(); } } catch (SQLException e) { e.printStackTrace(); } } public void insertOne(Score score){ try { this.connect(); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } public void insertAll(List<Score> list){ try { this.connect(); db.setAutoCommit(false); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); for(Score score:list){ ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } db.commit(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } //ここに追記 public List<Score> find(int num){ List<Score> list=new ArrayList<>(); try { this.connect(); ps=db.prepareStatement("SELECT * FROM scores ORDER BY score DESC LIMIT ?"); ps.setInt(1, num); rs=ps.executeQuery(); while(rs.next()){ Score score=new Score(); score.setId(rs.getInt("id")); score.setName(rs.getString("name")); score.setScore(rs.getInt("score")); score.setSex(rs.getInt("sex")); list.add(score); } } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } return list; } }
16.下からgson.jarファイルをダウンロード
17.zipを展開後、WEB-INF/lib/ファルダのにgson.jarをコピペで配置する。
18.controllerパッケージの中にGetData.java(Servlet)を以下のように作成する。
package controller; import java.io.IOException; import java.io.PrintWriter; 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 com.google.gson.Gson; import dao.ScoreDAO; import model.Score; @WebServlet("/GetData") public class GetData extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String count_s=request.getParameter("count"); int count; if(count_s ==null){ count=10; }else{ count=Integer.parseInt(count_s); } ScoreDAO dao=new ScoreDAO(); List<Score> list=dao.find(count); Gson gson = new Gson(); response.setContentType("application/json;charset=UTF-8"); PrintWriter out=response.getWriter(); out.print("{\"result\": " + gson.toJson(list)+"}"); } }
19.GetData.javaをサーバーから実行してみよう。以下のようにJSONが取得できれば成功だ。
JSONに多くの情報を詰める
20.より多くの情報を返却するAPIを作成する。まずはmodelパッケージにRankingResultクラスを作成する。
●model.RankingResult.java
package model; import java.io.Serializable; import java.util.List; public class RankingResult implements Serializable{ private int lastId;//最後に挿入したデータのid private int rank;//最後に挿入したデータの順位 private List<Score> list;//順位データを降順ソートしたリスト private boolean isRankingIn;//指定順位に入っているか public RankingResult(){} public int getLastId() { return lastId; } public void setLastId(int id) { this.lastId = id; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } public List<Score> getList() { return list; } public void setList(List<Score> list) { this.list = list; } public boolean isRankingIn() { return isRankingIn; } public void setRankingIn(boolean isRankingIn) { this.isRankingIn = isRankingIn; } }
21.ScoreDAOにメソッド追記する。
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import model.RankingResult; import model.Score; public class ScoreDAO { private Connection db; private PreparedStatement ps; private ResultSet rs; // 接続共通処理 private void connect() throws NamingException, SQLException { Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/jsp"); this.db = ds.getConnection(); } // 切断共通処理 private void disconnect() { try { if (rs != null) { rs.close(); } if (ps != null) { ps.close(); } if (db != null) { db.close(); } } catch (SQLException e) { e.printStackTrace(); } } public void insertOne(Score score){ try { this.connect(); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } public void InsertAll(List<Score> list){ try { this.connect(); db.setAutoCommit(false); ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)"); for(Score score:list){ ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); } db.commit(); } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } } public List<Score> find(int num){ List<Score> list=new ArrayList<>(); try { this.connect(); ps=db.prepareStatement("SELECT * FROM scores ORDER BY score DESC LIMIT ?"); ps.setInt(1, num); rs=ps.executeQuery(); while(rs.next()){ Score score=new Score(); score.setId(rs.getInt("id")); score.setName(rs.getString("name")); score.setScore(rs.getInt("score")); score.setSex(rs.getInt("sex")); list.add(score); } } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } return list; } //ここに追記 public RankingResult getRankingResult(Score score,int count){ //返却するRankingResultインスタンスを作成 RankingResult result=new RankingResult(); try { this.connect(); //第一引数で入ってきたScoreインスタンスをデータベースに挿入 ps=db.prepareStatement("INSERT INTO scores(name,score,sex) VALUES(?,?,?)",Statement.RETURN_GENERATED_KEYS); ps.setString(1, score.getName()); ps.setInt(2, score.getScore()); ps.setInt(3, score.getSex()); ps.executeUpdate(); //insertした際にオートインクリメントで付与されたid取得しresultインスタンスにセット rs=ps.getGeneratedKeys(); if(rs.next()){ result.setLastId(rs.getInt(1)); } //今挿入したデータの順位を求める(今挿入したデータより点数の大きいデータの数を数えてそれに1をたす) ps=db.prepareStatement("SELECT COUNT(*) + 1 AS rank FROM scores WHERE score > ?"); ps.setInt(1, score.getScore()); rs=ps.executeQuery(); if(rs.next()){ result.setRank(rs.getInt("rank"));//今挿入したデータは何位かをresultにセットする。 result.setRankingIn(rs.getInt("rank")<count);//今挿入したデータはランキングに入ったか?をresultにセット } List<Score> list=new ArrayList<>();//第二引数で指定のあった数だけ上位データを取得する。 ps=db.prepareStatement("SELECT * FROM scores ORDER BY score DESC LIMIT ?"); ps.setInt(1, count); rs=ps.executeQuery(); //レコードの数まわるループ while(rs.next()){ //レコードの情報を元にScoreインスタンスを作成 Score s=new Score(); s.setId(rs.getInt("id")); s.setName(rs.getString("name")); s.setScore(rs.getInt("score")); s.setSex(rs.getInt("sex")); //リストに追加 list.add(s); } result.setList(list);//作成したリストをresultにセット } catch (NamingException | SQLException e) { e.printStackTrace(); }finally{ this.disconnect(); } return result;//作成したRankingResultインスタンスを返却 } }
21.controllerパッケージに以下のようなGetRanking.java(Servlet)を作成する。
package controller; import java.io.IOException; import java.io.PrintWriter; 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 dao.ScoreDAO; import model.RankingResult; import model.Score; @WebServlet("/GetRanking") public class GetRanking extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); // parameterでcountが来てるか? String count = request.getParameter("count"); // countが来ていなかったらtop10そうでなければcount件のデータを取得する。 count = count == null ? "10" : count; String name = request.getParameter("name"); name = name == null ? "未入力" : name; String score = request.getParameter("score"); score = score == null ? "0" : score; String sex = request.getParameter("sex"); sex = sex == null ? "0" : sex; // Scoreインスタンスを作成 Score s = new Score(); // インスタンス値をつめる s.setName(name); s.setScore(Integer.parseInt(score)); s.setSex(Integer.parseInt(sex)); ScoreDAO dao = new ScoreDAO(); // RankingResultインスタンスを取得 RankingResult result = dao.getRankingResult(s, Integer.parseInt(count)); // パーサーをnew Gson gson = new Gson(); // コンテントタイプをjsonに指定 response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); // resultインスタンスをJSONにして出力する。 out.print(gson.toJson(result)); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
22.テストをするためにWebContentの直下に以下のようなtest.jspを作成すする。
●test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>Insert title here</title> </head> <body> <form action="GetRanking" method="post"> 件数:<input type="number" name="count" value="10"><br> 名前:<input type="text" name="name"><br> score:<input type="number" name="score"><br> 性別:<input type="radio" name="sex" value="0">男 <input type="radio" name="sex" value="1">女<br> <button type="submit">送信</button> </form> </body> </html>
23.フォームから適当にデータを入れてみよう。
24.以下のようにJSONデータが出力されれば成功だ。(ブラウザによってはファイル保存となるが、保存したのちテキストエディタで確認すればよい)
25.整形サイトを利用して見やすく表示してみる。先ほど入力したデータ30000点というのはベスト10に入っていなくて、699位で,
オートインクリメントで付与されたidが1001ということがわかる。それと合わせてトップ10のデータが表示されている。
26.このように実際のゲームに必要な情報をJSONとして出力できるようになっておくことが重要だ。この後UNITYからこのAPIにアクセスする課題があるので合わせてやってみるとよいだろう。
コメント