Добавление данных в сеанс в фильтре play framework

#java #scala #playframework-2.0

#java #scala #playframework-2.0

Вопрос:

У меня возникли проблемы с добавлением данных в сеанс в фильтре (EssentialFilter).

В scala api есть метод Result.withSession , Result.withNewSession но в java api его нет.

Как я могу вернуть результат из фильтра с новыми данными сеанса?

Пытался сделать это так:

 @Override
public EssentialAction apply(final EssentialAction next) {
    return EssentialAction.of( request -> {
        if (isAllowed(request)) {
            Accumulator<ByteString, Result> accumulator = next.apply(request);
            return accumulator.map(result -> {
                Session session = result.session();
                session.put("asdf", Long.toString(System.currentTimeMillis()));
                return resu<
            }, executor);
        } else {
            return Accumulator.done(Results.unauthorized());
        }
    });
}
 

Из того, что я вижу в debug / sources, к тому времени, когда результат возвращается в блок карты накопителя, result построил ResponseHeader, и модификация сеанса ничего не меняет.

Я попытался преобразовать результат в scala с asScala() помощью и предоставить новые элементы сеанса ( withSession() ), но у меня возникли проблемы с преобразованием сеанса java в сеанс scala / play. Может быть, кто-нибудь может указать, как это сделать правильно?

 Session session = result.session();
session.put("asdf", Long.toString(System.currentTimeMillis()));

play.api.mvc.Session newSession = ...?

return result.asScala().withSession(newSession).asJava();
 

[править]

Я получил эту работу с:

 scala.collection.immutable.Map<String, String> immutableMap = new scala.collection.immutable.HashMap<String,String>().empty();
for (Map.Entry<String, String> entry : session.entrySet()) {
  immutableMap = immutableMap.$plus(new Tuple2<>(entry.getKey(), entry.getValue()));
}
play.api.mvc.Session newSession = new play.api.mvc.Session(immutableMap);
 

но … как вы можете видеть, это действительно некрасиво. Нет ли другого, более причудливого способа сделать это?

Ответ №1:

Я бы посоветовал вам полностью преобразовать ваш фильтр в scala. Даже там это не безболезненно, но лучше, чем этот «уродливый» код, с которым вы также согласны.

Примером может быть:

   import akka.stream.Materializer
  import javax.inject._
  import play.api.Logger
  import play.api.mvc._
  import scala.concurrent.{ExecutionContext, Future}

  @Singleton
  class ExampleFilter @Inject()(
                                   implicit override val mat: Materializer,
                                   exec: ExecutionContext) extends Filter {


    override def apply(nextFilter: RequestHeader => Future[Result])
                      (requestHeader: RequestHeader): Future[Result] = {
      // Run the next filter in the chain. This will call other filters
      // and eventually call the action. Take the result and modify it
      // by adding a new header.

      val start = System.currentTimeMillis()
      nextFilter(requestHeader).map { result =>
        val end = System.currentTimeMillis() - start;
        Logger.debug(s"Service time in milliseconds: ${end}")
        result.withSession(requestHeader.session   ("ServiceTime" -> s"${end}"))
      }
    }

  }
 

Вероятно, вы это знаете, но рассматривайте это как поощрение использовать scala только для этой части.

К сожалению, Java для play не очень хорошо подходит. Вы часто сталкиваетесь с проблемами, связанными с конверсиями. Действительно больно…

Редактировать:

Для того, чтобы включить фильтр scala в ваши фильтры Java, вы должны выполнить следующие действия в своем Filters.java : (модифицировано из примера play-java) (важная часть : exampleFilter.asJava()

 @Singleton
public class Filters implements HttpFilters {

  private final Environment env;
  private final EssentialFilter exampleFilter;

  @Inject
  public Filters(Environment env, ExampleFilter exampleFilter) {
    this.env = env;
    this.exampleFilter = exampleFilter.asJava();
  }

  @Override
  public EssentialFilter[] filters() {
    // Use the example filter if we're running development mode. If
    // we're running in production or test mode then don't use any
    // filters at all.
    if (env.mode().equals(Mode.DEV)) {
      return new EssentialFilter[]{exampleFilter};
    } else {
      return new EssentialFilter[]{};
    }
  }
}