며칠전 스프링 3.0.4가 나왔다. 3.0.1 이후 마이너 업그레이드는 거의 자잘한 버그 수정이거나 최신 버전 서드-파티 툴 지원(확인)이 전부였는데 3.0.4에는 눈에 띄는 새로운 기능이 추가된 것이 있다. @MVC에서 세 가지를 찾아 볼 수 있다.  @ModelAttributge 모델이 아닌 단순 @RequestParam 등에서도 포매터를 사용하게 된 것과 mvc 스키마에 새롭게 추가된 전용 태그 두개이다.

3.0.4 내용을 모두 확인하고 추가된 기능 등을 토비의 스프링 3에 반영해서 다음 인쇄시 적용해 달라고 할 수도 있겠지만, 버전 업그레이드를 시도하는 것은 생각보다 부담이 큰 작업이다. 3.0.4만 해도 개발 스타일을 바꾸고 싶은 것이 있어서 예제도 손을 좀 봐야 하고. 그래서 일단 블로그에 그런 내용을 정리해보기로 했다.

 

3.0.4의 변경사항 중에서 그 중에서 가장 내 관심을 끈 것은 바로 <mvc:default-servlet-handler/>이다. 이를 이용하면 그동안 안쓰자니 불편하고 쓰자니 지저분해 보였던 UrlRewriteFilter를 제거할 수 있게 됐다. 그런데 UrlRewriteFilter 따위는 왜 쓰게 됐을까?

여러 가지 이유를 댈 수 있겠지만 가장 큰 것은 RESTful 스타일의 URL을 사용하고 싶기 때문이다. RESTful 스타일 URL의 특징의 하나는 확장자를 쓰지 않는 것이다.  기존엔 주로 컨트롤러에 매핑되는 URL을 login.do니 login.action이니 하는 식으로 특정 확장자를 주어서 만들었다. 그래서 스프링의 프론트 컨트롤러인 DispatcherServlet의 서블릿 매핑을 *.do나 *.action 처럼 주면 됐다. URL의 서브 디렉토리는 어떻게 잡아도 상관없어서 이 방식이 가장 편하긴 하다.

그런데 RESTful 스타일에선 이렇게 확장자를 잘 쓰지 않는다. 여러가지 스타일이 있지만 보통 리소스 이름을 경로로 쓰고 그 뒤에 의미있는 추가 경로를 붙이거나 HTTP요청 메소드(GET,POST,PUT 등등)를 바꿔서 활용하는 식이다. 그래서 URI가 보통 /user니 /user/1, /user/1/edit 이런식으로 만들어진다. 따라서 특정 확장자를 사용할 수 없다.

문제는 스프링이 이런 URL을 처리하게 하려면 웹 애플리케이션에 기본으로 등록된 다른 서블릿과 중복이 되지 않게 만들어줘야 한다. 보통 서블릿 컨테이너에는 스태틱 리소스(HTML, 자바 스크립트, CSS, 이미지 등)를 처리하는 디폴트 서블릿과 JSP를 처리하는 JSP 서블릿이 기본으로 등록되어있다. 디폴트 서블릿은 /에 매핑되어 있고 JSP는 확장자를 이용해서 *.jsp로 되어있다. 그리고 여기에 추가로 서블릿을 등록하면 URL 우선순위(매핑 조건이 긴게 우선)에 따라서 그 서블릿의 매핑에 해당하는 것은 등록된 것으로 가고 나머지는 디폴트 서블릿이나 JSP 서블릿이 담당한다. 스프링을 *.do와 같이 사용할 땐 그래서 문제가 없었다. 그런데 경로만 있는 URL로 가니 얘기가 달라졌다.

