// Developer · Debugging Reports

뉴스도 디버깅이 필요해

마주친 오류를 재현하고, 원인을 추적하고, 기록합니다. Java · Spring · DB · 실무 트러블슈팅.

debug — today.log
$ debug --trace "오늘의 뉴스"
> 헤드라인 파싱 중...
> 원인 추적: 근거 누락 · 출처 불명
> 패치 적용: 사실 확인 + 출처 보강
✓ RESOLVED
TOTAL
TODAY
YESTERDAY

Categories

웹개발/Spring

Spring *.do URL 패턴 정리, 공공 프로젝트는 왜 .do로 끝날까

자바를잡아2026. 7. 2. 08:00
반응형

왜 공공 프로젝트 URL은 .do로 끝날까

공공기관 프로젝트나 오래된 Spring 코드에 투입되면 URL이 죄다 /member/list.do, /board/view.do처럼 .do로 끝나는 걸 보게 된다. 처음 보면 "do라는 파일이 실제로 있나?" 싶지만 그렇지 않다. Spring *.do URL 패턴에서 .do는 실제 파일이 아니라, 이 요청을 컨트롤러가 처리하라는 표시일 뿐이다.

동작 원리는 간단하다. web.xml에서 ".do로 끝나는 요청은 DispatcherServlet(스프링 컨트롤러)이 받아라"고 매핑해 둔 것이다. 그래서 list.do라는 파일이 없어도 컨트롤러가 요청을 처리하고 화면을 돌려준다. 이 방식은 Struts 같은 과거 프레임워크 시절부터 이어진 관례이고, 전자정부 표준프레임워크(eGovFramework) 기반 사업에서 오랫동안 쓰여 공공 SI의 사실상 표준처럼 자리 잡았다.

.do 매핑과 / 매핑 비교

구분 *.do (확장자 매핑) / (기본 매핑)
매핑 대상 .do로 끝나는 요청만 모든 요청
정적 리소스 DispatcherServlet을 안 거침(자연 처리) 별도 리소스 설정 필요
URL 형태 /member/list.do /member/list
주 사용 시기 레거시, 공공 SI 최근 방식, REST
REST 스타일 부적합 적합
정적 리소스 404 위험 낮음 설정 누락 시 높음

web.xml에서 .do가 매핑되는 구조

1. DispatcherServlet 확장자 매핑

.do 패턴의 핵심은 web.xml의 servlet-mapping이다. DispatcherServlet의 url-pattern을 *.do로 지정해, 확장자가 .do인 요청만 스프링이 받도록 한다.

<!-- web.xml -->
<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>  <!-- .do로 끝나는 요청만 처리 -->
</servlet-mapping>

이 설정 덕분에 *.css, *.js, *.jpg 같은 정적 리소스 요청은 DispatcherServlet을 거치지 않고 WAS가 직접 처리한다. 그래서 / 매핑에서 자주 겪는 "정적 리소스 404" 문제가 .do 방식에서는 잘 생기지 않는다. 이것이 레거시에서 .do가 오래 쓰인 실용적 이유 중 하나다.

2. 컨트롤러는 .do까지 매핑한다

컨트롤러에서는 URL을 .do까지 포함해 매핑한다. 레거시는 긴 @RequestMapping 형태가 많다.

@Controller
public class MemberController {

    // /member/list.do 요청 처리
    @RequestMapping(value = "/member/list.do", method = RequestMethod.GET)
    public String list(Model model) {
        model.addAttribute("members", memberService.findAll());
        return "member/list"; // 뷰 이름 (JSP)
    }
}

요청 URL에 .do가 붙어 있어도, 반환하는 뷰 이름(member/list)에는 .do가 없다. .do는 어디까지나 "컨트롤러가 처리할 요청"이라는 입구 표시이고, 화면 경로와는 별개다. 이 부분을 헷갈리면 뷰를 못 찾는 실수를 한다.

.do 방식에서 정적 리소스 처리

앞서 말한 대로 .do 매핑은 정적 리소스를 자연스럽게 비켜 간다. *.do에 해당하지 않는 /css/style.css, /js/common.js 같은 요청은 DispatcherServlet이 받지 않으므로 WAS 기본 서블릿이 처리한다. JSP에서 정적 파일을 부를 때도 평소처럼 경로만 맞으면 된다.

<%-- JSP: 정적 리소스는 .do와 무관하게 직접 경로 --%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<script src="${pageContext.request.contextPath}/js/common.js"></script>

context path는 명시해 주는 편이 안전하다. 운영과 로컬의 배포 경로가 다를 수 있어서다. 정적 리소스 자체는 .do 매핑의 영향을 받지 않지만, context path 누락으로 인한 경로 문제는 .do 방식에서도 똑같이 발생할 수 있다.

