目次
新人に負けない本棚管理サイト その1(プロローグ)
新人に負けない本棚管理サイト その2(環境構築編)
新人に負けない本棚管理サイト その3(トップページ作成編)
新人に負けない本棚管理サイト その4(データベース検索編①)
目標
- データベースに問い合わせしてデータを取得する
- 取得したデータを画面に表示する ←今回はここまで
- 検索できるようにする
データの準備
使用するデータベースはMariaDBです。
セットアップ方法はその2を参照してください。
テーブル作成
CREATETABLEBooks(titleVARCHAR(100)primarykey,authorVARCHAR(20),publisherVARCHAR(20),finished__atDATEDEFAULTCURDATE())
仮データ登録
INSERTINTOBooksVALUES('Python Django超入門','掌田津耶乃','秀和システム','2019/08/31'),('React.js&Next.js超入門','掌田津耶乃','秀和システム',NULL),('PostgreSQL徹底入門 第4版','近藤雄太 他','翔泳社',NULL),('PHPフレームワークLaravel入門 第2版','掌田津耶乃','秀和システム','2019/10/31'),('PostgreSQLから始めるデータベース生活','まぐろ','まぐろのみぞおち','2019/11/03')
一緒にSearchResultComponentで仮に入れていた本データを削除します。
importReactfrom'react';import{Container,Row,Col,Table}from'react-bootstrap';exportdefaultclassSearchResultextendsReact.Component{render(){return(<Container><Row><Tablestripedborderedsize="sm"><thead><tr><th>タイトル</th><th>著者名</th><th>出版社</th><th>読了日</th></tr></thead><tbody>{/* 削除
<tr>
<td>Python Django超入門</td>
<td>掌田津耶乃</td>
<td>秀和システム</td>
<td>2019/08/31</td>
</tr>
...
<tr>
<td>PostgreSQLから始めるデータベース生活</td>
<td>まぐろ</td>
<td>まぐろのみぞおち</td>
<td>2019/11/03</td>
</tr>
*/}</tbody></Table></Row></Container>);}}
スタートアッププログラムを変更
Expressのインストール
リクエストの処理を定義するために、Node.jsのフレームワークのExpressをインストールします。
npm install express
スタートアッププログラム作成
まずプロジェクト直下にserver.js
を作ります。
引用:
constexpress=require('express')constnext=require('next')constdev=process.env.NODE_ENV!=='production'constapp=next({dev})consthandle=app.getRequestHandler()app.prepare().then(()=>{constserver=express();server.get('*',(req,res)=>{returnhandle(req,res);})server.listen(3000,(err)=>{if(err){throwerr}console.log('> Ready on http://localhost:3000')})}).catch((ex)=>{console.error(ex.stack)process.exit(1)})
次にpackage.jsonのscript部を書き換えます。
"scripts":{"dev":"node server.js","build":"next build","start":"NODE_ENV=production node server.js"}
そして再度npm run dev
すると、ターミナルに> Ready on http://localhost:3000
が表示されると思います。
この段階で(開発用の)Webサーバーが立ち上がったということになります。
404を解決する
今のままでは、/bookmanagerにアクセスしたあとリロードすると404が表示されます。
これはserver.jsで/bookmanager
にアクセスしたときの処理内容を定義していないため、どのページを表示させるか分からなかったためです。
じゃあ定義しよう!!
server.jsに以下のように追記します。
// (略)app.prepare().then(()=>{constserver=express();// 追記ここからserver.get('/bookmanager',(req,res)=>{returnapp.render(req,res,'/bookmanager',req.query);});// 追記ここまでserver.get('*',(req,res)=>{returnhandle(req,res);})server.listen(3000,(err)=>{if(err){throwerr}console.log('> Ready on http://localhost:3000')})}).catch((ex)=>{console.error(ex.stack)process.exit(1)})
これにより、/bookmanager
にgetリクエストが来たらpages/bookmanager/index.js
を表示させるという定義ができました。
何度リロードしても404になりません!!
データベースへ問い合わせ
最初にページを開いたときに、データベースから本情報を全件取ってきて表示させます。
メインの内容です!!
MariaDBへ接続するためのモジュールを追加
npm install mariadb
データベース接続情報を定義する
プロジェクト直下にmariadbConnection.js
を作ります。
constmariadb=require('mariadb/callback');constdbConfig={host:'192.168.xxx.xxx',user:'username',password:'yourpassword',database:'database-name'};constconnection=mariadb.createConnection(dbConfig);module.exports=connection;
データベースからデータ取得
bookmanagerページを開いたときにコンソールにデータを表示させてみましょう。
server.jsを書き換えます。
// (略)app.prepare().then(()=>{constserver=express();// 変更ここからconstconnection=require('./mariadbConnection');server.get('/bookmanager',(req,res)=>{letquery="SELECT title, author, publisher, DATE_FORMAT(finished_at, '%Y/%m/%d') AS finished_at FROM Books ORDER BY title";connection.query(query,(err,rows)=>{if(err)throwerr;console.log(rows);});returnapp.render(req,res,'/bookmanager',req.query);});// 変更ここまでserver.get('*',(req,res)=>{returnhandle(req,res);})server.listen(3000,(err)=>{if(err){throwerr}console.log('> Ready on http://localhost:3000')})}).catch((ex)=>{console.error(ex.stack)process.exit(1)})
npm run dev
してWebサーバーを再起動します。
その後bookmanagerページを開き、ターミナルを見てみると...
いいっすねぇ~(・∀・)
取得結果を画面にバインド(やることが多いです)
通常のWebアプリでは、以下のように検索する仕組みを作ると思います。
- 検索ボタンを押したとき、入力値をサーバーへ送る
- サーバーサイドのプログラムからデータベースへ、検索クエリを投げる
- 結果を画面へ返す
- 画面でイイカンジに表示する
つまり検索するたびにサーバーへリクエストが飛ぶため、ヒット件数が多かったりストアドプロシージャ/ファンクションを介したりする場合はそれなりに時間がかかります。
せっかくNextというエクストリームニュージェネレーションフレームワーク(言いたいだけ)を使っているのに、こんなクラシックなやり方で応答時間を増やすのはダメです!
そこで、
「最初にbookmanagerページを開いたときに一度だけ全件取得して、検索するときはそのデータから絞り込む」
ということをしてみます。
これならデータベースへの問い合わせは初めてページを開くときの一度のみになるので、圧倒的にレスポンスが短くなります。(ページをリロードしたときも初めて開いたとする)
ページオープン時に全件取得
NextにはgetInitialPropsという便利な関数があります。
カンタンに言うと「ページが表示されたとき一度だけ実行される非同期関数」って感じです。
やりたいことにもってこいの関数ですね。
この中でデータベースへ問い合わせをします。
まずbookmanagerページにgetInitialProps関数を追加します。
importLayoutfrom'../../components/layout';importReactfrom'react';import{Container,Row,Col,Table,Form}from'react-bootstrap';exportdefaultclassIndexextendsReact.Component{// 追記ここからstaticasyncgetInitialProps(){constres=awaitfetch('http://192.168.130.69:3000/bookmanager/get');constallBooks=awaitres.json();return{allBooks};}// 追記ここまでrender(){{/* 略 */}}
getInitialPropsの中でAPIを呼び結果を取得しています。
この呼び出しの定義をserver.jsで記述します。
app.prepare().then(()=>{constconnection=require('./mariadbConnection');// データベース呼び出し処理は削除してください。server.get('/bookmanager',(req,res)=>{/*
let query = "SELECT title, author, publisher, DATE_FORMAT(finished_at, '%Y/%m/%d') AS finished_at FROM Books ORDER BY title";
connection.query(query, (err, rows) => {
if(err) throw err;
console.log(rows);
});
*/returnapp.render(req,res,'/bookmanager',req.query);});// 追記ここからserver.get('/bookmanager/get',async(req,res)=>{letquery="SELECT title, author, publisher, DATE_FORMAT(finished_at, '%Y/%m/%d') AS finished_at FROM Books ORDER BY title";connection.query(query,(err,rows)=>{if(err)throwerr;res.json(rows);// レスポンスに取得データを持たせる});});// 追記ここまでserver.get('*',(req,res)=>{returnhandle(req,res);});server.listen(3000,(err)=>{if(err){throwerr;}console.log('> Ready on http://localhost:3000');});}).catch((ex)=>{console.error(ex.stack);process.exit(1);});
毎度のことながら、npm run dev
してアクセスします。
データベースには以下のデータが入っています。
title | author | publisher | finisher_at |
---|---|---|---|
PHPフレームワークLaravel入門 第2版 | 掌田津耶乃 | 秀和システム | 2019/10/31 |
PostgreSQLから始めるデータベース生活 | まぐろ | まぐろのみぞおち | 2019/11/03 |
PostgreSQL徹底入門 第4版 | 近藤雄太 他 | 翔泳社 | NULL |
Python Django超入門 | 掌田津耶乃 | 秀和システム | 2019/08/31 |
React.js&Next.js超入門 | 掌田津耶乃 | 秀和システム | NULL |
プリンをもっと見守る技術 M5StickVで体験するAIの世界 | aNo研 | aNo研 | 2020/05/26 |
アクセスすると...
ちゃんと表示されました(;^ω^)
お疲れ様でした
盛りだくさんで書くのも大変でした。
日本語を書くのがへたっぴなので、分かりづらいところがあると思います。
小さい目標を1つずつ達成して、
「現段階で何ができているのか」「次に何ができてほしいか」「ゴールまで到達するにはあと何ができなければならないか」
をまとめるようにすると、ワカラナイパニックに陥ることは少ないと思います。
と、私の会社の先輩が言っていました。
次回
条件を入力して検索できるようにします。