Написание пользовательских фильтров для Play! 2.2 в Java
У меня простой сценарий: автоматически добавляйте заголовок ответа на каждый HTTP-ответ; и я хочу сделать это на Java.
В src/play-filters-helpers/src/main/java/play/filters/*
есть примеры Actions, которые можно использовать в качестве аннотаций. Я бы не хотел добавлять @AddMyHeader
к каждому обработчику.
Глядя на Scala Фильтры в src/play-filters-helpers/src/main/scala/play/filters/*
и GzipFilter
, я вижу ясный механизм, но я не достаточно знаком с Scala для экстраполяции на Java.
Итак: куда мне идти?
Ответы
Ответ 1
К сожалению, пока еще нет хорошего способа создания и использования фильтров из Java. Но вы можете легко справиться с Scala.
Создайте новый файл app/filters/AddResponseHeader.scala
, содержащий:
package filters
import play.api.mvc._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object AddResponseHeader extends Filter {
def apply(f: (RequestHeader) => Future[SimpleResult])(rh: RequestHeader): Future[SimpleResult] = {
val result = f(rh)
result.map(_.withHeaders("FOO" -> "bar"))
}
}
И создайте новый файл app/Global.scala
, содержащий:
import filters.AddResponseHeader
import play.api.mvc.WithFilters
object Global extends WithFilters(AddResponseHeader)
Для каждого ответа должен применяться новый заголовок ответа.
UPDATE: есть способ использовать это в файле Global.java
:
@Override
public <T extends EssentialFilter> Class<T>[] filters() {
return new Class[] {AddResponseHeader.class};
}
И также измените object AddResponseHeader
выше на class AddResponseHeader
.
Ответ 2
Чтобы добавить настраиваемый фильтр (MyFilter.class), создайте файл Global.java в корневом пакете. Протестировано в PlayFramework 2.3.x и Java (JDK8)
import play.GlobalSettings;
import play.api.mvc.EssentialFilter;
public class Global extends GlobalSettings {
@Override
public <T extends EssentialFilter> Class<T>[] filters() {
return new Class[]{MyFilter.class};
}
}
Ответ 3
Для создания Play Filters нет хорошего API Java. Тем не менее, вы можете адаптировать существующие API Scala в хороший шаблон Java.
Например:
import play.api.mvc.*;
import scala.Function1;
import scala.concurrent.Future;
import scala.runtime.AbstractFunction1;
public abstract class JavaFilter implements Filter {
@Override
public Future<Result> apply(Function1<RequestHeader, Future<Result>> nextFilter, RequestHeader requestHeader) {
return nextFilter
.apply(requestHeader)
.map(new AbstractFunction1<Result, Result>() {
@Override
public Result apply(Result currentResult) {
return Apply(currentResult, requestHeader);
}
},
play.api.libs.concurrent.Execution.defaultContext());
}
@Override
public EssentialAction apply(EssentialAction next) {
return Filter$class.apply(this, next);
}
public abstract Result Apply(Result currentResult, RequestHeader requestHeader);
}
Пример реализации:
import play.api.mvc.RequestHeader;
import play.api.mvc.Result;
public class HelloFilter extends JavaFilter {
@Override
public Result Apply(Result currentResult, RequestHeader requestHeader) {
if (requestHeader.headers().get("X-Filter").isDefined()) {
ResultAdapter resultAdapter = new ResultAdapter(currentResult);
return resultAdapter.WithHeader("X-Hello", "World!");
}
return currentResult;
}
}
Для дальнейшего объяснения того, как это работает, см. мою статью в блоге об этом здесь