#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[]{};
}
}
}