티스토리 뷰

반응형
RequestMapping

@Controller & @RestController(Cotroller와 RestController)로 등록된 클래스는 자동으로 스프링 빈으로 등록이 되어 매핑이 된다

하지만 클라이언트가 요청한 URL에 매핑을 하기 위해서는 빈의 매핑 정보를 정의해야 한다

이때 사용하는 것이 바로 @RequestMapping이다

이름에서도 볼 수 있듯이 Spring MVC Framework의 RequestHandlerMappingHandler 인터페이스를 어노테이션화 한 것이다

 

RequestMapping Method Level

아래의 예시처럼 메서드에 @RequsetMapping을 추가하고 URL을 정의하면

클라이언트가 요청하는 URL에 따라 해당 메서드가 실행된다

/**
* Method Level RequestMapping
*/

@Controller //Controller 혹은 RestController로 지정해야 스프링이 매핑을 할 수 있다
public class RequestMappingExample {

    @RequestMapping("/example/view1")
    public String example1() {
        return "view1"; //Controller의 경우 String 반환 값을 입력하면 view로 반환한다
    }
    
    @RequestMapping("/example/view2")
    public String example2() {
        return "view2";
    }

}

또한 URL은 배열 형식으로 작성하여 다중 URL로 정의할 수도 있다

@RequestMapping("/example/view1", "/example/view3")

 

RequestMapping Class Level

@RequestMapping의 경우 Method 뿐만 아니라 Class 단위에도 적용이 가능하기 때문에

위의 예시에서 중복으로 작성된 URL을 공통으로 처리할 수도 있다

/**
* Class Level RequestMapping
*/

@Controller
@RequestMapping("/example") // 클래스 단위에 RequestMapping을 작성하면 메서드에 일괄적용 된다
public class RequestMappingExample {

    @RequestMapping("/view1")
    public String example1() {
        return "view1";
    }
    
    @RequestMapping("/view2")
    public String example2() {
        return "view2";
    }

}

 

RequestMapping with Method

단순히 URL만 정의한다면 클라이언트가 GET방식으로 접근하던 POST방식으로 접근하던 모두 접근이 가능하게 된다

또한 명확하게 메서드의 역할이 구분되지 않기 때문에 method 정의하는 것이 좋다

아래와 같이 RequestMapping에 method를 구분하게 되면 클라이언트는 해당 방식과 URL을 통해서만 접근이 가능하다

/**
* RequestMapping with Method
*/

@Controller
@RequestMapping("/example")
public class RequestMappingExample {
	
    //method가 구분되어 있다면 URL이 같아도 들어온 요청의 방식에 해당하는 메서드가 실행된다
    @RequestMapping(value = "/view1", method = RequestMethod.GET)
    public String example1() {
        return "view1";
    }

    @RequestMapping(value = "/view1", method = RequestMethod.POST)
    public String example2() {
        return "view2";
    }

}

또한 이렇게 메서드를 구분 짓게 된다면 같은 URL의 요청이 온다 하더라도 요청한 방식으로 구분하여 해당 메서드가 호출된다

(만약 올바른 메서드로 요청하지 않는 경우 405 HTTP 상태 코드(Method Not Allowed)를 반환한다)

 

RequestMapping with HTTP Request Method

기존 메서드로 구분하는 방식은 @RequestMapping이 중복 되어 어느 메서드를 받고 있는지 한눈에 살펴보기가 어렵다는 단점이 있다

그래서 여기서 더 나아가 HTTP의 메서드(HTTP 메서드의 글)를 활용하여 Mapping을 축약하는 방법을 사용하여 개선할 수 있다

(최근에는 REST API를 설계하면서 이 방법을 많이 사용한다고 한다)

 

굉장히 단순하게도 Mapping앞에 해당 메서드의 이름을 붙이면 된다

• @GetMapping

• @PostMapping

• @PutMapping

• @DeleteMapping

• @PatchMapping

//기존의 RequestMapping
@RequestMapping("/mapping", method = RequestMethod.GET or POST)
public String requestBasic() {
	return "view";
}

//Mapping 축약
@GetMapping("/mapping")
public String requestGet() {
	return "view";
}

