Вопрос по playframework-2.0, java – При использовании универсального контроллера, как вернуть представление, присущее конкретному контроллеру?

6

В результате этого ответа:https://stackoverflow.com/a/10708026/694597Мне интересно, как вернуть представление, присущее конкретному контроллеру при использовании универсального контроллера.

Ваш Ответ

1   ответ
6

Когда вы визуализируете представление в действии контроллера, вы просто вызываете простую функцию, которая была сгенерирована механизмом шаблонов:

public Application extends Controller {
  public static Result index() {
    return ok(views.html.index.render(42));
  }
}

Вот,render это метод объектаindex который имеет типTemplate1<Integer, Html>.

Теперь возникает вопрос: как написать универсальный контроллер, способный вызывать представление, специфичное для другого контроллера? Или просто:how to abstract over views?

Я вижу два решения:инверсия контроля а такжеreflection.

Давайте посмотрим, как реализовать оба варианта в простом сценарии использования. Скажем, у вас есть следующий общийShower<T> класс, способный вычислить ответ HTTP, содержащий представление HTML любого значения типаT:

public class Shower<T> {
  public Result show(T value) {
    // TODO return an HTML representation of `value`
  }
}

Inversion of control

РеализоватьShower<T> используя инверсию управления, нам просто нужно ввестиTemplate1<T, Html> Значение, используемое для выполнения рендеринга:

public class Shower<T> {

  public final Template1<T, Html> template;

  public Shower(Template1<T, Html> template) {
    this.template = template;
  }

  public Result show(T value) {
    return ok(template.render(value));
  }

}

Чтобы использовать его в контроллере, создайте статический экземплярShower<T> и введите шаблон для использования:

public class Application extends Controller {
  public static Shower<Foo> foo = new Shower<Foo>(views.html.Foo.show.ref());
}

Reflection

Вы можете счесть это слишком стандартным, чтобы явно вводить шаблон для использования в каждом случаеShower<T>Таким образом, у вас может возникнуть соблазн получить его путем отражения, основываясь на соглашении об именах, например показать значение типаFooпросто найдите объект с именемshow в упаковкеviews.html.Foo:

public class Shower<T> {

  private final Class<T> clazz;

  public Shower(Class<T> clazz) {
    this.clazz = clazz;
  }

  public Result show(T value) throws Exception {
    Class<?> object = Play.application().classLoader().loadClass("views.html." + clazz.getSimpleName() + ".show$");
    Template1<T, Html> template = (Template1<T, Html>)object.getField("MODULE$").get(null);
    return ok(template.render(value));
  }
}

(это способ доступа к объектам Scala с помощью отражения)

Вы можете использовать его в контроллере следующим образом:

public class Application extends Controller {
  public static Shower<Foo> foo = new Shower<Foo>(Foo.class);
}

Pros and cons

Решение на основе отражения требуетless boilerplate на сайте вызовов, но тот факт, что он опирается на соглашение об именах, делает егоmore fragile, Кроме того, это решение только потерпит неудачуat runtime когда он потерпит неудачу, в то время как первое решение покажет вам ваши отсутствующие шаблоныat compile time, Наконец, что не менее важно, решение на основе отражения может добавить некоторыеperformance overhead из-за отражения.

Error: User Rate Limit Exceeded
ref()Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededShowerError: User Rate Limit ExceededBuilder patternError: User Rate Limit ExceededEffective JavaError: User Rate Limit Exceeded Leonard Punt
Error: User Rate Limit Exceeded Leonard Punt

Похожие вопросы