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

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

<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 ответов

Решение

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

Я хотел бы дополнить ответ 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. Нашли расширение сервлета, верните.

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

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

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

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

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

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

Другие вопросы по тегам