[Spring] 16. @RequestMapping이란?

[Spring] 16. @RequestMapping이란?

이전 글에서는 DispatcherServlet에 대해 살펴봤습니다. DispatcherServlet은 Spring MVC에서 사용자의 요청을 가장 먼저 받아서 알맞은 Controller로 전달하는 Front Controller 역할을 합니다.

이번 글에서는 사용자의 URL 요청을 Controller 메서드와 연결하는 @RequestMapping에 대해 정리하겠습니다. Spring MVC에서 Controller를 작성할 때 가장 기본이 되는 어노테이션입니다.

핵심은 간단합니다. @RequestMapping은 특정 URL 요청을 어떤 Controller 또는 메서드가 처리할지 지정하는 어노테이션입니다.


1. @RequestMapping이란?

@RequestMapping은 요청 URL과 Controller 메서드를 연결할 때 사용합니다. 사용자가 브라우저에서 특정 주소로 요청을 보내면, Spring은 그 주소와 매핑된 Controller 메서드를 찾아 실행합니다.

사용자 요청
 → /board/list
 → BoardController의 list() 메서드 실행

예를 들어 게시글 목록 화면을 보여주는 요청이 있다고 해보겠습니다.

@Controller
public class BoardController {

    @RequestMapping("/board/list")
    public String list() {
        return "board/list";
    }
}

위 코드에서 사용자가 /board/list 주소로 요청하면 list() 메서드가 실행됩니다. 그리고 메서드는 board/list라는 View 이름을 반환합니다.


2. 요청 URL과 메서드 연결

Spring MVC에서는 요청 URL과 Controller 메서드가 매핑됩니다. 이 매핑 정보를 보고 DispatcherServlet은 어떤 Controller 메서드를 실행할지 결정합니다.

요청 URL: /board/list
실행 메서드: BoardController.list()

Controller 코드는 다음과 같이 작성할 수 있습니다.

@Controller
public class BoardController {

    @RequestMapping("/board/list")
    public String list() {
        return "board/list";
    }

    @RequestMapping("/board/write")
    public String writeForm() {
        return "board/write";
    }
}

이 경우 요청에 따라 실행되는 메서드가 달라집니다.

요청 URL 실행 메서드
/board/list list()
/board/write writeForm()

이렇게 URL마다 처리할 메서드를 나누면 요청 흐름을 명확하게 관리할 수 있습니다.


3. 클래스 레벨 @RequestMapping

@RequestMapping은 메서드 위에만 붙일 수 있는 것이 아닙니다. Controller 클래스 위에도 붙일 수 있습니다.

클래스 위에 붙이면 공통 URL 경로를 지정할 수 있습니다.

@Controller
@RequestMapping("/board")
public class BoardController {

    @RequestMapping("/list")
    public String list() {
        return "board/list";
    }

    @RequestMapping("/write")
    public String writeForm() {
        return "board/write";
    }
}

위 코드에서 클래스 위의 @RequestMapping("/board")는 공통 경로입니다. 메서드 위의 경로와 합쳐져 최종 요청 주소가 만들어집니다.

클래스 경로 메서드 경로 최종 URL
/board /list /board/list
/board /write /board/write

게시판 관련 요청이 모두 /board로 시작한다면 클래스 위에 공통 경로를 지정하는 것이 좋습니다. 코드가 더 깔끔해지고, URL 구조도 한눈에 보입니다.


4. method 속성

@RequestMapping은 URL뿐만 아니라 HTTP 요청 방식도 지정할 수 있습니다. HTTP 요청 방식에는 대표적으로 GET과 POST가 있습니다.

GET 데이터를 조회하거나 화면을 요청할 때 주로 사용합니다.
POST 폼 데이터를 전송하거나 데이터를 등록할 때 주로 사용합니다.

@RequestMapping에서 HTTP Method를 지정하려면 method 속성을 사용합니다.

@Controller
@RequestMapping("/board")
public class BoardController {

