Разница между / и / * в шаблоне отображения сервлета

175

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

<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только на root. На самом деле он примет http://host:port/context/hello, но отвергнет http://host:port/context/hello.jsp.

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

Candy Chiu
источник

Ответы:

268

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

/*На сервлете перекрывает все другие сервлеты, включая все сервлеты , предусмотренные servletcontainer , такие как сервлет по умолчанию и сервлет 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?

BalusC
источник
9
Спасибо. После некоторых исследований я бы хотел уточнить один тонкий момент. / перезаписывает сервлет по умолчанию, который устанавливает веб-сервер. Например, Tomcat устанавливает DefaultServlet, который обслуживает статические ресурсы. Использование / избавляет от сервлета по умолчанию как (скорее всего, нежелательный) побочный эффект.
Candy Chiu
Ну, я бы не назвал это «перезаписью», а «заменой». Может быть полезно заменить сервлет по умолчанию таким образом.
BalusC
1
<url-pattern> </ url-pattern> выдает ошибку: недопустимый <url-pattern> в отображении сервлета
тонкий
Сообщение об ошибке было от tomcat, а не от моей IDE; Тем не менее, я использую Tomcat 6, так что это, вероятно, проблема;)
slim
2
@BalusC, подскажите, пожалуйста, какой /**шаблон указывает?
Саджиб Ачарья
45

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

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

  1. Точный URL карты
  2. Карта подстановочных путей
  3. Расширения карты
  4. Сопоставить с сервлетом по умолчанию

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

  1. Следующие URL-адреса не установлены.
  2. Следующие сервлеты не установлены.
  3. Не соответствует никаким расширениям, следующий.
  4. Карта к сервлету по умолчанию, возврат.

Для отображения http://host:port/context/hello.jsp

  1. Следующие URL-адреса не установлены.
  2. Следующие сервлеты не установлены.
  3. Нашли расширение сервлета, верните.
Candy Chiu
источник
25

Возможно, вам нужно знать, как отображаются 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.

hakunami
источник
8

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

Для сопоставления хоста: port / context / hello.jsp

  1. Следующие URL-адреса не установлены.
  2. Найдены подстановочные пути, сервлеты , вернемся.

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

хе-хе
источник
2

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

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

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

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

Роберт Тупело-Шнек
источник