레거시 .do를 다룰 때 주의할 점

1. 기존 URL을 함부로 바꾸지 않는다

운영 중인 공공 시스템에서 .do URL은 외부 링크, 즐겨찾기, 연계 시스템, 권한 설정 등에 이미 박혀 있는 경우가 많다. URL을 바꾸면 이런 연결이 끊긴다. 유지보수에서 새 화면을 추가할 때는 기존 .do 규칙을 그대로 따르는 것이 안전하다. 임의로 일부만 / 방식으로 바꾸면 매핑 체계가 섞여 혼란이 커진다.

2. .do 방식과 / 방식을 섞을 때

레거시에 REST API를 일부 추가하면서 .do와 / 방식을 함께 써야 하는 경우가 있다. 이때는 매핑이 충돌하지 않도록 서블릿 매핑과 경로 설계를 신중히 한다. 확장자 매핑(*.do)과 기본 매핑(/)이 한 프로젝트에 공존하면, 정적 리소스 처리나 우선순위에서 예상치 못한 동작이 나올 수 있다. 적용 전 테스트 환경에서 충분히 확인한다.

<!-- 혼용 시 예시: 두 매핑이 공존할 때 동작을 반드시 확인 -->
<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- REST용 별도 서블릿/매핑을 추가하는 경우 경로 설계 주의 -->

실무에서 자주 하는 실수

  • .do를 실제 파일로 오해해 해당 파일을 찾는 경우. .do는 매핑용 가상 확장자다.
  • 컨트롤러 매핑에 .do를 빠뜨려(/member/list) 요청이 안 잡히는 경우. web.xml이 *.do만 받으므로 컨트롤러도 .do까지 맞춘다.
  • 반환 뷰 이름에 .do를 붙여 JSP를 못 찾는 경우. .do는 요청 URL에만, 뷰 이름엔 붙이지 않는다.
  • 운영 중 URL을 .do에서 /로 바꿔 외부 연계·즐겨찾기가 끊기는 경우.
  • .do와 / 매핑을 검증 없이 섞어 정적 리소스나 우선순위 문제가 생기는 경우.

FAQ

Q1. .do는 실제 파일인가요?

아니다. web.xml에서 DispatcherServlet이 처리하도록 매핑한 가상 확장자다. .do로 끝나면 컨트롤러가 받는다는 표시일 뿐, 그런 파일은 없다.

Q2. 왜 공공 프로젝트는 .do를 많이 쓰나요?

과거 프레임워크(Struts 등) 시절부터 이어진 관례이고, 전자정부 표준프레임워크 기반 사업에서 오래 쓰여 표준처럼 자리 잡았다. 정적 리소스 처리가 단순하다는 실용적 이점도 있다.

Q3. .do 방식과 / 방식 중 뭐가 좋나요?

우열 문제가 아니라 시기·환경 차이다. REST 스타일에는 / 방식이 맞지만, 레거시 유지보수에서는 기존 .do 체계를 따르는 게 안전하다.

Q4. 컨트롤러 매핑에 .do를 꼭 적어야 하나요?

web.xml이 *.do만 DispatcherServlet으로 보내는 구조라면, 컨트롤러 @RequestMapping도 .do까지 맞춰야 요청이 연결된다.

Q5. .do URL에서 정적 리소스가 404 나기도 하나요?

.do 매핑 자체는 정적 리소스를 비켜 가므로 / 매핑보다 404 위험이 낮다. 다만 context path 누락 같은 경로 문제는 .do 방식에서도 동일하게 생길 수 있다.

정리

Spring *.do URL 패턴에서 .do는 실제 파일이 아니라, web.xml에서 DispatcherServlet이 처리하도록 매핑한 가상 확장자다. *.do 요청만 컨트롤러가 받고 정적 리소스는 WAS가 직접 처리하므로, / 매핑에서 흔한 정적 리소스 404 문제가 잘 생기지 않는다. 이 단순함과 과거 프레임워크의 관례가 맞물려 공공 SI에서 오래 쓰였다. 레거시를 다룰 때는 기존 .do 규칙을 그대로 따르고, 운영 URL을 함부로 바꾸지 않으며, .do와 / 방식을 섞을 때는 매핑 충돌과 정적 리소스 처리를 테스트 환경에서 먼저 확인하는 것이 안전하다. 결국 .do는 낡은 게 아니라 그 시절의 합리적 선택이었다고 이해하면 레거시 코드를 읽기가 한결 수월해진다.

반응형