Spring Boot with AngularJS html5Mode Spring Boot with AngularJS html5Mode angularjs angularjs

Spring Boot with AngularJS html5Mode


Use this controller to forward the URI to index.html in order to preserve AngularJS routes. Source https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii

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

In this solution ForwardController forwards only paths, which are not defined in any other Controller nor RestController. It means if you already have:

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

both controllers are going to work properly - @RequestMapping(value = "api/offers") is checked before @RequestMapping(value = "/**/{[path:[^\\.]*}")


I had same problem. As far as I know, in html5 mode, angularjs don't resolve hash but entered url or url added through pushState.

The problem was that PathResourceResolver map directories but not files. Because it intended to serve requested files from directory but not to rewrite urls. For app it's mean, if you refresh your browser window or type url like http://example.com/mystate, it's query "/mystate" from the server. If spring don't know url, they return 404. One of the solutions is map every possible state to index.html like here (source, btw look at webjars - it's great!). But in my case I can safely map "/**" to index.html and therefore my solution is to override 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;                    }                });    }}


I found a solution I can live with it.

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

The angularjs app has to be under the subdomain app. If you do not want that you could create a subdomain like app.subdomain.com that mapps to your subdomain app. With this construct you have no conflicts with webjars, statis content and so on.