Java

220521 Springboot 분노의 API만들기

Vince_rf 2022. 5. 21. 23:46

# 스프링 2주차 小怒의 내용 정리

220523 기준 이것은 그저 Restcontroller을 이용해 만드는 방식이라는 것을 알고 결국 中怒로 격상하였다. 

1. models 패키지 생성 ( 앞으로 만들 대부분의 repository 와 domain은 models 패키지에 만든다.) 

2. models 패키지 안에 Person클래스, PersonRepository( 인터페이스 ) 생성 ( Person은 임의로 정한 프로젝트 )

3. build.gradle -> dependencies -> maven repository에서 가져온 JSON IN JAVA gradle 코드 추가 -> dependencies 옆에 실행버튼 으로 실행 -> BUILD SUCCESSFUL 메시지 확인

4. (H2 데이터베이스 쓸 때) 

resources -> application.properties에다가 
spring.h2.console.enabled=true // h2콘솔 보이게 해주는 코드
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MYSQL // h2 데이터베이스를 쓰겠다는 코드

추가

5.public class Person 클래스 위에 @NoArgsConstructor (기본생성자가 없을 때 자동생성) 와 @Entity (테이블임을 나타냄) 어노테이션 추가, 매개변수를 가진 생성자 추가

6-1. 멤버변수 프라이빗으로 선언 ( ID를 고유번호로 주고 ID로 데이터를 구분할 것이기 때문에 ID에 @ID 어노테이션과 @GeneratedValue(strategy = GenerationType.AUTO) (자동증가명령) 추가

6-2. 나머지 멤버변수는 @Column(nullable = false) (컬럼값이고 값이 존재해야함을 나타냄)어노테이션 추가

7. 게터 추가 ( 세터는 Repository에서 자동으로 처리를 해줄 것임 )  -> 게터 추가를 건너 뛰려면 15번 항목 참조.

8. PersonRepository 인터페이스에 
public interface PersonRepository extends JpaRepository<Person, Long> {
}
추가, Repository 인터페이스는 SQL역할을 대신해주는 인터페이스이기 때문에, SQL을 자바언어로 번역해주는 JpaRepository를 상속받는다. <Person, Long> ( Person이라는 클래스를 쓸 것이고, ID의 형태는 Long이다 )

9. application.properties 에 spring.jpa.show-sql=true (스프링이 JPA로 작동할 때 SQL을 보여달라는 뜻) 추가

10-1. models 패키지에 Timestamped 클래스 생성

@MappedSuperclass // 상속했을 때, 컬럼으로 인식하게 합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/수정 시간을 자동으로 반영하도록 설정
public abstract class Timestamped { // 추상클래스이기 때문에 상속으로만 쓸 수 있다.

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

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

을 추가한다. 

10-2.그 후에 Person 클래스로 돌아가서 -> public class Person extends Timestamped 퍼블릭 클래스가 Timestamped 클래스를 상속받게 한다.

10-3. 그 후에 PersonApplication으로 가서 @SpringBootApplication 어노테이션 위에 @EnableJpaAuditing을 추가해준다.

11. PersonApplication main함수 아래에

@Bean
        public CommandLineRunner demo(PersonRepository personRepository){
        return (args) -> {
            // 데이터 저장하기
            repository.save(new Course("프론트엔드의 꽃, 리액트", "임민영"));

// 데이터 전부 조회하기
            List<Course> courseList = repository.findAll(); // personRepository.fineAll(); 등 repository 모두 personRepository 로 변경
            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());
            }

// 데이터 하나 조회하기
            Course course = repository.findById(1L).orElseThrow( // findById는 아이디를 통해서 데이터를 찾는 방식인데, 우리가 설정해준 ID는 Long타입이기 때문에 숫자뒤에 L을 붙여줬다.  
                    () -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.") // .orElseThrow() 는 괄호안에 해당 아이디를 찾지 못했을 때 어떻게 하라는 명령을 담은 메서드가 들어간다. 
       // new NullPointerException("아이디가 존재하지 않습니다.") 도 가능하다.
            );

        };
        }

를 추가하고 Person에 맞게 고쳐준다.

