148 votes

Servlet pour servir du contenu statique

Je déploie une application web sur deux conteneurs différents (Tomcat et Jetty), mais leurs servlets par défaut pour servir le contenu statique ont une manière différente de traiter la structure d'URL que je veux utiliser ( détails ).

Je cherche donc à inclure un petit servlet dans la webapp pour servir son propre contenu statique (images, CSS, etc.). La servlet doit avoir les propriétés suivantes :

  • Pas de dépendances externes
  • Simple et fiable
  • Soutien aux If-Modified-Since (c.-à-d. l'en-tête personnalisé getLastModified méthode)
  • (Facultatif) support pour l'encodage gzip, etags,...

Un tel servlet est-il disponible quelque part ? Le plus proche que je puisse trouver est exemple 4-10 du livre sur les servlets.

Mise à jour : La structure URL que je veux utiliser - au cas où vous vous poseriez la question - est simplement :

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

Ainsi, toutes les requêtes doivent être transmises à la servlet principale, à moins qu'elles ne soient destinées à l'application static path. Le problème est que le servlet par défaut de Tomcat ne prend pas en compte le ServletPath (il cherche donc les fichiers statiques dans le dossier principal), alors que Jetty le fait (il cherche donc dans le répertoire static dossier).

0 votes

Pourriez-vous préciser la "structure URL" que vous souhaitez utiliser ? Créer la vôtre, sur la base de l'exemple 4-10, semble être un effort trivial. Je l'ai fait moi-même de nombreuses fois...

0 votes

J'ai modifié ma question pour élaborer la structure de l'URL. Et oui, j'ai fini par créer ma propre servlet. Voir ma réponse ci-dessous.

1 votes

Pourquoi n'utilisez-vous pas le serveur web pour le contenu statique ?

56voto

Taylor Gautier Points 2044

J'ai trouvé une solution légèrement différente. C'est un peu bricolé, mais voici la correspondance :

<servlet-mapping>   
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</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>*.png</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>*.js</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>myAppServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Il s'agit essentiellement de faire correspondre tous les fichiers de contenu par extension à la servlet par défaut, et tout le reste à "myAppServlet".

Il fonctionne à la fois dans Jetty et Tomcat.

13 votes

En fait, vous pouvez ajouter plus d'une balise url-pattern à l'intérieur du servelet-mapping ;)

5 votes

Les servlets 2.5 et plus récents prennent en charge plusieurs balises url-pattern dans le servlet-mapping.

0 votes

Faites simplement attention aux fichiers d'index (index.html) car ils peuvent prendre le pas sur votre servlet.

46voto

axtavt Points 126632

Il n'est pas nécessaire de personnaliser complètement l'implémentation de la servlet par défaut dans ce cas, vous pouvez utiliser cette simple servlet pour envelopper la demande dans l'implémentation du conteneur :

package com.example;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class DefaultWrapperServlet extends HttpServlet
{   
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        RequestDispatcher rd = getServletContext().getNamedDispatcher("default");

        HttpServletRequest wrapped = new HttpServletRequestWrapper(req) {
            public String getServletPath() { return ""; }
        };

        rd.forward(wrapped, resp);
    }
}

0 votes

Cette question présente un moyen astucieux de faire correspondre / à un contrôleur et /static à un contenu statique à l'aide d'un filtre. Vérifiez la réponse votée après la réponse acceptée : stackoverflow.com/questions/870150/

1 votes

30voto

Will Hartung Points 57465

J'ai eu de bons résultats avec FileServlet car il prend en charge la quasi-totalité du protocole HTTP (balises, découpage en morceaux, etc.).

0 votes

Merci ! Des heures de tentatives ratées et de mauvaises réponses, et voilà qui a résolu mon problème.

4 votes

Cependant, afin de servir du contenu à partir d'un dossier extérieur à l'application (je l'utilise pour servir un dossier à partir du disque, disons C:\resources ) J'ai modifié la ligne suivante : this.basePath = getServletContext().getRealPath(getInitParameter("basePath")) ; Et je l'ai remplacé par : this.basePath = getInitParameter("basePath") ;

1 votes

Une version actualisée est disponible à l'adresse suivante showcase.omnifaces.org/servlets/FileServlet

20voto

Bruno De Fraine Points 11478

J'ai fini par rouler mes propres StaticServlet . Il prend en charge If-Modified-Since Il devrait également être capable de servir des fichiers statiques à partir de fichiers de guerre. Ce n'est pas un code très difficile, mais il n'est pas non plus entièrement trivial.

Le code est disponible : StaticServlet.java . N'hésitez pas à faire des commentaires.

Mise à jour : Khurram s'interroge sur le ServletUtils qui est référencée dans StaticServlet . C'est simplement une classe avec des méthodes auxiliaires que j'ai utilisée pour mon projet. La seule méthode dont vous avez besoin est coalesce (qui est identique à la fonction SQL COALESCE ). Voici le code :

public static <T> T coalesce(T...ts) {
    for(T t: ts)
        if(t != null)
            return t;
    return null;
}

2 votes

Ne nommez pas votre classe interne Erreur. Cela pourrait prêter à confusion car vous pourriez la confondre avec java.lang.Error. De plus, votre web.xml est-il le même ?

0 votes

Merci pour l'avertissement d'erreur. web.xml est le même, avec "default" remplacé par le nom du StaticServlet.

1 votes

Quant à la méthode coalesce, elle peut être remplacée (dans la classe Servlet) par commons-lang StringUtils.defaultString(String, String)

11voto

Panagiotis Korros Points 3073

J'ai eu le même problème et je l'ai résolu en utilisant le code de la "servlet par défaut" de la base de code de Tomcat.

https://github.com/apache/tomcat/blob/master/java/org/apache/catalina/servlets/DefaultServlet.java

El DefaultServlet est le servlet qui sert les ressources statiques (jpg, html, css, gif etc) dans Tomcat.

Cette servlet est très efficace et possède certaines des propriétés que vous avez définies ci-dessus.

Je pense que ce code source, est un bon moyen de commencer et de supprimer les fonctionnalités ou les dépendances dont vous n'avez pas besoin.

  • Les références au paquet org.apache.naming.resources peuvent être supprimées ou remplacées par du code java.io.File.
  • Les références au paquet org.apache.catalina.util ne sont probablement que des méthodes/classes utilitaires qui peuvent être dupliquées dans votre code source.
  • Les références à la classe org.apache.catalina.Globals peuvent être intégrées ou supprimées.

0 votes

Cela semble dépendre de beaucoup de choses, de org.apache.* . Comment l'utiliser avec Jetty ?

0 votes

Vous avez raison, cette version a trop de dépendances pour Tomcat (et elle supporte aussi beaucoup de choses que vous ne voulez peut-être pas. Je vais modifier ma réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X