Java, IntelliJ/Spring

Java Spring_API-GET/POST/PUT/DELETE

고로케 2021. 6. 27.
반응형
  • API :  클라이언트가 정한대로 서버에게 요청(Request)을 보내면,
    서버가 요구사항을 처리하여 응답(Response)을 반환합니다.
  • REST주소에 명사, 요청 방식에 동사를 사용함으로써 의도를 명확히 드러냄을 의미합니다.
    동사는 CRUD를 지칭한다.

CRUD 란 : 정보관리의 기본 기능

:  생성 (Create)→ 조회 (Read)→ 변경 (Update)→ 삭제 (Delete)


REST :   A에 대해 생성(POST)/조회(GET)/수정(PUT)/삭제(DELETE) 요청을 하는 것

예시)

GET /courses       → 강의 전체 목록 조회 요청

GET /courses/1     → ID가 1번인 녀석 조회 요청

POST /courses      → 강의 생성 요청

PUT /courses/3     → ID가 3번인 녀석 수정 요청

DELETE /courses/2 → ID 2번인 녀석 삭제 요청

 

 

 

API - GET (조회)

1)  controller 패키지 -> CourseController.java클래스 생성하기

코드 입력

@RequiredArgsConstructor  // final -> @RequiredArgsConstructor 입력
@RestController   // json 으로 응답해야하니까 
public class CourseController {

    // CourseRepository를 멤버변수로 하자 꼭 필요하니까 final
    private final CourseRepository courseRepository;

    @GetMapping("/api/courses")
    public List<Course> getCourses() {
        return courseRepository.findAll();
    }
}

 

2)  결과 확인

ARC 프로그램으로 확인해보자

Advanced REST Client (다운로드 링크)

 

Advanced REST Client

 

install.advancedrestclient.com

 

API - POST (생성)

1. GET에서 생성한 CourseController.java 클래스에 아래 코드 삽입

 

- @PostMapping("/api/courses") : 괄호 안의 주소로 오면 아래 메소드가 실행된다.

- 아래 생성한 public Course createCourse()는 기본적으로 생성한 Course를 반환한다.

- createCourse(@RequestBody CourseRequestDto requestDto)  괄호 안의 내용

  :  정보를 몰고다니는 CourseRequestDto 랑 같은 형태로 정보를 받는다. 반드시 @RequestBody 어노테이션을 작성해주어야 한다.

*Spring은 요청을 주고 받는 방식을 강제한다.
Post/Put이나 데이터를 주고 받을 때 API단에서 넘어오는 데이터를 잘 받으려면
RequestBody 형태로 받아줘야한다.
private final CourseService courseService;

// PostMapping을 통해서, 같은 주소라도 방식이 다름을 구분합니다.
@PostMapping("/api/courses") 
public Course createCourse(@RequestBody CourseRequestDto requestDto) {
		// requestDto 는, 생성 요청을 의미합니다.
		// 강의 정보를 만들기 위해서는 강의 제목과 튜터 이름이 필요하잖아요?
    // 그 정보를 가져오는 녀석입니다.
    
		// 저장하는 것은 Dto가 아니라 Course이니, Dto의 정보를 course에 담아야 합니다.
		// 잠시 뒤 새로운 생성자를 만듭니다.
		Course course = new Course(requestDto);
		
		// JPA를 이용하여 DB에 저장하고, 그 결과를 반환합니다.
    return courseRepository.save(course);
}

 

 

2. Course course = new Course(requestDto); 이부분의 오류

:  Course 클래스에 requestDto 파라미터로 받는 생성자가 아직 안만들어져 있기 때문이다.

controller 패키지의 CourseController.java 안에 아래 코드를 작성해주자.

# CourseController.java
    public Course(CourseRequestDto requestDto){
        this.title  = requestDto.getTitle();
        this.tutor = requestDto.getTutor();
    }

 

3. 결과 확인하기

1) Application 실행 후 ARC 프로그램에서 GET요청

 

2) POST 요청하면 에러가 난다,,?! Bad Request

 

=> POST 는 요청하는 방식이 정해져있는데 안지켜서 그렇다.

 

*해결 방법

: Spring POST방식에서 데이터를 전달하는 방식은 엄격하게 정해져 있기에 룰을 암기해야한다

 

1. HEADERS 탭 -> ADD 누르고 -> Name : Content-Type / Value : application/json 으로 설정해준다.

 

2. BODY 탭 -> input 창에 다음과 같이 작성한다.

작성 형식

{
"key1값": "value1값",
"key2값": "value2값"
}

3. 다시 POST 요청을 한다. 결과 확인

 

API - PUT (수정)

1. 다음 코드를 controller 패키지의 CourseController.java 에 추가한다.

 

- @PutMapping("/api/courses/{id}") : api course에 ID 값 넣어서 수정요청이 오면 

- 아래에 있는 public Long updateCourse() 라는 메소드를 실행해라

* { } 중괄호 안에는 변수명, 변형되는 값이 들어간다

* @PathVariable 어노테이션을 써야 변수명을 가져다 쓸 수 있다.

 

- 메서드 역할 : 아이디와 변경할 데이터를 가져오면 return 변경한 다음 id 값을 돌려주겠다

@PutMapping("/api/courses/{id}")
public Long updateCourse(@PathVariable Long id, @RequestBody CourseRequestDto requestDto) {
    return courseService.update(id, requestDto);
}

작성했으면 Application 을 실행 시킨다.

 

2. ARC 로 PUT 요청 해보기

1) 먼저 ARC로 GET 요청을 한다.

2)  PUT으로 변경하고 주소 courses 뒤에 /1 입력한다.

   HEADERS : Name : Content-Type / Value : application/json 설정

  

 

3) BODY 탭에 수정할 내용 입력 -> SEND 클릭

 

* 결과 

return 으로 

        return courseService.update(id, requestDto);

id 값을 돌려줬기 때문에 1이 출력됐다.

 

다시 결과를 확인하기 위해 GET요청을 한다.

* 이때 courses뒤에 /1 은 지워준다.

내용이 바뀐걸 확인했다.

 

API - Delete (삭제)

아래 코드를 controller 패키지의 CourseController.java 맨 아래 붙여 넣는다. -  끝

    @DeleteMapping("/api/courses/{id}")
    public Long deletCourse(@PathVariable Long id) {
        // 쿼리를 날리는 부분 : repository
        courseRepository.deleteById(id);
        return id;
    }

 

완성코드 접은 글

더보기

<application.properties>

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.show-sql=true

 

Week02Application

package com.sparta.week02;

import com.sparta.week02.Service.CourseService;
import com.sparta.week02.domain.Course;
import com.sparta.week02.domain.CourseRepository;
import com.sparta.week02.domain.CourseRequestDto;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import java.util.List;

@EnableJpaAuditing
@SpringBootApplication
public class Week02Application {

    public static void main(String[] args) {
        SpringApplication.run(Week02Application.class, args);
    }

    // Week02Application.java 의 main 함수 아래에 붙여주세요.
    @Bean
    public CommandLineRunner demo(CourseRepository courseRepository, CourseService courseService) {
        return (args) -> {
            courseRepository.save(new Course("프론트엔드의 꽃, 리액트", "고로케"));

            System.out.println("데이터 인쇄");
            List<Course> courseList = courseRepository.findAll();
            for (int i = 0; i < courseList.size(); i++) {
                Course course = courseList.get(i);
                System.out.println(course.getId());
                System.out.println(course.getTitle());
                System.out.println(course.getTutor());
            }

            CourseRequestDto requestDto = new CourseRequestDto("웹개발의 봄, Spring", "무야호");
            courseService.update(1L, requestDto);
            courseList = courseRepository.findAll();
            for (int i = 0; i < courseList.size(); i++) {
                Course course = courseList.get(i);
                System.out.println(course.getId());
                System.out.println(course.getTitle());
                System.out.println(course.getTutor());
            }
        };
    }
}

 

Service 패키지

>CourseService.java

package com.sparta.week02.Service;

import com.sparta.week02.domain.Course;
import com.sparta.week02.domain.CourseRepository;
import com.sparta.week02.domain.CourseRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@RequiredArgsConstructor
@Service // 스프링에게 이 클래스는 서비스임을 명시
public class CourseService {

