Spring boot

(스프링 부트 기초)GET 방식과 URL 주소 설계

mynote6676 2025. 6. 19. 08:52

학습 목표

 

REST API 기반으로 주소 맵핑 처리

 

1. GET방식에 주소 맵핑

2. 클라이언트에서 보낸 값을 받는 방식에 이해 응답에 이해

3.Path Variable 방식으로 값을 보내거나 받는 방식에 이해

4. Query Parameter 방식으로 값을 받는 방법 이해

  key=value 구조 데이터 파싱 처리

  Map 사용 방식 구조 처리

  Dto 객체를 만들어서 처리

 

| 참고자료

https://joont92.github.io/spring/MessageConverter/

 

[spring] MessageConverter

앞서 우리가 HTTP 요청을 모델에 바인딩하고 클라이언트에 보낼 HTTP 응답을 만들기 위해 뷰를 사용했던 방식과는 달리, HTTP 요청 본문과 HTTP 응답 본문을 통째로 메세지로 다루는 방식이다. 주로 X

joont92.github.io

 

참고자료 필사

더보기

[spring] MessageConverter

 

앞서 우리가 HTTP 요청을 모델에 바인딩하고 클라이언트에 보낼 HTTP 응답을 만들기 위해 뷰룰 사용했던 방식과는 

달리,

HTTP 요청 본문관 HTTP 응답 본문을 통째로 메세지로 다루는 방식이다.

