Différence entre / et / * dans le modèle d'URL de mappage de servlet

175

Le code familier:

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

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

Je crois comprendre que cela /*correspond à http://host:port/context/*.

Et pourquoi pas /? Il ne correspond certainement pas http://host:port/contextuniquement à la racine. En fait, il acceptera http://host:port/context/hello, mais rejettera http://host:port/context/hello.jsp.

Quelqu'un peut-il expliquer comment est http://host:port/context/hellomappé?

Candy Chiu
la source

Réponses:

268

<url-pattern>/*</url-pattern>

Le /*sur un servlet remplace tous les autres servlets, y compris tous les servlets fournis par le servletcontainer tels que le servlet par défaut et le servlet JSP. Quelle que soit la demande que vous lancez, elle se retrouvera dans ce servlet. C'est donc un mauvais modèle d'URL pour les servlets. Habituellement, vous souhaitez utiliser uniquement /*un Filterfichier. Il est capable de laisser la demande continuer vers n'importe laquelle des servlets écoutant un modèle d'URL plus spécifique en appelant FilterChain#doFilter().

<url-pattern>/</url-pattern>

Le /ne remplace aucun autre servlet. Il remplace uniquement le servlet par défaut intégré du servletcontainer pour toutes les demandes qui ne correspondent à aucun autre servlet enregistré. Ceci n'est normalement appelé que sur les ressources statiques (CSS / JS / image / etc) et les listes de répertoires. Le servlet par défaut intégré du servletcontainer est également capable de traiter les demandes de cache HTTP, le streaming multimédia (audio / vidéo) et les reprises de téléchargement de fichiers. Habituellement, vous ne voulez pas remplacer le servlet par défaut car vous auriez autrement à vous occuper de toutes ses tâches, ce qui n'est pas vraiment trivial (la bibliothèque d'utilitaires JSF OmniFaces a un exemple open source ). C'est donc aussi un mauvais modèle d'URL pour les servlets. Quant à savoir pourquoi les pages JSP n'atteignent pas ce servlet, c'est parce que le servlet JSP intégré du servletcontainer sera appelé, ce qui est déjà mappé par défaut sur le modèle d'URL plus spécifique *.jsp.

<url-pattern></url-pattern>

Ensuite, il y a aussi le modèle d'URL de chaîne vide . Cela sera appelé lorsque la racine de contexte est demandée. Ceci est différent de l' <welcome-file>approche qui n'est pas invoquée lorsqu'un sous-dossier est demandé. C'est probablement le modèle d'URL que vous recherchez réellement au cas où vous voudriez un " servlet de page d'accueil ". Je dois simplement admettre que je m'attendrais intuitivement à ce que le modèle d'URL de chaîne vide et le modèle d'URL de barre oblique /soient définis exactement dans l'autre sens, donc je peux comprendre que beaucoup de débutants ont été confus à ce sujet. Mais c'est ce que c'est.

Contrôleur avant

Si vous réellement l' intention d'avoir un servlet contrôleur frontal, vous feriez mieux de map sur un modèle d'URL plus spécifique comme *.html, *.do, /pages/*, /app/*, etc. Vous pouvez cacher les ressources statiques modèle d'URL du contrôleur avant et le capot sur un modèle d'URL commune comme /resources/*, /static/*, etc , avec l' aide d'un filtre de servlet. Voir aussi Comment empêcher les ressources statiques d'être gérées par le servlet du contrôleur frontal qui est mappé sur / * . Il convient de noter que Spring MVC a un servlet de ressources statiques intégré, c'est pourquoi vous pouvez mapper son contrôleur frontal sur /si vous configurez un modèle d'URL commun pour les ressources statiques dans Spring. Voir aussi Comment gérer le contenu statique dans Spring MVC?

BalusC
la source
9
Merci. Après quelques recherches, j'aimerais clarifier un point subtil. / écrase le servlet par défaut installé par le serveur Web. Par exemple, Tomcat installe un DefaultServlet qui sert des ressources statiques. Utiliser / se débarrasser du servlet par défaut comme effet secondaire (très probablement indésirable).
Candy Chiu
Eh bien, je n'appellerais pas cela «écrasement», mais «remplacement». Il peut être utile de remplacer le servlet par défaut comme ça.
BalusC
1
<url-pattern> </url-pattern> génère une erreur: <url-pattern> non valide dans le mappage de servlet
slim
Le message d'erreur venait de tomcat, pas de mon IDE; cependant, j'utilise Tomcat 6, donc c'est probablement le problème;)
slim
2
@BalusC, pouvez-vous me dire quel /**motif indique?
Sajib Acharya
45

Je voudrais compléter la réponse de BalusC avec les règles de mappage et un exemple.

Règles de mappage de la spécification Servlet 2.5:

  1. Mapper l'URL exacte
  2. Mapper les chemins génériques
  3. Extensions de carte
  4. Mapper au servlet par défaut

Dans notre exemple, il y a trois servlets. / est le servlet par défaut que nous avons installé. Tomcat installe deux servlets pour servir jsp et jspx. Donc pour cartographierhttp://host:port/context/hello

  1. Aucun servlet d'URL exact installé, ensuite.
  2. Aucuns servlets de chemins génériques installés, ensuite.
  3. Ne correspond à aucune extension, ensuite.
  4. Mappez sur le servlet par défaut, retournez.

Carte http://host:port/context/hello.jsp

  1. Aucun servlet d'URL exact installé, ensuite.
  2. Aucuns servlets de chemins génériques installés, ensuite.
  3. Servlet d'extension trouvé, retour.
Candy Chiu
la source
25

Peut-être avez-vous également besoin de savoir comment les URL sont mappées, car j'ai souffert 404pendant des heures. Il existe deux types de gestionnaires traitant les requêtes. BeanNameUrlHandlerMappinget SimpleUrlHandlerMapping. Lorsque nous avons défini a servlet-mapping, nous utilisons SimpleUrlHandlerMapping. Une chose que nous devons savoir est que ces deux gestionnaires partagent une propriété commune appelée alwaysUseFullPathqui est par défaut false.

falsesignifie ici que Spring n'utilisera pas le chemin complet pour mapper une URL sur un contrôleur. Qu'est-ce que ça veut dire? Cela signifie que lorsque vous définissez un servlet-mapping:

<servlet-mapping>
    <servlet-name>viewServlet</servlet-name>
    <url-pattern>/perfix/*</url-pattern>
</servlet-mapping>

le gestionnaire utilisera réellement la *partie pour trouver le contrôleur. Par exemple, le contrôleur suivant fera face à une 404erreur lorsque vous le demandez en utilisant/perfix/api/feature/doSomething

@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
    @RequestMapping(value = "/doSomething", method = RequestMethod.GET) 
    @ResponseBody
    public String doSomething(HttpServletRequest request) {
        ....
    }
}

C'est un match parfait, non? Mais pourquoi 404. Comme mentionné précédemment, la valeur par défaut de alwaysUseFullPathest false, ce qui signifie que dans votre demande, uniquement /api/feature/doSomethingest utilisée pour trouver un contrôleur correspondant, mais aucun contrôleur ne se soucie de ce chemin. Vous devez modifier votre URL /perfix/perfix/api/feature/doSomethingou la supprimer perfixde la base MyController @RequestingMapping.

hakunami
la source
8

Je pense que la réponse de Candy est plutôt correcte. Il y a une petite partie que je pense autrement.

Pour mapper l'hôte: port / context / hello.jsp

  1. Aucun servlet d'URL exact installé, ensuite.
  2. Servlets de chemins génériques trouvés , retour.

Je crois que pourquoi "/ *" ne correspond pas à host: port / context / hello car il traite "/ hello" comme un chemin au lieu d'un fichier (car il n'a pas d'extension).

hehe
la source
2

La différence essentielle entre /*et /est qu'un servlet avec mappage /*sera sélectionné avant tout servlet avec un mappage d'extension (comme *.html), tandis qu'un servlet avec mappage /ne sera sélectionné qu'après que les mappages d'extension sont pris en compte (et sera utilisé pour toute demande qui ne le fait pas) t correspond à autre chose --- c'est le "servlet par défaut").

En particulier, un /*mappage sera toujours sélectionné avant un /mappage. Le fait d'avoir l'un ou l'autre empêche toute requête d'atteindre le propre servlet par défaut du conteneur.

L'un ou l'autre ne sera sélectionné qu'après les mappages de servlet qui sont des correspondances exactes (comme /foo/bar) et ceux qui sont des mappages de chemin plus longs que /*(comme /foo/*). Notez que le mappage de chaîne vide correspond exactement à la racine de contexte ( http://host:port/context/).

Reportez-vous au chapitre 12 de la spécification du servlet Java, disponible dans la version 3.1 à l' adresse http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html .

Robert Tupelo-Schneck
la source