web-dev-qa-db-fra.com

Botte à ressort avec AngularJS html5Mode

Je lance mon application Web avec Spring Boot. Il utilise une classe principale simple pour démarrer un serveur Tomcat intégré:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {

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

}

Je veux configurer le serveur de manière à ce qu’il puisse gérer angularjs html5mode qui sera activé avec 

$locationProvider.html5Mode(true);

Les publications pertinentes d’autres utilisateurs indiquent que vous devez rediriger vos messages vers la racine. le mode html5 supprime le hashbag de l'URL. Si vous actualisez la page, le serveur ne trouve pas la page car il ne gère pas le hachage. voir: AngularJS - Pourquoi, lors du changement d'adresse URL, $ routeProvider ne semble pas fonctionner et j'ai une erreur 404

16
Rudolf Schmidt

J'ai trouvé une solution avec laquelle je peux vivre.

@Controller
public class ViewController {

    @RequestMapping("/")
    public String index() {
        return "index";
    }

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

L'application angularjs doit être sous l'application de sous-domaine. Si vous ne le souhaitez pas, vous pouvez créer un sous-domaine tel que app.subdomain.com mappé sur votre application de sous-domaine. Avec cette construction, vous n’aurez aucun conflit avec les webjars, le contenu de statistiques, etc.

10
Rudolf Schmidt

J'ai eu le même problème. Pour autant que je sache, en mode html5, angularjs ne résout pas le hachage mais entre une URL ou une URL ajoutée à traverspushState .

Le problème était que PathResourceResolver correspondait aux répertoires mais pas aux fichiers. Parce qu'il avait pour but de servir les fichiers demandés à partir du répertoire mais pas de réécrire les urls. Pour app c'est moyen, si vous actualisez la fenêtre de votre navigateur ou tapez l'URL du type http://example.com/mystate , c'est la requête "/ mystate" du serveur. Si le printemps ne connaît pas l’URL, il renvoie 404. L’une des solutions consiste à mapper tous les états possibles à index.html comme ici ( source , en passant par les webjars - c’est génial!). Mais dans mon cas, je peux mapper en toute sécurité "/ **" à index.html et, par conséquent, ma solution consiste à remplacer 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;
                    }
                });
    }
}
22
Anton Bessonov

Utilisez ce contrôleur pour transférer l'URI vers index.html afin de préserver les itinéraires AngularJS. Source 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:/";
    }
} 

Dans cette solution, ForwardController ne transmet que les chemins qui ne sont définis dans aucune autre variable Controller ni RestController. Cela signifie que si vous avez déjà:

@RestController
public class OffersController {

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

les deux contrôleurs vont fonctionner correctement - @RequestMapping(value = "api/offers") est vérifié avant @RequestMapping(value = "/**/{[path:[^\\.]*}")

21
Eduardo Eljaiek

Un petit ajustement à un code précédent qui fonctionne pour moi.

// 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;
                }
            });
}

}

4
vlk32

Vous pouvez transférer toutes les ressources non trouvées vers votre page principale en fournissant un fichier ErrorViewResolver personnalisé . Il vous suffit de l'ajouter à votre classe @Configuration:

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

Mon application Angular 5 fonctionne enfin avec Spring Boot avec ou sans spring-boot-starter-Tomcat en tant que provided (intégré) ou non! 

/**
 * 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");
    }
}
2
Gil-galad

Je viens de rencontrer le problème similaire où je voulais configurer des ressources et en même temps, je voulais utiliser le mode AngularJS Html5 activé.

Dans mon cas, mes fichiers statiques ont été servis à partir de la route /public. J'ai donc utilisé le mappage de requête suivant pour mon action d'indexation et tout fonctionne correctement.

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

1- D'abord vous créez un nouveau contrôleur puis copiez et collez le code simple ci-dessous 

@Controller
public class viewController {

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

}

3- supprimer 2 élément ci-dessous de l'application angulaire

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

2- dans l'application angulaire, vous devez ajouter $locationProvider.html5Mode(true); à la route d'application 

3- N'oubliez pas de placer la balise de base avant toute requête http dans votre fichier index.html

<head>
<base href="/"> /* Or whatever your base path is */

//call every http request for style and other 
...
</head>

ça marche bien pour moi

0
MostafaMashayekhi

J'avais le même problème lorsque j'utilisais Html5Mode angulaire . La solution qui fonctionnait pour moi consistait à configurer la page d'erreur 404 dans web.xml en attribuant le chemin d'accès à ma vue Index dans mon cas "/".

<error-page>
    <error-code>404</error-code>
    <location>/</location>
</error-page>

De même, vous pouvez essayer de configurer la page d’erreur lors du démarrage printanier. pour référence, vous pouvez vérifier ce lien.

Page d'erreur personnalisée d'amorçage de printemps et 404

0
modern