web-dev-qa-db-fra.com

SpringMVC peut-il être configuré pour traiter toutes les demandes, mais exclure les répertoires de contenu statique?

Si je mappe mon application Spring pour traiter toutes les demandes entrantes ('/ *'), les demandes de contenu statique renvoient des 404. Par exemple, une demande de "myhost.com/css/global.css" renverrait un 404, même si la ressource existe déjà lorsque Spring intercepte la demande.

L'alternative consiste à mapper SpringMVC vers un sous-répertoire (par exemple, '/ home /'), mais dans ce cas, vous devez passer ce répertoire dans tous les liens de l'application. Y a-t-il un moyen de mapper SpringMVC à '/ ' et d'exclure un ensemble de répertoires du traitement?

Ma configuration actuelle de web.xml est la suivante:

<servlet>
    <servlet-name>springApp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

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

Idéalement, j'aimerais que le mappage soit comme suit:

 <servlet-mapping>
    <servlet-name>springApp</servlet-name>
    <url-pattern>/*</url-pattern>
    <exclude>/css/*,/js/*</exclude>
 </servlet-mapping>

Est-ce que ce genre de chose est possible?

58
Rich Kroll

Si vous voulez faire cela uniquement avec Spring, c'est possible mais un peu brouillon:

  1. Vous devrez soit utiliser un fichier SimpleUrlHandlerMapping pour lequel vous pouvez spécifier explicitement les modèles d'URL devant être mappés aux contrôleurs OR et étendez-le pour prendre en charge les URL "ignorées" telles que "css/**".
  2. Vous devez écrire votre propre implémentation HttpRequestHandler qui consiste essentiellement en "getServletContext (). GetRequestDsipatcher (). Include ()" pour renvoyer la ressource demandée telle quelle.
  3. Vous devrez enregistrer ce gestionnaire en tant que defaultHandler pour le SimpleUrlHandlerMapping ci-dessus.

Une fois que tout cela est fait, toutes les demandes qui ne peuvent pas être mappées sur vos contrôleurs seront transférées à votre HttpRequestHandler et servies "telles quelles".

7
ChssPly76

NOTE: cette réponse s'applique à Spring 3.0.4+ SEULEMENT

(BTW, cette question a également été traitée ici: Spring servant du contenu statique avec mvc: resources, xsd invalide )

Consultez le projet Spring mvc-showcase dans le répertoire Spring Subversion . Il montre exactement ce que vous voulez faire, à savoir que vous pouvez définir des ressources statiques qui ne seront pas traitées par DisapatcherServlet. Voir le fichier /mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml. Voici un extrait de la façon dont je gère ces exclusions, où JS, CSS et les images se trouvent dans la racine du contexte de l'application (avec l'espace de noms MVC mappé sur mvc:

<!-- resources exclusions from servlet mapping -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
56
atrain

J'ai résolu le problème en servant du contenu statique via le servlet 'par défaut', qui sert simplement le contenu au client. Donc, mon web.xml ressemble à ceci:

<servlet>
    <servlet-name>MyApp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>MyApp</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping> <!-- The 'dynamic' content -->

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping> <!-- The 'static' content -->

J'espère que cela t'aides.

27
user153415

Le moyen le plus simple pour moi (si vous utilisez une version assez récente de Spring) est

<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...
4
Daniel Egan

Une façon de le faire serait avec les filtres. Il vous faudrait écrire un peu de code personnalisé, mais ce n'est pas mal. Voici un exemple si vous ne souhaitez pas transmettre de fichiers * .css ou * .js à votre servlet Spring:

web.xml:

<filter-mapping>
    <filter-name>fileTypeFilter</filter-name>
    <filter-class>foo.FileTypeFilter</filter-class>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Classe Java:

public class FileTypeFilter implements Filter {
     public void init(FilterConfig conf) {
         // init logic here
     }

     public void destroy() {
        // release resources here
     }

     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
          if(shouldExclude(req)) {
              chain.doFilter(req, res);
              //some logic so the request doesnt go to the servlet

              //maybe you could just forward
              //the request directly to the file getting accessed.  not sure if that would work
          }

          //file should be passed to the servlet; you can do some logic here
          //if you want         
     }
     private boolean shouldExclude(ServletRequest req) {
         if(req instanceof HttpServletRequest) {
             HttpServletRequest hreq = (HttpServletRequest) req;
             return (hreq.getRequestURI().endsWith(".css") ||
                     hreq.getRequestURI().endsWith(".js"));
         }
         return false;
    }
}

Je n'ai pas testé cela, mais je pense que cela fonctionnera.

EDIT: Il n'y a pas de fonctionnalité d'exclusion dans les spécifications de servlet. Je ne pense pas qu'il y ait un bon moyen de faire cela au printemps, mais cela permet essentiellement d'obtenir la même chose dans votre message.

EDIT 2 : Si vous voulez pouvoir changer facilement ce qui est filtré, vous pouvez simplement utiliser Spring pour injecter quelque chose dans le filtre au moment de l'exécution. 

EDIT 3 : Je viens de me rendre compte que si vous transférez directement dans le fichier, le filtre sera refait et vous serez pris dans une boucle infinie. Il y a peut-être une autre façon de faire cela avec des filtres, mais honnêtement, je ne suis pas sûr de ce que c'est.

3
Alex Beardsley

J'ai le même problème et voici comment je l'ai résolu:

Ce qui suit a été ajouté au fichier web.xml:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.css</url-pattern>
    <url-pattern>*.ico</url-pattern>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.htc</url-pattern>
    <url-pattern>*.gif</url-pattern>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>

Ce qui suit a été ajouté au fichier de définition du bean servlet MVC spring3 (tel que applicationContext.xml, le fichier configuré dans web.xml en tant que contextConfigLocation.):

<mvc:annotation-driven /> 
<mvc:default-servlet-handler />
2
Green Lei

Qu'est-ce que vous utilisez pour servir vos images statiques?.

Si vous utilisez Tomcat, vous mettrez quelque chose comme ceci dans votre httpd.conf:

JkUnMount /*.css  webapp

Où 'webapp' est l'entrée de votre workers.properties.

Désolé, je ne peux pas vous donner une solution purement Spring, mais voici comment je le fais.

2
Darren Greaves

Avez-vous une ou des extensions cohérentes pour les demandes que vous souhaitez traiter par le répartiteur Spring (je pense que la plupart des exemples Spring utilisent un * .htm)? Dans ce cas, vous pouvez mapper les extensions que vous souhaitez traiter, de manière à contourner vos fichiers css et js.

Sinon, je suis d’accord avec Nalandial, l’approche Filtre est probablement la meilleure solution pour l’instant.

0
jridley

J'utilise un chemin d'URL virtuel pour récupérer la ressource dont j'ai besoin. J'utilise généralement Spring MVC, je ne pouvais donc pas avoir de javascripts ni de css dans le dossier/WEB-INF/views. J'ai créé cette servlet personnalisée pour autoriser UNIQUEMENT l'accès aux fichiers .js et .css dans le dossier/WEB-INF/views. Dans votre cas, si vous déplacez le dossier/css et le dossier/js vers un dossier parent tel que/resource, ma solution vous sera applicable.

Vous pouvez changer le String url = "YOUR_RESOURCE_FOLDER"

Ainsi, par exemple, chemin virtuel peut être quelque chose comme http://www.mysite.com/resources/path/path/app.js

Cela mappera vers mon /WEB-INF/views/path/path/app.js

web.xml

<servlet>
    <servlet-name>ResourceDispatcherServlet</servlet-name>
    <servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>ResourceDispatcherServlet</servlet-name>
    <url-pattern>/resource/*</url-pattern>
</servlet-mapping>

servlet

public class ResourceDispatcherServlet extends HttpServlet {

    public void init() throws ServletException {

    }

    public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {


        String servletPath = req.getServletPath();   // /resource
        String pathInfo = req.getPathInfo();         // /path/path/app.js

        String url = "/WEB-INF/views" + pathInfo;

        String lastPath = StringUtil.substringAfterLast(pathInfo, "/");
        String extension = StringUtil.substringAfterLast(lastPath, ".");

        try {
            RequestDispatcher dispatcher = null;
            if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension))) {
                dispatcher = req.getRequestDispatcher(url);
            }

            if (dispatcher != null) {
                dispatcher.include(req, rsp);
            }
            else {
                rsp.sendError(404);
            }
        }
        catch (Exception e) {
            if (!rsp.isCommitted()) {
                rsp.sendError(500);
            }
        }
    }
}
0
webpro2828

Dans mon cas, tout allait bien. Mais j'ai un problème dans un contrôleur

c'était mon problème @RequestMapping (method = RequestMethod.GET)

y change pour cela:

@RequestMapping(value = "/usuario", method = RequestMethod.GET)

et il fonctionne

recherchez un contrôleur qui a @RequestMappgin et changez-le.

0
user3193801

Si vous utilisez Spring 3.0.4 ou une version ultérieure, utilisez la solution fournie par atrain

Sinon, vous pouvez faire ceci simple chose:

peut-être avez-vous la structure de répertoires statiques suivante à servir:

WebContent
   |
   WEB-INF
     |
    public
        |
       css
        |
       js
        |
       img

Eclipse Les projets Web dynamiques génèrent par défaut la structure suivante: WebContent/WEB-INF. Déplacez le dossier public de votre répertoire WEB-INF dans le répertoire WebContent.

Côté client

référencer vos fichiers statiques de la manière suivante:

<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">

Voici ma référence.

0
Vikram