Как получить доступ к статическим ресурсам при отображении сервлета глобального переднего контроллера на /*


я сопоставил Spring MVC dispatcher как глобальный сервлет переднего контроллера на /*.

<servlet>       
  <servlet-name>home</servlet-name>         
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>     
</servlet>  
<servlet-mapping>       
  <servlet-name>home</servlet-name>         
  <url-pattern>/*</url-pattern>     
</servlet-mapping>

однако это сопоставление останавливает доступ к статическим файлам, таким как CSS, JS, изображения и т. д., которые находятся в .

как я могу получить к ним доступ в любом случае?

17 54

17 ответов:

я столкнулся с этим также и никогда не находил отличное решение. Я закончил отображение моего сервлета на один уровень выше в иерархии URL:

<servlet-mapping>       
  <servlet-name>home</servlet-name>             
  <url-pattern>/app/*</url-pattern>     
</servlet-mapping>

и теперь все в базовом контексте (и в вашем каталоге /res) может обслуживаться вашим контейнером.

сопоставьте сервлет контроллера с более конкретным url-pattern как /pages/*, поместите статическое содержимое в определенную папку, например /static и создать Filter прослушивание /* который прозрачно продолжает цепочку для любого статического контента и отправляет запросы на сервлет контроллера для другого контента.

в двух словах:

<filter>
    <filter-name>filter</filter-name>
    <filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>controller</servlet-name>
    <servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>controller</servlet-name>
    <url-pattern>/pages/*</url-pattern>
</servlet-mapping>

со следующим в фильтре doFilter():

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/static")) {
    chain.doFilter(request, response); // Goes to default servlet.
} else {
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

нет, это не заканчивается /pages в браузере адресная строка. Он полностью прозрачен. Вы можете при необходимости сделать "/static" и/или "/pages" an init-param фильтра.

С Весна 3.0.4.Отпустите и выше, вы можете использовать

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

Как видно Весна Ссылка.

что вы делаете, это добавить файл приветствия в вашем интернете.xml

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

а затем добавьте это в свои сопоставления сервлетов, чтобы, когда кто-то идет в корень вашего приложения, они отправляются в индекс.html внутренне, а затем сопоставление будет внутренне отправлять их на сервлет, который вы сопоставляете с

<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/index.html</url-pattern>
</servlet-mapping>

конечный результат: вы посещаете /приложение, но вам представлен сервлет/Application / MainActions без нарушения каких-либо других корневых запросов.

сделать это? Так ваше приложение по-прежнему находится на дополнительном url-адресе, но автоматически отображается, когда пользователь переходит в корень вашего сайта. Это позволяет вам иметь /images / bob.img все еще идет в обычное место, но ' / ' - это ваше приложение.

Если вы используете Tomcat, вы можете сопоставить ресурсы с сервлетом по умолчанию:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

и доступ к ресурсам с url http://{context path}/static / res/...

также работает с Jetty, не уверен в других контейнерах сервлетов.

обслуживание статического контента с соответствующим суффиксом в нескольких определениях сопоставления сервлетов решило проблему безопасности, которая упоминается в одном из комментариев в одном из опубликованных ответов. Цитируется ниже:

Это была дыра безопасности в Tomcat (содержимое WEB-INF и META-INF доступно таким образом), и она была исправлена в 7.0.4 (и будет перенесена на 5.x и 6.х также). - BalusC 2 '10 ноября в 22: 44

это мне очень помогло. А вот как я решил ее:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>

начиная с 3.0.4 вы должны быть в состоянии использовать mvc:resources в сочетании с mvc:default-servlet-handler как описано в весенний документации для достижения этой цели.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources

причина столкновения, по-видимому, заключается в том, что по умолчанию корневой контекст " / " должен обрабатываться организацией.апаш.Каталина.сервлеты.DefaultServlet. Этот сервлет предназначен для обработки запросов на статические ресурсы.

Если вы решите убрать его с вашего собственного сервлета, с целью обработки динамических запросов, этот сервлет верхнего уровня также должен выполнять любые задачи, выполняемые оригинальным обработчиком catalina "DefaultServlet".

Если вы читали через документы tomcat они упоминают, что True Apache (httpd) лучше, чем Apache Tomcat для обработки статического контента, поскольку он специально создан для этого. Я думаю, потому что Tomcat по умолчанию использует org.апаш.Каталина.сервлеты.DefaultServlet для обработки статических запросов. Поскольку все это завернуто в JVM, а Tomcat предназначен для контейнера Servlet/JSP, они, вероятно, не писали этот класс как супер-оптимизированный статический обработчик контента. Это здесь. Он выполняет свою работу. Хороший достаточно.

но это то, что обрабатывает статический контент, и он живет в "/". Поэтому, если вы положили туда что-то еще, и эта вещь не обрабатывает статические запросы, упс, там идут ваши статические ресурсы.

Я искал повсюду Один и тот же ответ, и ответ, который я получаю везде, - "если вы не хотите, чтобы это было так, не делайте этого".

короче говоря, ваша конфигурация вытесняет статический обработчик ресурсов по умолчанию с помощью что-то, что не является статическим обработчиком ресурсов вообще. Вам нужно будет попробовать другую конфигурацию, чтобы получить результаты, которые вы ищете (как и я).

"статические" файлы в App Engine не доступны непосредственно вашим приложением. Вам нужно либо загрузить их дважды, либо обслуживать статические файлы самостоятельно, а не использовать статический обработчик.

лучший способ справиться с этим-использовать какой-то переписывание URL. Таким образом, вы можете иметь чистые restful URL-адреса, а не с любыми расширениями, т. е. abc.com/welcom/register в отличие от abc.com/welcome/resister.html

Я использую Tuckey URL это круто.

Он получил инструкции о том, как настроить веб-приложения.Я установил его с помощью своего веб-приложения Spring MVC. Конечно, все было хорошо, пока я не захотел использовать аннотации для проверки Spring 3 как @Email или @Null для объектов домена.

когда я добавляю директивы Spring mvc:

< mvc:annotation-driven  /> 
< mvc:default-servlet-handler />

.. это нарушает хороший код Ol Tuckey. Видимо,< mvc:default-servlet-handler /> заменяет Tuckey, который я все еще пытаюсь решить.

добавьте папки, которые вы не хотите запускать обработку сервлетов в <static-files> раздел вашего appengine-web.XML-файл.

Я только что сделал это и похоже, что все начинает работать нормально. Вот моя структура:

/

/ pages/<.jsp>

/ css

я добавил "/ pages / ** " и "/ css/** " к <static-files> раздел и теперь я могу перейти к a .JSP-файл изнутри сервлета doGet, не вызывая бесконечного цикла.

после безуспешной попытки фильтровать подход (он почему-то не вошел в функцию doFilter ()) я немного изменил свою настройку и нашел очень простое решение для проблемы корневого обслуживания:

вместо того, чтобы служить " / * " в моем основном сервлете я теперь слушаю только выделенные языковые префиксы "АН", "АН/ *", "ДЕ", "ДЕ -/ *"

статический контент обслуживается сервлетом по умолчанию и пустые корневые запросы идут в индекс.jsp, который вызывает мой основной сервлет с язык по умолчанию:

(никакого другого контента на странице индекса.)

Я обнаружил, что с помощью

<mvc:default-servlet-handler />

весной MVC servlet bean definition file работает для меня. Он передает любой запрос, который не обрабатывается зарегистрированным контроллером MVC, в исходный обработчик контейнера по умолчанию, который должен служить ему статическим содержимым. Просто убедитесь, что у вас нет зарегистрированного контроллера, который обрабатывает все, и он должен работать просто отлично. Не уверен, почему @logixplayer предлагает перезапись URL; вы можете достичь эффекта, который он ищет, просто адекватно использование только Spring MVC.

Я бы рекомендовал использовать фильтр вместо сервлета по умолчанию, когда это возможно.

другие две возможности:

написать FileServlet себя. Вы найдете множество примеров, надо просто открыть файл по URL и записать его содержимое в выходной поток. Затем используйте его для обслуживания статического запроса файла.

создайте экземпляр класса FileServlet, используемого Google App Engine и службой вызовов (запрос, ответ) на этом файловом сервере, когда вам нужно обслуживать статический файл по заданному URL.

вы можете сопоставить /res / * с вашим Fileservlet или что-то еще, чтобы исключить его из обработки DispatcherServlets, или вызвать его непосредственно из DispatcherServlet.

и, я должен спросить, что говорит Весенняя документация об этом столкновении? Я никогда им не пользовался.

Я нашел более простое решение с фиктивным индексным файлом.

создайте сервлет (или используйте тот, который вы хотели ответить на"/"), который сопоставляется с "/index.формат html" (Решения, упомянутые здесь, используют отображение через XML, я использовал версию 3.0 с аннотацией @WebServlet) Затем создайте статический (пустой) файл в корне статического содержимого с именем "index.html"

Я использовал Jetty, и произошло то, что сервер распознал файл вместо перечисления каталога, но когда попросил ресурс, вместо этого мой сервлет взял под свой контроль. Все остальные статические материалы остались без изменений.

в Embedded Jetty мне удалось добиться чего-то подобного, добавив отображение для каталога "css" в интернете.XML. Явно говоря ему использовать DefaultServlet:

<servlet>
  <servlet-name>DefaultServlet</servlet-name>
  <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>DefaultServlet</servlet-name>
  <url-pattern>/css/*</url-pattern>
</servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>

и если вы хотите использовать конфигурацию на основе аннотаций, используйте ниже код

@Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }