P3] Ch 04. 스프링 부트 시작하기

uuuu.jini·2022년 1월 5일
0
post-thumbnail

목차

1.스프링 부트란
2. REST Client 설치 하기
3. GET API
4. Post API
5. PUT API
6. DELETE API
7. Response 내려주기
8. Object Mapper


1. 스프링 부트란

스프링 부트는 단순히 실행되며, 프로덕션 제품 수준 의 스프링 기반 어플리케이션을 쉽게 만들 수 있다. 여기서 프로덕션 제품수준이란 상품이 되어서 실제 사용자에게 제공이 가능한 수준까지 개발을 할 수 있다는 의미이다. 또한, 스프링 구성이 거의 필요하지 않고 jar로 실행하는 java 어플리케이션의 생성이 가능하다.

spring initaialize 패키지 다운 페이지를 통해 패키지 zip파일 다운 가능하다.

필수 요소 , 간단 설정, 빠르고, 대규모, 안정적, 불편설정 제거 등의 편리한 기능 제공으로 spring boot는 많이 사용되고 있다.


2. Hello Spring Boot

Rest Client 설치하기
rest Client 다운로드
웹 어플리케이션 개발시 GET 방식이 아닌 여러 메소드를 Test 하기 위한 툴

웹에서 요청을 받아서 hello spring boot를 반환하는 간단한 Controller를 구성해보았다.

@RestController // 해당 class 는 REST API 처리하는 Controller이다.
@RequestMapping("/api") // URI 를 지정해주는 Annotation
public class ApiController {

    @GetMapping("/hello") // http://localhost:8080/api/hello
    public String hello(){
        return "hello spring boot!";
    }
}

@RestController 는 rest api 처리를 해주는 Controller라는 것을 명시해주는 Annotation이고 @RequestMapping("주소") 는 URI와 연결해주는 annotation으로서 class를 정의하기 전에 필수로 작성해주어야 한다. 로컬 서버를 사용하고 있으므로, 주소는 http://localhost:8080 /api 로 해당 컨트롤러가 실행되며, GET 방식일 경우의 응답을 위해 @GetMapping("주소") 를 사용하여 해당 주소로 Get 요청이 올 경우 응답을 해준다.


3. GET API

@GetMapping()

ctrl키를 누르고 해당 어노테이션 클릭시 안에 들어갈 수 있는 속성들의 종류를 확인할 수 있으며, 그 중 value 와 path를 주로 사용한다.속성은 명시적으로 지정 하여 사용할 수 있다. ex) path='/hi'

이전에 사용하던 방법으로는 @RequestMapping을 사용하여 속성으로 path와 method를 받을 수 있으며, 이는 모든 메소드에 응답하므로 method로 정해주어야 한다.

Path Variable VS Query Parameter

Path Variable

주소를 요청할 때 데이터를 넘기는 방법 중의 하나로 변수를 경로처럼 작성하여 보낸다.

#id가 444번인 회원
/api/444 

http://localhost:8080/api/get/path-variable/{name}
여기서 {}안의 값은 변화할 수 있는 값의 속성 이름으로서 해당 값이 요청으로 넘어올 경우 (예로, yoojin) yoojin이라는 값이 name에 저장되게 된다. 이를 지정하기 위해서는 @GetMapping("/path-variable/{name}") 으로 변경되는 값을 {}안에 넣어주는 것이다. 그리고 대응 메소드의 매개변수로 @PathVariable String name 를 넘겨줌으로써 해당 값을 받아와서 사용할 수 있게 해준다. !!이때 주소에서 지정한 변수명과 매개변수 내의 어노테이션의 변수명을 같게 지정해주어야 한다.!!

  • 이름이 다르게 지정되는 것을 원하는 경우 @PathVariable(name= "name") String pathName 과 같이 name 속성으로 해당 변수명을 지정해주어야 한다.
    @GetMapping("/path-variable/{name}")
    public String pathVariable(@PathVariable String name){ 
        System.out.println("PathVariable: " + name);
        return name;
    }

Query Parameter

서버나 클라리언트에 무엇이 필요한지 묻는 문자열로서 주소 뒤에 물음표를 붙여 key=value 형식으로 작성하며, 여러개일 경우 &를 붙여준다.

#id가 444번인 회원
/api?id=444

👎 [java map 자료구조] 👎

Map은 선언 시 <key,value>로 값을 넣는다.
주요 메소드로

Map.put(key,value); // Map안의 값 넣기 
Map.get(key); // 안의 값 가져오기
Map.size(); //크기 확인
Map.replace(key,value); // 안의 내용 변경하기
Map.containsKey(key); // 키가 들어있는지 확인
Map.containsValue(value); //값이 들어있는지 확인
Map.isEmpty(); //크기가 0인지 확인
Map.remove(key);  //Map 안의 내용 삭제
Map.entrySet(); // Map의 전체 내용 가져오기 

Query Parameter를 사용하기 위한 세가지 방법이 있으며, 이를 아래에서 설명할 것 이다.
/api/get/query-param?name=yoojin&email=yoojin@gmail.com&age=25의 주소로 요청을 하는 것을 예로 들며, @GetMapping을 통하여 주소를 연결한 후 여러가지 방법을 통해 해당 쿼리의 값들을 가지고 온다.

1. Map으로 query Paramter를 받는 방법

해당 키와 value값을 map으로 받아서 각각을 getkey또는 getValue로 접근하는 방식으로 어떤 key던 오는 모든 값을 받는 것이 가능하다. 키가 명시되어 있지 않아서 개발하기에 불편할 수 있다.

    @GetMapping("/query-param")
    public String queryParam(@RequestParam Map<String,String> queryParam){ 
        StringBuilder sb = new StringBuilder();
        queryParam.entrySet().forEach(entry -> {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
            System.out.println("\n");
            sb.append(entry.getKey() + '=' + entry.getValue()  + '\n');
        });
        return sb.toString();
    }

@GetMapping 으로 주소를 지정해준뒤 뒤의 =으로 연결된 여러 key와 value를 Map형식으로 받아오기 위하여 매개변수로 Map형을 사용하였으며, 요청을 받아오기 위해서는 @RequestParam 어노테이션이 필요하다.

2. 명시적으로 key를 지정해주는 방법

해당 키의 이름을 지정하여 받아오는 방법으로 명시적이므로 개발하기에 편리하다.

    @GetMapping("/query-param02")
    public String queryParam02(
        @RequestParam String name, 
        @RequestParam String email,
        @RequestParam int age
        ){
        System.out.println(name+email+age);
        return name+email+age;
    }

매개변수로 받아올 key값의 이름을 명시해준다. 이때 위와 마찬가지로 @RequestParam 을 사용해야 한다.

3.클래스로 받아올 key값의 생성해두는 방법

받아올 값들을 미리 class로 구성해두고, 객체를 사용한다.

    @GetMapping("/query-param03") 
   public String queryParam03(UserRequest userRequest){  	
   System.out.println(userRequest.getName()+userRequest.getEmail()+userRequest.getAge());
       return userRequest.toString();
   }

가장 현업에서 많이 사용되는 방법이며, 클래스로 생성해둔 각 변수들을 받아올 속성의 이름과 일치 시켜주어야 하며, 어노테이션을 사용하지 않아 쉽게 사용할 수 있다.


4. POST API

JSON 데이터

{
	"key" : "value"
}
  • 자료형 : string, number, boolean, object({}), array([])
    카멜 케이스 phoneNumber, 스네이크 케이스 phone_number 의 둘중 하나를 이용한다.

  • 예시

{
	"phone_number" : "010-1111-2222",
  	"age" : 10, //number 형
  	"isAgree" : false, //boolean 형
  	"account" : { //object형의 value를 받음 '{}'
      	"email" : "steve@gmail.com",
      	"password" : "1234"
    }
}

//user 조회 하는 경우
{
  "user_list" : [ //array 형의 value를 받음 [] , 안에 동일한 키 값을 가진 object를 포함하고 있다. 
	{
  "account" : "abcd",
  "password" : "1234",
		}
    {
  "account" : "aaaa",
  "password" : "1111",
		}
    
    ]
}

@PostMapping()

Get 메소드와 동일하게 처음 클래스 윗부분에는 항상 @RestController@RequestMapping 을 설정한다.

post방식은 생성으로서 멱등하지 않고, 주로 path variable형식을 사용하며, data body를 포함시켜 서버에 전송한다. 이때, 주소와 매칭 시키는 어노테이션인 @PostMapping 과 바디의 Json 데이터를 파싱하여 받아오기 위한 어노테이션인 @RequestBody 를 사용한다.

    @PostMapping("/post2")
    public String post2(@RequestBody PostRequestDto postRequestDto){
        return postRequestDto.toString();
    }

post도 get과 동일하게 map으로 데이터를 받을 수 있으나 이럴 경우 어떤 키가 들어오는지 알 수 없어 명확하지 않다는 문제가 생긴다. 그래서 해당 dto를 만들어 사용한다. 이때 사용하는 변수 명 ( 속성 명 )은 받아오는 데이터들의 키의 이름과 동일해야 한다.

@JsonProperty("이름")

카멜 케이스와 스네이크 케이스가 일치하지 않을 경우 null값이 전송되는 현상이 발생하며, 이를 매칭해주기 위해서는 @JsonProperty("이름") 을 해당 변수명위에 붙여준다.

@JsonProperty("phone_number")
private String phoneNumber;

path-vriable을 받는 방식은 Get 과 동일함으로 이를 참고한다.


5. PUT API

post방식과 굉장히 비슷하며, @RestController()@RequestMapping(주소) 를 항상 작성하고 시작한다.

@PutMapping

Put메소드는 생성과 수정을 하며, 멱등하고 path variable을 사용한다. 데이터 바디(json)을 포함시켜 요청을 할 수 있다.


    @PutMapping("/put")
    public PostRequestDto put(@RequestBody PostRequestDto postRequestDto){
        System.out.println(postRequestDto);
         return postRequestDto;    
    }

@PostMapping() 을 통하여 주소를 매핑하고, 클래스로 설정한 해당 데이터 형태로 json데이터를 파싱받는다. 해당 객체를 반환할 경우 @JsonNaming() 을 통하여 일괄적으로 적용한 타입(스네이크,카멜)에 따라 적용후 json 파일을 반환(Response)해준다.

@JsonNaming()

한 클래스의 모든 변수의 규칙을 카멜 또는 스네이크로 일괄적으로 적용해주는 것이다. 가장 위에 작성하며 위에서 배운 @JsonProperty() 와 다르게 한번에 적용할 수 있다. value = PropertyNamingStrategy.SnakeCaseStrategy.class 또는 Camel로 작성이 가능하다.

@PathVariable

다른 메소드와 사용방법이 같으며, 주소의 {} 안의 이름과 해당 @PathVariable로 선언한 이름이 일치해야 한다는 것에 주의해야 한다.

 @PutMapping("/put2/{userID}")
    public PostRequestDto put2(@RequestBody PostRequestDto postRequestDto, @PathVariable String userID){
        System.out.println(userID);
        return postRequestDto;
    }

6. DELETE API

Delete 메소드는 삭제 API이며, 멱등하고 안정하지 않다. Path Variable과 Query Parameter모두 사용하지만 , Data Body를 가지지 않는다.

@DeleteMapping()

get방식과 동일하다.


    @DeleteMapping("/delete/{userId}") 
    public void delete(@PathVariable String userId, @RequestParam String account){
        System.out.println(userId);
        System.out.println(account);
    }

delete 메소드는 삭제 api이므로, 여러가지 값을 받지 않는다. 주로 @PathVariable을 사용하거나 @RequestParam을 통하여, query를 받는 형식으로 작성한다. 삭제이므로 데이터가 없어도 에러를 발생하지 않고 항상 200 OK를 리턴한다.


7.Response 내려주기

1] String response

   @GetMapping("/text")
    public String text(@RequestParam String account){
        return account;
    }

반환값을 string 형태로 작성한다.

2] json response

@RestController 에서는 object형을 반환하는 경우 자동으로 json데이터의 형태로 반환해준다.

    @PostMapping("/json")
    public User json(@RequestBody User user){
        return user; //항상 200 OK 를 리턴한다.
    }

request -> object mapper -> object -> method -> object -> object mapper -> json -> response 의 순서로 변경되어 요청된 json이 object형태로 변환되어 해당 자바 메소드를 거치며 , 응답시에는 다시 json데이터 형태로 변환된다.위와 같이 반환을 할 경우에는 항상 200 ok를 반환한다. 이때 , 다른 응답 상태를 리턴하기 위해 밑의 방법을 사용한다.

3] ResponseEntity

응답 상태와 데이터를 함께 보낼 수 있는 방법으로, 명확하게 설정할 수 있어서 주로 사용하는 방법이다.

    @PutMapping("/put")
    public ResponseEntity<User> put(@RequestBody User user){
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }

4] @Controller

@RestController 가 아닌 @Controller 이용시에는 해당 메소드가 string을 리턴시 resource에 접근하여 해당 페이지를 반환해준다.

    @RequestMapping ("/main")
    public String main(){ //리턴형이 string 일 경우 자동으로 resource의 html을 찾아준다.
        return "main.html";
    }

해당 어노테이션 안에서 json데이터를 리턴하기 위해서는 @ResoponseBody를 사용해야 한다. 주로 RestController에서 자동으로 json데이터로 반환해주는 것을 사용하므로 해당 방법은 주로 사용하지 않는다.

@JsonIclude 는 원하는 값들만 json 데이터에 포함시킬 수 있다.


8.Object Mapper

main 이 아닌 test에 작성한다.
object Mapper 는 Json(text) 를 Object로 Object를 Json(text)로 변환해주는 역할을 한다.

var objectMapper = new ObjectMapper() 를 활용하여 변환을 수행한다.

1] Object -> Text(json)

object mapper가 get메소드를 참조하므로 해당 object 클래스에는 get 메소드(getter)가 필요하다. 이때, 다른 메소드에는 get이 포함되지 않도록 해야한다.

        User user  = new User("steve",10,"010-2222-33");
        var text = objectMapper.writeValueAsString(user);
        System.out.println(text);

objectMapper의 writeValueAsString 메소드를 사용하며 인자로 해당 object 클래스를 받아서 text(json)형태로 변환하여 준다.

2] Text(json) -> Object

Object Mapper 가 default 생성자를 필요로 하므로 해당 object 클래스에 기본 생성자가 있어야 한다.

        var objectUser = objectMapper.readValue(text,User.class);
        System.out.println(objectUser);

objectMapper의 readValue 메소드를 사용하며 인자로 변환할 text와 변환할 object 클래스를 받아서 Object로 변환하여 준다.

@JsonNaming은 기존에 알던 방식과 동일하게 사용된다. 즉 , 해당 케이스로 object를 지정해 놓앗을 경우 해당 케이스가 일관적으로 json데이터에 적용된다.

profile
멋쟁이 토마토

0개의 댓글