Je développe un backend printanier pour une application à une seule page basée sur reac, où j'utilise react-router pour le routage côté client.
A côté de la page index.html, le serveur distribue des données sur le chemin /api/**
.
Afin de servir mon index.html à partir de src/main/resources/public/index.html
sur le chemin racine /
de mon application, j'ai ajouté un gestionnaire de ressources.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/").addResourceLocations("/index.html");
}
Ce que je veux, c'est servir la page index.html lorsqu'aucune autre route ne correspond, par exemple. quand j'appelle un chemin autre que /api
.
Comment configurer un tel itinéraire fourre-tout au printemps?
Puisque mon application de réaction pouvait utiliser la racine comme cible avancée, cela a finalement fonctionné pour moi.
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/**/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
.setViewName("forward:/");
}
}
Pour être honnête, je ne sais pas pourquoi il faut que ce soit exactement dans ce format spécifique pour éviter une boucle de transmission infinie.
J'ai un PWA basé sur un polymère hébergé dans mon application Spring Boot, ainsi que des ressources Web statiques telles que des images et une API REST sous "/ api/...". Je veux que l'application côté client gère le routage des URL pour le PWA. Voici ce que j'utilise:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* Ensure client-side paths redirect to index.html because client handles routing. NOTE: Do NOT use @EnableWebMvc or it will break this.
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// Map "/"
registry.addViewController("/")
.setViewName("forward:/index.html");
// Map "/Word", "/Word/word", and "/Word/word/Word" - except for anything starting with "/api/..." or ending with
// a file extension like ".js" - to index.html. By doing this, the client receives and routes the url. It also
// allows client-side URLs to be bookmarked.
// Single directory level - no need to exclude "api"
registry.addViewController("/{x:[\\w\\-]+}")
.setViewName("forward:/index.html");
// Multi-level directory path, need to exclude "api" on the first part of the path
registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}")
.setViewName("forward:/index.html");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/");
}
}
Cela devrait également fonctionner pour les applications Angular et React.
Avoid @EnableWebMvc
Par défaut, Spring-Boot sert un contenu statique dans src/main/resources
:
Jetez un oeil à ceci et ceci ;
Ou conservez @EnableWebMvc et substituez addViewControllers
Avez-vous spécifié @EnableWebMvc
? Jetez un oeil à ceci: Java Spring Boot: comment mapper la racine de mon application (“/”) sur index.html?
Soit vous supprimez @EnableWebMvc, soit vous pouvez redéfinir addViewControllers
:
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
Ou définir un contrôleur pour intercepter /
Vous pouvez jeter un oeil à ce projet exemple de spring-boot-reactjs sur github :
Il fait ce que vous voulez en utilisant un contrôleur:
@Controller
public class HomeController {
@RequestMapping(value = "/")
public String index() {
return "index";
}
}
Son index.html
est sous src/main/resources/templates
J'utilise réagit et réagit-routeur dans mon application de démarrage printanière. Il était aussi simple que de créer un contrôleur mappé sur /
et des sous-arbres de mon site Web comme /users/**
Voici ma solution
@Controller
public class SinglePageAppController {
@RequestMapping(value = {"/", "/users/**", "/campaigns/**"})
public String index() {
return "index";
}
}
Les appels Api ne sont pas interceptés par ce contrôleur et les ressources sont gérées automatiquement.
J'ai trouvé une réponse en regardant cette question
@Bean
public EmbeddedServletContainerCustomizer notFoundCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
}
};
}
Pour répondre à votre question spécifique qui implique de servir la Single Page App (SPA) dans tous les cas sauf la route / api, voici ce que j'ai fait pour modifier la réponse de Petri.
J'ai un modèle nommé polymère qui contient l'index.html pour mon SPA. Le défi est donc devenu de transférer toutes les routes sauf/api et/public-api à cette vue.
Dans mon WebMvcConfigurerAdapter, je substitue addViewControllers et utilisais l'expression régulière suivante: ^ ((?!/Api/|/public-api /).)*$
Dans votre cas, vous voulez l'expression régulière: ^ ((?!/Api /).)*$
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:^((?!/api/).)*$}").setViewName("polymer");
super.addViewControllers(registry);
}
Cela permet de frapper http: // localhost ou http: // localhost/community de servir mon SPA et tous les autres appels que le SPA passe en cours de routage vers http : // localhost/api/posts , http: // localhost/public-api/posts , etc.