- 03-5820-1777平日10:00〜18:00
- お問い合わせ
画面側はS3を使用しても良いですが、Amplifyの方がzipファイルでのデプロイや、Gitからのデプロイに対応していて便利そうなので、そちらを使用しました。
1.画面一覧
2.画面イメージ
3.Lambda
以上の3つのLambda関数を用意します。
4.DB
商品情報テーブルとID作成用のシーケンステーブルを用意し、項目は以下を用意します。
商品テーブル
5.Api Gateway
Api GatewayはVue.jsへのRestApiを提供するのに使用し、URLとメソッドに応じて、対応するLambda関数を呼び出します。URLとメソッドに応じた呼び出すLambda関数を表にまとめます。
URL | メソッド | 呼び出すLambda |
---|---|---|
/goodslist | GET | GetGoodsList |
/goodsbyid | POST | GetGoodsById |
/registgoods | POST | RegistGoods |
1.DynamoDB設定
※今回はDynamoDBを使用していますが、JOINなど複雑な検索が必要なものはRDBを使用した方が良いと思います。
・テーブル作成画面で必要な情報を入力し、テーブルを作成する。
商品テーブル、シーケンステーブルの2つを作成します。
・テーブルを選択して、項目を追加していきます。
・シーケンステーブルも同様に項目を追加します。
シーケンステーブルは項目追加の際に、TABLE_NAMEにgoodsという文字列を入れておきます。
2.Lambda実装
・実行ロールの作成
LambdaからDynamoDBへのアクセスを許可するポリシーを持ったロールを作成します。
後にLambda作成の際にこのロールを使用します。
上記のポリシーを持ったロールを作成します。
ロール名は「LambdaAccessDynamoDB」にしました。
・関数作成
関数作成画面で必要な情報を入力し、関数を作成します。
・関数の実装
Pythonであれば、AWSにエディタが用意されているので、そこから実装を行う事が出来るので、この画面で実装、
デプロイをして行きます。
デプロイ後、テストも出来るので便利です。
・商品一覧取得関数(GetGoodsList)の実装
import json
import boto3
# boto3を使用してDynamoDBにアクセス
dynamodb = boto3.resource('dynamodb')
def lambda_handler(event, context):
# テーブル名を指定し、テーブル操作オブジェクト取得
goodsTable = dynamodb.Table('Goods')
# テーブルの全情報を取得する
response = goodsTable.scan()
if response['ResponseMetadata']['HTTPStatusCode'] != 200:
print(response) # エラーレスポンスを表示
else:
print('Successed.')
return response
・ID指定で商品取得関数(GetGoodsById)の実装
import json
import boto3
# boto3を使用してDynamoDBにアクセス
dynamodb = boto3.resource('dynamodb')
def lambda_handler(event, context):
# テーブル名を指定し、テーブル操作オブジェクト取得
goodsTable = dynamodb.Table('Goods')
# Lamba呼び出し元から渡されたIDを取得
id = event['ID']
# IDを指定して、データを取得
response = goodsTable.get_item(
Key={'ID': id }
)
if response['ResponseMetadata']['HTTPStatusCode'] != 200:
print(response) # エラーレスポンスを表示
else:
print('Successed.')
return response
渡されるデータの形式の例は以下です。4の部分は適当な数値に代わります。
数値はダブルクォーテーションなどで囲まないようにして下さい。
{
"ID": 4
}
・登録、更新関数の実装
import json
import boto3
import decimal
# boto3を使用してDynamoDBにアクセス
dynamodb = boto3.resource('dynamodb')
# シーケンステーブルからIDを取得しカウントアップし更新
def get_next_seq(table, tablename):
response = table.update_item(
Key = {
'TABLE_NAME' : tablename
},
UpdateExpression='set SEQ = SEQ + :val',
ExpressionAttributeValues = {
':val' : 1
},
ReturnValues='UPDATED_NEW'
)
return response['Attributes']['SEQ']
def lambda_handler(event, context):
# テーブル名を指定し、テーブル操作オブジェクト取得
goodsTable = dynamodb.Table('Goods')
# IDを取得する
id = event['ID']
# IDが0の場合は、IDをシーケンスから取得する
if id == 0:
seqtable = dynamodb.Table('Sequence')
id = get_next_seq(seqtable, 'goods')
# テーブル更新メソッドを呼ぶ。
# keyで設定されている値がなかった場合は新規登録、存在する場合は更新になる
response = goodsTable.update_item(
# キー項目の値設定
Key={
'ID': id
},
# 更新式を記述、項目名は別名を使用する
UpdateExpression='SET #CODE = :code, #NAME = :name, #CATEGORY = :category, #PRICE = :price',
# ここで項目の別名を指定しないとエラーになる
ExpressionAttributeNames={
"#CODE": "CODE",
"#NAME": "NAME",
'#CATEGORY': 'CATEGORY',
'#PRICE': 'PRICE',
},
# 更新式で指定した変数の値を設定
ExpressionAttributeValues={
':code': event['CODE'],
':name': event['NAME'],
':category': event['CATEGORY'],
':price': event['PRICE']
}
)
if response['ResponseMetadata']['HTTPStatusCode'] != 200:
print(response) //エラーレスポンスを表示
else:
print('Successed.')
return response
渡されるデータの形式の例は以下です。
上が新規登録例、下が更新例です。IDが0かどうかで判断しています。
{
"ID": 0,
"CODE": "GC9989",
"NAME": "商品G",
"CATEGORY": "002",
"PRICE": 1000
}
{
"ID": 5,
"CODE": "GC9989",
"NAME": "商品G",
"CATEGORY": "002",
"PRICE": 1000
}
3.ApiGateway設定
Vue.jsからアクセスするのはRestAPIでのアクセスが必要なので、RestAPIを提供しLambdaを呼び出してくれる、ApiGatewayという機能を使用します。
ApiGatewayサービスのページ行って、APIを作成ボタンを押下するとのタイプを選択できます。
「REST API」で構築します。
・API作成
APIの作成を押すとAPIが作成されます。
・ステージの作成
まずステージを作成します。
ステージは開発版、本番用またはヴァージョン事に分けたい場合などに有効みたいです。
ACLの設定やログの設定などが可能です。
今回は、1つしか使用しないので、「prod」という名前で作成します。
指定した名称はアクセスする際のURLに含まれます。
・リソースの作成
次はリソースを作成します。
リソースを作成すると、その中にメソッドを作成しLambda関数と関連付けます。
リソースは、「5.Api Gateway」で定義したURL分の3つを作成します。
リソース名に「goodslist」、「goodsbyid」、「registgoods」をそれぞれ指定します。
・メソッドの作成
リソースを作成したら次はメソッドを作成していきます。
メソッドも「5.Api Gateway」で定義したメソッドを作成します。
リソースを選択してメソッド作成を押下します。
メソッドを選択します。
横のチェックボタンを押下するとメソッドが作成されます。
作成後、メソッドとLambda関数を関連付けます。
上記のようにLambda関数を指定して保存すれば完了です。
・CORS有効化
次に、他のオリジン(ドメインにプロトコル、ポート番号が追加されたもの)からアクセス可能にする為の設定を
行います。
これは各リソース毎に行う必要があります。
CORSの有効化を押下します。
右下のボタンを押下すると確認画面が表示されるので、それをはいを押下すると設定完了です。
Api GatewayへのアクセスURL
ステージ画面から見る事が出来ます。
このURLにリソース名を追加しアクセスします。
4.Vue.js実装
次はVue.jsの実装を見ていきます。
Vue.jsプロジェクトを作成して実装を行っています。
簡単な画面なので特に特別な事はしていませんので、実装だけ張っていきます。
・GoodsList.vue(商品一覧画面)
<template>
<div style="text-align:left;">
<div class="table" style="width:600px;">
<table>
<thead>
<tr>
<th>コード</th>
<th>名前</th>
<th>カテゴリ</th>
<th>価格</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="(data) in goodsList" :key="data.ID">
<td>{{ data.CODE }}</td>
<td class="tdname">{{ data.NAME }}</td>
<td>{{ categoryDatas.find( c => c.id === data.CATEGORY ).name }} </td>
<td>{{ data.PRICE }}</td>
<td><router-link :to="{ name: 'editGoods', params:{id:data.ID}}">編集</router-link></td>
</tr>
</tbody>
</table>
</div>
<input type="button" @click="addGoods" value="新規登録">
</div>
</template>
<script>
import goodsRepository from '../composables/GoodsRepository'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
export default ({
name: 'GoodsList',
setup(){
//GoodsRepositoryモジュールからの変数、メソッドを宣言
//カテゴリ用データ、商品リスト、商品取得メソッド
const { categoryDatas, getGoods } = goodsRepository()
const goodsList = ref([])
//ルータ使用変数宣言
const router = useRouter()
//新規作成ボタン押下時の処理
const addGoods = () => {
router.push("/registGoods")
}
//データ取得時のコールバック( GoodsRepositoryのgetCodesメソッドに渡す)
const callback = ( result, data )=>{
if( result != "success"){
alert( result );
}else{
goodsList.value = data
}
}
//商品情報取得
getGoods( callback )
//template上で使用する変数を宣言
return{
goodsList,
addGoods,
getGoods,
categoryDatas
}
}
})
</script>
<style>
.table{
height: 380px;
width:580px;
overflow: auto;
border:solid 1px;
}
table thead th {
border: 1px solid #CCC;
text-align: center;
background-color: #EFEFEF;
border-top : 1px solid #CCC;
border-left : 1px solid #CCC;
border-right : 1px solid #CCC;
border-bottom : 0px solid #CCC;
cursor:pointer;
}
table tbody td{
min-width:100px;
max-width:auto;
height:25px;
}
.tdname{
min-width:200px;
}
</style>
・EditGoods.vue(商品登録・更新画面)
<template>
<div>
<div class="inputItemDiv"><div class="inputTitleDiv">コード</div><input class="input" type="text" v-model="goods.CODE"></div>
<div class="inputItemDiv"><div class="inputTitleDiv">商品名</div><input class="input" type="text" v-model="goods.NAME"></div>
<div class="inputItemDiv"><div class="inputTitleDiv">カテゴリ</div>
<select class="select" name="category" v-model="goods.CATEGORY">
<option v-for="categoryData in categoryDatas" :value="categoryData.id" :key="categoryData.id">
{{ categoryData.name }}
</option>
</select>
</div>
<div class="inputItemDiv"><div class="inputTitleDiv">価格</div><input class="input" type="text" v-model="goods.PRICE"></div>
<div class="inputItemDiv" style="text-align:right">
<button type="button" class="button" @click='cancel'>キャンセル</button>
<button :disabled="resAllVal" type="button" class="button" @click='regist'>登録</button>
</div>
</div>
</template>
<script>
import goodsRepository from '../composables/GoodsRepository'
import { useRoute, useRouter } from 'vue-router'
import { ref } from 'vue'
export default ({
name: 'EditGoods',
setup( ){
const goods = ref({ID:0, CODE:'',NAME:'',CATEGORY:'001',PRICE:0})
//GoodsRepositoryモジュールからの変数、メソッドを宣言
const { categoryDatas, getGoodsById, registGoods } = goodsRepository()
//ルータ使用変数宣言
const route = useRoute()
const router = useRouter()
//データ取得時のコールバック( GoodsRepositoryのgetGoodsByIdメソッドに渡す)
const getCallback = ( result, data ) =>{
if( result != "success"){
alert( result )
}else{
goods.value = data
}
}
//パラメータでIDが渡された際は、商品情報を取得する
console.log(route.params.id)
if( route.params.id != null ){
console.log("getGoodsById")
getGoodsById( route.params.id, getCallback )
}
//登録ボタン押下時の処理
const regist = () => {
registGoods( goods.value, regCallback )
}
//登録ボタン押下時のコールバック( GoodsRepositoryのregistGoodsメソッドに渡す)
const regCallback = ( result ) =>{
if( result == "success"){
alert("登録完了");
router.push("/")
}else{
alert( result );
}
}
//キャンセル処理 商品一覧画面へ戻る
const cancel = () => {
router.push("/")
}
//template上で使用する変数を宣言
return{
categoryDatas,
goods,
regist,
cancel
}
}
})
</script>
<style>
.inputItemDiv{
width:360px;
overflow: hidden;
margin:2px;
}
.inputTitleDiv{
float: left;
width:100px;
height:25px;
}
.inputDiv{
float: left;
width:250px;
height:25px;
}
.input{
width:250px;
height:20px;
}
.inputread{
width:250px;
height:20px;
background-color: #ccc;
}
.select{
width:257px;
height:25px;
}
.button{
width:100px;
}
.validateError{
color:red;
width:250px;
font-size:12px;
}
</style>
・GoodsRepository(商品情報のサーバへのアクセス)
import { ref } from 'vue'
import axios from 'axios'
//商品情報の取得、登録、編集などの機能を提供する
export default function (){
const apiGatewayUrl = 'https://kgxc1b2bea.execute-api.ap-northeast-1.amazonaws.com/prod'
//カテゴリのマスタを宣言、refとして宣言
const categoryDatas = ref([])
categoryDatas.value.push({id:'001', name:'本'})
categoryDatas.value.push({id:'002', name:'ゲーム'})
//商品をIDで指定して取得するメソッド
const getGoodsById = async( id, callback ) =>{
try{
var formData = {"ID": Number( id ) }
//formData.append("ID", Number( id ) )
var response = await requestServerPost( "/goodsbyid", formData )
console.log(response.Item)
callback("success", response.Item)
}catch(e){
callback(e)
}
}
//商品登録、更新メソッド
//sereraccess.jsのメソッドをコール
const registGoods = async( regGoods, callback ) => {
try{
var response = await requestServerPost( "/registgoods", regGoods )
console.log( response )
callback("success")
}catch(e){
callback(e)
}
}
//商品情報取得
const getGoods = async( callback ) => {
try{
//Spring Bootにaxiosで商品取得依頼
var response = await requestServerGet( "/goodslist" )
console.log( response.Items )
//コールバックに結果を返す
callback( "success", response.Items )
}catch(e){
console.log(e)
callback(e)
}
}
//axiosのGetメソッドでApiGatewayにアクセス
const requestServerGet = ( url ) =>{
return new Promise((resolve, reject) => {
axios
.get( apiGatewayUrl + url)
.then(response => {
resolve(response.data)
}).catch(error => {
reject(error)
})
}).catch((e) => {
throw e
})
}
//axiosのGetメソッドでApiGatewayにアクセス
const requestServerPost = ( url, formDate ) =>{
return new Promise((resolve, reject) => {
axios
.post( apiGatewayUrl + url, formDate)
.then(response => {
resolve(response.data)
}).catch(error => {
reject(error)
})
}).catch((e) => {
throw e
})
}
//当該ライブラリが提供する変数、メソッドを宣言
return{
getGoods,
getGoodsById,
registGoods,
categoryDatas
}
}
・router/index.js(ルーター情報)
import { createRouter, createWebHistory } from 'vue-router'
import GoodsList from '../views/GoodsList.vue'
import EditGoods from '../views/EditGoods.vue'
const routes = [
{
path: '/',
name: 'goodsList',
component: GoodsList
},
{
path: '/editGoods/:id',
name: 'editGoods',
component: EditGoods,
props: true
},
{
path: '/registGoods',
name: 'registGoods',
component: EditGoods,
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
5.Amplifyに配置
では最後にAmplifyにVue.jsをデプロイしていきます。
今回は、Vue.jsのファイルをアップロードしてデプロイする方法にします。
・Vue.jsビルド、zip形式のまとめる
まず、Vue.jsプロジェクトをビルドします。
npm run build
プロジェクトルート/distディレクトリにビルド後のファイル群が配置されるので、そのファイル群はzipで纏めます。
名称はindex.zipにします。
・Amplifyアプリケーション作成、zipファイルをデプロイ
ウェブアプリケーションをホストの「使用を開始する」ボタンを押下します。
「Gitプロバイダーなしでデプロイ」を選択します。
GitHubからの選択などにするとGitHubにコミット時、自動的にデプロイしてくれるらしいので、他の記事で此方も試していたいと思います。
適当なアプリケーション名、環境名を入力し、先ほど作成したzipファイルをドラッグアンドドロップします。
デプロイが完了すると上記の画面が表示されます。DomainのURLにアクセスすると作成したWebページを見る事が出来ます。
以上で終了になります。今回はAWS上でVue.jsとLamdbaを使用したWebアプリケーション作成方法を例を1つ試してみました。
他にもロードバランサーを使用したり、ドメインを変えてと色々出来る事があるので、それは後に記事にしようと思います。