백엔드/Spring

[Spring] 스프링 HTTP 요청 받기

happy_life 2022. 7. 22. 11:11

목차

1.로거

2. 요청 매핑

3. HTTP 요청 - 기본, 헤더 조회

4. HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form

5. HTTP 요청 파라미터 - @RequestParam

6. HTTP 요청 파라미터 - @ModelAttribute

7. HTTP 요청 메시지 - 단순 텍스트

8. HTTP 요청 메시지 - JSON

 

 

 

 

 

로거

개요

스프링 부트 라이브러리에는 logging이 포함되어있다. 기본적으로 SLF4J와 Logback 라이브러리를 사용한다. 로그 라이브러리에는 여러가지가 있는데, 이를 통합해 인터페이스로 제공하는 것이 SLF4J 라이브러리이다.

 

사용법

로그 선언

private Logger log = LoggerFactory.getLogger(getclass());

@Slf4j 롬복 사용도 가능하다.

 

로그 호출

log.info(" info log = {}", name);
log.trace("trace log = {}", name);
log.debug("debug log = {}", name);
log.warn("warn log = {}", name);
log.error("error log={}", name);

 

로그 레벨 설정

 

application.properties

#전체 로그 레벨 설정(기본 info)
logging.level.root=info
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug

설정에 따라, 로그가 출력되는 범위가 달라진다.

 

올바른 로그 사용법

log.debug("data" + data)와 같은 식으로 사용하지 않는다. 만약 debug를 사용하지 않는 로그 레벨인 경우에도, 코드에 연산이 있으면, 문자 더하기 연산이 발생해 효율성이 떨어진다.

log.debug("debug log = {}", name);

 

로그 장점

1. 쓰레드 정보, 클래스 이름 등의 부가 정보를 함께 볼 수 있다.

2. 로그 레벨에 따라 개발 서버에서는 모든 록를 출력하고, 운영서버에서는 출력하지 않는 등 상황에 맞게 로그를 조절할 수 있다.

3. 팡리이나, 네트워크 등 로그를 다른 위치에도 남길 수 있다.

4. 성능도 System.out보다 더 좋다.

 

 

요청 매핑

HTTP 메서드 매핑

HTTP 통신 방식 중 GET만 허용한다는 의미에서 method = RequestMethod.GET을 파라미터로 넣어주는데, 스프링은 GetMapping등 간단하게 코드를 줄인 어노테이션을 제공한다.

메서드 매핑 축약

 

 

PathVariable(경로 변수) 사용

@ResponseBody
@GetMapping("/request-mapping-path/{userId}")
public String mappingPathVariable(@PathVariable("userId") String data) {
    log.info("mapping Path userId={}", data);
    return "ok";
}

Url로 넘어온 값을 받아서 사용할 수 있다.

출력 결과

 

 

특정 파라미터 조건 매핑

@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
    log.info("mappingParam");
    return "ok";
}

 

 

특정 헤더 조건 매핑

@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
    log.info("mappingHeader");
    return "ok";
}

 

Content-Type 헤더 기반 추가 매핑

@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
    log.info("mappingConsumes");
    return "ok";
}

클라이언트로부터 서버가 전송받는 리소스의 형태를 지정한다.

 

 

Accept 헤더 기반 추가 매핑

@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
    log.info("mappingProduces");
    return "ok";
}

 

서버가 클라이언트에게 제공하는 리소스의 형태를 지정한다.

 

 

 

http 요청 - 기본, 헤더 조회

 

애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.

    @ResponseBody
    @GetMapping("/request-mapping-header")
    public String mappingHeader(HttpServletRequest request,
                                HttpServletResponse response,
                                Locale locale,
                                @RequestHeader("host") String host,
                                @CookieValue(value = "myCookie", required = false) String cookie){

        log.info("request={}", request);
        log.info("response={}", response);
        log.info("locale={}", locale);
        log.info("header host={}", host);
        log.info("myCookie={}", cookie);
        return "ok";
    }

 

출력결과

 

 

HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form

 

@Slf4j
@Controller
public class RequestParamController {

    @RequestMapping("request-param-v1")
    public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));
        log.info("username={}, age={}", username, age);

        response.getWriter().write("ok");
    }
}

get이든 Post든 데이터의 형태가 같게 들어오므로 위의 코드를 통해 파라미터로 값을 받을 수 있다.

 

요청: http://localhost:8080/request-param-v1?username=kim&age=25

결과값

 

 

 

HTTP 요청 파라미터 - RequestParam

 

1) 기본