12. Person 클래스에 update 메서드 추가 ( 보통 가장 아래에 추가 )  ( RequestDto가 만들어져 있다면 16번 항목 참조 ) ( RequetDto가 없을 경우에 먼저 만들어놔도 무방하니 16번 항목 참조해서 먼저 만들면 편함 )

public void update(Course course) {
    this.title = course.title;
    this.tutor = course.tutor;
}

추가하고 나서, Person에 맞게 고쳐준다.

13. 프로젝트 패키지 안에 service 패키지를 추가해준다. ( 이러면 프로젝트 패키지 안에 새로 생성한 패키지는 models, service가 된다. )
service 패키지 안에 PersonService 클래스를 생성하고 아래를 추가한다. ( 중간에    // 생성자를 통해~~~~~~~@Transactional 를 생략하고 싶다면 15-2 항목 참조 )

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

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

// 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록
// 스프링에게 알려줌
    public CourseService(CourseRepository courseRepository) {
        this.courseRepository = courseRepository;
    }

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

추가 후에, Person에 맞게 고친다.

14. PersonApplication 으로 가서 데이터 findAll 아래에 다음의 update코드를 추가한다.  ( RequestDto가 만들어져 있다면 16번 항목 참조 )

//데이터 업데이트
            Course new_course = new Course("웹개발의 봄, Spring", "임민영");
            courseService.update(1L, new_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());
            }
        };

추가 후에, Person에 맞게 고친다. 주의할 점은, personService가 추가됐으므로, 
public CourseService(CourseRepository courseRepository) 를 public CourseService(CourseRepository courseRepository, PersonService personService) 로 바꿔줘야한다. 

15-1. Lombok의 사용법은 다음과 같다. 
Person클래스로 가서 Getter를 지운다. 그 후에 Person 클래스의 public 클래스위에 @Getter 어노테이션을 추가해준다.

15-2. PersonService 클래스로 가서 아래의 코드를 삭제한다.

    // 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록
    // 스프링에게 알려줌
    public PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

그 후에, 상단에 @RequiredArgsConstructor 어노테이션을 추가해주면 된다.

16-1. models에 PersonRequestDto 클래스 생성 후에 아래의 코드를 추가

@Getter
@Setter
@RequiredArgsConstructor
public class PersonRequestDto {
    private final String name;
    private final int age;
    private final String address;
    private final String job;
}

그 후에, PersonApplication 으로 가서 업데이트 부분을 고쳐준다.

Person new_person = new Person("박이김",53,"울릉도","교사");
            personService.update(1L, new_person);

첫 두 줄이 위와 같이 되어있을텐데, 이것을

PersonRequestDto personRequestDto = new PersonRequestDto("박이김",53,"울릉도","교사");
            personService.update(1L, personRequestDto);

이렇게 고쳐준다. 그리고 PersonService 클래스로 가서 역시 업데이트 부분을 살펴보면

@Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌
    public Long update(Long id, Person person) {

시작 부분이 위와 같다. 이것을

@Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌
    public Long update(Long id, PersonRequestDto personRequestDto) {

이렇게 고쳐주고 아래 부분에 

person1.update(person);   역시 person1.update(personRequestDto); 로 바꿔준다.

16-2. 그래도 빨간줄이 남아있을텐데 이번에는 Person 클래스에서 update 부분을 손봐줘야한다.

public void update(PersonRequestDto personRequestDto) {
        this.name = personRequestDto.getName();
        this.age = personRequestDto.getAge();
        this.address = personRequestDto.getAddress();
        this.job = personRequestDto.getJob();
    }

주의 사항은 personRequestDto.get~~~(); 로 변한다는 것.

17. 프로젝트 패키지에 controller 패키지를 만들고 내부에 PersonController 클래스를 생성한다. ( 그러면 프로젝트 패키지 내부에는 models, service, contoller 패키지가 존재하게 된다. )
그 후에, 아래의 코드를 추가해서 Person에 맞게 수정한다.

@RequiredArgsConstructor
@RestController
public class CourseController {

    private final CourseRepository courseRepository;

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

그 후에, http://localhost:8080/api/persons로 접속하면 JSON이 출력될 것이다.

'Java' 카테고리의 다른 글

220523 대체 게터 세터는 왜 씀?  (0) 2022.05.23