【Kotlin】SpringBootでGetのコントローラーを動かすまで【SpringBoot】

最近黒べこ本(会社のお金で)買いました。サーバーサイドでもKotlinはいいぞ。
今回はKotlinのSpringBootでハロワします。
記事執筆時点でのプロジェクトリポジトリは以下。
github.com

やること

  1. SpringInitializrでプロジェクトの概形を作る
  2. Controllerを追加する
SpringInitializrでプロジェクトの概形を作る

https://start.spring.io/
使い方はネット上に解説記事が有るので省略します。
自分はGradle Project/Kotlin、Spring Boot 2.1.1で初期化しました。
f:id:wrongwrongwrongwrong163377:20181202144343p:plain
そのままやるとパッケージ名が大文字になってしまうので、その点は修正を行いました。

Controllerを追加する

以下のような形でMyControllerという名前でコントローラーを追加しました。
f:id:wrongwrongwrongwrong163377:20181202144505p:plain

import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("my")
class MyController{
    @GetMapping
    fun myGetTest(model: Model): String{
        return "hello from spring boot"
    }
}

このままだとimplementsが足りなかったり警告が出たりするので、build.gradleに以下の2つを追加します。

implementation(group: 'org.springframework.boot', name: 'spring-boot-starter-web')
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

追加後全文。

