Меньше подробный способ создания Play 2 javascript router

В настоящее время я определяю свой javascript-маршрутизатор приложения довольно достоверным способом.

def javascriptRoutes = Action { implicit request =>
  import routes.javascript._
  Ok(Routes.javascriptRouter("jsRoutes")(
    Login.method1,Login.Method2,
    OtherController.method1,OtherController.method2,
    //[...]
  )).as("text/javascript")
}

Я действительно хотел бы создать javascriptRouter со всеми маршрутами в файле routes, поэтому мне не нужно вручную обновлять определение javascriptRoutes каждый раз, когда я добавляю новый контроллер метод.

Есть ли способ выполнить эту задачу или существует даже несколько менее подробный способ определения javascriptRouter?

Ответ 1

Вы можете сделать это через отражение так:

val routeCache = {
    import routes._
    val jsRoutesClass = classOf[routes.javascript]
    val controllers = jsRoutesClass.getFields().map(_.get(null))
    controllers.flatMap { controller =>
        controller.getClass().getDeclaredMethods().map { action =>
            action.invoke(controller).asInstanceOf[play.core.Router.JavascriptReverseRoute]
        }
    }
}

def javascriptRoutes = Action { implicit request =>
    Ok(Routes.javascriptRouter("jsRoutes")(routeCache:_*)).as("text/javascript")
}

Это было получено из сгенерированных исходных файлов, найденных в target/ scala -2.x.x/src_managed. Вы действительно можете добавить свой собственный генератор источников и самостоятельно проанализировать файл маршрутов, но я нахожу, что я делаю это через отражение легче.

Дополнительная вещь, которую вы, возможно, захотите сделать, - это отфильтровать методы, которые вы не хотите, поскольку это даст вам ВСЕ маршруты (включая сам javascriptRouter).

Ответ 2

Кроме того, если вы используете Play 2.4, некоторые классы/пакеты были изменены:

def javascriptRoutes = Action { implicit request =>
  Ok(play.api.routing.JavaScriptReverseRouter("jsRoutes")(routeCache:_*)).as("text/javascript")
}

val routeCache: Array[JavaScriptReverseRoute] = {
  import routes._
  val jsRoutesClass: Class[javascript] = classOf[routes.javascript]
  val controllers = jsRoutesClass.getFields.map(_.get(null))
  val met = for (
    controller <- controllers;
    method <- controller.getClass.getDeclaredMethods if method.getReturnType == classOf[play.api.routing.JavaScriptReverseRoute]
  ) yield method.invoke(controller).asInstanceOf[play.api.routing.JavaScriptReverseRoute]
  met
}

Ответ 3

Мне это нужно в java. Копируем его здесь, если он кому-то полезен.

public static Result javascriptRoutes() throws IllegalAccessException, IllegalArgumentException,
        InvocationTargetException {

    // use reflection to get the fields of controllers.routes.javascript
    Set<Object> reverseRoutes = new HashSet<Object>();
    for (Field f : controllers.routes.javascript.class.getFields()) {
        // get its methods
        for (Method m : getAllMethods(f.getType(), withReturnType(JavascriptReverseRoute.class))) {
            // for each method, add its result to the reverseRoutes
            reverseRoutes.add(m.invoke(f.get(null)));
        }
    }

    // return the reverse routes
    response().setContentType("text/javascript");
    return ok(Routes.javascriptRouter("jsRoutes",
            reverseRoutes.toArray(new JavascriptReverseRoute[reverseRoutes.size()])));
}

Ответ 4

Очень приятное решение этой проблемы. Если у вас есть JavaScript-маршруты в другом субпакете, вам нужно объявить routeCache следующим образом

val routeCache = {
  val jsRoutesClass = classOf[controllers.api.routes.javascript]
  val controllerArray = jsRoutesClass.getFields().map(_.get(null))
  controllerArray.flatMap { controller =>
    controller.getClass().getDeclaredMethods().map { action =>
    action.invoke(controller).asInstanceOf[play.core.Router.JavascriptReverseRoute]
  }
 }
}

Ответ 5

Расширение ответа @rochb для Play 2.4 Java, где имена пакетов несколько разные, с поддержкой нескольких пакетов контроллеров.

public Result javascriptRoutes() throws IllegalAccessException, IllegalArgumentException,
        InvocationTargetException {

    // use reflection to get the fields of controllers.routes.javascript and other controller packages
    Set<Object> reverseRoutes = new HashSet<Object>();
    Class[] routeClasses = {controllers.routes.javascript.class, com.example.package1.routes.javascript.class, com.example.package2.routes.javascript.class};
    for (int i = 0; i < routeClasses.length; i++) {
        for (Field f : routeClasses[i].getFields()) {
            // get its methods
            for (Method m : getAllMethods(f.getType(), withReturnType(play.api.routing.JavaScriptReverseRoute.class))) {
                // for each method, add its result to the reverseRoutes
                reverseRoutes.add(m.invoke(f.get(null)));
            }
        }
    }
    // return the reverse routes
    response().setContentType("text/javascript");
    return ok(Routes.javascriptRouter("jsRoutes",
            reverseRoutes.toArray(new play.api.routing.JavaScriptReverseRoute[reverseRoutes.size()])));
}