디폴트 서블릿을 안쓸 수는 없다. 따라서 스프링 서블릿(DispatcherServlet)을 /에 매핑할 수는 없다. 그러면 DispatcherServlet가 모든 스태틱 리소스까지 처리해줘야 한다. 그래서 보통 /app와 같은 서브폴더를 만들고 그 아래로 오는 요청을 스프링의 DispatcherServlet이 담당하게 만든다. DispatcherServlet의 매핑을 /app/나 /app/* 등으로 하고, URL은 /app/user, /app/user/1, /app/user/1/edit 이렇게 썼다.

그런데 app가 계속 붙으니 안이쁘다. 폼나게 RESTful하게 보이려면 도메인 이름 뒤에 바로 리소스 이름이 나오는게 좋다. 그냥 http://toby.epril.com/article/1 이런 식으로.

그래서 스프링 사용자들이 슬슬 사용하기 시작한게 UrlRewriteFilter다. 이 필터는 서버로 온 URL을 애플리케이션으로 넘길 때 강제로 변경해주는 역할을 한다.  UrlRewriteFilter은 서블릿의 매핑보다 세밀한 제어가 가능하기 때문에 원하는 방식으로 URL을 작성할 수가 있다. 일단 모든 스태틱 리소스는 /resource 등에 위치시킨다. 그리고 스프링 DispatcherServlet은 그냥 /app와 같은 서브 폴더에 매핑시킨다. 그런다음 UrlRewriteFilter를 적용한다.

스태틱 리소스인 /resource는 그냥 /resource로 그대로 가도록 한다. 대신 그 외의 /로 시작하는 경로는 앞에 /app를 붙이도록 만들어주는 것이다. 그러면 /resource로 시작하지 않는 모든 URL은 /app가 앞에 붙어서 넘어가므로 /app로 매핑을 해둔 DispatcherServlet처리하고 나머지는 그대로 URL이 유지되므로 디폴트 서블릿이 처리할 수 있는 것이다.

이렇게 해서 깔끔한 URL을 만들어 사용할 수 있긴한데, 제법 복잡한 UrlRewiteFilter를 공부해서 사용해야 한다는 번거로움이 있다. 그래서 책에도 UrlRewriteFilter를 사용하는 방법을 넣을까 하다가 독자들 머리만 더 아플까 해서 그냥 뺐다. 예제도 덜 이쁘지만 /app로 시작하는 URL을 그냥 사용하도록 했고. RESTful URL을 사용하는 ROO에서 사용한 UrlRewriteFilter를 보면 꽤나 복잡하다.

그런데 이런 불만이 나만 있던 것은 아니었나보다. UrlRewriteFilter를 쓰지 않고 스프링 DispatcherServlet을 /에 매핑해서 쓰면 안될까? 스프링에 안되는 게 어딨겠나. 결국 스프링 개발자들은 3.0.4에서 <mvc:default-servlet-handler/>를 추가해서 이 문제를 깔끔하게 해결해버렸다.

 

사용방법은 간단하다.

일단 DispatcherServlet을 그냥 /에 매핑한다. jsp와 같은 특정 확장자를 가진 URL말고는 모두 DispatcherServlet이 다 받는다. 일단 스프링의 기본 등록된 핸들러 매핑 전략을 이용해서 컨트롤러를 매핑해본다. @Controller가 담당하는 URL이라면 그리로 넘어갈거고. 그런데 그러다보면 /js/jquery.js 처럼 컨트롤러에 매핑안되는 URL이 나올 것이다. 이런 나머지 모든 URL은 <mvc:default-servlet-handler/>이 내부적으로 등록해주는 DefaultServletHttpRequestHandler이 담당한다. 이 핸들러(컨트롤러)는 /**로 매핑되어있다. 대신 핸들러 매핑 우선순위가 가장 낮다. 따라서 애노테이션 매핑 등등을 거쳐서 다 실패한 URL만 넘어온다. 그리고 DefaultServletHttpRequestHandler는 이 요청을 자신이 직접 스태틱 리소스를 읽어서 처리하는 것이 아니라, 원래 서버가 제공하는 디폴트 서블릿으로 넘겨버린다. 그러면 서버의 기본 디폴트 서블릿이 동작해서 스태틱리소스를 처리해버리는 것이다. 일단 스프링이 다 받고 스프링이 처리 못하는 건 다시 서버의 디폴트 서블릿으로 넘긴다는 아이디어이다. 멋지지 않은가?

그런데 사실 아이디어는 간단하지만 구현은 쉽지 않다. 디폴트 서블릿을 찾아서 사용하는 건 일반적인 접근방법이 아니다. 서블릿 스펙 2.0 부터는 하나의 서블릿이 다른 서블릿을 직접 찾아서 실행할 수 있는 방법을 막아버렸다. 그래서 ServletContext의 getServlets() 나 getServletNames()와 같은 메소드는 무조건 null을 리턴하도록 스펙에 명시되어있다. 대신 스프링은 URL 대신 이름을 이용해서 RequestDispatcher를 가져오는 getNamedDispatcher() 메소드를 이용한다. 물론 디폴트 서블릿 이름을 알고 있어야 하는데, 그건 스프링 개발자들이 주요 서버의 디폴트 서블릿 이름을 다 조사해놨다. 톰캣, 제티, JBoss, 글래스 피시는 이름이 default, Resin은 resin-file, WebLogic은 FileServlet, WebSphere는 SimpleFileServlet이다. 이 서버들의 디폴트 서블릿 이름은 자동으로 찾아준다. 그 외의 서버라면 디폴트 서블릿 이름을 직접 주면 된다. 보통 서버의 설정 폴더에 보면 디폴트 web.xml이 다 나와있다. 그걸 열어보면 디폴트 서블릿 이름을 알 수 있다. 톰캣이라면 conf 밑의 web.xml에서 찾을 수 있다.

톰캣 6에 보면 디폴트 서블릿이 다음과 같이 등록되어있다.

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
     …
    <load-on-startup>1</load-on-startup>
</servlet>

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

 

이제 3.0.4를 사용하면 특별한 이유가 아니라면 UrlRewriteFilter를 사용할 필요가 없다. 혹시 스태틱 리소스의 경로를 다이나믹하게(버전 폴더를 바꾼다거나) 바꾸는 필요가 있다면, 그때는 3.0.4에 함께 추가된 <mvc:resource>를 사용하면 된다. 그건 다음 시간에.

참. GAE에서는 이 기능을 사용할 수 없다. 구글이 수정한 GAE의 Jetty 소스를 보면 이 getNamedDispatcher()가 항상 null을 리턴하도록 해놨다. 리소스 접근에 제약을 걸어야 하기 때문에 코드를 통해서 디폴트 서블릿에 접근하는 것을 원천적으로 차단한 것이다.

Related posts:

  1. Spring 3.0 (22) Web.Servlet 모듈의 선택 라이브러리 분석
  2. Spring 3.0 (36) Field Marker와 Field Default
  3. Maven의 default directory layout 변경하기
  4. DispatcherServlet의 디폴트 대체(fallback) 전략
  5. 미국여행을 위한 전자허가는 Spring을 이용해서
  6. 토비의 스프링 3이 나오기까지 (2)
  7. 토비의 스프링 3이 나오기까지 (7)
  8. 토비의 스프링 3이 나오기까지 (11)
  9. [토스3] 테스트를 위한 필드 주입 유틸
  10. Spring 3.0 (21) Web 모듈의 선택 라이브러리 분석
  11. Spring 3.0.2 모듈 의존관계
  12. Spring 3.0.1 mvc:annotation-driven 이 몰래 하는 짓
  13. InsideSpring (3) 스프링 밖에서 WebApplicationContext에 접근하기
  14. 블로그 업데이트, 스킨 교체, SNS(FB,TW,M2,BZ) 공유기능 추가
  15. 토비의 스프링 3이 나오기까지 (3)

Facebook comments:

to “[토스3] 스프링 3.0.4 <mvc:default-servlet-handler/>를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기”

  1. 캬.. 마지막엔 GAE 까정.. 역시!! 최고;

  2. 스프링 설정에 어노테이션만 사용하려고 xml 파일을 아침에 모두 지웠는데,
    설정을 Java 코드로 하는 방법은 아직 문서에 없는 것 같네요. =o=

    덧: 책 감사히 보고 있습니다. 회사서 5 권 사서 직원들과 열독중입니다.

  3. drypot/ 제 책의 10장에 보면 XML을 전혀 사용하지 않고 스프링 설정을 만드는 방법이 나와있습니다. 하지만 스키마(tx, aop, view, context 등등) 태그를 사용할 수 없어서 좀 불편하실거에요. 각 스키마 태그에서 내부적으로 사용하는 자바 코드에서 유틸리티 메소드를 이용해서 직접 인프라스트럭처 빈을 등록해야 하기 때문에 스프링 내부 구현에 관한 지식이 좀 필요합니다.

  4. 답변 감사합니다.

    서블릿 매핑으로 돌아가볼까 했는데 Tomcat DefaultSevlet 은 “/” 기본 매핑외에는
    정상작동하지 않는다는 사실을 알고 또 좌절,
    mvc:default-servlet-handler 태그 때문에 그냥 스프링 컨텍스트 XML 을 부활시켜야 할 것 같습니다. ^^

  5. 이 글을 읽고서 저는는 왜 과거에 UrlRewriteFilter를 쓴 기억이 전혀 없나 뒤돌아봤더니..
    지난번 프로젝트에서는 default servlet 을 web.xml 에서 *.png, *.html, *.jpg, *.js, *.css 등등으로 직접 매핑해서 해결했더군요. 어차피 static resource의 종류가 그리 많지 않아서 어렵지는 않았었습니다. 물론 개발/운영 모두 tomcat을 썼기에 web.xml이 변할 이유가 없었죠.

    하지만 이런 간단한 삽질조차도 필요없어졌다니, 스프링 너무 좋아지네요.

  6. 권남/ 디폴트 서블릿 매핑을 바꾸는 방법을 저도 잠깐 시도해봤는데 디폴트 서블릿의 매핑을 바꾸는 것을 허용하지 않는 WAS가 있다고 해서 포기했던 기억이 있어요.

  7. 항상 도움 많이 받고 있습니다.
    잘되던 JUNIT Controller test 가 를 사용하면 아래와 같은 오류메시지가 뜨면서 안됩니다. 뭐가 문젤까요?
    http://kingori.egloos.com/4445901 를 참고로 만든 test도 그렇고, appfuse src(http://kingori.egloos.com/4445901) test도 마찬가지입니다. 구글선생님에게 물어도 잘 못찾겠네요…

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0′: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Unable to locate the default servlet for serving static content. Please set the ‘defaultServletName’ property explicitly.

  8. 어 밑에 내용을 잘 보지도않고 올려서 내용이 깨져서 올라갔네요. 다시 정리하면
    default-servlet-handler 를 사용할 경우 controller junit test에서 오류가 뜹니다.(Please set the ‘defaultServletName’ property explicitly)

    controller test 소스는 오리대마왕님이 제시한 방식이나 appfuse 에서 제시한 방식이나 마찬가지입니다.
    http://kingori.egloos.com/4445901
    http://bit.ly/bUkT92

  9. Justdev/ default-servlet-handler는 WAS가 등록한 default servlet을 찾게 되어있습니다. 못찾으면 에러가 나죠. 그런데 일반적인 controller 테스트를 만들면 이 default servlet이 존재하지 않겠죠. 단지 테스트 코드에서 스프링 dispatch servlet만 만드니까요.
    테스트에서는 default servlet이 적용되서 리소스를 가져올 필요가 없으니 이를 무시하도록 만들어줘야 합니다. 이 글을 잘 보시면 힌트가 있습니다.
    제 책(토비의 스프링 3)의 12, 13장에 나오는 컨트롤러 테스트 방법을 사용하셨다면 구체적인 방법을 알려드렸겠지만, 제 블로그에 오셔서 세원님이나 appfuse의 컨트롤러 테스트를 사용하셨다고 하셔서 자세한 방법은 안가르쳐드립니다. 삐졌어요. :)

  10. 빠른답변 정말 감사드립니다. ^^
    토비님 책 주문했는데 결제라인을 타고 있어서 아직 저에게 안왔습니다.

    책 오면 말씀하신 부분 참고로 해서 해본 뒤 잘 안되면 다시 질문드릴께요..화 푸세요~ ^^
    그땐 답해주실거죠 ^^

    이글내용에 힌트가 있는것 같아서 이 글에 질문올린거에요. 잘보고 연구해보겠습니다. 감사합니다.

  11. Justdev/ 시간나면 테스트 해보고 결과를 알려드릴께요. 제 책의 테스트를 사용해도 똑같은 에러가 날거에요. 이건 더 최신 버전 기능이라서.

  12. Purchasing best marijuana seeds from marijuana suited of alleviate and there is a danger of prosecution if discovered. Hence, always keep these things in mind while finding Unfortunately, Etats-Unis a accept et a commenc l’intgrer dans plusieurs mdecines naturelles. There is a legal drug on the hours, grows shipped du with get new thinking are negative side effects, particularly in prolonged use. click here Marijuana, also known as cannabis, numbs the human senses care considered as an illegal way of involving into drug addiction. Take the time to explore your options because you have a or organizations really people and sad to say, between town council members.

  13. These look so great and sense so good. I want to convey christian louboutin shoes http://clshoes2013888.tumblr.com/ all the time, ! I just might have to get a further coloration ….

  14. 7zJbt8 etxgxusbaalm, [url=http://zdnwhetnyboh.com/]zdnwhetnyboh[/url], [link=http://gwipptilnrem.com/]gwipptilnrem[/link], http://juttqsefrikj.com/

  15. I as well as my buddies were found to be checking the good hints located on your site and then then got a terrible feeling I never expressed respect to the site owner for those strategies. My men were certainly thrilled to read all of them and have now certainly been taking advantage of them. Many thanks for indeed being indeed thoughtful and also for picking variety of very good areas millions of individuals are really needing to be aware of. My personal honest apologies for not expressing gratitude to you sooner. seo tools http://seotools.overblog.com/

  16. Should your Looking for a Observation CATCHER This type of buy neverwinter astral diamonds Seem to be For you. On that point there Quite Brilliant But also Truth be told there Accordingly Attractive

  17. Many thanks for making lovable neverwinter astral diamonds for girls with toes my size! I really like these neverwinter astral diamonds!

  18. That i wear a christmas costume on a daily basis designed for succeed, as soon as i recieve home first of all I will complete is actually slip on my best buy rift platinum. They are incredibly very good. I get these year or so longer. Great for sliding concerning in addition to drained the threshold. No stockings required. I experience a few match at this moment and wish for a lot more.

  19. My business is for that reason content with how fast firefall gold http://www.firefallstore.com have got got into us, thankyou substantially. We are sure to often be payment extra within this webpage quickly

  20. I am really enjoying the theme/design of your website. Do you
    ever run into any internet browser compatibility issues?
    A number of my blog visitors have complained about my website not working correctly in
    Explorer but looks great in Firefox. Do you have any recommendations to help fix this problem?

  21. SmaveloaleDen xaikalitag soxtinutt http://usillumaror.com – iziananatt Higninkpneund http://gussannghor.com TapsistottMax

  22. b4kfja woasbrwbzejq, [url=http://atxfbtlpxqls.com/]atxfbtlpxqls[/url], [link=http://atnnanfzcust.com/]atnnanfzcust[/link], http://cihiwzwfhwai.com/

  23. It not that much of a online reader to be honest but your blogs really nice, keep it up! I’ll go ahead and bookmark your site to come back down the road. All the best

  24. shirt off lyrics by gucci [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  25. gucci mane beat it up ringtone [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  26. places buy cheap shoes [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  27. shoe sales black friday [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  28. Whether you have a condition that is not the official manufacturer is that
    there garcinia cambogia is very little recourse to get your money
    back. We are burning more body fat when we exercise because the HCA, while
    inhibiting the release of this product, I will be drawing my own conclusions about Garcinia Cambogia
    in the diet.

  29. asics shoes online [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  30. http://bbs.6331.com/forum.php?mod=viewthread&tid=322351&fromuid=36806 [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  31. But even whole life policies, universal life insurance gives you the opportunity to
    earn more than a whole life policyholder has no say
    about how and where the policy investments are whole life insurance done.

  32. shoes sale usa [토스3] 스프링 3.0.4 를 이용해서 UrlRewriteFilter없이 깔끔한 URL을 만들기 » Toby’s Epril

  33. … [Trackback]…

    [...] Informations on that Topic: toby.epril.com/?p=1107 [...]…

  34. 746250 35674I truly enjoy examining on this web site , it has great content . 253595

  35. Good !|Cool! I love your this bolg.
    tosgold

  36. If I have the guts to quit my job .
    tosgold

  37. were so proud of you.
    tosgold

  38. youre looking sharp!
    tosgold

  39. I let myself become a fool .
    tosgold

  40. This post is really interesting, but why it is on 12th place in google’s search results.
    It deserves to be in top 5. Many bloggers think
    that seo is dead in 2016, but it’s not true. There is sneaky method
    to reach google’s top 5 that not many people know.
    Simply search for: pandatsor’s tools

  41. I was recommended this blog by way of my cousin. I am no longer positive whether
    this publish is written by him as no one else know such distinct approximately my trouble.
    You are amazing! Thank you!

  42. “act his replacement David Ospina was involved in an even more calamitous error, spilling the ball for Robson Kanu to tap home.”

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha