10 votes

Manière moins verbeuse de générer le routeur javascript de Play 2

Actuellement, je définis le routeur JavaScript de mon application de manière assez verbeuse

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

Ce que j'aimerais vraiment faire, c'est créer un javascriptRouter avec toutes les routes du fichier routes, afin de ne pas avoir à mettre à jour manuellement la définition de javascriptRoutes chaque fois que j'ajoute une nouvelle méthode de contrôleur.

Y a-t-il un moyen d'accomplir cette tâche, ou existe-t-il même une manière légèrement moins verbeuse de définir le javascriptRouter?

17voto

thatsmydoing Points 639

Vous pouvez le faire via la réflexion de la manière suivante :

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")
}

Ceci a été dérivé des fichiers sources générés trouvés dans target/scala-2.x.x/src_managed. Vous pourriez en fait ajouter votre propre générateur de code source et analyser le fichier des routes vous-même, mais je trouve que le faire via la réflexion est plus facile.

Une chose supplémentaire que vous pourriez vouloir faire est de filtrer les méthodes que vous ne voulez pas car cela vous donnera TOUS les chemins (y compris le javascriptRouter lui-même).

3voto

Matias P Points 61

Aussi, si vous utilisez Play 2.4, certaines classes/packages ont été modifiés :

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
}

2voto

rochb Points 1535

J'avais besoin de cela en java. Je le copie ici au cas où cela soit utile pour quelqu'un.

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

    // utiliser la réflexion pour obtenir les champs de controllers.routes.javascript
    Set reverseRoutes = new HashSet();
    for (Field f : controllers.routes.javascript.class.getFields()) {
        // obtenir ses méthodes
        for (Method m : getAllMethods(f.getType(), withReturnType(JavascriptReverseRoute.class))) {
            // pour chaque méthode, ajouter son résultat aux reverseRoutes
            reverseRoutes.add(m.invoke(f.get(null)));
        }
    }

    // retourner les routes inversées
    response().setContentType("text/javascript");
    return ok(Routes.javascriptRouter("jsRoutes",
            reverseRoutes.toArray(new JavascriptReverseRoute[reverseRoutes.size()])));
}

1voto

Matias P Points 61

Très belle solution par thatsmydoing. Si vous avez les routes JavaScript dans un autre sous-package, vous devez déclarer routeCache comme ceci

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]
  }
 }
}

1voto

bravo2 Points 683

Expansion de la réponse de @rochb pour Play 2.4 Java, où les noms des packages sont légèrement différents, avec prise en charge de plusieurs packages de contrôleurs.

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

    // utiliser la réflexion pour obtenir les champs de controllers.routes.javascript et d'autres packages de contrôleurs
    Set reverseRoutes = new HashSet();
    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()) {
            // obtenir ses méthodes
            for (Method m : getAllMethods(f.getType(), withReturnType(play.api.routing.JavaScriptReverseRoute.class))) {
                // pour chaque méthode, ajouter son résultat aux reverseRoutes
                reverseRoutes.add(m.invoke(f.get(null)));
            }
        }
    }
    // retourner les routes inversées
    response().setContentType("text/javascript");
    return ok(Routes.javascriptRouter("jsRoutes",
            reverseRoutes.toArray(new play.api.routing.JavaScriptReverseRoute[reverseRoutes.size()])));
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X