    @RequestMapping(value = "/write", method = RequestMethod.GET)
    public String writeForm() {
        return "board/write";
    }

    @RequestMapping(value = "/write", method = RequestMethod.POST)
    public String write(BoardDto boardDto) {
        return "redirect:/board/list";
    }
}

위 코드는 같은 /board/write 주소를 사용하지만 HTTP Method에 따라 실행되는 메서드가 다릅니다.

요청 용도 실행 메서드
GET /board/write 글쓰기 화면 요청 writeForm()
POST /board/write 글쓰기 등록 처리 write()

이처럼 같은 URL이라도 요청 방식에 따라 다른 처리를 할 수 있습니다.


5. @GetMapping과 @PostMapping

실제 Spring 프로젝트에서는 @RequestMapping(method = RequestMethod.GET)보다 @GetMapping, @PostMapping을 더 자주 사용합니다.

@GetMapping은 GET 요청을 처리하는 어노테이션입니다. @PostMapping은 POST 요청을 처리하는 어노테이션입니다.

@Controller
@RequestMapping("/board")
public class BoardController {

    @GetMapping("/write")
    public String writeForm() {
        return "board/write";
    }

    @PostMapping("/write")
    public String write(BoardDto boardDto) {
        return "redirect:/board/list";
    }
}

위 코드는 앞에서 본 @RequestMapping 코드와 같은 의미입니다. 다만 더 짧고 읽기 쉽습니다.

기존 방식 축약 방식
@RequestMapping(method = RequestMethod.GET) @GetMapping
@RequestMapping(method = RequestMethod.POST) @PostMapping

처음에는 @RequestMapping의 의미를 이해하고, 실제 코드를 작성할 때는 @GetMapping@PostMapping을 사용하면 좋습니다.


6. 대표적인 Mapping 어노테이션

Spring에서는 HTTP Method에 맞춰 여러 Mapping 어노테이션을 제공합니다.

어노테이션 HTTP Method 주 사용 목적
@GetMapping GET 조회, 화면 요청
@PostMapping POST 등록, 폼 전송
@PutMapping PUT 전체 수정
@PatchMapping PATCH 일부 수정
@DeleteMapping DELETE 삭제

JSP나 Thymeleaf 기반 게시판에서는 처음에 @GetMapping@PostMapping을 가장 많이 사용합니다. REST API를 만들 때는 @PutMapping, @PatchMapping, @DeleteMapping도 자주 등장합니다.


7. 게시판 기능 기준 Mapping 예시

게시판 기능을 기준으로 URL과 Mapping을 정리하면 다음처럼 만들 수 있습니다.

기능 요청 설명
게시글 목록 GET /board/list 게시글 목록 화면 조회
게시글 작성 화면 GET /board/write 글쓰기 화면 요청
게시글 등록 POST /board/write 글쓰기 폼 전송 처리
게시글 상세 GET /board/detail 게시글 상세 화면 조회
게시글 삭제 POST /board/delete 게시글 삭제 처리

이 구조를 Controller로 작성하면 다음과 같습니다.

@Controller
@RequestMapping("/board")
public class BoardController {

    @GetMapping("/list")
    public String list() {
        return "board/list";
    }

    @GetMapping("/write")
    public String writeForm() {
        return "board/write";
    }

    @PostMapping("/write")
    public String write(BoardDto boardDto) {
        return "redirect:/board/list";
    }

    @GetMapping("/detail")
    public String detail() {
        return "board/detail";
    }

    @PostMapping("/delete")
    public String delete() {
        return "redirect:/board/list";
    }
}

클래스에 @RequestMapping("/board")를 붙였기 때문에 메서드에는 /list, /write, /detail처럼 하위 경로만 작성하면 됩니다.


8. value와 path

@RequestMapping에서는 valuepath를 사용할 수 있습니다. 둘 다 요청 경로를 지정할 때 사용합니다.

