Разница между/и/* в шаблоне 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.