[Spring] Handler Method

배창민·2025년 10월 15일
post-thumbnail

Handler Method

요청을 컨트롤러 메서드로 보낼 때, 메서드 시그니처에 선언한 타입/어노테이션에 따라 스프링이 알맞은 값을 자동 주입한다.


한눈에 보는 치트시트

분류선언 예시주입되는 것주요 포인트
요청 객체WebRequest서블릿 독립적 요청 API파라미터 조회, 세션 접근 등 기본 기능
HttpServletRequest/Response서블릿 API필터/헤더/바디 등 저수준 제어
단일 파라미터@RequestParam String name쿼리/폼 필드required, defaultValue, 다중값은 List/배열
여러 파라미터@RequestParam Map<String,String>모든 폼 필드 맵키는 name 속성
커맨드 객체@ModelAttribute MenuDTO dtoDTO에 바인딩기본생성자+세터 필요, 모델에 자동 담김
세션HttpSession세션 객체setAttribute, invalidate()
@SessionAttributes("id")모델→세션 자동 승격컨트롤러 단위, 제거는 SessionStatus#setComplete()
HTTP Body/헤더/쿠키@RequestBody String/DTO요청 본문JSON 본문은 DTO와 함께 사용 권장
@RequestHeader("content-type") String ct특정 헤더Map<String,String>도 가능
@CookieValue("JSESSIONID") String sid특정 쿠키required=false로 선택적 주입

1) WebRequest

@GetMapping("regist")
public void regist() { } // 반환값 void면 요청 경로가 뷰 이름(templates/first/regist.html)

@PostMapping("regist")
public String registMenu(Model model, WebRequest request) {
    String name = request.getParameter("name");
    int price = Integer.parseInt(request.getParameter("price"));
    int categoryCode = Integer.parseInt(request.getParameter("categoryCode"));

    model.addAttribute("message",
        name + "을(를) 신규 메뉴 목록의 " + categoryCode + "번 카테고리에 " + price + "원으로 등록 하셨습니다!");
    return "first/messagePrinter";
}

포인트

  • 서블릿 API에 종속되지 않는 요청 추상화.
  • 간단 파라미터 읽기와 모델 조합에 적합.

2) @RequestParam

@PostMapping("modify")
public String modifyMenuPrice(
        Model model,
        @RequestParam(required = false) String modifyName,
        @RequestParam(defaultValue = "0") int modifyPrice) {

    model.addAttribute("message", modifyName + "메뉴의 가격을 " + modifyPrice + "로 변경하였습니다.");
    return "first/messagePrinter";
}

여러 파라미터 한 번에

@PostMapping("modifyAll")
public String modifyMenu(Model model, @RequestParam Map<String, String> params) {
    String name = params.get("modifyName2");
    int price = Integer.parseInt(params.get("modifyPrice2"));
    model.addAttribute("message", "메뉴의 이름을 " + name + "(으)로, 가격을 " + price + "원으로 변경하였습니다.");
    return "first/messagePrinter";
}

포인트

  • 기본값 미지정 + 누락 시 400 → required=false 또는 defaultValue 사용.
  • 타입 변환은 스프링이 수행(변환 불가 시 예외).

3) @ModelAttribute (커맨드 객체)

public class MenuDTO {
  private String name; private int price; private int categoryCode; private String orderableStatus;
  public MenuDTO() {} // 기본생성자 필수
  // 각 필드의 setter 필수
}

@PostMapping("search")
public String searchMenu(@ModelAttribute("menu") MenuDTO menu) {
    // "menu" 키로 Model에 자동 저장
    return "first/searchResult";
}

포인트

  • name == DTO 필드명 + 세터 필요.
  • 키를 지정하지 않으면 타입명 첫 글자 소문자로 모델에 담김.

4) 세션: HttpSession vs @SessionAttributes

4-1) HttpSession 직접 사용

@PostMapping("login1")
public String sessionTest1(HttpSession session, @RequestParam String id) {
    session.setAttribute("id", id);
    return "first/loginResult";
}

@GetMapping("logout1")
public String logoutTest1(HttpSession session) {
    session.invalidate(); // 전체 세션 무효화
    return "first/loginResult";
}

4-2) @SessionAttributes로 모델→세션 승격

@Controller
@RequestMapping("/first/*")
@SessionAttributes("id")
public class FirstController { ... }

@PostMapping("login2")
public String sessionTest2(Model model, @RequestParam String id) {
    model.addAttribute("id", id); // 선언된 키면 세션에 자동 저장
    return "first/loginResult";
}

@GetMapping("logout2")
public String logoutTest2(SessionStatus status) {
    status.setComplete(); // 이 컨트롤러의 세션 속성만 만료
    return "first/loginResult";
}

포인트

  • invalidate()는 세션 전체 종료, setComplete()컨트롤러 수준 세션 속성만 제거.
  • 컨트롤러 범위로 로그인 아이디 같은 가벼운 상태 유지에 적합.

5) @RequestBody + 헤더/쿠키

@PostMapping("body")
public void bodyTest(@RequestBody String body,
                     @RequestHeader("content-type") String contentType,
                     @CookieValue(value = "JSESSIONID", required = false) String sid) {

    System.out.println(contentType); // ex) application/x-www-form-urlencoded
    System.out.println(sid);
    System.out.println(body);        // 폼 제출이면 쿼리스트링 형태
}

JSON 본문 바인딩 예

@PostMapping("body-json")
public ResponseEntity<Void> save(@RequestBody MenuDTO menu) {
    // Jackson이 JSON → MenuDTO 변환
    return ResponseEntity.ok().build();
}

포인트

  • 전통 폼(application/x-www-form-urlencoded)은 보통 @RequestParam/@ModelAttribute 사용.
  • JSON 요청은 DTO + @RequestBody로 메시지 컨버터가 자동 변환.
  • @RequestHeader, @CookieValue는 개별 추출에 편리하고 required=false로 선택화 가능.

체크리스트

  • 단일/간단 값 → @RequestParam
    여러 값 한 번에 → @RequestParam Map
  • 폼 DTO 바인딩 → @ModelAttribute (기본생성자·세터 필수)
  • 세션 보관 → HttpSession 직접 or @SessionAttributes로 모델 승격
    제거는 invalidate() vs SessionStatus#setComplete() 차이 인지
  • JSON 본문 → @RequestBody DTO
    헤더/쿠키 → @RequestHeader, @CookieValue
  • void 반환 시 요청 경로가 뷰 이름으로 사용됨
  • 누락 가능 파라미터는 required=false/defaultValue로 안전하게 처리

필요한 선언만 시그니처에 올리면 스프링이 나머지를 채운다. 요청 형태와 유지 범위를 기준으로 올바른 파라미터 방식을 고르는 것이 핵심.

profile
개발자 희망자

0개의 댓글