Je souhaite configurer mon application Spring Boot pour rediriger toute demande 404 non trouvée vers mon application à page unique.
Par exemple, si j'appelle localhost:8080/asdasd/asdasdasd/asdasd
qui n'existe pas, il devrait être redirigé vers localhost:8080/notFound
.
Le problème est que je n'ai qu'une seule page qui réagit et qu'elle s'exécute dans le chemin d'accès racine localhost:8080/
. Donc, spring devrait rediriger vers localhost:8080/notFound
et ensuite transmettre à /
(pour garder la route).
Cela devrait faire l'affaire: ajoutez une page d'erreur pour 404 qui route vers /notFound
et transmettez-la à votre SPA (en supposant que l'entrée est sur /index.html
):
@Configuration
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
Voici l'exemple complet de Spring Boot 2.0:
@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
Au cas où quelqu'un trébucherait ici pour savoir comment gérer les routes et les chemins angulaires/React/autres dans une application Spring Boot - mais ne renvoie pas toujours index.html pour un 404 - cela peut être effectué dans un contrôleur Spring standard RequestMapping. Cela peut être fait sans ajouter de contrôleurs de vue et/ou personnaliser la page d'erreur du conteneur.
RequestMapping prend en charge les caractères génériques, vous pouvez donc le faire correspondre à un ensemble de chemins bien connus (par exemple, des itinéraires angulaires, etc.) dans votre application et ensuite seulement renvoyer index.html:
@Controller
public class Html5PathsController {
@RequestMapping( method = {RequestMethod.OPTIONS, RequestMethod.GET}, path = {"/path1/**", "/path2/**", "/"} )
public String forwardAngularPaths() {
return "forward:/index.html";
}
}
Une autre option (empruntée à un ancien article de Spring ici: https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii ) consiste à utiliser une convention de dénomination:
@Controller
public class Html5PathsController {
@RequestMapping(value = "/{[path:[^\\.]*}")
public String redirect() {
return "forward:/index.html";
}
}
La configuration ci-dessus correspond à tous les chemins qui ne contiennent pas de période et qui ne sont pas déjà mappés vers un autre contrôleur.
Ici la configuration de la sécurité (SecurityConfig.Java)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private UserSecurityService userSecurityService;
private BCryptPasswordEncoder passwordEncoder() {
return SecurityUtility.passwordEncoder();
}
private static final String[] PUBLIC_MATCHERS = {
"/css/**",
"/js/**",
"/data/**",
"/sound/**",
"/img/**",
"/",
"/login",
"/logout,
"/error",
"/index2",
};
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().
/* antMatchers("/**").*/
antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
//.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
http
.csrf().disable().cors().disable()
.formLogin().failureUrl("/login?error")
.defaultSuccessUrl("/index2")
.loginPage("/login").permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll()
.and()
.rememberMe()
.and()
.sessionManagement().maximumSessions(3600)
.and().
invalidSessionUrl("/login");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSecurityService).passwordEncoder(passwordEncoder());
}
}
Si non trouvé aucune ressource rediriger vers la page d'erreur
@Controller
public class IndexController implements ErrorController{
private static final String PATH = "/error";
@RequestMapping(value = PATH)
public String error() {
return PATH;
}
@Override
public String getErrorPath() {
return PATH;
}
}
Page d'erreur comme
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1000/xhtml"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<meta http-equiv="refresh" content="5;url=/login" />
<body>
<h1>Page not found please login the system!</h1>
</body>
</html>