web-dev-qa-db-fra.com

Comment accéder aux ressources statiques lors du mappage d'une servlet de contrôleur frontal global sur / *

J'ai mappé le répartiteur Spring MVC en tant que servlet de contrôleur frontal global sur /*.

<servlet>       
  <servlet-name>home</servlet-name>         
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>     
</servlet>  
<servlet-mapping>       
  <servlet-name>home</servlet-name>         
  <url-pattern>/*</url-pattern>     
</servlet-mapping>

Cependant, ce mappage arrête l'accès aux fichiers statiques comme CSS, JS, images, etc. qui sont tous dans le /res/ dossier.

Comment puis-je y accéder de toute façon?

58
Rahul Garg

J'ai également rencontré cela et je n'ai jamais trouvé de bonne solution. J'ai fini par mapper ma servlet un niveau plus haut dans la hiérarchie des URL:

<servlet-mapping>       
  <servlet-name>home</servlet-name>             
  <url-pattern>/app/*</url-pattern>     
</servlet-mapping>

Et maintenant, tout dans le contexte de base (et dans votre répertoire/res) peut être servi par votre conteneur.

12
Gandalf

Mappez le servlet du contrôleur sur un url-pattern Plus spécifique comme /pages/*, Placez le contenu statique dans un dossier spécifique comme /static Et créez une Filter écoute sur /* Qui continue de manière transparente la chaîne pour tout contenu statique et envoie les demandes au servlet du contrôleur pour tout autre contenu.

En un mot:

<filter>
    <filter-name>filter</filter-name>
    <filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>controller</servlet-name>
    <servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>controller</servlet-name>
    <url-pattern>/pages/*</url-pattern>
</servlet-mapping>

avec ce qui suit dans la fonction doFilter() du filtre:

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/static")) {
    chain.doFilter(request, response); // Goes to default servlet.
} else {
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

Non, cela ne se termine pas avec /pages Dans la barre d'adresse du navigateur. C'est totalement transparent. Vous pouvez si nécessaire faire de "/static" Et/ou "/pages" Un init-param Du filtre.

71
BalusC

Avec Spring 3.0.4.RELEASE et supérieur, vous pouvez utiliser

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

Comme vu dans Spring Reference .

43
Joaquín L. Robles

Ce que vous faites, c'est ajouter un fichier de bienvenue dans votre web.xml

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

Et puis ajoutez ceci à vos mappages de servlet afin que lorsque quelqu'un va à la racine de votre application, il soit envoyé en interne à index.html, puis le mappage les enverra en interne au servlet auquel vous le mappez

<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/index.html</url-pattern>
</servlet-mapping>

Résultat final: vous visitez/Application, mais le servlet/Application/MainActions s'affiche sans perturber aucune autre demande racine.

Trouver? Ainsi, votre application se trouve toujours à une sous-URL, mais est automatiquement présentée lorsque l'utilisateur accède à la racine de votre site. Cela vous permet d'avoir le fichier /images/bob.img toujours à l'endroit habituel, mais "/" est votre application.

19
casey

Si vous utilisez Tomcat, vous pouvez mapper les ressources vers le servlet par défaut:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

et accédez à vos ressources avec l'url http: // {chemin de contexte}/static/res/...

Fonctionne également avec Jetty, pas sûr des autres conteneurs de servlets.

17
user112483

La diffusion de contenu statique avec le suffixe approprié dans plusieurs définitions de mappage de servlet a résolu le problème de sécurité mentionné dans l'un des commentaires dans l'une des réponses publiées. Cité ci-dessous:

Il s'agissait d'une faille de sécurité dans Tomcat (les contenus WEB-INF et META-INF sont accessibles de cette façon) et il a été corrigé dans 7.0.4 (et sera également porté sur 5.x et 6.x). - BalusC 2 novembre 10 à 22:44

ce qui m'a beaucoup aidé. Et voici comment je l'ai résolu:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>
16
GO'

Depuis la version 3.0.4, vous devriez pouvoir utiliser mvc:resources en combinaison avec mvc:default-servlet-handler comme décrit dans la documentation du printemps pour y parvenir.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources

9
digitaljoel

La raison de la collision semble être due au fait que, par défaut, la racine de contexte, "/", doit être gérée par org.Apache.catalina.servlets.DefaultServlet. Cette servlet est destinée à gérer les demandes de ressources statiques.

Si vous décidez de le supprimer avec votre propre servlet, dans le but de gérer les demandes dynamiques, ce servlet de niveau supérieur doit également effectuer toutes les tâches accomplies par le gestionnaire d'origine "DefaultServlet" de catalina.

Si vous lisez les documents Tomcat, ils mentionnent que True Apache (httpd) est meilleur qu'Apache Tomcat pour gérer le contenu statique, car il est spécialement conçu pour cela. Je suppose que Tomcat utilise par défaut org.Apache.catalina.servlets.DefaultServlet pour gérer les requêtes statiques. Comme tout est enveloppé dans une machine virtuelle Java et que Tomcat est destiné à servir de conteneur Servlet/JSP, ils n'ont probablement pas écrit cette classe en tant que gestionnaire de contenu statique super optimisé. C'est là. Il fait le travail. Assez bien.

Mais c'est la chose qui gère le contenu statique et elle vit à "/". Donc, si vous y mettez autre chose et que cette chose ne gère pas les requêtes statiques, WHOOPS, vos ressources statiques vont.

J'ai cherché haut et bas pour la même réponse et la réponse que je reçois partout est "si vous ne voulez pas que ça fasse ça, ne faites pas ça".

En résumé, votre configuration déplace le gestionnaire de ressources statiques par défaut avec quelque chose qui n'est pas du tout un gestionnaire de ressources statiques. Vous devrez essayer une configuration différente pour obtenir les résultats que vous recherchez (comme je le ferai).

5
Bill

Les fichiers "statiques" dans App Engine ne sont pas directement accessibles par votre application. Vous devez soit les télécharger deux fois, soit servir les fichiers statiques vous-même, plutôt que d'utiliser un gestionnaire statique.

3
Nick Johnson

La meilleure façon de gérer cela est d'utiliser une sorte de réécriture d'URL. De cette façon, vous pouvez avoir des URL propres et reposantes, et PAS avec des extensions, par exemple abc.com/welcom/register par opposition à abc.com/welcome/resister.html

J'utilise RL Tuckey ce qui est plutôt cool.

Il contient des instructions sur la configuration de votre application Web. Je l'ai configurée avec mon application Web Spring MVC. Bien sûr, tout allait bien jusqu'à ce que je veuille utiliser des annotations pour les validations Spring 3 comme @Email ou @Null pour les objets de domaine.

Quand j'ajoute les directives Spring mvc:

< mvc:annotation-driven  /> 
< mvc:default-servlet-handler />

.. il casse le bon vieux code Tuckey. Apparemment, < mvc:default-servlet-handler /> remplace Tuckey, que j'essaie toujours de résoudre.

2
logixplayer

Ajoutez les dossiers que vous ne souhaitez pas déclencher le traitement de servlet dans le <static-files> section de votre fichier appengine-web.xml.

Je viens de faire ça et on dirait que les choses commencent à fonctionner correctement. Voici ma structure:

/

/pages/<.jsp fichiers>

/ css

J'ai ajouté "/ pages/**" et "/ css/**" au <static-files> section et je peux maintenant transférer vers un fichier .jsp depuis l'intérieur d'un servlet doGet sans provoquer une boucle infinie.

1
MStodd

J'ai trouvé qu'en utilisant

<mvc:default-servlet-handler />

au printemps, le fichier de définition du bean servlet MVC fonctionne pour moi. Il transmet toute demande qui n'est pas traitée par un contrôleur MVC enregistré au gestionnaire par défaut d'origine du conteneur, qui doit le servir de contenu statique. Assurez-vous simplement qu'aucun contrôleur enregistré ne gère tout, et cela devrait fonctionner très bien. Vous ne savez pas pourquoi @logixplayer suggère une réécriture d'URL; vous pouvez obtenir l'effet qu'il recherche juste en utilisant Spring MVC seul.

1
Jules

Après avoir essayé l'approche du filtre sans succès (il n'a pas entré la fonction doFilter () pour une raison quelconque), j'ai un peu changé ma configuration et trouvé une solution très simple pour le problème de service racine:

Au lieu de servir "/ *" dans mon servlet principal, j'écoute désormais uniquement les préfixes de langue dédiés "EN", "EN/*", "DE", "DE/*"

Le contenu statique est servi par le servlet par défaut et les demandes racine vides vont à l'index.jsp qui appelle mon servlet principal avec la langue par défaut:

<jsp: include page = "/ FR /" /> (aucun autre contenu sur la page d'index.)

1
sebut

Je recommande d'essayer d'utiliser un filtre au lieu d'une servlet par défaut dans la mesure du possible.

Deux autres possibilités:

Écrivez vous-même un FileServlet. Vous trouverez de nombreux exemples, il suffit d'ouvrir le fichier par URL et d'écrire son contenu dans le flux de sortie. Ensuite, utilisez-le pour servir la demande de fichier statique.

Instanciez une classe FileServlet utilisée par Google App Engine et appelez le service (demande, réponse) sur ce FileServlet lorsque vous devez servir le fichier statique à une URL donnée.

Vous pouvez mapper/res/* à YourFileServlet ou quoi que ce soit pour l'exclure de la gestion de DispatcherServlets, ou l'appeler directement à partir de DispatcherServlet.

Et, je dois demander, que dit la documentation de Spring sur cette collision? Je ne l'ai jamais utilisé.

0
alamar

En ce qui concerne Tomcat, beaucoup dépend de la version particulière. Il y avait un correctif de bogue https://bz.Apache.org/bugzilla/show_bug.cgi?id=50026 ce qui signifie que le mappage de servlet (autre que pour '/') pour le servlet par défaut se comporte différemment dans Tomcat 6.0.29 (et versions antérieures) par rapport aux versions ultérieures.

0
Mike Beaumont

Dans Embedded Jetty, j'ai réussi à obtenir quelque chose de similaire en ajoutant un mappage pour le répertoire "css" dans web.xml. Lui dire explicitement d'utiliser DefaultServlet:

<servlet>
  <servlet-name>DefaultServlet</servlet-name>
  <servlet-class>org.Eclipse.jetty.servlet.DefaultServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>DefaultServlet</servlet-name>
  <url-pattern>/css/*</url-pattern>
</servlet-mapping>
0
QaZ

J'ai trouvé une solution plus simple avec un fichier d'index factice.

Créez un servlet (ou utilisez celui auquel vous vouliez répondre "/") qui correspond à "/index.html" (les solutions mentionnées ici utilisent le mappage via XML, j'ai utilisé la version 3.0 avec l'annotation @WebServlet) Ensuite, créez un statique fichier (vide) à la racine du contenu statique nommé "index.html"

J'utilisais Jetty, et ce qui s'est passé, c'est que le serveur a reconnu le fichier au lieu de répertorier le répertoire, mais lorsqu'on lui a demandé la ressource, mon servlet a pris le contrôle à la place. Tous les autres contenus statiques n'ont pas été affectés.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>

et si vous souhaitez utiliser une configuration basée sur des annotations, utilisez le code ci-dessous

@Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
0
Jekin Kalariya