404が見つからないリクエストを単一ページアプリにリダイレクトするように、Spring Bootアプリを構成したい。
たとえば、存在しないlocalhost:8080/asdasd/asdasdasd/asdasd
を呼び出す場合、localhost:8080/notFound
にリダイレクトする必要があります。
問題は、単一ページの反応アプリがあり、ルートパスlocalhost:8080/
で実行されることです。したがって、springはlocalhost:8080/notFound
にリダイレクトし、/
に転送する必要があります(ルートを維持するため)。
これはトリックを行うはずです:/notFound
にルーティングする404のエラーページを追加し、それをSPAに転送します(エントリが/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"));
};
}
}
これは、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"));
};
}
}
Spring BootアプリでAngular/React /その他のルートとパスを処理する方法を探している人がいる場合-404のindex.htmlを返すとは限りません-標準のSpringコントローラRequestMappingで行うことができます。これは、View Controllerの追加やコンテナエラーページのカスタマイズなしで実行できます。
RequestMappingはワイルドカードをサポートしているので、アプリケーション内の既知のパス(angularルートなど)のセットと一致させてから、前方index.htmlを返すことができます。
@Controller
public class Html5PathsController {
@RequestMapping( method = {RequestMethod.OPTIONS, RequestMethod.GET}, path = {"/path1/**", "/path2/**", "/"} )
public String forwardAngularPaths() {
return "forward:/index.html";
}
}
別のオプション(ここにある古いSpringの記事から引用: https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii )は命名規則を使用することです:
@Controller
public class Html5PathsController {
@RequestMapping(value = "/{[path:[^\\.]*}")
public String redirect() {
return "forward:/index.html";
}
}
上記の構成は、ピリオドを含まず、別のコントローラーにまだマップされていないすべてのパスに一致します。
//add this controller : perfect solution(from jhipster)
@Controller
public class ClientForwardController {
@GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
ここでセキュリティ構成(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());
}
}
エラーページへのリソースリダイレクトが見つからない場合
@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;
}
}
のようなエラーページ
<!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>
単にimplementingorg.springframework.boot.web.servlet.error.ErrorController私のためにトリックをしました。 ReactでSpringBoot 2.0を使用します。 (ここでそれを行う方法に興味があるなら、私が作った定型的なプロジェクトです: https://github.com/archangel1991/react-with-spring )
@Controller
public class CustomErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
}
なぜこれが機能しているのかわかりません。