@RequestMapping(value = "/board/list")
public String list() {
    return "board/list";
}
@RequestMapping(path = "/board/list")
public String list() {
    return "board/list";
}

두 코드는 요청 경로를 지정한다는 점에서 비슷하게 사용할 수 있습니다. 일반적으로는 아래처럼 값만 짧게 작성하는 경우가 많습니다.

@RequestMapping("/board/list")
public String list() {
    return "board/list";
}

@GetMapping, @PostMapping에서도 마찬가지로 경로를 짧게 작성할 수 있습니다.

@GetMapping("/board/list")
public String list() {
    return "board/list";
}

9. 여러 URL을 하나의 메서드에 매핑하기

하나의 메서드가 여러 URL을 처리하도록 만들 수도 있습니다.

@Controller
public class HomeController {

    @RequestMapping({"/", "/home", "/main"})
    public String home() {
        return "home";
    }
}

위 코드는 /, /home, /main 요청이 모두 home() 메서드로 연결됩니다.

/
 /home
 /main
 → home() 실행

다만 너무 많은 URL을 하나의 메서드에 몰아넣으면 관리가 어려워질 수 있습니다. 관련 있는 URL만 묶는 것이 좋습니다.


10. View 이름과 요청 URL 구분하기

Spring MVC를 처음 공부할 때 자주 헷갈리는 부분이 요청 URL과 View 이름입니다.

@GetMapping("/board/list")
public String list() {
    return "board/list";
}

여기서 /board/list는 사용자가 요청하는 URL입니다. 반면 board/list는 Controller가 반환하는 View 이름입니다.

요청 URL @GetMapping("/board/list")에 작성하는 값
View 이름 return "board/list";에 작성하는 값

둘의 문자열이 비슷할 수는 있지만 의미는 다릅니다. 요청 URL은 사용자가 접근하는 주소이고, View 이름은 Spring이 찾아야 할 화면 이름입니다.


11. redirect와 Mapping

Controller에서 redirect:를 사용하면 다른 URL로 다시 요청을 보내게 됩니다.

@PostMapping("/write")
public String write(BoardDto boardDto) {
    return "redirect:/board/list";
}

위 코드는 게시글 등록 처리가 끝난 뒤 /board/list로 다시 이동하라는 뜻입니다. 이때 /board/list는 View 이름이 아니라 요청 URL입니다.

POST /board/write
 → 게시글 등록 처리
 → redirect:/board/list
 → GET /board/list 다시 요청
 → 목록 화면 표시

등록, 수정, 삭제 후에는 보통 redirect를 사용합니다. 그래야 새로고침했을 때 같은 POST 요청이 반복되는 문제를 줄일 수 있습니다.


12. 자주 하는 실수

1) 같은 URL과 같은 Method를 중복 작성하는 경우

같은 Controller 또는 여러 Controller에 같은 URL과 같은 HTTP Method가 중복되면 Spring이 어떤 메서드를 실행해야 할지 판단하기 어려워집니다.

@GetMapping("/board/list")
public String list1() {
    return "board/list";
}

@GetMapping("/board/list")
public String list2() {
    return "board/list2";
}

이런 구조는 피해야 합니다. 요청 URL과 HTTP Method 조합은 명확해야 합니다.

2) GET과 POST를 구분하지 않는 경우

화면을 보여주는 요청과 데이터를 처리하는 요청은 구분하는 것이 좋습니다.

GET /board/write
 → 글쓰기 화면 보여주기

POST /board/write
 → 글쓰기 등록 처리

같은 URL을 쓰더라도 GET과 POST를 나누면 기능의 의미가 명확해집니다.

3) View 이름에 redirect를 잘못 사용하는 경우

return "board/list";return "redirect:/board/list";는 의미가 다릅니다.

코드 의미
return "board/list"; View 이름을 반환합니다.
return "redirect:/board/list"; /board/list URL로 다시 요청합니다.

등록, 수정, 삭제 후에는 보통 redirect를 사용하고, 단순 화면 출력은 View 이름을 반환합니다.

