web-dev-qa-db-fra.com

mapper toutes les demandes au lieu d'un modèle spécifique dans Spring Boot

J'ai une seule application VueJS dans l'application Spring Boot et je souhaite que vue-router gère toutes les demandes au lieu de celles dont l'url commence par le /rest/**.

J'ai donc écrit l'expression régulière ^(?!/rest/).* pour qu'elle corresponde à tout ce qui ne commence pas par le /rest/ et j'essaie de mapper la requête de la manière suivante:

@Controller
public class MainController {

@RequestMapping(value = "/{path:^(?!/rest/).*}")
    public String forwardRequests() {
        return "forward:/";
    }
}

mais ça ne marche pas. Qu'est-ce que je fais mal?

EDIT

J'ai un fichier de contrôleur de repos:

@RestController
@RequestMapping(path = "/rest/project")
public class ProjectController {

    @Autowired
    private ProjectService projectService;

    @GetMapping(value = "/{id}")
    public Project getProjectById(@PathVariable Long id) {
        return projectService.getProjectById(id);
    }
}

qui retourne JSON avec les détails du projet. J'ai des pages comme /login et /projekty donc je dois les transférer à index.html pour gérer le routage avec vue. Je sais que je peux faire quelque chose comme ça:

@Controller
public class MainController {

    @RequestMapping(value = {"/login", "/projekty"}, method = RequestMethod.GET)
    public String forwardRequests() {
        return "forward:/";
    }
}

et cela fonctionne très bien, mais je ne veux pas spécifier explicitement toutes les URL, c’est pourquoi j’essaie d’utiliser une expression régulière. Et je pense que j'utilise mal la variable path, mais je ne sais pas comment.

https://spring.io/guides/tutorials/spring-security-and-angular-js/ section Using "Natural" Routes

4
kojot

Eh bien, comme l'a dit @JDB, la AntPathMatcher compare les chemins et trouve la meilleure correspondance. Ainsi, vous n'avez pas à vous soucier des ordinateurs d'extrémité, qui ont des chemins spécifiés, comme mon API /rest.

Vous pouvez ajouter ceci:

@RequestMapping(value = "/{path:[^\\.]*}")
public String redirect() {
  return "forward:/";
}

et toutes vos demandes, par exemple. /login, sera transmis correctement à index.html, où javascript peut le gérer.

Le problème concerne les URL telles que /project/edit/33. Ils ne correspondent pas à cette expression régulière, vous verrez donc le Whitelabel Error Page 404 Not Found. Vous pouvez écrire ceci:

@RequestMapping(value = "/**/{path:[^\\.]*}")
public String redirect() {
  return "forward:/";
}

et cela fonctionne bien, mais si la sécurité est activée, le /ouath/token renverra:

{  
   "timestamp":"2018-02-05T09:13:28.104+0000",
   "status":405,
   "error":"Method Not Allowed",
   "exception":"org.springframework.web.HttpRequestMethodNotSupportedException",
   "message":"Request method 'POST' not supported",
   "path":"/oauth/token"
}

vous devez donc exclure les urls oauth:

@RequestMapping(value = {"/{path:[^\\.]*}", "/**/{path:^(?!oauth).*}/{path:[^\\.]*}"}, method = RequestMethod.GET)
public String forward() {
    return "forward:/";
}

et ça marche bien.

Si vous rencontrez des problèmes avec d'autres points de terminaison fournis par la structure, tels que /health, vous pouvez modifier l'expression régulière en /**/{path:^(?!oauth|health).*}/{path:[^\\.]*}.

Ça a l'air moche, mais ça marche. Je crois que quelqu'un affichera ici une solution meilleure et plus propre.

4
kojot

Je ne connais pas le printemps en particulier, alors je me fie à ma connaissance en me basant sur l'expérience acquise avec d'autres cadres.

Premièrement, le modèle ne devrait-il pas exclure la barre oblique, puisque vous l'incluez déjà dans votre chemin?

/{path:^(?!rest/).*}

Si cela ne fonctionne pas, tout ce que je peux penser, c'est que AntPathMatcher ne prend pas en charge les antécédents de recherche.

Le modèle typique de cette conception consiste à implémenter les routes /rest/* et /*. Dans certains cadres, il suffit de les commander correctement. Selon la documentation de Spring MVC , vous devrez peut-être jouer avec les règles pour rendre la route /rest/* "plus spécifique".

Voici les règles:

Lorsque plusieurs modèles correspondent à une URL, ils doivent être comparés pour trouver la meilleure correspondance. Ceci est effectué via AntPathMatcher.getPatternComparator (String path), qui recherche des modèles plus spécifiques.

Un modèle est moins spécifique s'il comporte un nombre inférieur de variables URI et des caractères génériques uniques comptés pour 1 et des caractères génériques doubles comptés pour 2. Si le score est égal, le modèle le plus long est choisi. Avec le même score et la même longueur, le modèle avec plus de variables URI que de caractères génériques est choisi.

Le modèle de mappage par défaut/** est exclu de l'évaluation et est toujours trié en dernier. Les modèles de préfixes tels que/public/** sont également considérés comme moins spécifiques que les autres modèles qui ne possèdent pas de double caractère générique.

Pour plus de détails, voir AntPatternComparator dans AntPathMatcher et n'oubliez pas que l'implémentation PathMatcher utilisée peut être personnalisée. Voir Correspondance de chemin dans la section de configuration.

Donc, sur la base de mon interprétation de ces règles et de votre code, je pense que quelque chose dans ce sens fonctionnerait:

// Your more specific patterns will take precedence
@RequestMapping(value = "/rest/**")
    public String handleRestRequests() {
        // forward this to your rest services
    }
}

// Your less specific patterns will only apply if the more specific ones don't match
@RequestMapping(value = "/**")
    public String forwardRequests() {
        // Everything else
        return "forward:/";
    }
}
1
JDB

Après un deuxième regard ... votre chaîne est /{path:^(?!/rest/).*}.

Il existe un premier /, puis l'expression régulière déclare également un premier /. Cette expression rationnelle correspond à /rest/* car elle vérifie /(?!/rest/).* et non (?!/rest/).*.

Ancienne réponse fausse, voir commentaire @JDB

Le caractère / est un caractère spécial dans les expressions rationnelles et doit être échappé.

@Controller
public class MainController {

    @RequestMapping(value = "/{path:^(?!\\/rest\\/).*}")
    public String forwardRequests() {
        return "forward:/";
    }
}

\ étant également un caractère d'échappement pour les chaînes en Java, vous en avez besoin de 2.

0
kagmole

Vous pouvez ajouter une méthode de gestionnaire par défaut

@RequestMapping()
  String default(){ 
    return "This is a default method";
  }
0
Ali Zhagparov