@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
        @RequestParam("username") String memberName,
        @RequestParam("age") int memberAge) {
    log.info("username={}, age={}", memberName, memberAge);
    return "ok";
}

@ResponseBody: View 조회를 무시하고, HTTP message body에 직접 입력한다.

@RequestParam: 파라미터 이름으로 바인딩을 한다.

 

 

2) 파라미터 이름과 변수 이름이 같을 때 @RequestParam("")생략 가능

@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
        @RequestParam String username,
        @RequestParam int age) {
    log.info("username={}, age={}", username, age);
    return "ok";
}

username 변수명이 파라미터 이름 username과 같으므로 생략할 수 있다.

 

 

3) 이름이 같고 String, int, Integer 등의 단순 타입일 때 @RequestParam도 생략 가능

@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(
        String username, int age) {
    log.info("username={}, age={}", username, age);
    return "ok";
}

 

 

4) 파라미터 필수 여부 - requestParamRequired

@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(
        @RequestParam(required=true) String username,
        @RequestParam(required=false) Integer age) {

    log.info("username={}, age={}", username, age);
    return "ok";
}

만약 required= true로 설정된 파라미터가 요청에 없을 경우, 400 예외가 발생한다.

 

400 예외

 

주의점

1. /request-param?username= 파라미터 이름만 있고 값이 없는 경우 400오류가 나지 않고 빈문자로 통과되므로  주의해야 한다.

 

2. 기본형(primitive)에 null을  입력할 수 없다. 예를 들어,  위의 예제에서 int age에 null 입력하는 것은 불가능(500 예외 발생) 따라서 null 을 받을 수 있는 Integer 로 변경하거나, 또는 다음에 나오는 defaultValue 사용해야 한다.

 

 

 

5) 기본 값 적용 - default

@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
        @RequestParam(required=true, defaultValue = "guest") String username,
        @RequestParam(required=false, defaultValue = "-1") Integer age) {

    log.info("username={}, age={}", username, age);
    return "ok";
}

 

값이 없거나, 빈문자의 경우 default 값이 들어온다.

default

 

6) 파라미터 Map 조회 - requestParamMap

@ResponseBody
@RequestMapping("/request-param-map")
public String requestParamMap(@RequestParam Map<String, Object> paramMap){
    log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));

    return "ok";
}

 

 

HTTP 요청 파라미터 - @ModelAttribute
    @ResponseBody
    @PostMapping("/request-mapping-model")
    public String mappingModel(@ModelAttribute Member member) {
        log.info("membername={}, memberage={}", member.getName(), member.getAge());
        return "ok";
    }

@ModelAttribute를 통해 요청에 의해 입력받은 파라미터를 자동으로 넣는다.

 

결과

 

 

 

 

 

HTTP 요청 메시지 - 단순 텍스트

 

앞서 사용한 @RequestParam과 @ModelAttribute는 요청 파라미터를 조회하는 기능이다. 이와 달리 HTTP 메시지 바디를 직접 조회하는 방법들에 대해 알아보자.

 

1) InputStream

@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {

    ServletInputStream inputStream = request.getInputStream();
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody={}", messageBody);

    response.getWriter().write("ok");
}

 

 

Postman을 통한 예시

 

 

 

2) Input, Output 스트림, Reader

@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer writer) throws IOException{

    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody={}", messageBody);

    writer.write("ok");
}

 

 

3) HttpEntity

@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {
    String messageBody = httpEntity.getBody();
    log.info("messageBody={}", messageBody);

    return new HttpEntity<>("ok");
}

 

4) RequestBody

@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) {

    log.info("messageBody={}", messageBody);

    return "ok";
}

현업에서 가장 많이 쓰는 방식이다. 사실 이 방식을 설명하기 위해 위의 내용들이 있다고 해도 무방하다.

 

 

 

 

 

HTTP 요청 메시지 - JSON

아래 처럼 단순화의 과정을 거쳤다.

단순화 과정

 

 

간단 예제 코드

@ResponseBody
@PostMapping("/request-mapping-json")
public String mappingJson(@RequestBody Member member) {
    log.info("membername={}, memberage={}", member.getName(), member.getAge());
    return "ok";
}

출력

 

 

 

 

 

 

 

 

 

 

 

본 포스팅은 김영한님 인프런 강의내용을 바탕으로 복습을 위해 작성하였습니다. 강의를 통해 배운 개념을 바탕으로 추가적으로 공부한 부분과 간단한 코드 예제를 작성하였습니다. 코드 전체를 복사한 것이 아니라 임의로 수정하거나 생략하였습니다.