4) 클래스 레벨 경로와 메서드 경로를 합친 최종 URL을 착각하는 경우

@RequestMapping("/board")
public class BoardController {

    @GetMapping("/list")
    public String list() {
        return "board/list";
    }
}

위 코드의 최종 URL은 /list가 아니라 /board/list입니다. 클래스 레벨 경로와 메서드 경로가 합쳐진다는 점을 기억해야 합니다.

5) 405 Method Not Allowed 오류

URL은 맞는데 요청 방식이 맞지 않으면 405 오류가 발생할 수 있습니다. 예를 들어 Controller는 POST만 받도록 되어 있는데 브라우저에서 GET으로 접근하면 문제가 생깁니다.

@PostMapping("/board/write")
public String write(BoardDto boardDto) {
    return "redirect:/board/list";
}

이 메서드는 POST 요청만 처리합니다. 브라우저 주소창에서 직접 /board/write로 접근하면 GET 요청이 되므로 이 메서드와 매핑되지 않습니다.


13. DispatcherServlet과 @RequestMapping의 관계

DispatcherServlet은 사용자의 요청을 가장 먼저 받습니다. 그다음 HandlerMapping을 통해 @RequestMapping, @GetMapping, @PostMapping 정보를 확인합니다.

사용자 요청
 → DispatcherServlet
 → HandlerMapping이 Mapping 정보 확인
 → 알맞은 Controller 메서드 찾기
 → HandlerAdapter가 메서드 실행

즉, @RequestMapping은 DispatcherServlet이 요청을 어떤 Controller 메서드로 보낼지 결정하는 데 필요한 매핑 정보입니다.


정리

@RequestMapping은 요청 URL을 Controller 또는 Controller 메서드와 연결하는 어노테이션입니다. 클래스 위에 붙이면 공통 경로를 지정할 수 있고, 메서드 위에 붙이면 실제 요청을 처리할 메서드를 지정할 수 있습니다.

@RequestMapping 요청 URL과 Controller 메서드를 연결합니다.
@GetMapping GET 요청을 처리합니다.
@PostMapping POST 요청을 처리합니다.
클래스 레벨 Mapping 공통 URL 경로를 지정합니다.
메서드 레벨 Mapping 실제 요청 처리 메서드를 지정합니다.

실제 개발에서는 @RequestMapping으로 공통 경로를 잡고, 메서드에는 @GetMapping, @PostMapping을 사용하는 경우가 많습니다.

@Controller
@RequestMapping("/board")
public class BoardController {

    @GetMapping("/list")
    public String list() {
        return "board/list";
    }

    @PostMapping("/write")
    public String write(BoardDto boardDto) {
        return "redirect:/board/list";
    }
}

이 구조를 이해하면 Spring MVC에서 URL 요청이 어떤 Controller 메서드와 연결되는지 쉽게 파악할 수 있습니다.


연습해보기

아래 요청을 처리하는 Controller 구조를 직접 생각해보세요.

GET  /member/join
POST /member/join
GET  /member/login
POST /member/login

회원가입 화면과 로그인 화면은 GET 요청으로 보여줄 수 있습니다. 회원가입 처리와 로그인 처리는 POST 요청으로 나눌 수 있습니다.

@Controller
@RequestMapping("/member")
public class MemberController {

    @GetMapping("/join")
    public String joinForm() {
        return "member/join";
    }

    @PostMapping("/join")
    public String join(MemberDto memberDto) {
        return "redirect:/member/login";
    }

    @GetMapping("/login")
    public String loginForm() {
        return "member/login";
    }

    @PostMapping("/login")
    public String login(MemberLoginDto memberLoginDto) {
        return "redirect:/";
    }
}

다음 글에서는 @GetMapping@PostMapping을 더 자세히 정리하겠습니다. GET과 POST의 차이를 이해하면 화면 요청과 데이터 처리 요청을 더 명확하게 나눌 수 있습니다.