developer tip

모든 요청을 처리하도록 SpringMVC를 구성 할 수 있지만 정적 컨텐츠 디렉토리는 제외 할 수 있습니까?

optionbox 2020. 12. 12. 10:38
반응형

모든 요청을 처리하도록 SpringMVC를 구성 할 수 있지만 정적 컨텐츠 디렉토리는 제외 할 수 있습니까?


들어오는 모든 요청 ( '/ *')을 처리하도록 스프링 애플리케이션을 매핑하면 정적 콘텐츠 요청이 404를 반환합니다. 예를 들어 "myhost.com/css/global.css"에 대한 요청은 Spring이 요청을 가로 채기 때문에 리소스가 존재하더라도 404를 반환합니다.

대안은 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>

이런 종류의 것이 가능합니까?


Spring만으로 이것을하고 싶다면 가능하지만 약간 지저분합니다.

  1. 컨트롤러에 매핑되어야하는 URL 패턴을 명시 적으로 지정하거나 "css / **"와 같은 "무시"URL을 지원하도록 확장 할 수 있는 SimpleUrlHandlerMapping 을 사용해야합니다.
  2. 요청 된 리소스를있는 그대로 반환하려면 기본적으로 "getServletContext (). getRequestDsipatcher (). include ()"호출로 구성되는 고유 한 HttpRequestHandler 구현 을 작성해야합니다 .
  3. 위의 SimpleUrlHandlerMapping에 대해 해당 핸들러를 defaultHandler로 등록해야합니다.

모든 작업이 완료되면 컨트롤러에 매핑 할 수없는 모든 요청이 사용자에게 전달되어 HttpRequestHandler"있는 그대로"제공됩니다.


참고 :이 답변은 Spring 3.0.4+에만 적용됩니다.

(BTW,이 질문은 여기서도 다루었습니다 : Spring은 mvc : resources, invalid xsd로 정적 콘텐츠를 제공합니다 )

Spring subversion 샘플 저장소 에서 Spring mvc-showcase 프로젝트를 확인하십시오 . 즉, 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/" />

클라이언트에게 콘텐츠를 제공하는 '기본'서블릿을 통해 정적 콘텐츠를 제공하여 해결했습니다. 따라서 내 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 -->

도움이 되었기를 바랍니다.


나에게 가장 간단한 방법은 (늦은 버전의 Spring을 사용하는 경우)

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

이를 수행하는 한 가지 방법은 필터를 사용하는 것입니다. 약간의 사용자 지정 코드를 작성해야하지만 나쁘지 않습니다. 다음은 * .css 또는 * .js 파일을 Spring 서블릿에 전달하지 않으려는 경우의 예입니다.

web.xml :

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

자바 클래스 :

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 : 파일로 직접 전달하면 필터가 다시 수행되고 무한 루프에 빠질 것임을 깨달았습니다. 필터로이를 수행하는 다른 방법이있을 수 있지만 솔직히 그것이 무엇인지 잘 모르겠습니다.


정적 이미지를 제공하기 위해 무엇을 사용하고 있습니까? Apache 인 경우 css / js 요청을 앱 서버에 전달하지 않도록 Apache를 구성 할 수 있습니다.

Tomcat을 사용하는 경우 httpd.conf에 다음과 같이 입력합니다.

JkUnMount /*.css  webapp

여기서 'webapp'은 workers.properties의 항목입니다.

순수한 Spring 솔루션을 줄 수 없어서 미안하지만 이것이 내가하는 방법입니다.


나는 같은 문제가 있었고 여기에 내가 어떻게 해결했는지가 있습니다.

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>

다음은 spring3 MVC 서블릿 빈 정의 파일 (예 : web.xml에서 contextConfigLocation으로 구성된 파일 인 applicationContext.xml)에 추가되었습니다.

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

Spring 디스패처에서 처리하려는 요청에 대해 일관된 확장이 있습니까 (대부분의 Spring 예제에서 * .htm을 사용한다고 생각합니다)? 이 경우 css 및 js 파일을 우회하는 처리하려는 확장에 매핑 할 수 있습니다.

그렇지 않으면 Nalandial에 동의 할 것입니다.이 시점에서 필터 접근 방식이 아마도 최선의 해결 방법 일 것입니다.


가상 URL 경로를 사용하여 필요한 리소스를 검색합니다. 일반적으로 Spring MVC를 사용하므로 / WEB-INF / views 폴더 아래에 자바 스크립트와 CSS를 사용할 수 없습니다. 이 사용자 정의 서블릿은 / WEB-INF / views 폴더 내의 .js 및 .css 파일에 대한 액세스 만 허용합니다. 귀하의 경우 / 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에서 제공하는 솔루션을 사용해야합니다.

그렇지 않으면 다음과 같은 간단한 일을 할 수 있습니다 .

perhaps you have following static directory structure you want to serve:

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

Eclipse Dynamic web projects by default generate following structure: WebContent/WEB-INF. Move the public folder out of your WEB-INF directory into WebContentdirectory.

On client side

refer your static files in following way:

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

Here is my reference.


In my case everything was ok. But i have a problem in a Controller

that was my problem @RequestMapping( method = RequestMethod.GET)

y change for this:

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

and it works

look for a controller that has bad @RequestMappgin and change.


It's cleaner to use UrlRewriteFilter to redirect the request to your servlet, here an example of urlrewrite.xml

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

NOTES:

  • It's important the last <rule> is in the bottom so img, js, css will be caught first
  • The <outbound-rule> is optional and is just to make the existing
    <c:url value="/app/some" /> render /some instead of /app/some

Usually, big websites prefer using another server only to handle static content. Requests of static content goes to one server and dynamic goes to another (with spring, in this case).

In many cases, Nginx server (http://nginx.com/), a recent and very fast server.

But this is not trivial to do. A lot of configurations.

참고URL : https://stackoverflow.com/questions/1234298/can-springmvc-be-configured-to-process-all-requests-but-exclude-static-content

반응형