주로 XML 이나 JSON을 이용한  AJAX( JavaScript와 XML 형식을 이용한 비동기적 정보 교환 기법이다 기능이나

웹 서비스를 개발할 때 사용된다.

 

아래와 같이 스프링 @RequestBody와 @ResponseBody를 통해 구현할 수 있다.

@ResponseBody // 응답
@RequestMapping(value= "/hello", method=RequestMethod.POST)
public String hello(@RequestBody String param){ // 요청
    return "result";
}

위와 같은 애노테이션을 명시해두게 되면 스프링은 메세지 컨버터라는 것을 사용하여 HTTP 요청이나 응답을 메세지로

변환하게 된다.

즉, 위처럼 파라미터 부분에 @RequestBody를 입력할 경우, 파라미터 타입에 맞는 메세지 컨버터를 선택한 뒤 리턴값을

통째로 메세지로 변환한 뒤 리턴해주는 것이다.

 

|참고로 GET  방식은 요청일 경우 HTTP 요청 본문이 없으므로 @RequestBody를 사용할 수 없다. @RequestParam이나

@ModelAttribute를 사용해야 한다.

 

메시지 컨버터의 종류

이렇게 사용되는 메세지 컨버터는 AnnotationMethodHandlerAdapter 를 통해 등록할 수 있고, 이미 디폴트로 4가지 메세지 컨버터가 등록되어 있다.

 

아래는 디폴트 메세지 컨버터들이다.

 

ByteArrayHttpMessageConverter

지원하는 오브젝트 타입은 byte[]이고, 미디어타입은 모든 것을 다 지원한다.

즉 파라미터에 @RequestBody byte[] parme과 같이 작성하면 모든 요청을 다 byte배열로 받을 수 있다는 말이다.

그리고 리턴타입을 byte[]로 했을 경우 content-Tybeapplcation/octet-stream으로 설정되어 전달된다.

바이너리 정보를 주고 받을 경우가 아니라면 그닥 유용해 보이진 않는다.

 

StringHttpMessageConverter

지원하는 오브젝트 타입은 String이고, 미디어타입은 모든 것을 다 지원한다.

파리미터에 사용할 경우 HTTP 본문을 그대로 String으로 가져올 수 있게되거,

리턴에 사용할 경우 단순 문자열을 그대로 전달해줄 수 있다.

content-Tybetext/plain으로 전달된다.

 

FormHttpMessageConverter

지원하는 오브젝트 타입은 MultivalueMap<String, String>이고, 미디어타입은 application/x-www-form-urlencoded만 지원한다. 

 

SourceHttpMessageConvreter

 

지원하는 오브젝트 타입은 Domsource, SAXSource, StreamSource이고, 미디어타입은 application/xmal,

application/*+xml, txt/xml 세가지를 지원한다.

xml 문서를 Source타입의 오브젝트로 변환하고 싶을 때 사용할 수 있다.

하지만 요즘은 OXM 기술이 많이 발달 되었으므로 이 또한 잘 쓰이지 않는다.

 

아래는 디폴트가 아닌 메세지 컨버터들이다. 실제로 이 컨버터들이 더 유용하다.

여기서 필요한게 있다면 직접 AnnotationMethodHanderAdapter의 messageConverters에 등록하고 사용해야 한다.

<bean class="org.springframework...AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappintJacksonHttpMessageConverter" />
            <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
        </list>
    </property>
</bean>

 

다른 전략과 마친가지로 위와 같이 등록 시 디폴트 전략이 모두 무시된다는 점에 주의해야한다.

 

Jaxb2RootElementHttpMessageConverter

JAXB의 @XmlRootElement와 @XmlType이 붙은 클래스를 이용해 XML과 오브젝트 사이의 메세지 변환을 지원한다.

이 컨버터를 등록할 때는 marshaller와 unmarshaller를 설정해줘야 한다.
지원하는 미디어 타입은 SourceHttpMessageCoverter와 동일하다.

 

MappingJacksonHttpMessageCoverter

Jackson의 objectMapper를  이용해서 JSON과 오브젝트 사이의 변환을 지원한다.

지원하는 미디어 타입은 application/json이다.

변환하는 오브젝트 타입의 제한은 없지만 프로퍼티를 가진 자바빈 스타일이나 HashMap을 이용해야 정확한 변환 결과를

얻을 수 있다.

 


멱등성(Idempotency)이란 같은 작업을 여러 번 수행해도 결과가 달라지지 않는 성질을 의미합니다

 
이 개념은 특히 HTTP메서드나 데이터베이스 연산에서 자주 사용됩니다.



멱등성을 가짐 (GET,PUT,DELET)

비 멱등성을 가짐(POST)



멱등성의 의미?

- 안정성 : 멱등성을 가진 연산은 중복 요청에 대해 안전합니다. 네트워크 문제로 인해 동일한 요청이 여러 번 전달되더라도,

최종 결과를 변하지 않으므로 안전하게 처리할 수 있습니다. 

- 데이터 일관성: 멱등성은 시스템이 일관된 상태를 유지하도록 도와줍니다. 특히 분산 시스템에서 동일한 작업이 여러 번 실행될 

가능성이 있을 때, 멱등성은 데이터 무결성을 보장합니다.

멱등성(Idempotency)이란 같은 작업을 여러번 수행해도 결과가 달라지지 않는 성질을 의미합니다.

 

멱등성이란 같은 작업을 여러번 수행해도 결과가 달라지지 않는 성질을 의미하며, 주로 HTTP 메서드나 데이터 베이스 연산에서 

사용됩니다. 멱등성을 가진 연산은 안정적이고 예측 가능하며, 시스템의 일관성을 유지하는 데 중요한 역활을 합니다.

 

쿼리 스트링(Query String)과 경로 매개변수(Path parameter)는 모두 HTTP요청에서 피라미터를 전달하는
방식입니다. 그러나 다음과 같은 차이점이 있습니다.

쿼리 스트링(Query String)
- URL 뒤에 ? 를 붙이고 파라미터를 key-value 쌍으로 전달합니다.
-파라미터는 &로 구분되며, =로 key와 value를 구분합니다.
-브라우저의 캐시와 검색 엔진에서 높은 가중치를 부여합니다.
-파라미터를 전달할 때 Key와 value를 쌍으로 전달하기 때문에, 순서를 변경해도 문제가 없습니다.
-예시 : http://example.com/search?q=keyword&page=1

경로 매개변수 (Path parameter)
-URL 경로의 일부로 파라미터를 전달합니다.
-경로 변수(Path parameter)를 사용하여 파리미터를 전달하며, {}로 변수를 감싸서 표시합니다.
일반적으로 RESTful API에서 사용되며, URL 자체가 파라미터 정보를 전달합니다.
-파라미터를 전달할 때 Key와 value를 쌍으로 전달하지 않습니다.
예시: http://example.com/users/{id}

 

package com.example.demo1.controller;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * GET 방식 요청 주소 설계와 핸들러 처리를 
 * 학습한다.
 *
 */
 
 //IoC의 대상 -- 스프링 프레임워크가 자동으로 new 해줌
 @controller // 스프링 프레임워크 안에 --> 뷰 리졸브 --> 해당 경로에 파일 차즌 일을 함
 //Reatcontroller // 데이터를 반환 하는 일을 함
 // @RestController//  @Controller + @ResponsBody
public class GetApiController {

    // GET 방식으로 요청을 하면 처리하는 메서드를 만들어 두어야 한다.
    // 주소 설계 - http://localhost:8080/hello
    @GetMapping("/hello")
    @ResponseBody // 야 파일 경로를 찾는게 아니라 그냥 데이터를 반환 해
    public String hello() {
        // index.mustache <--- 파일 찾기 
        return "index";
    }

    /**
     * 쿼리스트링 방식 (@RequestParam)
     * 주소설계
     * http://localhost:8080/qs1?name=둘리
     * @param name=value
     * @return String
     */
    @GetMapping("/qs1")
    public String qs1(@RequestParam(name = "name") String name) {
       return "응답받은 name키값의 값은 = " + name;
    }


    /**
     * 웹브라우저 주소창에 작성하는 주소 (Get 요청 방식)
     * 쿼리 스트링 방식
     * 주소 설계 
     * http://localhost:8080/qs2?name=둘리&age=10
     * required = false, defaultValue = "고길동"
     */

    @GetMapping("qs2")
    public String qs2(@RequestParam(name = "name") String name,
                        @RequestParam(name = "age",
                                required = false, defaultValue = "0") int age) {

        System.out.println("name : " + name);
        System.out.println("age : " + age);

        return "name="+name+"&age="+age;
    }

    /**
     * 쿼리스트링 방식(@RequestParam)
     * 주소 설계
     * http://localhost:8080/qs3?name=둘리&age=10&groupId=com.tenco
     * @param name, age, groupId
     * @return String
     * 직접 설계 먼저
     */
    @GetMapping("/qs3")
    public String qs3(@RequestParam(name = "name")String name,
                      @RequestParam(name = "age")Integer age,
                      @RequestParam(name = "groupId")String groupId) {

        System.out.println("name:"+name);
        System.out.println("age:"+age);
        System.out.println("groupId:"+groupId);

        return "name:"+name + "&age:"+age +"&groupId:"+groupId;
    }

    // 주소 설계 :
    // http://localhost:8080/qs4
    @GetMapping("/qs4")
    @ResponseBody
    public User helloObject() {
        // 응답시에 데이터를 반환 단 (User Object로 내려 보자)
        // Object (서버 측) 응답시킬 때 -- 잭슨, Gson
        // new User("마이콜", 20); --> 문자열로 변환 시키기 위해서
        // 반드시 @Getter 가 있어야 한다.
        // MappingJackson2HttpMessageConverter 동작 함
        return new User("마이콜", 20);
    }


    // 내부 클래스
    @AllArgsConstructor
    @Getter
    class User {
        private String name;
        private Integer age;

    }

    // http://localhost:8080/qs5?a=둘리&b=10&c=com.tenco
    @GetMapping("/qs5")
    @ResponseBody
    public String qs5(@RequestParam Map<String, String> data) {
        // Map 방식으로 동적으로 들어오는 키와값을 받아서 처리해 보자.
        StringBuffer sb = new StringBuffer();
        data.entrySet().forEach(entry -> {
            System.out.println(entry.getKey() + " = " + entry.getValue());
            sb.append(entry.getKey()+"="+entry.getValue()+"\n");
        });

        return sb.toString();
    }


} // end of outer class
728x90