SlideShare una empresa de Scribd logo
1 de 33
株式会社 FLECT
小西俊司
 FLECTの主力言語はPlay1
◦ しかしPlay1はもはやメンテされていない模様
◦ 1.3が出ると一瞬聞いたような気もするが。。。(--
 Play1開発者がPlay2を使う場合に
◦ Play1でのやり方との対比でPlay2での方法を知る
◦ 言語とFrameworkの両方を同時に学ぶのは辛いのでとりあえ
ずScalaが良く分かってなくてもなんとなく開発できる気にす
るのがゴール
◦ これどうするんだっけ?と思った時に見る資料(主に俺が)
 ただしBest Practiceはまだまだ模索中なのでもっと良
い方法があるはずとも思う。
◦ というかPlay2自体まだまだそんな感じ
◦ 間違ってもここに書いてあることを鵜呑みにしてはいけない
 自力で頑張れ
◦ List, Map, Option, パターンマッチ, case classあたりがわかれ
ばとりあえず使える
 禁止技
◦ 途中でReturn
◦ Nullとの比較(Optionを使用する)
 Scalaでどう書けば良いのかわからん!と思った時にはと
りあえずJavaだと思って書けばOK
 慣れるまでimportでワイルドカードは使わない
◦ Play(というかScala全般)でimportはワイルドカードで書く文化
でサンプル等もほとんどそうなっているが、それだとクラス構成
が全く分からない。
◦ 特にimplicit関数を把握しないまま使うのは危険だと思う
◦ 列挙型やImplicit関数などワイルドカードでインポートしないと
使いづらいものもあるが、それを見極めるためにも最初は自力で
書く
 Play2のインストールはzipを展開してPATHを通
すだけ
 しかし「play(.bat)」という実行スクリプトの名
前がPlay1とバッティングする。。。
◦ →実行スクリプトを「play2(.bat)」とリネームすれば問
題なく共存して使える
package controllers
import play.api.mvc.Controller
import play.api.mvc.Action
object Application extends Controller {
def index = Action {
Ok(views.html.index("Your new application is ready."))
}
def hello = Action {
Ok("Hello world")
}
}
デフォルトで定義されている
Action
Okは「200 OK」のレスポンス
views.xxxxはviewsフォルダにあ
るテンプレートファイルへの参照
で
renderTemplate相当
renderText相当
 Play1と違ってワイルドカードルーティングはないのでroutesの
編集も必要
 多くのメソッドでリクエスト情報を暗黙引数として要求される
ので常にimplicitキーワード付きで参照するようにする
package controllers
import play.api.mvc.Controller
import play.api.mvc.Action
object Application extends Controller {
def index = Action { implicit request =>
Ok(views.html.index("Your new application is ready."))
}
def hello = Action {implicit request =>
Ok("Hello world")
}
}
Implicitをつけると暗黙の引数として利用でき
る
@(name: String)(implicit lang: Lang)
@main(Messages("hello")) {
<div>
@Messages("hello") @name
</div>
}
これがないとMessageの国際化がされない
 使用するパラメータはすべて宣言する必要がある
◦ 最初はPlay1に比べてかなり面倒な気がするがパラメータの不
備がコンパイルエラーで拾えるのがメリット
 マジックワードは「@」のみ
 「@{…}」で自由にScalaコードを記述可能
 上の例で使用している機能
◦ 親テンプレートとして@mainを呼び出している
◦ @Messagesで国際化されたメッセージリソースを出力
◦ 引数@nameを出力
 ワイルドカードは使えない
 Actionの参照には引数を含める必要がある
 PATHの一部をActionの引数として渡せる
 GETパラメータはActionの引数として渡せるがPOSTパラメータは渡せ
ない
 パラメータには省略時のデフォルトが定義できる
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / controllers.Application.index
GET /hello controllers.Application.hello
GET /hello2/:name controllers.Application.hello2(name)
GET /hello2 controllers.Application.hello2(name ?= "guest")
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
Play1に比べて面倒
 Ok、Redirect、BadRequest、などHttpステータ
ス毎にメソッドが用意されている
 Content-Typeは引数によって自動的に識別
◦ Play1の「renderXXX」に相当するメソッドはない
◦ あるいは
のように「as」メソッドで明示
 Play1のようなトリックはない
◦ renderXXXXが実はExceptionだとか
◦ Controllerのメソッドを呼ぶと勝手にリダイレクトされ
るとか
Ok(“””{“name”:”konishi”}”””).as(“application/json”)
 Formを使用する
◦ Case classを作ってそこにマッピングするのが楽
private val queryForm = Form(mapping(
"id" -> optional(text),
"kind" -> of[QueryKind],
"name" -> text,
"group" -> default(text, ""),
"sql" -> text,
"desc" -> optional(text),
"setting" -> optional(text)
)(QueryInfo.apply)(QueryInfo.unapply));
 https://github.com/shunjikonishi/sqltool/blob
/master/app/controllers/QueryTool.scala
 個別に取得したい場合は以下のようにすると取れ
る
◦ ユーティリティメソッドを作っておかないとものすごく
面倒
val name: Option[String] =
request.body.asFormUrlEncoded.flatMap(_.get("name").map(_.head));
 Play1とほとんど変わらない
◦ application.confの「application.langs」で使用する言
語を宣言
◦ 言語毎に「messages.xx」をconfディレクトリに作成
◦ リソースの参照はMessagesクラスを使用
 同一ファイル内に複数言語のメッセージを定義し
たい場合はGlobal.scalaにPlay1で使用していた
ResourceGenを組み込むことができる
◦ https://github.com/shunjikonishi/sqltool/blob/ma
ster/app/Global.scala
 Play1の「conf/dependencies.yml」相当のファ
イルは「project/Build.scala」
 JDBCドライバはデフォルトで入っていないので
PostgreSQLなどのJDBCドライバを使用する場合
は自分で組み込む必要がある
 https://github.com/shunjikonishi/sqltool/blo
b/master/project/Build.scala
 Herokuで使う場合、Play1ではivysetting.xmlが
自前で用意できなかったためリポジトリの追加が
できなかったがPlay2では問題なくできる
◦ flectCommonなどの内部jarをリポジトリから取得でき
る
 Application.confにデータベース定義を追加
 Play1ではDBはひとつしか定義できなかったが複数定
義可能になった
 ORMapperはない
 代わりにAnormが組み込まれている
◦ 多分SelectBuilderとの相性は良い
◦ https://github.com/shunjikonishi/sqltool/blob/master/
app/models/QueryManager.scala
//グループ名の一部を抜き出す処理
SQL("""
SELECT distinct groupname FROM sqltool_sql
WHERE groupname LIKE {gl}
ORDER BY groupname
"""
).on(
"gl" -> (parent + "/%")
).apply.map{ row =>
val g = row[String]("groupname").substring(parent.length + 1);
g.split("/")(0);
}.toSet.toList;
 CacheAPIはset,get,removeの3メソッドのみと
なった
 Memcachedを使用する場合はプラグインが必要
◦ https://github.com/mumoshu/play2-memcached
◦ Play1と同じくserializableなオブジェクトをキャッシュ
に保存可能
◦ Case classはserializableなのでそのままキャッシュに
保存可能
 https://github.com/orefalo/play2-
authenticitytoken
 をいれると、Play1相当のことができるらしい
◦ MemcachedもそうだがPlay1にあった機能が足りてない
場合は有志がプラグインとして作っている印象
 Play1の時に作った自前のCSRFモジュールをプラ
グインとして移植しても良いけど微妙。
 JSONライブラリがgsonからjackson(のScalaラッ
パーであるjerkson)に変わった
 Case classをJSONにparse/formatするだけなら
JSON.formatをimplicitで定義するだけで良い。
 加工が必要な場合は自分でFormatを定義
◦ JSONのキーを変数名とは別にしたい
◦ Case class中のあるフィールドはJSONに含めたくない
 https://github.com/shunjikonishi/sqltool/blo
b/master/app/models/QueryInfo.scala
 https://github.com/shunjikonishi/sqltool/blo
b/master/app/models/SQLToolImplicits.scala
 ScalaのXMLリテラルがそのまま使用できる
◦ もっとも最近ではREST APIはほとんどJSONなのでほと
んど使うことはない
◦ 以前にXMLリテラルでXMLを組み立てようとした際に、
手続き的な処理が必要になってどうするのが良いのか
迷った記憶があるが詳細は忘れた。
 JavaScriptやCSSは「app/assets」に置く
 このフォルダに置いたファイルでは
◦ CoffeeScriptがJavaScriptに変換される
◦ LESSがcssに変換される
◦ js/cssのminify版が生成される(xxx.min.jsでアクセスで
きる)
 イメージなどは「public」に置く。
◦ assetsに置いても良いと思うが意味がないし、多分こっ
ちの方が速い
 Play1と同じく実体はCookie
 セッションIDがない
◦ Memcacheを使用する場合に困る
◦ 自前のFilterで対応
//OAuth認証のTokenをsessionに持たせる
Ok(views.html.login(url)).withSession(
"token" -> token.getOAuthToken()
)
 Play1と同じく次のリクエストまで有効なFlashが使用でき
る
◦ 仕組みもPlay1と同じ
◦ https://github.com/shunjikonishi/sqltool/blob/master/app
/controllers/QueryTool.scala//ファイル インポート後にインポート件数を付けてメイン画面にリダイレクト
Redirect("/main").flashing(
"Import-Insert" -> insertCount.toString,
"Import-Update" -> updateCount.toString
);
 取得側のコード
◦ Implicit requestが必要
◦ https://github.com/shunjikonishi/sqltool/blob/master/app
/controllers/Application.scala
def main = Action { implicit request =>
val importInsert = flash.get("Import-Insert").getOrElse("0").toInt;
val importUpdate = flash.get("Import-Update").getOrElse("0").toInt;
…
}
 Request.body.asMultipartFormDataからアップ
ロードされたファイルをjava.io.Fileとして取り出
せる
◦ Play1は引数にFileを宣言するだけだったのですごく面倒
になった
◦ https://github.com/shunjikonishi/sqltool/blob/ma
ster/app/controllers/QueryTool.scaladef importSql = Action { implicit request =>
request.body.asMultipartFormData match {
case Some(mdf) =>
mdf.file("file") match {
case Some(file) =>
...
case None => BadRequest;
}
case None => BadRequest;
}
}
なんか冗長なのでもっときれいな書き方
があると思う
 Ok.sendFileメソッドを使う
◦ Play1では添付ファイルのダウンロードと削除を同時に
やろうとするとすごく面倒だったのが楽になった
◦ https://github.com/shunjikonishi/sqltool/blob/ma
ster/app/controllers/QueryTool.scala
def exportSql = Action { implicit request =>
val file = File.createTempFile("temp", ".sql");
try {
man.exportTo(file);
Ok.sendFile(file, fileName={ f=> "export.sql"}, onClose={ () => file.delete()});
} catch {
case e: Exception =>
e.printStackTrace;
Ok(e.toString);
}
}
 Play1と同じようにWSクラスで外部WebServiceに
アクセス可能
 Play1とほぼ同じような使い方だが同期APIがなく
なって非同期APIのみなので同期で使用したい場
合は自分でFutureから結果を取り出す必要がある
 Play1のPluginのように全リクエストで共通的に
行う処理はFilterクラスとして実装
◦ SessionIDFilter(リクエストにセッションIDを付加する)
◦ https://github.com/shunjikonishi/sqltool/blob/ma
ster/app/jp/co/flect/play2/filters/SessionIdFilter.sc
ala
◦ AccessControlFilter(Basic認証とIP制限)
◦ https://github.com/shunjikonishi/sqltool/blob/ma
ster/app/jp/co/flect/play2/filters/AccessControlFilt
er.scala
◦ 便宜的にSQLTool内で作成しているが必要に応じて
Plugin化する
 Globalクラスの宣言にWithFiltersで組み込み
 https://github.com/shunjikonishi/sqltool/blo
b/master/app/Global.scala
object Global extends WithFilters(SessionIdFilter, AccessControlFilter) {
…
}
 Play1の@throwsや@beforeのような処理を行う場合
はActionの合成を使用する
◦ https://github.com/shunjikonishi/sqltool/blob/master/
app/controllers/GoogleTool.scala
//GoogleSpreadsheetの設定が有効でない場合はInternalServerErrorを返す
def filterAction(f: Request[AnyContent] => Result): Action[AnyContent] = Action
{ request =>
if (GoogleSpreadsheetManager.enabled) {
f(request);
} else {
InternalServerError("Google account is not setuped.");
}
}
def showSheet(bookName: String, sheetName: String) = filterAction { implicit request
=>
...
}
 Akkaを直接使う
◦ https://github.com/shunjikonishi/sqlsync/blob/ma
ster/app/Global.scala
//HerokuのWebDynoを眠らせないために自分自身をポーリング
val appname = sys.env.get("HEROKU_APPLICATION_NAME");
if (appname.nonEmpty) {
Akka.system.scheduler.schedule(0 seconds, 10 minutes) {
WS.url("http://" + appname.get + ".herokuapp.com/assets/ping.txt").get()
}
}
 ログライブラリはlog4jからLogback+SLF4Jに変
更になった
 play.api.Loggerを直接使うこともできるが、個
別にLoggerインスタンスを生成して使用すること
もできるようになった
 ログレベルの設定はapplication.conf内で個別に
行える
logger.root=ERROR
logger.play=INFO
logger.application=DEBUG
logger.jp.co.flect=INFO
#logger.com.google=DEBUG
logger.Schedule=INFO
 Play1にあったAppIDはない
 ので、開発/本番環境で設定を切り替えたい場合
はapplication.conf自体を切り替える
◦ 起動コマンド
play run –Dconfig.resource=prod.conf
 Confファイル内では別のconfファイルをインク
ルードでき、キーをオーバーライドすることが可
能include "application.conf"
key.to.override=blah
 HerokuのスケジューラからPlay2を起動したい場合
◦ 重いので可能であればJavaクラス単体にするなどした方が良
い
 target/startスクリプトに起動オプションを渡して起
動
target/start –Dsqltool.mode=schedule
 ローカルで動かす場合はあらかじめ「play stage」コ
マンドを叩いてlibをビルドする必要がある
 Windowsの場合は.batは生成されないので自分でバッ
チファイルを書く必要がある
 コマンドが長いのでrakeで起動するようにしている
https://github.com/shunjikonishi/sqltool/blob/master/sqltool.bat
https://github.com/shunjikonishi/sqltool/blob/master/Rakefile
 Global.onStartで起動オプションによって処理を分岐
◦ 終了時には問答無用でSystem.exitしている(多分問題ないは
ず)
◦ https://github.com/shunjikonishi/sqltool/blo
b/master/app/Global.scala
val mode = sys.props.get("sqltool.mode").getOrElse("web");
mode match {
case "schedule" =>
Schedule.main();
System.exit(0);
case “setup” =>
…
System.exit(0);
case _ =>
}
 Play1でできていたことは頑張れば全部できる
 Play1では標準機能でできていたことがプラグイ
ンが必要になって面倒になった気がするが、言い
換えれば組み合わせの自由度が上がったというこ
とでもある
◦ もっとも発展途上の印象もぬぐえない
 コード量はおそらくPlay1の半分以下になる
◦ case classとListがあるだけでもJavaの生産性をはるか
に凌駕していると思う
多分使える

Más contenido relacionado

Más de Shunji Konishi

Salesforceのハッカソンに参加した話
Salesforceのハッカソンに参加した話Salesforceのハッカソンに参加した話
Salesforceのハッカソンに参加した話Shunji Konishi
 
Salesforce連携のためのOData入門
Salesforce連携のためのOData入門Salesforce連携のためのOData入門
Salesforce連携のためのOData入門Shunji Konishi
 
プロキシーを使ってテストを楽にする
プロキシーを使ってテストを楽にするプロキシーを使ってテストを楽にする
プロキシーを使ってテストを楽にするShunji Konishi
 
Javascriptのあれやこれやをまとめて説明してみる
Javascriptのあれやこれやをまとめて説明してみるJavascriptのあれやこれやをまとめて説明してみる
Javascriptのあれやこれやをまとめて説明してみるShunji Konishi
 
MochaとChaiでやるJavaScriptテスト
MochaとChaiでやるJavaScriptテストMochaとChaiでやるJavaScriptテスト
MochaとChaiでやるJavaScriptテストShunji Konishi
 
SendGridサンプルの紹介
SendGridサンプルの紹介SendGridサンプルの紹介
SendGridサンプルの紹介Shunji Konishi
 
セキュリティの考え方
セキュリティの考え方セキュリティの考え方
セキュリティの考え方Shunji Konishi
 
一番簡単なWebSocketの試し方
一番簡単なWebSocketの試し方一番簡単なWebSocketの試し方
一番簡単なWebSocketの試し方Shunji Konishi
 
WebSocketでリアルタイムクイズアプリを作ってみた
WebSocketでリアルタイムクイズアプリを作ってみたWebSocketでリアルタイムクイズアプリを作ってみた
WebSocketでリアルタイムクイズアプリを作ってみたShunji Konishi
 
良質なコードを高速に書くコツ
良質なコードを高速に書くコツ良質なコードを高速に書くコツ
良質なコードを高速に書くコツShunji Konishi
 
Playframework1でSeleniumテスト
Playframework1でSeleniumテストPlayframework1でSeleniumテスト
Playframework1でSeleniumテストShunji Konishi
 
Heroku Dyno再起動時の振る舞い
Heroku Dyno再起動時の振る舞いHeroku Dyno再起動時の振る舞い
Heroku Dyno再起動時の振る舞いShunji Konishi
 
Dyno cycling behavior of Heroku
Dyno cycling behavior of HerokuDyno cycling behavior of Heroku
Dyno cycling behavior of HerokuShunji Konishi
 
Herokuで使えるRDBMS管理者ツール
Herokuで使えるRDBMS管理者ツールHerokuで使えるRDBMS管理者ツール
Herokuで使えるRDBMS管理者ツールShunji Konishi
 
お手軽Ajaxアプリケーションの作り方
お手軽Ajaxアプリケーションの作り方お手軽Ajaxアプリケーションの作り方
お手軽Ajaxアプリケーションの作り方Shunji Konishi
 
Herokuのログ解析ツール
Herokuのログ解析ツールHerokuのログ解析ツール
Herokuのログ解析ツールShunji Konishi
 
文字コードのお話
文字コードのお話文字コードのお話
文字コードのお話Shunji Konishi
 

Más de Shunji Konishi (20)

Salesforceのハッカソンに参加した話
Salesforceのハッカソンに参加した話Salesforceのハッカソンに参加した話
Salesforceのハッカソンに参加した話
 
Salesforce連携のためのOData入門
Salesforce連携のためのOData入門Salesforce連携のためのOData入門
Salesforce連携のためのOData入門
 
プロキシーを使ってテストを楽にする
プロキシーを使ってテストを楽にするプロキシーを使ってテストを楽にする
プロキシーを使ってテストを楽にする
 
Javascriptのあれやこれやをまとめて説明してみる
Javascriptのあれやこれやをまとめて説明してみるJavascriptのあれやこれやをまとめて説明してみる
Javascriptのあれやこれやをまとめて説明してみる
 
MochaとChaiでやるJavaScriptテスト
MochaとChaiでやるJavaScriptテストMochaとChaiでやるJavaScriptテスト
MochaとChaiでやるJavaScriptテスト
 
SendGridサンプルの紹介
SendGridサンプルの紹介SendGridサンプルの紹介
SendGridサンプルの紹介
 
セキュリティの考え方
セキュリティの考え方セキュリティの考え方
セキュリティの考え方
 
一番簡単なWebSocketの試し方
一番簡単なWebSocketの試し方一番簡単なWebSocketの試し方
一番簡単なWebSocketの試し方
 
WebSocketでリアルタイムクイズアプリを作ってみた
WebSocketでリアルタイムクイズアプリを作ってみたWebSocketでリアルタイムクイズアプリを作ってみた
WebSocketでリアルタイムクイズアプリを作ってみた
 
良質なコードを高速に書くコツ
良質なコードを高速に書くコツ良質なコードを高速に書くコツ
良質なコードを高速に書くコツ
 
Heroku tips1
Heroku tips1Heroku tips1
Heroku tips1
 
Playframework1でSeleniumテスト
Playframework1でSeleniumテストPlayframework1でSeleniumテスト
Playframework1でSeleniumテスト
 
Heroku Dyno再起動時の振る舞い
Heroku Dyno再起動時の振る舞いHeroku Dyno再起動時の振る舞い
Heroku Dyno再起動時の振る舞い
 
Dyno cycling behavior of Heroku
Dyno cycling behavior of HerokuDyno cycling behavior of Heroku
Dyno cycling behavior of Heroku
 
Herokuで使えるRDBMS管理者ツール
Herokuで使えるRDBMS管理者ツールHerokuで使えるRDBMS管理者ツール
Herokuで使えるRDBMS管理者ツール
 
お手軽Ajaxアプリケーションの作り方
お手軽Ajaxアプリケーションの作り方お手軽Ajaxアプリケーションの作り方
お手軽Ajaxアプリケーションの作り方
 
Herokuのログ解析ツール
Herokuのログ解析ツールHerokuのログ解析ツール
Herokuのログ解析ツール
 
Excel2 canvas
Excel2 canvasExcel2 canvas
Excel2 canvas
 
特盛!Heroku
特盛!Heroku特盛!Heroku
特盛!Heroku
 
文字コードのお話
文字コードのお話文字コードのお話
文字コードのお話
 

Último

20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directoryosamut
 
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。iPride Co., Ltd.
 
PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000Shota Ito
 
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxIoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxAtomu Hidaka
 
UPWARD_share_company_information_20240415.pdf
UPWARD_share_company_information_20240415.pdfUPWARD_share_company_information_20240415.pdf
UPWARD_share_company_information_20240415.pdffurutsuka
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
新人研修のまとめ       2024/04/12の勉強会で発表されたものです。新人研修のまとめ       2024/04/12の勉強会で発表されたものです。
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。iPride Co., Ltd.
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 

Último (9)

20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory
 
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
 
PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000
 
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxIoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
 
UPWARD_share_company_information_20240415.pdf
UPWARD_share_company_information_20240415.pdfUPWARD_share_company_information_20240415.pdf
UPWARD_share_company_information_20240415.pdf
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
新人研修のまとめ       2024/04/12の勉強会で発表されたものです。新人研修のまとめ       2024/04/12の勉強会で発表されたものです。
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 

Play1 to Play2