Różnica między / i / * we wzorcu adresu URL mapowania serwletu

175

Znajomy kod:

<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>

Rozumiem, że /*odwzorowuje http://host:port/context/*.

A co powiesz /? Z pewnością nie jest http://host:port/contextmapowany tylko do roota. W rzeczywistości zaakceptuje http://host:port/context/hello, ale odrzuci http://host:port/context/hello.jsp.

Czy ktoś może wyjaśnić, w jaki sposób jest http://host:port/context/hellomapowany?

Candy Chiu
źródło

Odpowiedzi:

268

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

/*Na serwletu zastępuje wszystkie inne serwlety, w tym wszystkie serwlety świadczonych przez servletcontainer takich jak domyślnego apletu i serwletu JSP. Cokolwiek odpalisz, trafi do tego serwletu. Jest to zatem zły wzorzec adresu URL dla serwletów. Zwykle chcesz korzystać /*na zasadzie Filtertylko. Jest w stanie pozwolić, aby żądanie było kontynuowane do dowolnego z serwletów nasłuchujących na bardziej szczegółowym wzorcu adresu URL przez wywołanie FilterChain#doFilter().

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

/Nie zastępuje żadnego innego serwletu. Zastępuje tylko wbudowany domyślny serwlet servletcontainer dla wszystkich żądań, które nie pasują do żadnego innego zarejestrowanego serwletu. Zwykle jest to wywoływane tylko w przypadku zasobów statycznych (CSS / JS / image / etc) i list katalogów. Wbudowany domyślny serwlet serwletu servletcontainer może również obsługiwać żądania pamięci podręcznej HTTP, strumieniowe przesyłanie multimediów (audio / wideo) i wznawianie pobierania plików. Zwykle nie chcesz, aby zastąpić domyślny aplet jak można inaczej trzeba dbać o wszystkich swoich zadań, co nie jest dokładnie trywialne (JSF biblioteki narzędzie OmniFaces ma open source przykład). Jest to zatem również zły wzorzec adresu URL dla serwletów. Jeśli chodzi o to, dlaczego strony JSP nie trafiają do tego serwletu, to dlatego, że zostanie wywołany wbudowany serwlet JSP serwletu kontenera serwletu, który jest już domyślnie odwzorowany na bardziej szczegółowy wzorzec adresu URL *.jsp.

<url-pattern></url-pattern>

Jest też pusty wzorzec adresu URL ciągu . Zostanie to wywołane, gdy zażąda się kontekstowego katalogu głównego. Różni się to od <welcome-file>podejścia, w którym nie jest wywoływane, gdy żądany jest dowolny podfolder. Najprawdopodobniej jest to wzorzec adresu URL, którego faktycznie szukasz na wypadek, gdybyś potrzebował „ serwletu strony domowej ”. Muszę tylko przyznać, że intuicyjnie spodziewałbym się, że pusty wzorzec adresu URL w postaci ciągu i wzorzec adresu URL z ukośnikiem /zostaną zdefiniowane dokładnie na odwrót, więc rozumiem, że wielu początkujących było w tym zdezorientowanych. Ale tak właśnie jest.

Kontroler przedni

W przypadku, gdy rzeczywiście zamierzają mieć serwletu kontrolera z przodu, wtedy bym najlepiej map go na bardziej konkretnego adresu URL podobnego wzorca *.html, *.do, /pages/*, /app/*, itd. Można schować zasobów statycznych kontroler frontowy URL wzór i pokrywa na wspólny wzorzec URL like /resources/*, /static/*etc za pomocą filtru serwletów. Zobacz także Jak zapobiegać obsłudze statycznych zasobów przez serwlet kontrolera frontowego, który jest odwzorowany na / * . Należy zauważyć, że Spring MVC ma wbudowany serwlet zasobów statycznych, dlatego można zmapować jego kontroler frontowy, /jeśli skonfigurujesz wspólny wzorzec adresu URL dla zasobów statycznych w Spring. Zobacz także Jak obsługiwać statyczną zawartość w Spring MVC?

BalusC
źródło
9
Dzięki. Po kilku badaniach chciałbym wyjaśnić subtelną kwestię. / nadpisuje domyślny serwlet instalowany przez serwer WWW. Na przykład Tomcat instaluje DefaultServlet, który obsługuje zasoby statyczne. Użycie / pozbycie się domyślnego serwletu jako (najprawdopodobniej niepożądanego) efektu ubocznego.
Candy Chiu,
Cóż, nie nazwałbym tego „nadpisywaniem”, ale „zastępowaniem”. W ten sposób może być przydatne zastąpienie domyślnego serwletu.
BalusC
1
<url-pattern> </url-pattern> zgłasza błąd: Nieprawidłowe <url-pattern> w mapowaniu serwletów
szczupły
Komunikat o błędzie pochodzi z tomcat, a nie z mojego IDE; jednak używam Tomcata 6, więc pewnie w tym problem;)
slim
2
@BalusC, czy możesz mi powiedzieć, jaki /**wzór wskazuje?
Sajib Acharya
45

Chciałbym uzupełnić odpowiedź BalusC o zasady mapowania i przykład.

Reguły mapowania ze specyfikacji Servlet 2.5:

  1. Zamapuj dokładny adres URL
  2. Mapuj ścieżki z symbolami wieloznacznymi
  3. Rozszerzenia map
  4. Odwzoruj na domyślny serwlet

W naszym przykładzie mamy trzy serwlety. / jest domyślnym serwletem instalowanym przez nas. Tomcat instaluje dwa serwlety do obsługi plików jsp i jspx. Więc do mapowaniahttp://host:port/context/hello

  1. Nie zainstalowano żadnych dokładnych serwletów URL.
  2. Następnie nie zainstalowano żadnych serwletów ścieżek symboli wieloznacznych.
  3. Następnie nie pasuje do żadnych rozszerzeń.
  4. Odwzoruj na domyślny serwlet, powrót.

Aby zmapować http://host:port/context/hello.jsp

  1. Nie zainstalowano żadnych dokładnych serwletów URL.
  2. Następnie nie zainstalowano żadnych serwletów ścieżek symboli wieloznacznych.
  3. Znaleziono serwlet rozszerzenia, powrót.
Candy Chiu
źródło
25

Być może musisz wiedzieć, jak mapowane są adresy URL, ponieważ cierpiałem 404przez wiele godzin. Istnieją dwa rodzaje programów obsługi obsługujących żądania. BeanNameUrlHandlerMappingi SimpleUrlHandlerMapping. Kiedy zdefiniowaliśmy a servlet-mapping, używamy SimpleUrlHandlerMapping. Jedną rzeczą, którą musimy wiedzieć, jest to, że te dwa programy obsługujące mają wspólną właściwość o nazwie, alwaysUseFullPathktóra jest domyślnie false.

falsetutaj oznacza, że ​​Spring nie użyje pełnej ścieżki do mapowania adresu URL do kontrolera. Co to znaczy? Oznacza to, że kiedy definiujesz servlet-mapping:

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

program obsługi faktycznie użyje *części, aby znaleźć kontroler. Na przykład następujący kontroler napotka 404błąd, gdy zażądasz użycia/perfix/api/feature/doSomething

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

To idealne połączenie, prawda? Ale dlaczego 404. Jak wspomniano wcześniej, domyślna wartość alwaysUseFullPathto false, co oznacza, że ​​w żądaniu /api/feature/doSomethingjest używana tylko do znalezienia odpowiedniego kontrolera, ale żaden kontroler nie dba o tę ścieżkę. Musisz zmienić swój adres URL na /perfix/perfix/api/feature/doSomethinglub usunąć perfixz bazy MyController @RequestingMapping.

hakunami
źródło
8

Myślę, że odpowiedź Candy jest w większości poprawna. Myślę, że jest jedna mała część.

Aby zmapować hosta: port / kontekst / hello.jsp

  1. Nie zainstalowano żadnych dokładnych serwletów URL.
  2. Znalezione ścieżki z symbolami wieloznacznymi serwlety , powrót.

Uważam, że dlaczego "/ *" nie pasuje do host: port / context / hello, ponieważ traktuje "/ hello" jako ścieżkę zamiast pliku (ponieważ nie ma rozszerzenia).

hehe
źródło
2

Zasadnicza różnica między /*i /polega na tym, że serwlet z mapowaniem /*zostanie wybrany przed jakimkolwiek serwletem z mapowaniem rozszerzenia (takim jak *.html), podczas gdy serwlet z mapowaniem /zostanie wybrany dopiero po rozważeniu mapowania rozszerzenia (i będzie używany dla każdego żądania, które nie nie pasuje do niczego innego - jest to „domyślny serwlet”).

W szczególności /*mapowanie będzie zawsze wybierane przed /mapowaniem. Posiadanie jednego z nich zapobiega docieraniu żądań do domyślnego serwletu kontenera.

Każda z nich zostanie wybrana dopiero po odwzorowaniach serwletów, które są dokładnymi dopasowaniami (jak /foo/bar) i tymi, które są odwzorowaniami ścieżek dłuższymi niż /*(podobne /foo/*). Zwróć uwagę, że odwzorowanie pustego ciągu jest dokładnym dopasowaniem do kontekstowego root ( http://host:port/context/).

Zobacz rozdział 12 specyfikacji Java Servlet Specification, dostępny w wersji 3.1 pod adresem http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html .

Robert Tupelo-Schneck
źródło