@PostMapping("/mapping")
public String requestPost() {
	return "view";
}

@PutMapping("/mapping")
public String requestPut() {
	return "view";
}

@DeleteMapping("/mapping")
public String requestDelete() {
	return "view";
}

@PatchMapping("/mapping")
public String requestPatch() {
	return "view";
}

메서드가 구분되기 때문에 같은 URL을 사용하고 있다 하더라도 요청되는 메서드 방식과 같은 메서드가 호출된다

이로써 기존의 방법보다 훨씬 깔끔하여 한눈에 각 메서드들이 무슨 메서드 방식을 받을 수 있는지 알 수 있다

 

조건부 Mapping

이외에도 Mapping에 제약 조건을 걸어 매핑할 수도 있다

해당 매핑의 제약 조건을 충족하지 않을 시 클라이언트는 접근을 할 수 없다

 

Parameter

(잘 사용하지는 않는다고 한다)

클라이언트가 요청하는 URL에 특정 파라미터 값을 요구하거나 제외하여 매핑할 수 있다

/**
 * Paramter 제약조건 예시
 * params="mode",
 * params="!mode"
 * params="mode=debug"
 * params="mode!=debug" (! = )
 * params = {"mode=debug","data=good"}
 */
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
    return "view";
}

 

• HTTP Header

파라미터와 비슷하지만 HTTP의 Header를 사용한다

/**
 * Header 제약조건 예시
 * headers="mode",
 * headers="!mode"
 * headers="mode=debug"
 * headers="mode!=debug" (! = )
 */
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
    return "view";
}

 

Consume(HTTP Content-type)

(잘 사용하지는 않는다고 한다)

HTTP의 Content-Type에 제약조건을 걸어 매핑한다

Consume이라는 말 그대로 서버가 소비할 수 있는 Content-Type을 제한하는 것이다

/**
 * Content-Type Header 제약조건 예시
 * consumes="application/json"
 * consumes="!application/json"
 * consumes="application/*"
 * consumes="*\/*"
 * MediaType.APPLICATION_JSON_VALUE
 */
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
    return "view";
}

만약 올바른 미디어 타입으로 요청이 오지 않을 시 HTTP 415 상태 코드(Unsupported Media Type)를 반환한다

 

• Produce(HTTP Accept)

HTTP 요청의 Accept 헤더를 기반으로 미디어 타입을 매핑한다

/**
 * Accept Header 제약조건 예시 
 * produces = "text/html"
 * produces = "!text/html" 
 * produces = "text/*"
 * produces = "*\/*"
 */
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
    return "view";
}

 

REST API 설계

가장 기본이 되는 CRUD를 사용하여 회원 관리 REST API를 만든다고 해보자 (REST API의 글)

REST API의 핵심인 리소스의 표현과 행위의 표현을 충족하기 위해서

앞에서 살펴보았던 Mapping의 축약 방법을 활용하면 좀 더 깔끔하게 설계가 가능하다

 

'members'라는 리소스 표현하면서 아래와 같이 각 메서드로 구분하여 API를 설계한다

회원 목록 조회 : GetMapping("/members")
회원 등록 : PostMapping("/members")
회원 조회 : GetMapping("/members/{memberId}")
회원 수정 : PatchMapping("/members/{memberId}")
회원 삭제 : DeleteMapping("/members/{memberId}")

 

핵심정리

URL 매핑을 위하여 @RequestMapping을 사용한다

메서드 혹은 클래스 단위로 Mapping을 주어 중복 URL을 공통으로 처리할 수 있다

각 매핑은 조건부로 제약조건을 주어 추가 매핑을 할 수 있다

HTTP메서드에 따라 축약된 Mapping을 사용하면 훨씬 가독성이 좋은 코드를 작성할 수 있다

또한 이 축약 Mapping을 활용하여 REST API를 설계할 수 있다

 

더보기

개인 학습을 위해 작성되는 글입니다.

제가 잘못 알고 있는 점에 대한 지적 / 더 나은 방향에 대한 댓글을 환영합니다.

 

참조 링크:

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

https://mangkyu.tistory.com/49

 

반응형
댓글