【Kotlin/Spring】Kotlin版SpringBoot開発環境を構築する
Kotlin版Spring Boot開発環境構築のメモです。
検証環境はMac OS X Mojave 10.14.2 になります。
IntelliJ IDEのインストール
今回はIDEとしてIntelliJを使用します。 IntelliJはKotlinの開発元であるJetbrain社が開発していることもあって、Kotlinのサポートはバッチリです。
下記リンクより遷移後、DownloadボタンからIntelliJをダウンロードできます。
プロジェクトの作成
次に、Spring InitializerからSpringプロジェクトの雛形を取得します。
取得するプロジェクトに関して、いくつかオプションを選択していきます。
まずビルドツールとして Maven
Gradle
のうち何れかを選択します。今回は Gradle
のプロジェクトを作成していきます。
次に言語選定です。主要なJVM言語 Java
Gloovy
Kotlin
から選択できます。 今回はKotlinで書くので「Kotlin」 を選択。
次にSpringのバージョンを選択します。今回は安定版の 2.1.1
を選択します。
プロジェクトのメタ情報について設定します。
GroupはGradleのGroupIDとなり、プロジェクトを一意に識別するためのものです。プロジェクトのソースファイルを含めるパッケージと同一にすることが慣習となっています。
ArtifactIDはいわゆるプロジェクト名です。
メタ情報に関する記述は下記参照。
最後にSpringに追加したいライブラリを入力・選択します。
今回はWeb(Webページ生成/APIインタフェース等のWeb関連機能)、JPA(永続化機能)、Security(認証機能)を選択しました。
最後に「Cenerate Project」ボタンを押して、zipファイルをダウンロードしてください。
プロジェクトを開く
次は、ダウンロードしたプロジェクトをIntelliJで開きます。
ダウンロードした圧縮済みプロジェクトを解凍し、解凍後のプロジェクトを任意のディレクトリに配置してください。 その後、ダウンロード(+インストール)したIntelliJを起動し、起動後ダイアログ中の「Open」をクリックしてください。
するとディレクトリ選択のためのファイルダイアログが開かれます。 ここでIntelliJで開きたいプロジェクトを選択。
「OK」をクリック。
これでプロジェクトがIntelliJ上に読み込まれました。
あとは開発するのみ!
ローカルでSpringアプリケーションを起動
実際にアプリケーションをローカルで起動してみます。
起動の前に、 build.gradle
を少し編集します。
Spring Data JPAライブラリを読み込むとDBの設定が必要になるため、
今回は一旦外しておきます。
「View」->「Tool Windows」->「Gradle」 を選択。
「(プロジェクト名)」-> 「Tasks」->「application」->「bootRun」を右クリックし、「Run '(プロジェクト名)[bootRun]'」 を選択。
するとビルド・アプリケーションの起動が始まります。
23:39:41: Executing task 'bootRun'... :compileKotlin w: ... ated :compileJava NO-SOURCE :processResources UP-TO-DATE :classes UP-TO-DATE :bootRun . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.1.RELEASE) ... 2019-01-09 23:40:22.533 INFO 31168 --- [ main] c.r.n.rpg.rpgkit.RpgKitApplicationKt : Started RpgKitApplicationKt in 18.3 seconds (JVM running for 19.039)
アプリケーションの起動はこれで成功です!
参考文献
【Docker】イメージビルド時にキャッシュを使用しない
メモ。
Dockerイメージ作成時、デフォルトだと過去のビルドキャッシュが存在する場合そちらを使用してしまいます。
$ ls Dockerfile $ docker build -t hoge .
Step 2/20 : COPY entrypoint.sh /sbin/entrypoint.sh ---> Using cache ---> 5214f6bedefd
これにより、コマンドの実行結果やファイル内容の反映が上手くいかない場合があります。
--no-cache
を指定することで、キャッシュが存在する場合も無視してビルドを実行できます。
$ docker build -t hoge . --no-cache
---> 5d870d6990ba Step 2/20 : COPY entrypoint.sh /sbin/entrypoint.sh
以上です。
【Kotlin】Java(8) -> Kotlinやってみて「良い」と思ったことリスト
Kotlinをやっていて、Java(8)と比較して良いな、と思った部分を書きました。
null許容型
Swiftなどにもありますが、Kotlinではnull許容型が定義されており、それと対を成すようにデフォルトの型宣言ではnullが許容されないようになっています。
val hoge: String = null // Error:(9, 23) Null can not be a value of a non-null type String val hoge: String? = null // OK
エルビス演算子(?:)
オペランド(被演算子)がnullのときのデフォルト値を設定できる
String fuga = hoge == null ? "hoge is null" : hoge;
↓
val fuga = hoge ?: "hoge is null"
第一級関数
Kotlinは関数を言語仕様に持ち、かつそれらを第一級関数として扱えます(値として扱える)。
fun hoge(arg1: String) { println(arg1) } fun main(args: Array<String>) { val func = ::hoge // Javaのメソッド参照のように渡す func("hoge") }
if式
Scalaやpythonのように、ifが式なので返り値を持ちます。
val isHoge = true; val hoge = if (isHoge) "hoge" else "not hoge"
文字列テンプレート
JavaScript言語仕様が持つ文字列テンプレートをKotlinでも使用できます。
文字列リテラル内で $
を使って変数を文字列として埋め込みます。
val message = "Hello, Kotlin!" println("Welcome to Kotlin world : $message")
${}
を使用すると、カッコ内に式を使用できます。
val kotlin = "Kotlin!" val java = "Java" val isKotlin = true println("Hello ${if (isKotlin) kotlin else java}")
クラスフィールドにデフォルトでアクセサがつく
immutableフィールド val
で宣言した場合はgetterのみが、
mutableフィールド var
で宣言した場合はsetter+getterが生成されます。
Kotlinでは暗黙的にgetter/setterが呼ばれます。
class Gorilla( val name: String, var isAdult: Boolean // getter + setter ) fun main(args: Array<String>) { val gorilla = Gorilla("ゴリラ", true) // 暗黙的なgetter呼び出し println(gorilla.name) // ゴリラ println(gorilla.isAdult) // true // 暗黙的なsetter呼び出し gorilla.isAdult = false println(gorilla.isAdult) // false }
値forループの廃止
言語仕様で for (int i = 0; i < 10; i++)
のような繰り返し変数をインクリメントしていく for
文が廃止されており、基本的に拡張forループのみを使用することになります。
Kotlinでfor文による値のインクリメントは ..
演算子によるレンジによって実現できます。
for (i in 1..10) { println(i) // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
レンジは逆順・数値飛ばしが可能です。
for(i in 10 downTo 1) { println(i) // 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }
for(i in 1..10 step 2) { println(i) // 1, 3, 5, 7, 9 }
レンジは閉区間であり、..
演算子の右側の値を数列に含みます。
開区間のレンジを作る場合、 until
を利用します。
for(i in 1 until 10) { println(i) // 1, 2, 3, 4, 5, 6, 7, 8, 9 }
分割代入
オブジェクトプロパティを複数の変数に代入することができます。
fun divMod(a: Int, b: Int) : Pair<Int, Int> { return Pair(a / b, a % b) } fun main(args: Array<String>) { val (div, mod) = divMod(10, 3) println("div: $div , mod: $mod") }
when式
Javaではif/switch文で処理できた複数の分岐処理が、Kotlinではwhen式と呼ばれる言語仕様で実装できます。 when式は式として評価されるので分岐先で結果を返す・変数に入れるなどの操作ができます。 whenはJavaのswitch文のように並列に記述できます。
fun main(args: Array<String>) { val num = 3; println(fizzbuzz123(num)) // } fun fizzbuzz123(num: Int): String{ return when (num) { 1 -> "fizzbuzz" 2 -> "fizz" 3 -> "buzz" else -> "$num" } }
また引数を省略することで、値マッチングの代わりに条件式による分岐が可能になります。
fun main(args: Array<String>) { val num = 3; println(fizzbuzz(num)) } fun fizzbuzz(num: Int): String{ return when { num % 15 == 0 -> "fizzbuzz" num % 3 == 0 -> "fizz" num % 5 == 0 -> "buzz" else -> "$num" } }
名前付き引数/デフォルト引数
名前付き引数・デフォルト引数もサポートされています。
fun add(a: Int, b: Int = 1) :Int { return a + b; } fun main(args: Array<String>) { println(add(1,2)) //3 println(add(1)) //2 println(add(a = 4,b = 2)) // 6 }
全般的に他言語で実装済みのモダンで使いやすい言語仕様が入っている印象でした。 まだまだ良いところがありそうなので、追記するかもしれません。
【Kotlin】Kotlin CLIでKotlinをJavaバイトコードにコンパイル/実行する
今日はじめてKotlinを触ってみたのですが、その際に使用したKotlin CLIによるコンパイルと実行のメモです。
Kotlin CLIのインストール
実施環境:Mac OS X Mojave 10. 14.2
brew でインストールできます。
$ brew update $ brew install kotlin
コンパイル
適当な .kt
ファイルを用意します。
hoge.kt
fun main(args: Array<String>) {
println(args)
}
kotlinc
コマンドでコンパイルします(オプションでKotlinランタイムを含めたjarを生成)。
$ kotlinc hoge.kt -include-runtime -d hoge.jar
jar
ファイルが生成されるので、Java同様 java
コマンドで実行します。
$ ls hoge.kt hoge.jar $ java -jar hoge.jar [Ljava.lang.String;@1b6d3586
コンパイル時に -include-runtime
でKotlinランタイムを含めているのは、Kotlinコンパイラでコンパイルされて生成されたバイトコードがKotlinランタイムのライブラリに依存しているためです。ランタイムを含めずにそのままコンパイルすると、実行時に kotlin/jvm/internal/Intrinsics
クラスが見つからず ClassNotFoundException
例外を送出します。
$ kotlinc hoge.kt $ kotlinc _hoge.class Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics at _hoge.main(1_5_1_compile.kt) Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 1 more
ちなみに kotlinc
コマンドを引数なしで実行すると、インタラクティブシェル(REPL)が起動されます。
$ kotlinc Welcome to Kotlin version 1.3.11 (JRE 1.8.0_131-b11) Type :help for help, :quit for quit >>> println("Hello, Kotlin CLI !") Hello, Kotlin CLI ! >>> :help Available commands: :help show this help :quit exit the interpreter :dump bytecode dump classes to terminal :load <file> load script from specified file
参考文献
【Twitter】Twitter OAuthでメールアドレスの第三者共有を許可する設定
メモ。
Twitter OAuth1.0a認証にて、メールアドレス認可を第三者に行いたい場合、下記のような設定が必要になります。
1. OAuth認証ページURLリクエストに include_email
を含める
https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true
2. Developerアカウントダッシュボード App details
でTerms of ServiceURL
Privacy policy URL
を設定する
3. Developerアカウントダッシュボード Permission
で Additional permissions
の Request email address from users
を有効にする
以上です。
【npm/yarn】パッケージをダウングレードする
メモ。
npm
では、パッケージのダウングレードを行う場合、一旦パッケージを削除してから再度インストールし直す必要があります。
$ npm remove cowsay $ npm install --save cowsay@1.0.0
yarn
であれば、 yarn upgrade [パッケージ名]@[version]
で指定したバージョンにそのままダウングレードしてくれます。もちろんアップグレードも可能。
$ yarn upgrade cowsay@1.0.0
yarn
は楽でいいですね。個人的には npm
と違ってデフォルトでローカルパッケージインストールなのが安心です。
【React Native/Expo】Google Oauth認証で認証後リダイレクトを行う
前回の記事では、Expoを使用して作成したReact NativeアプリにGoogleのOAuth認証を実装しました。
今回はその認証後にリダイレクト先URLを設定し、リダイレクト先にログインユーザの情報にアクセスするためのトークンを渡す手順について書いていきます。
WebクライアントIDの作成
認証後にリダイレクト可能なエンドポイントを設定するため、WebクライアントIDを作成します。
下記Google認証設定のページに遷移し、「認証情報の作成」ボタンをクリックします。
ボタンをクリックすると作成したい認証情報のメニューが表示されるので「OAuth クライアントID」をクリック。
作成するクライアントIDの種類を選択します。今回はWebクライアントIDが欲しいので「Webアプリケーション」を選択。
すると詳細設定用のフォームが出現するのでIDの名称を入力し、リダイレクトしたいURLのドメインを「承認済みのJavaScript生成元」に、「承認済みのリダイレクトURL」にURLをそれぞれ入力します。入力が完了したら「作成」をクリック。
するとIDが作成されます。同時にクライアントIDを掲載したダイアログが表示されるので、IDをコピーしましょう。以降の工程ではこのIDをクライアントIDとして使用します。
アプリケーション側の実装
アプリケーション側の実装についても触れていきます。 以降の実装では、下記記事のアプリケーション作成を前提としています。
App.js
前回の記事 で作成した App.js
中の signInWithGoogle
を以下のように変更します。
authUrl
のパラメータである client_id
には 先程取得したWebクライアントIDを入力してください。また redirect_url
にはリダイレクト先のURLを入力してください。
async signInWithGoogle() { try { const result = await Expo.AuthSession.startAsync({ authUrl: `https://accounts.google.com/o/oauth2/v2/auth?` + `&client_id={WebクライアントID}` + `&redirect_uri={リダイレクトURL}` + `&response_type=code` + `&access_type=offline` + `&scope=profile`, }); if (result.type === 'success') { console.log('Google Access Token: ' + result.accessToken); } } catch (e) { console.log(e); } }
Backend
今回は認証後のリダイレクト先として自前のバックエンドAPIサーバを指定すします。例として以下のようなSpring実装のAPIエンドポイントを用意し、Google OAuth認証後はこのエンドポイントに対してリクエストが飛びます。
下記実装ではAPIリクエストが届くとバックエンド側のコンソールにトークンIDが表示されるようにしています。実際はトークンIDを利用して、Google認可ユーザの情報を取り扱ったりすることが多いです。
@RestController public class OAuthController { @RequestMapping(value = "/oauth/google", method = RequestMethod.GET) public void signInWithGoogle(@RequestParam String code) { System.out.println(code); } }
Demo
それでは、実際にアプリを動かしてみます。
npm start
でExpo Developer toolsを起動し、QRコードをクライアント端末でスキャンしインストールを開始します。詳細な手順は下記記事に載っているので、適宜参照していただければ幸いです。
アプリを端末にインストールして起動したら、中央の「Sign in with Google」 ボタンを押します。
すると 「Expoがサインインのために"expo.io"を使用しようとしています`」と書かれたダイアログが出現するので、「続ける」をタップします。
続けて起動したアプリが別のサービス上でログインすることへの許可を求めてくるので、「Yes」をタップ。
するとGoogleの認証画面に遷移します。すでに端末上でGoogleログイン済みのアカウントがある場合、アカウント一覧からログインしたいアカウントを選択します。
認証に成功するとリダイレクトが実行され、バックエンドログにトークンIDが表示されているのがわかります。
2019-01-02T20:13:33.22+0900 [APP/PROC/WEB/0] OUT aBcd...(トークンIDが続く)
これでリダイレクト成功です!
OAuth認証は自前のサービスに組み込んで認証に使う場合が多く、リダイレクトでGoogleなどのSNS上にあるユーザ情報にサービスがアクセスさせなければいけない場面も割と多いので、今後も頻繁にメモしていきたいですね。