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

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

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

Ответ 1

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

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

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

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

<url-pattern></url-pattern>

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

Передний контроллер

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

Ответ 2

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

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

  • Точный URL карты
  • Подстановочные пути карты
  • Расширения карты
  • Карта для сервлета по умолчанию

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

  • Нет установленных сервлетов URL. Далее.
  • Нет сервлетов подстановочных путей, установленных далее.
  • Не соответствует никаким расширениям, далее.
  • Вернитесь к сервлету по умолчанию.

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

  • Нет установленных сервлетов URL. Далее.
  • Нет сервлетов подстановочных путей, установленных далее.
  • Найден сервлет расширения, верните.

Ответ 3

Возможно, вам нужно знать, как отображаются URL-адреса, так как я терпел 404 в течение нескольких часов. Существует два типа обработчиков, обрабатывающих запросы. BeanNameUrlHandlerMapping и SimpleUrlHandlerMapping. Когда мы определили a 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, чтобы найти соответствующий контроллер, но Controller не заботится об этом пути. Вам нужно либо изменить URL-адрес на /perfix/perfix/api/feature/doSomething, либо удалить perfix из базы MyController @RequestingMapping.

Ответ 4

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

Чтобы отобразить узел: port/context/hello.jsp

  • Нет установленных сервлетов URL. Далее.
  • Найденные сервлеты с шаблонами подстановок, возврат.

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

Ответ 5

Существенное различие между /* и / заключается в том, что сервлет с отображением /* будет выбран до любого сервлета с расширением (например, *.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.