はじめに
前の記事で、React+Amplify+Cognito認証のアプリで画像ファイルをS3にアップロードするまで行いました。
この記事では、Excel ファイルを S3 にアップロードし、S3 のトリガーで Lambda 関数(C#)を起動し、Excel ファイルを読み込んだ結果をログに出力するまでを行います。
前の記事の続きになるので、Amplify、Cognito、S3 などの環境設定については前の記事を参考にしてください。
Lambda 関数(C#)を作成
Visual Studio 2019 Community Edition に AWS Toolkit for Visual Studio をインストールして、S3 のテンプレートを使用して雛形を作成します。
そして、NPOI を Nuget よりインストールします。
C# で Excel を読み込むライブラリについては、以下の記事を参考にしてください。
実際に Excel を読み込む Lambda 関数は以下のようになります。S3 のイベントで呼び出され、S3Event に必要な情報が渡されます。
using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Threading.Tasks; using NPOI.SS.UserModel; using Amazon.Lambda.Core; using Amazon.Lambda.S3Events; using Amazon.S3; using Amazon.S3.Util; [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] namespace AWSLambda1 { public class Function { IAmazonS3 S3Client { get; set; } public Function() { S3Client = new AmazonS3Client(); } public Function(IAmazonS3 s3Client) { this.S3Client = s3Client; } // S3 のイベントで呼び出される関数 public async Task FunctionHandler(S3Event evnt, ILambdaContext context) { var s3Event = evnt.Records?[0].S3; if(s3Event == null) { return; } try { // S3 ファイルを取得する。s3Eventにバケット名とオブジェクトキーが含まれている。 var res = await this.S3Client.GetObjectAsync(s3Event.Bucket.Name, s3Event.Object.Key); // 日時をファイル名につけるの重要! var filePath = "/tmp/" + (DateTime.Now).ToString("yyyyMMdd_HHmmss_") + s3Event.Object.Key; await res.WriteResponseStreamToFileAsync(filePath, false, System.Threading.CancellationToken.None); // Create で xls,xlsx に対応 IWorkbook workbook = WorkbookFactory.Create(filePath); ISheet worksheet = workbook.GetSheetAt(0); // 最終行数を取得 int lastRow = worksheet.LastRowNum; for (int i = 0; i <= lastRow; i++) { // 行取得 IRow row = worksheet.GetRow(i); // セルの値取得 ICell cell1 = row?.GetCell(0); ICell cell2 = row?.GetCell(1); // ログに出力 LambdaLogger.Log(cell1?.StringCellValue + "," + (cell2?.NumericCellValue).ToString()); } // Excel クローズ workbook.Close(); // ファイル削除 File.Delete(filePath); } catch(Exception e) { context.Logger.LogLine($"Error getting object {s3Event.Object.Key} from bucket {s3Event.Bucket.Name}. Make sure they exist and your bucket is in the same region as this function."); context.Logger.LogLine(e.Message); context.Logger.LogLine(e.StackTrace); throw; } } } }
基本的にはコメントを付けたとおりなのですが、1点補足しておきます。
S3 のファイルを /tmp にコピーしてきていますが、これは S3 ファイルを直接プログラムで読み込むことができないので、/tmp に一時的にコピーしています。なお、この/tmp は上限が512MBになっているのでご注意ください。
今回は NPOI を Nuget でインストールしたため、Zip ファイルで Lambda 関数をアップロードする必要があります。詳しくは、以下の記事を参考にしてください。
なお、Lambda 関数の実行ロールには、S3 と CloudWatch へのアクセス権限が必要なので、IAM から権限付与しておいてください。
Lambda 関数に S3 イベントトリガーを設定する
Lambda 関数ができあがったので、イベントトリガーとして S3 のイベントトリガーを設定します。
Lambda 関数の画面で、S3 のバケットの PUT イベントをトリガーとして追加します。トリガーも有効化します。
React の実装
前の記事では、画像ファイルをアップロードするのでPhotoPicker
を使用しましたが、今度は Excel ファイルをアップロードするのでDropzone
というライブラリを使用します。
下記のように、プロジェクトにインストールします。
$ yarn add react-dropzone @types/react-dropzone
App.tsx
は以下のようになります。
import React from 'react'; import { withAuthenticator } from "aws-amplify-react"; import { Storage, Auth } from 'aws-amplify'; import Dropzone from 'react-dropzone'; import './App.css'; const App: React.FC = () => { const putFiles = (files : any[]) => { for (const file of files) { Storage.put(file.name, file,{ contentType: file.type }) .then (result => console.log(result)) .catch(err => console.log(err)); } } return ( <> <button onClick={() => Auth.signOut()}>サインアウト</button> <Dropzone onDrop={putFiles}> {({getRootProps, getInputProps}) => ( <section> <div className="fileArea" {...getRootProps()}> <input {...getInputProps()} /> <p>Drag 'n' drop some files here, or click to select files</p> </div> </section> )} </Dropzone> </> ); } export default withAuthenticator(App);
App.css
は以下のようになります。
.App { text-align: center; } .fileArea { width: 100%; height: 200px; background-color: skyblue; }
動作させてみる
今回の Excel ファイルは以下のようなデータが入っているものになります。
では、React アプリを起動します。
$ yarn start
以下の画面が表示されるので、Excel ファイルをドラッグ&ドロップしてアップロードします。
CloudWatch のログを確認すると、以下のように S3 のイベントから Lambda 関数が起動して、想定したデータが出力されていることがわかります。
デプロイ先でも動作させてみる
念のため、自動デプロイを行ってみて動作するかも確認します。
リモートリポジトリに変更を反映させます。
$ git add . $ git commit -m "Add excel feature." $ git push origin master
反映ができたようなので、Excel ファイルをアップロードしてみます。
正しくログが出力されました。
おわりに
React+Amplify+Cognito認証のアプリで Excel ファイルを S3 にアップロードして Lambda(C#) で読み込んで、CloudWatch にログを出力することができました。
実際にはかなり苦戦しましたが、できるようになってよかったです。
参考になれば幸いです。