    // final: 서비스에게 꼭 필요한 녀석임을 명시
    private final CourseRepository courseRepository;

    @Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌
    public Long update(Long id, CourseRequestDto requestDto) {
        Course course1 = courseRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
        );
        course1.update(requestDto);
        return course1.getId();
    }
}

 

domain 패키지

>Course

package com.sparta.week02.domain;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor // 기본생성자를 대신 생성해줍니다.
@Entity // 테이블임을 나타냅니다.
public class Course extends Timestamped {

    @Id // ID 값, Primary Key로 사용하겠다는 뜻입니다.
    @GeneratedValue(strategy = GenerationType.AUTO) // 자동 증가 명령입니다.
    private Long id;


    @Column(nullable = false) // 컬럼 값이고 반드시 값이 존재해야 함을 나타냅니다.
    private String title;

    @Column(nullable = false)
    private String tutor;

    public Course(CourseRequestDto requestDto) {
        this.title = requestDto.getTitle();
        this.tutor = requestDto.getTutor();

    }

    public Course(String title, String tutor) {
        this.title = title;
        this.tutor = tutor;
    }

    public void update(CourseRequestDto requestDto) {
        this.title = requestDto.getTitle();
        this.tutor = requestDto.getTutor();
    }
}

 

domain 패키지

>CourseRepository 인터페이스

package com.sparta.week02.domain;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@RequiredArgsConstructor
public class CourseRequestDto {
    private final String title;
    private final String tutor;
}

 

domain 패키지

>CourseRequestDto.java 클래스

package com.sparta.week02.domain;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@RequiredArgsConstructor
public class CourseRequestDto {
    private final String title;
    private final String tutor;
}

 

domain 패키지

> Timestamped.java 클래스

package com.sparta.week02.domain;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@MappedSuperclass // 상속했을 때, 컬럼으로 인식하게 합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/수정 시간을 자동으로 반영하도록 설정
public class Timestamped {

    @CreatedDate // 생성일자임을 나타냅니다.
    private LocalDateTime createdAt;

    @LastModifiedDate // 마지막 수정일자임을 나타냅니다.
    private LocalDateTime modifiedAt;
}

 

controller 패키지

>CourseeController.java 클래스

package com.sparta.week02.controller;

import com.sparta.week02.Service.CourseService;
import com.sparta.week02.domain.Course;
import com.sparta.week02.domain.CourseRepository;
import com.sparta.week02.domain.CourseRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RequiredArgsConstructor  // final -> @RequiredArgsConstructor 입력
@RestController   // json 으로 응답해야하니까
public class CourseController {

    private final CourseService courseService;

    // PostMapping을 통해서, 같은 주소라도 방식이 다름을 구분합니다.
    @PostMapping("/api/courses")
    public Course createCourse(@RequestBody CourseRequestDto requestDto) {
        // requestDto 는, 생성 요청을 의미합니다.
        // 강의 정보를 만들기 위해서는 강의 제목과 튜터 이름이 필요하잖아요?
        // 그 정보를 가져오는 녀석입니다.

        // 저장하는 것은 Dto가 아니라 Course이니, Dto의 정보를 course에 담아야 합니다.
        // 잠시 뒤 새로운 생성자를 만듭니다.
        Course course = new Course(requestDto);

        // JPA를 이용하여 DB에 저장하고, 그 결과를 반환합니다.
        return courseRepository.save(course);
    }


    // CourseRepository를 멤버변수로 하자 꼭 필요하니까 final
    private final CourseRepository courseRepository;

    @GetMapping("/api/courses")
    public List<Course> getCourses() {
        return courseRepository.findAll();
    }

    @PutMapping("/api/courses/{id}")
    public Long updateCourse(@PathVariable Long id, @RequestBody CourseRequestDto requestDto) {
        return courseService.update(id, requestDto);
    }

    @DeleteMapping("/api/courses/{id}")
    public Long deletCourse(@PathVariable Long id) {
        // 쿼리를 날리는 부분 : repository
        courseRepository.deleteById(id);
        return id;
    }
}

 

 

 

 

 

반응형

댓글