Spring Boot con AngularJS html5Mode

Comienzo mi aplicación web con arranque de spring. Utiliza una clase principal simple para iniciar un servidor tomcat integrado:

@Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

Quiero configurar el servidor de forma que pueda manejar angularjs html5mode que se activará con

 $locationProvider.html5Mode(true); 

Las publicaciones relevantes de otros usuarios muestran que debe redireccionar a la raíz. el modo html5 elimina el hashbag de la url. Si actualiza la página, el servidor no encuentra la página porque no maneja el hash. ver: AngularJS – ¿Por qué al cambiar la dirección url $ routeProvider no parece funcionar y me sale un error 404

Tuve el mismo problema Hasta donde yo sé, en modo html5, angularjs no resuelve el hash pero ingresa url o url agregados a través de pushState .

El problema era que PathResourceResolver asignaba directorios pero no archivos. Porque tenía la intención de servir archivos solicitados desde el directorio pero no reescribir urls. Para la aplicación es malo, si actualiza la ventana de su navegador o escribe url como http://example.com/mystate , es la consulta “/ mystate” del servidor. Si la spring no conoce la URL, devuelven 404. Una de las soluciones es hacer un mapa de todos los estados posibles de index.html como aquí ( fuente , por cierto, mire webjars, ¡es genial!). Pero en mi caso puedo mapear “/ **” de forma segura a index.html y, por lo tanto, mi solución es anular PathResourceResolver # getResource:

 @Configuration @EnableConfigurationProperties({ ResourceProperties.class }) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Autowired private ResourceProperties resourceProperties = new ResourceProperties(); @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { Integer cachePeriod = resourceProperties.getCachePeriod(); registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/") .setCachePeriod(cachePeriod); registry.addResourceHandler("/**") .addResourceLocations("classpath:/static/index.html") .setCachePeriod(cachePeriod).resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { return location.exists() && location.isReadable() ? location : null; } }); } } 

Utilice este controlador para reenviar el URI a index.html para preservar las rutas AngularJS. Fuente https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii

 @Controller public class ForwardController { @RequestMapping(value = "/**/{[path:[^\\.]*}") public String redirect() { // Forward to home page so that route is preserved. return "forward:/"; } } 

En esta solución, ForwardController reenvía solo rutas, que no están definidas en ningún otro Controller ni RestController . Significa si ya tienes:

 @RestController public class OffersController { @RequestMapping(value = "api/offers") public Page getOffers(@RequestParam("page") int page) { return offerService.findPaginated(page, 10); } } 

ambos controladores van a funcionar correctamente – @RequestMapping(value = "api/offers") se verifica antes de @RequestMapping(value = "/**/{[path:[^\\.]*}")

Encontré una solución en la que puedo vivir.

 @Controller public class ViewController { @RequestMapping("/") public String index() { return "index"; } @RequestMapping("/app/**") public String app() { return "index"; } } 

La aplicación angularjs debe estar bajo la aplicación de subdominio. Si no desea, puede crear un subdominio como app.subdomain.com que se asigna a su aplicación de subdominio. Con este constructo no tienes conflictos con webjars, contenido statis, etc.

Un pequeño ajuste a un código anterior que me funciona.

 // Running with Spring Boot v1.3.0.RELEASE, Spring v4.2.3.RELEASE @Configuration @EnableConfigurationProperties({ ResourceProperties.class }) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Autowired private ResourceProperties resourceProperties = new ResourceProperties(); @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { Integer cachePeriod = resourceProperties.getCachePeriod(); final String[] staticLocations = resourceProperties.getStaticLocations(); final String[] indexLocations = new String[staticLocations.length]; for (int i = 0; i < staticLocations.length; i++) { indexLocations[i] = staticLocations[i] + "index.html"; } registry.addResourceHandler( "/**/*.css", "/**/*.html", "/**/*.js", "/**/*.json", "/**/*.bmp", "/**/*.jpeg", "/**/*.jpg", "/**/*.png", "/**/*.ttf", "/**/*.eot", "/**/*.svg", "/**/*.woff", "/**/*.woff2" ) .addResourceLocations(staticLocations) .setCachePeriod(cachePeriod); registry.addResourceHandler("/**") .addResourceLocations(indexLocations) .setCachePeriod(cachePeriod) .resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { return location.exists() && location.isReadable() ? location : null; } }); } 

}

Puede reenviar todos los recursos no encontrados a su página principal proporcionando ErrorViewResolver personalizado. Todo lo que necesita hacer es agregar esto a su clase @Configuration:

 @Bean ErrorViewResolver supportPathBasedLocationStrategyWithoutHashes() { return new ErrorViewResolver() { @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) { return status == HttpStatus.NOT_FOUND ? new ModelAndView("index.html", Collections.emptyMap(), HttpStatus.OK) : null; } }; } 

¡Finalmente conseguí que mi aplicación Angular 5 funcionara con la bota de resorte con o sin spring-boot-starter-tomcat según lo provided (incrustado) o no!

 /** * Needed for html5mode (PathLocationStrategy in Angular). Every path except api/* and resources (css, html, js, woff, etc..) * should be redirect to index.html and then should angular managed routes (which could be correct or non existing). */ @RestController @RequestMapping public class ForwardController { @GetMapping(value = "/**/{[path:[^\\.]*}") public ModelAndView forward() { return new ModelAndView("/index.html"); } } 

Acabo de encontrar el problema similar en el que quería configurar Resources y al mismo tiempo quería usar el modo AngularJS Html5 habilitado.

En mi caso, mis archivos estáticos fueron servidos desde /public route, así que usé el siguiente mapeo de solicitud en mi acción de índice y todo funciona bien.

 @RequestMapping(value = {"", "/", "/{[path:(?!public).*}/**"}, method = GET) public String indexAction() { return "index"; } 

Tuve el mismo problema al usar Html5Mode angular. La solución que funcionó para mí fue configurar la página de error para 404 en web.xml asignando la ruta a mi vista de índice en mi caso “/”.

  404 /  

Del mismo modo, puede intentar configurar la página de error en el arranque de spring. como referencia, puede consultar este enlace.

Spring boot y página personalizada de error 404

Primero, creas un nuevo Controlador y luego copias y pega un código simple debajo

 @Controller public class viewController { @RequestMapping(value = "/**/{[path:[^\\.]*}") public String redirect() { // Forward to home page so that route is preserved. return "forward:/"; } } 

3- eliminar 2 elementos debajo de la aplicación angular

 $locationProvider.hashPrefix('!'); $urlRouterProvider.otherwise("/"); 

2- en la aplicación angular, debe agregar $locationProvider.html5Mode(true); a la ruta de la aplicación

3- No olvides colocar la etiqueta base antes de cualquier solicitud http en tu archivo index.html

   /* Or whatever your base path is */ //call every http request for style and other ...  

me funciona bien