Можно ли настроить SpringMVC для обработки всех запросов, но исключить статические каталоги содержимого? - PullRequest
58 голосов
/ 05 августа 2009

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

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

Моя текущая конфигурация web.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 голосов
/ 29 декабря 2010

ПРИМЕЧАНИЕ: этот ответ относится ТОЛЬКО к Spring 3.0.4+

(Кстати, этот вопрос также был рассмотрен здесь: Spring, обслуживающий статический контент с mvc: resources, invalid xsd )

Ознакомьтесь с проектом Spring mvc-showcase в репозитории примеров Subversion Spring . Он показывает, что именно вы хотите сделать, а именно то, что вы можете разграничить статические ресурсы, которые не будут обрабатываться 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/" />
27 голосов
/ 10 августа 2009

Я решил, передавая статический контент через сервлет «по умолчанию», который просто передает контент клиенту. Так что мой web.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 -->

Надеюсь, это поможет.

7 голосов
/ 05 августа 2009

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

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

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

4 голосов
/ 15 ноября 2012

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

<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...
3 голосов
/ 05 августа 2009

Один из способов сделать это - использовать фильтры. Вы должны написать немного собственного кода, но это не плохо. Вот пример, если вы не хотите передавать файлы * .css или * .js в ваш сервлет Spring:

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;
    }
}

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

РЕДАКТИРОВАТЬ : В спецификации сервлета нет никаких исключающих функций. Я не думаю, что есть хороший способ сделать это в Spring, но он, по сути, достигает того же в вашем посте.

РЕДАКТИРОВАТЬ 2 : Если вы хотите иметь возможность легко изменять то, что фильтруется, вы можете просто использовать Spring для добавления чего-либо в Фильтр во время выполнения.

РЕДАКТИРОВАТЬ 3 : Я только что понял, что если вы перейдете прямо к файлу, он снова выполнит фильтр, и вы попадете в бесконечный цикл. Может быть другой способ сделать это с фильтрами, но я, честно говоря, не уверен, что это такое.

2 голосов
/ 22 сентября 2015

У меня такая же проблема, и вот как я ее решил:

В файл web.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>

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

<mvc:annotation-driven /> 
<mvc:default-servlet-handler />
2 голосов
/ 05 августа 2009

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

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

JkUnMount /*.css  webapp

Где 'webapp' - это запись из вашего works.properties.

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

0 голосов
/ 14 декабря 2015

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

это была моя проблема @RequestMapping (method = RequestMethod.GET)

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

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

и все работает

найдите контроллер с плохим @RequestMappgin и измените его.

0 голосов
/ 06 марта 2014

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

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

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

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

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

На стороне клиента

ссылается на ваши статические файлы следующим образом:

<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">

Вот моя ссылка.

0 голосов
/ 03 июля 2013

Я использую виртуальный 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);
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...