buildscript {
	ext {
		kotlinVersion = '1.2.71'
		springBootVersion = '2.1.1.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
		classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
		classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
	}
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.wrongwrong'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
	kotlinOptions {
		freeCompilerArgs = ["-Xjsr305=strict"]
		jvmTarget = "1.8"
	}
}
compileTestKotlin {
	kotlinOptions {
		freeCompilerArgs = ["-Xjsr305=strict"]
		jvmTarget = "1.8"
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation('org.springframework.boot:spring-boot-starter')
	implementation(group: 'org.springframework.boot', name: 'spring-boot-starter-web')

	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	implementation("org.jetbrains.kotlin:kotlin-reflect")

	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

	testImplementation('org.springframework.boot:spring-boot-starter-test')
}

アクセス結果

動かした上でhttp://localhost:8080/myへアクセスすると、以下が表示されます。
f:id:wrongwrongwrongwrong163377:20181202145028p:plain

続き

バリデーションまでやってます。
wrongwrong163377.hatenablog.com

【日記】次に引っ越す時意識したいことメモ

東京で次に引っ越す時に意識しておきたいことをまとめます。

必須

自由に捨てられるゴミ捨て場

住んでるマンションは24時間いつでもゴミを捨てられます。
これがとても便利でした。
ズボラかつ平日は朝遅い時間に通勤しがちなので助かります。

会社との距離が2km以上3km以内

この距離だと帰りに歩く/走るのに丁度よかったです。
住み始めた時は通勤が不安でしたが、気がつくと学生時代より運動していました。
運動は本当に大事。

通勤時に割と座れる

混んでるのが嫌なので、割と座れる位の環境がいいなと思います。

自分の住んでいる場所はバス路線の根本で、本数そのものが非常に多いので、バスを選べば混雑も避けられました。

準必須

洗濯機を置くスペースが広い

洗濯は手間なので、大きめの洗濯乾燥機を置けると助かるなと思います。

そこまでうるさくない

首都高が真ん前を走っているせいでうるさく感じる場面が結構有りました。
日頃はそこまでうるさくないんですが、時々爆音エンジンで走ってるのが居てイラッときます。
立地的にはものすごく便利なんですが、もうちょっとうるさくない環境が欲しいです。

オートロック

鍵を掛け忘れることが有ったり無かったりするので、オートロックが有ると安心できます。

できれば

広い部屋

スペース欲しいです。
高くなるので優先度は低いですが。

蛇口の形

↓で言うシングルレバー式やサーモスタット式が最初から有ると嬉しいです。

jyusetu.com

家賃が安い

ムリダナ。
真面目な話、北海道に居た時は半分以下の家賃で倍以上の面積に住めてたので、東京の家賃の高さは異常だと思います……。

【JavaScript】オブジェクトをディープコピーする

JavaScriptには素の状態でディープコピーを取得する機能が無く、ただ代入してもシャローコピーとなってしまい、バックアップを一時的に持っておくような作業には使えません。

やり方

自分で書こうとすると手間が大きかったので、Lodashを導入した上で、そこからclone関数を使うのが一番手軽だと思います。
flaviocopes.com

生JSで実装された内容

以下はtatsuo fukuchi様が実装した例です。
qiita.com

おまけ的な

オブジェクト同士の完全比較のisEqualsなど、Lodashには非常に有用な関数が揃っています。
導入も簡単ですし、とりあえず詰まったらLodashから探してくるのが今の所簡単そうかな……。

【読書感想】「社会調査」のウソ―リサーチ・リテラシーのすすめ

 

「社会調査」のウソ―リサーチ・リテラシーのすすめ (文春新書)

「社会調査」のウソ―リサーチ・リテラシーのすすめ (文春新書)

 

統計データを作る・解釈する難しさ

この本では全編に渡って「ダメな社会調査」が実例とともに示されます。

統計データというのは便利なもので、それを使うことで様々なものを客観的に評価することができます。
一方、データを作る・解釈するという過程では、様々なバイアスを排除して実態を明らかにすることが求められます。
この作業の難易度は非常に高く、「素人が思いつきで作ったようなデータ」には全くと言っていいほど価値がありません。

この事自体はデータを作る側として実感がありましたし、実際におかしなデータと解釈に触れる機会もままありましたが、読んでいて「まさかここまでとは」という気分でした。

というかこの本、発売日が20年近く前なんですよね……。

 データは真実だが実態ではない

データそのものは真実です。
しかし、それが検証したかった内容を検証できているかや、それに対する解釈が実態を捉えているかは別の問題です。

自分が作る側に回る時は、その辺りをちゃんと意識してデータを作ったり、解釈していこうと思います。

文中で触れられていた通り、「生産されたゴミは使い回され、新たなゴミを生む」んですよね。
データを作る人間は、自分の行った全てが未来永劫他人に迷惑をかけ続ける可能性を意識して行動する必要があるということを意識しなければならないと、改めて感じました*1

どんな立場でも、データに関わる人間は一度読んでおくべき本だったと思います。

*1:最近では、そもそもデータを参照しないまま施策を決めたり、恣意的な改ざんが有ったりと、あらゆる面でデータ軽視の状況が見られますが……。

【JavaScript】JasmineでsetTimeOut/crearTimeOutをspyOnする

Karma + JasmineでsetTimeOut/crearTimeOutをモックにします。

コード

setTimeOutには戻り値を設定しています。複数回呼ぶときはreturnValues(100, 101, 102...)としてやると、呼ぶごとに戻り値を変えられます。

//timeout系をmock化
spyOn(window, 'setTimeout').and.returnValue(100);
spyOn(window, 'clearTimeout');

//呼び出しチェック
expect(setTimeout).toHaveBeenCalled();
expect(clearTimeout).toHaveBeenCalled();

参考文献

stackoverflow.com

【HTML/CSS】複数の要素を同期してScrollする【JavaScript】

複数要素を同期してScrollさせます。
強引な実装だと思うので、もっとスマートな実装が有れば教えてください。

やりたいこと

以下のような機能を実現します。

  • 複数要素を同時にScrollさせる
  • 全ての要素から同様に操作が行えるようにする
  • 高さが異なる場合でも動く

実装

以下のようにすればやれます。

let scrollFrom = null; //呼び出し元記憶用
let timeoutId = 0; //タイムアウトの破棄用

//スクロール同期制御類
let handleScroll = (callFrom) => {
    //呼び出し元をセットする
    if(scrollFrom === null){
        scrollFrom = callFrom;
    }
    //呼び出し元が違うなら何もしない
    if(scrollFrom !== callFrom) return;

    //タイムアウトが設定されているなら破棄する
    if(timeoutId !== 0) clearTimeout(timeoutId);
    //タイムアウトを設定、timeoutと呼び出し元を初期化
    timeoutId = setTimeout(()=>{
        timeoutId = 0;
        scrollFrom = null;
    }, 100);

    //スクロール率を設定
    const basis = document.getElementById(callFrom);
    const scrollRatio = basis.scrollTop / (basis.scrollHeight - basis.clientHeight);
    //スクロール実行
    const elements = document.getElementsByClassName("sync-scroll");
    for(let i = 0; i < elements.length; i++){
        //呼び出し元は操作しない
        if(elements[i].id === callFrom) continue;
        //要素をscroll
        elements[i].scrollTop =
            (elements[i].scrollHeight - elements[i].clientHeight) * scrollRatio;
    }
}

利用例

動く例を貼ってみました。
解説用に開発者ツールへの出力を入れているので、解説を読む方はそちらも確認してみてください。



a

b

c

d

e

f

g

h

i

j

k

l

m

n

o

p


0

1

2

3

4

5

6

7

8

9

解説

コードを解説します。

呼び出し元の記録と、記録のリセット

このコードでは呼び出し元を記録したり、setTimeoutを利用してリセットしたりしています。
これは、onscrollは呼び出し元に関わらず実行されてしまうため、「要素1をスクロール→要素2がスクロール→要素1がスクロール……」と連鎖が起きるのを防ぐための仕組みです。
サンプルを動かした上で開発者ツールのconsoleログを見てもらえば分かりますが、handleScrollの呼び出しは1スクロールごとに2回起きています。
スクロールは短時間に連続して起こるものなので、一定時間だけ呼び出し元を記録し、その呼び出し元以外からの操作はブロックするという形で対応を行いました。
setTimeoutで作成したリセットタイマーはそのままにしておくと誤作動するため、clearTimeoutで破棄しています。

高さの操作

高さは$element.scrollTopに値を入れることで操作できます。
$element.scrollTopの範囲は$element.scrollHeight - $element.clientHeightで出せるので、後は全要素のスクロール率を揃えれば同期したスクロールが可能になります。

【プログラミング】JetBrains製IDEでwebpackのビルド時に長時間Indexingが走る状態への対処

問題

webpadkでbabelのビルドを走らせると、Indexingが長時間走ってIDEの補完やらビルドやらができなくなる状況が発生していました。

原因

ビルド結果の出力されるフォルダもIDEAの管理下になっていたため、大量のファイルをIndexingしていたことが原因でした。

対策

下記の手順で、フォルダを右クリック→Mark Directory Asから除外(Excluded)することで解決します。
qiita.com