Разница между / и / * в шаблоне отображения сервлета - PullRequest
168 голосов
/ 10 ноября 2010

Знакомый код:

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

Насколько я понимаю, /* отображается на http://host:port/context/*.

Как насчет /?Это точно не отображается на http://host:port/context только корень.Фактически, он примет http://host:port/context/hello, но отклонит http://host:port/context/hello.jsp.

Может кто-нибудь объяснить, как отображается http://host:port/context/hello?

Ответы [ 5 ]

251 голосов
/ 10 ноября 2010

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

/* в сервлете переопределяет все остальные сервлеты, включая все сервлеты, предоставляемые сервлет-контейнером, такие как сервлет по умолчанию и сервлет JSP. Какую бы просьбу вы не уволили, она окажется в этом сервлете Таким образом, это плохой шаблон URL для сервлетов. Обычно вы хотите использовать /* только на Filter. Он может разрешить выполнение запроса любому сервлету, прослушивающему более конкретный шаблон URL, вызвав FilterChain#doFilter().

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

/ не переопределяет любой другой сервлет. Он заменяет только встроенный сервлет по умолчанию для сервлет-контейнера для всех запросов, который не соответствует ни одному другому зарегистрированному сервлету. Обычно это вызывается только для статических ресурсов (CSS / JS / image / etc) и списков каталогов. Встроенный в сервлет контейнер сервлетов по умолчанию также способен обрабатывать запросы кеша HTTP, потоковую передачу мультимедиа (аудио / видео) и возобновление загрузки файлов. Обычно вы не хотите переопределять сервлет по умолчанию, так как в противном случае вам придется позаботиться обо всех его задачах, что не совсем тривиально (служебная библиотека JSF OmniFaces имеет открытый исходный код пример ). Таким образом, это также плохой шаблон URL для сервлетов. Почему JSP-страницы не попадают в этот сервлет, это потому, что будет вызван встроенный сервлет JSP сервлет-контейнера, который уже по умолчанию сопоставлен с более конкретным шаблоном URL *.jsp.

<url-pattern></url-pattern>

Тогда есть также шаблон URL пустой строки . Это будет вызвано при запросе корневого контекста. Это отличается от подхода <welcome-file> тем, что он не вызывается при запросе любой подпапки. Скорее всего, это шаблон URL, который вы на самом деле ищете, если вам нужен " сервлет домашней страницы ". Надо только признать, что я интуитивно ожидал, что шаблон URL пустой строки и шаблон URL-адреса косой черты / будут определены совершенно наоборот, поэтому я могу понять, что многие начинающие пользователи запутались в этом. Но это то, что есть.

Фронт-контроллер

В случае, если вы на самом деле намереваетесь иметь сервлет фронт-контроллера, лучше всего сопоставить его с более конкретным шаблоном URL, таким как *.html, *.do, /pages/*, /app/* и т. д. Вы можете скрыть шаблон URL-адреса фронт-контроллера и скрыть статические ресурсы в общем шаблоне URL, например /resources/*, /static/* и т. д., с помощью фильтра сервлетов. См. Также Как предотвратить обработку статических ресурсов сервлетом фронт-контроллера, который отображается в / *. Следует отметить, что Spring MVC имеет встроенный сервлет статических ресурсов, поэтому вы можете сопоставить его фронт-контроллер с /, если вы настроите общий шаблон URL для статических ресурсов в Spring. См. Также Как обрабатывать статический контент в Spring MVC?

42 голосов
/ 10 ноября 2010

Я бы хотел дополнить ответ BalusC правилами сопоставления и примером.

Правила отображения из спецификации Servlet 2.5:

  1. Карта точный URL
  2. Карта подстановочных путей
  3. Карта расширений
  4. Отображение на сервлет по умолчанию

В нашем примере есть три сервлета. / является установленным нами сервлетом по умолчанию. Tomcat устанавливает два сервлета для обслуживания jsp и jspx. Так к карте http://host:port/context/hello

  1. Следующие сервлеты не установлены, затем.
  2. Следующие сервлеты путей с подстановочными знаками не установлены.
  3. Не соответствует ни одному добавочному номеру, следующий.
  4. Отображение на сервлет по умолчанию, возврат.

На карту http://host:port/context/hello.jsp

  1. Точные сервлеты URL не установлены, затем.
  2. Следующие сервлеты путей с подстановочными знаками не установлены.
  3. Найден дополнительный сервлет, возврат.
22 голосов
/ 15 сентября 2015

Возможно, вам нужно знать, как отображаются URL-адреса, так как я страдал 404 часами.Есть два вида обработчиков, обрабатывающих запросы.BeanNameUrlHandlerMapping и SimpleUrlHandlerMapping.Когда мы определили servlet-mapping, мы используем SimpleUrlHandlerMapping.Нам нужно знать одну вещь: эти два обработчика имеют общее свойство, называемое alwaysUseFullPath, которое по умолчанию равно false.

false здесь означает, что Spring не будет использовать полный путь для сопоставления URL-адреса с контроллером.Что это значит?Это означает, что когда вы определяете servlet-mapping:

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

, обработчик фактически использует часть * для поиска контроллера.Например, следующий контроллер столкнется с ошибкой 404, когда вы запросите его, используя /perfix/api/feature/doSomething

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

Это идеальное совпадение, верно?Но почему 404.Как упоминалось ранее, значение по умолчанию alwaysUseFullPath равно false, что означает, что в вашем запросе только /api/feature/doSomething используется для поиска соответствующего контроллера, но контроллер не заботится об этом пути.Вам нужно либо изменить свой URL-адрес на /perfix/perfix/api/feature/doSomething, либо удалить perfix из базы MyController @RequestingMapping.

8 голосов
/ 14 ноября 2014

Я думаю, что ответ Кенди в основном правильный.Есть одна небольшая часть, которую я считаю иначе.

Чтобы отобразить хост: port / context / hello.jsp

  1. Точные сервлеты URL не установлены, затем.
  2. Найдены подстановочные знаки сервлетов , возвращаем.

Я считаю, что поэтому "/ *" не соответствует host: port / context / hello, потому что вместо него "/ hello" трактуется как путьфайла (поскольку он не имеет расширения).

2 голосов
/ 27 июля 2017

Существенная разница между /* и / заключается в том, что сервлет с отображением /* будет выбран перед любым сервлетом с отображением расширения (например, *.html), тогда как сервлет с отображением / будетвыбирается только после того, как будут рассмотрены сопоставления расширений (и будет использоваться для любого запроса, который не соответствует ничему другому - это «сервлет по умолчанию»).

В частности, сопоставление /* всегда будетбыть выбранным перед отображением /.Наличие любого из них запрещает каким-либо запросам достигать собственного сервлета по умолчанию контейнера.

Любой из них будет выбран только после сопоставлений сервлета, которые являются точными совпадениями (например, /foo/bar), и сопоставлений путей, которые длиннее /* (например/foo/*).Обратите внимание, что отображение пустой строки является точным соответствием для корневого контекста (http://host:port/context/).

См. Главу 12 Спецификации сервлета Java, доступной в версии 3.1, по адресу http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html.

...