1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ratpack入門 (8) - セッション

Last updated at Posted at 2018-02-09

Ratpack入門シリーズ

  1. Ratpack入門 (1) - Ratpackとは
  2. Ratpack入門 (2) - アーキテクチャー
  3. Ratpack入門 (3) - hello world 詳解
  4. Ratpack入門 (4) - ルーティング & 静的コンテンツ
  5. Ratpack入門 (5) - Json & Registry
  6. Ratpack入門 (6) - Promise
  7. Ratpack入門 (7) - Guice & Spring
  8. Ratpack入門 (8) - セッション
  9. Ratpack入門 (9) - Thymeleaf

セッション

Ratpackはデフォルトではセッションを提供しません。いわゆるStickyセッションを使うには、ratpack-sessionモジュールが必要です。Redisによるセッションサポートを有効にするには、さらにratpack-session-redisモジュールが必要です。

build.gradle
dependencies {
    compile "io.ratpack:ratpack-session:1.5.1"
}

モジュールを登録する必要があります。前述のようにRatpackは、拡張モジュールをGuiceのモジュールとして提供しています。

Function<Registry, Registry> registry = ratpack.guice.Guice.registry( bindings -> {
    bindings.module( SessionModule.class );
} );

セッションを管理するSessionクラスをRegistryから取得して、セッションのデータを操作します。ハンドラーのContextRegistryを継承しているので、Context.get()メソッドを呼び出して、セッションを取得できます。

Session session = context.get( Session.class );

セッションのキーには、Stringやクラス自体を使用することができます。しかしStringのキーではデータの取得にキャストが必要になり、クラスを使用する場合は同じクラスを登録できなくなります。一番いい方法は、SessionKey<T>クラスを使用することです。

public static final SessionKey<String> KEY = SessionKey.of( "KEY_NAME", String.class );

キーの名前と型を指定することで、安全にデータのやり取りを行うことができます。

データの取得及び設定には、それぞれget(SessionKey)およびset(SessionKey<T>, T)を使用します。これらの操作はブロッキング操作として扱われます。従って、これらのメソッドは直接値を返すのではなく、PromiseおよびOperationを返します。これはセッションの情報がどう保存されるかは実装依存であり、サーバー内部ではなく外部のKVSなどに保存されることも想定しているためです。

以下、ユーザーがサイトを訪れた回数と時間を保存する例です。

Session session = ctx.get( Session.class );

session.get( countKey ).flatRight( v -> session.get( lastVisit ) ).then( pair -> {

    int count = pair.left.orElse( 0 );

    String response = count == 0
                      ? "This is the first visit."
                      : "You have visited " + count + " times.\n" +
                        "Last visit: " + pair.right.get().format( DateTimeFormatter.ISO_LOCAL_DATE_TIME );

    session.set( countKey, count + 1 )
           .next( session.set( lastVisit, LocalDateTime.now() ) )
           .then( () -> {
               ctx.render( response );
           } );
} );

get()が返す型はPromise<Optional<T>>です。Optionalにラップしてくれるので、Servletのようにnullチェックする必要がありません。
見てのとおり、複数の値を取得しようとするとPromiseが重なってコードが汚くなります。getData()メソッドで、まとめて値を取得できます。
また、保存されたデータはJavaのシリアライズ機能によって直列化されます。そのため、Serializableを実装している必要があります。シリアライズはSessionSerializerによって行われます。Registryに独自の実装を提供することで、シリアライズの手法を変更できます。

ClientSideSessionModule

ratpack-sessionのデフォルト実装はGuavaのキャッシュを利用したインメモリーキャッシュを使います。一方、ClientSideSessionModuleを使用することで、クッキーに暗号化してデータを保存する、クライアントサイドセッションを使うモジュールも用意されています。

デフォルトでは情報は暗号化されません。必ずキーを指定する必要があります。

ratpack-session-redis

セッション情報をRedisに保存するために、ratpack-session-redisモジュールが用意されています。

build.gradle
dependencies {
    compile "io.ratpack:ratpack-session-redis:1.5.1"
}

モジュールを設定します。

RedisSessionModule redisModule = new RedisSessionModule();
redisModule.configure( config -> {
    config.setHost( "localhost" );
    config.setPort( 6379 );
    config.setPassword( null );
} );

Function<Registry, Registry> registry = ratpack.guice.Guice.registry( bindings -> {
    bindings.module( SessionModule.class );
    bindings.module( redisModule );
} );

RedisSessionModuleは、必ずSessionModuleに登録する必要があります。Ratpackは後から登録されたクラスを優先します。順番を逆にしてしまうと、Sessionの実装がRedisではなく、Stickyセッションのものになってしまいます。
ここではホストやポートをプログラムから設定していますが、ConfigSourceから設定することができます。

使い方自体は通常のratpack-sessionと同様です。設定してしまえば、バックエンドがRedisになっていることを意識することはありません。

Redisサーバーには、セッションIDをそのままキーとして、データが保存されます。セッションIDはデフォルトではUUIDが使われます。IDの生成はSessionIdGenerator経由で行われ、Registryから実装を切り替えられます。

キャプチャ2.png

# redis-cli
127.0.0.1:6379> keys *
1) "036f9723-3df8-e018-9abe-2db2bca5f6f6"
127.0.0.1:6379> get 036f9723-3df8-e018-9abe-2db2bca5f6f6
"\xac\xed\x00\x05sr\x006ratpack.session.internal.DefaultSession$SerializedForm\x00\x00\x00\x00\x00\x00\x00\x02\x0c\x00\x00xpw\xd3\x00\x01\x00\x02\x01\x00\x05COUNT\x01\x00\x11java.lang.Integer\x00\x00\x00
Q\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x02\x01\x00\nLAST_V
ISIT\x01\x00\x17java.time.LocalDateTime\x00\x00\x003\xac\xed\x00\x05sr\x00\rjava.time.Ser\x95]\x84\xba\x1b\"H\xb2\x0c\x00\x00xpw\x0e\x05\x00\x00\a\xe2\x02\t\r8!\x1a\xe1\xb6\xc0xx"
127.0.0.1:6379>

ちなみに、Redisとの通信はLettuceを使用しています(いつもキャベツと間違える)。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?