Можно ли настроить SpringMVC для обработки всех запросов, но исключить каталоги статического содержимого?


Если я сопоставляю свое приложение spring для обработки всех входящих запросов ( '/ * ' ), то запросы на статическое содержимое возвращают 404's. например, запрос на "myhost.com/css/global.css" вернул бы 404, хотя ресурс существует, поскольку Spring перехватывает запрос.

альтернативой является сопоставление SpringMVC с подкаталогом (например ' / home/'), но в этом случае вы должны передать этот каталог во всех ссылках внутри приложения. Есть ли способ, чтобы карту к инфраструктуре springmvc - / и исключить набор каталогов из обработки?

мой нынешний веб.конфигурация xml:

<servlet>
    <servlet-name>springApp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

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

В идеале я хотел бы, чтобы отображение было чем-то вроде следующего:

 <servlet-mapping>
    <servlet-name>springApp</servlet-name>
    <url-pattern>/*</url-pattern>
    <exclude>/css/*,/js/*</exclude>
 </servlet-mapping>

возможно ли такое?

13 56

13 ответов:

Если вы хотите сделать это только с весной, это возможно, но немного грязно:

  1. вы должны использовать SimpleUrlHandlerMapping для которого вы можете явно указать шаблоны URL, которые должны быть сопоставлены с контроллерами или расширить его для поддержки "игнорировать" URL-адреса, такие как "css/**".
  2. вам нужно будет написать свой собственный HttpRequestHandler реализация, которая в основном будет состоять из "getServletContext().getRequestDsipatcher ().include () " вызов для возврата запрошенного ресурса как есть.
  3. вы должны будете зарегистрировать этот обработчик как defaultHandler для вышеупомянутого SimpleUrlHandlerMapping.

Как только все это будет сделано, все запросы, которые не могут быть сопоставлены с вашими контроллерами, будут перенаправлены на ваш HttpRequestHandler и подаются "как есть".

Примечание: этот ответ относится только к Spring 3.0.4+

(кстати, этот вопрос также рассматривался здесь: пружина обслуживания статического контента с MVC:ресурсы, поврежденных xsd-схемы)

Проверьте проект Spring mvc-showcase весной Subversion samples repository. Он показывает именно то, что вы хотите сделать, а именно, что вы можете определить статические ресурсы, которые не будут обрабатываться DisapatcherServlet. См. файл /mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml. Вот фрагмент того, как я обрабатываю эти исключения, где JS, CSS и изображения находятся в корневом контексте приложения (с пространством имен MVC, сопоставленным с mvc:

<!-- resources exclusions from servlet mapping -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />

Я решил, обслуживая статический контент через сервлет "по умолчанию", который просто обслуживает контент клиенту. Так что моя паутина.XML выглядит так:

<servlet>
    <servlet-name>MyApp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>MyApp</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping> <!-- The 'dynamic' content -->

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping> <!-- The 'static' content -->

надеюсь, что это помогает.

самый простой способ для меня (если использовать достаточно позднюю версию Spring) - это

<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...

один из способов сделать это будет с фильтрами. Вам придется написать немного пользовательского кода, но это не плохо. Вот пример, если вы не хотите проходить *.css или *.JS файлы для вашего весеннего сервлета:

web.XML-код:

<filter-mapping>
    <filter-name>fileTypeFilter</filter-name>
    <filter-class>foo.FileTypeFilter</filter-class>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Java-класс:

public class FileTypeFilter implements Filter {
     public void init(FilterConfig conf) {
         // init logic here
     }

     public void destroy() {
        // release resources here
     }

     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
          if(shouldExclude(req)) {
              chain.doFilter(req, res);
              //some logic so the request doesnt go to the servlet

              //maybe you could just forward
              //the request directly to the file getting accessed.  not sure if that would work
          }

          //file should be passed to the servlet; you can do some logic here
          //if you want         
     }
     private boolean shouldExclude(ServletRequest req) {
         if(req instanceof HttpServletRequest) {
             HttpServletRequest hreq = (HttpServletRequest) req;
             return (hreq.getRequestURI().endsWith(".css") ||
                     hreq.getRequestURI().endsWith(".js"));
         }
         return false;
    }
}

Я не проверял это, но я думаю, что это будет работать.

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

EDIT 2: если вы хотите легко изменить то, что фильтруется, вы можете просто использовать Spring, чтобы ввести что-то в фильтр во время выполнения.

редактировать 3: я только что понял, что если вы перейдете непосредственно к файлу, он снова сделает фильтр, и вы попадете в бесконечный цикл. Может быть, есть другой способ сделать это с фильтрами, но я честно не уверен, что это.

что вы используете для обслуживания статических изображений? Если это Apache, то вы можете настроить Apache, чтобы не передавать запросы css/js на сервер приложений.

Если вы используете Tomcat, вы бы поместили что-то вроде этого в свой httpd.conf:

JkUnMount /*.css  webapp

где 'webapp' - это запись от ваших работников.свойства.

Извините, я не могу дать вам чистый весенний раствор, но вот как я это делаю.

Я получил ту же проблему, и вот как я ее решил:

в Сеть было добавлено следующее.xml-файл:

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

в файл определения компонента сервлета spring3 MVC (например, applicationContext.xml, файл, настроенный в web.xml как contextConfigLocation.):

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

есть ли у вас последовательное расширение(ы) для запросов, которые вы хотите обработать Spring dispatcher (я считаю, что большинство примеров Spring используют a *.htm)? В этом случае вы можете сопоставить расширения, которые вы хотите обработать, которые обойдут ваши файлы css и js.

в противном случае я бы согласился с Nalandial, подход фильтра, вероятно, лучшая работа вокруг на данный момент.

Как правило, крупные сайты предпочитают использовать другой сервер только для обработки статического контента. Запросы статического контента идут на один сервер, а динамического - на другой (в данном случае с spring).

во многих случаях, сервер Nginx (http://nginx.com/), недавний и очень быстрый сервер.

но это не тривиально сделать. Много конфигураций.

Я использую виртуальный URL-адрес для получения нужного мне ресурса. Обычно я использую Spring MVC, поэтому я не мог иметь javascripts и css в папке /WEB-INF/views. Я придумал этот пользовательский сервлет, чтобы только разрешить доступ .js & .файлы css в папке/WEB-INF / views. В вашем случае, если вы переместите папку /css и папку /js в родительскую папку, такую как /resource, тогда мое решение будет применимо к вам.

вы можете изменить строку url = "YOUR_RESOURCE_FOLDER"

Так например, виртуальный путь может быть чем-то вродеhttp://www.mysite.com/resources/path/path/app.js

это будет отображаться на мой / WEB-INF / views/path/path / app.js

web.xml

<servlet>
    <servlet-name>ResourceDispatcherServlet</servlet-name>
    <servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>ResourceDispatcherServlet</servlet-name>
    <url-pattern>/resource/*</url-pattern>
</servlet-mapping>

сервлет

public class ResourceDispatcherServlet extends HttpServlet {

    public void init() throws ServletException {

    }

    public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {


        String servletPath = req.getServletPath();   // /resource
        String pathInfo = req.getPathInfo();         // /path/path/app.js

        String url = "/WEB-INF/views" + pathInfo;

        String lastPath = StringUtil.substringAfterLast(pathInfo, "/");
        String extension = StringUtil.substringAfterLast(lastPath, ".");

        try {
            RequestDispatcher dispatcher = null;
            if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension))) {
                dispatcher = req.getRequestDispatcher(url);
            }

            if (dispatcher != null) {
                dispatcher.include(req, rsp);
            }
            else {
                rsp.sendError(404);
            }
        }
        catch (Exception e) {
            if (!rsp.isCommitted()) {
                rsp.sendError(500);
            }
        }
    }
}

если вы используете Spring 3.0.4 и выше, вы должны использовать решение atrain

в противном случае, вы можете сделать это простой всего:

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

WebContent
   |
   WEB-INF
     |
    public
        |
       css
        |
       js
        |
       img

Eclipse динамические веб-проекты по умолчанию генерируют следующую структуру:WebContent/WEB-INF. Двигай public папка из вашего каталога WEB-INF в

это чище использовать UrlRewriteFilter чтобы перенаправить запрос на ваш сервлет, вот пример urlrewrite.xml

<urlrewrite>
    <rule>
        <from>^/img/(.*)$</from>
        <to>/img/</to>
    </rule>
    <rule>
        <from>^/js/(.*)$</from>
        <to>/js/</to>
    </rule>
    <rule>
        <from>^/css/(.*)$</from>
        <to>/css/</to>
    </rule>
    <rule>
        <from>^/(.*)$</from>
        <to>/app/</to>
    </rule>
    <outbound-rule>
        <from>/app/(.*)$</from>
        <to>/</to>
    </outbound-rule>
</urlrewrite>

Примечания:

  • важно последнее <rule> находится в нижней части, поэтому img, js, css будут пойманы первыми
  • The <outbound-rule> - это необязательным и просто сделать существующий
    <c:url value="/app/some" /> оказать /some вместо /app/some

в моем случае все было ок. Но у меня есть проблема в контроллере

Это была моя проблема @RequestMapping (method = RequestMethod.Получите)

y изменение для этого:

@RequestMapping(value = "/usuario", method = RequestMethod.GET)

и работает

ищите контроллер, который имеет плохой @RequestMappgin и изменения.