[SPRING_입문]/개발일지

[2주차 과제] Spring Boot를 이용한 서버 구축

Code_Otaku 2022. 6. 18. 13:54

1. Setting [application.properties]

server.port=8090

spring.jpa.open-in-view=false

spring.h2.console.enabled=true

spring.jpa.show-sql=true
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MYSQL

스프링부트는 기본적으로 서버의 포트넘버가 8080으로 지정되어 있다.

하지만 본인은 이미 오라클 서버에서 해당 포트를 쓰고 있기 때문에

별도로 비활성화를 해주지 않는 이상 계속 충돌이 일어날 수밖에 없다.

 

하지만 이클립스 환경에서 만들고 있는 토이 프로젝트도 있기 때문에 오라클을 안쓸수는 없읆..

 

때문에 귀찮더라도 매번 config 값을 새롭게 갱신해주는 방법 밖에 없다.

 

 

2. [Person.java]

package com.sparta.server_run.domain;

// Auto Import

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

import javax.persistence.*;

@Getter // Generate getter automatically using Lombok
@Setter // Generate setter automatically using Lombok
@RequiredArgsConstructor // Lombok 기능을 사용하여 비어있는 생성자 자동생성
@Entity // Hey, Java! there is table on this page.

public class Person {

    @Id // This is Primary Key
    @GeneratedValue(strategy = GenerationType.AUTO) // Generate Table ID automatically.
    private Long id;
    // Table No.

    @Column(nullable = false) // This column must have value!
    private String name;
    // 이름

    @Column(nullable = false) // This column must have value!
    private String sex;
    // 성별

    @Column(nullable = false) // This column must have value!
    private int age;
    // 나이

    @Column(nullable = false) // This column must have value!
    private String job;
    // 직업

    @Column(nullable = false) // This column must have value!
    private String addr;
    // 주소

    @Column(nullable = false) // This column must have value!
    private String hobby;
    // 취미

    public Person(Long id, String name, String sex, int age,
                  String job, String addr, String hobby) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.job = job;
        this.addr = addr;
        this.hobby = hobby;
    }

    public Person(PersonRequestDto requestDto) {
        this.id = requestDto.getId();
        this.name = requestDto.getName();
        this.sex = requestDto.getSex();
        this.age = requestDto.getAge();
        this.job = requestDto.getJob();
        this.addr = requestDto.getAddr();
        this.hobby = requestDto.getHobby();
    }

    public void update(PersonRequestDto requestDto) {
        this.id = requestDto.getId();
        this.name = requestDto.getName();
        this.sex = requestDto.getSex();
        this.age = requestDto.getAge();
        this.job = requestDto.getJob();
        this.addr = requestDto.getAddr();
        this.hobby = requestDto.getHobby();
    }

}

코멘트를 상당히 심혈을 기울여서 달아놨기 때문에 별도의 설명은 필요없을 것 같다.

 

어노테이션 하나만으로 Getter나 Setter가 자동생성되는 저 아름다운 기능을 보아라.

갓 자바를 배우기 시작했을 때 한땀, 한땀 손으로 쳐가면서 만들어준 기억이 생생하다.

 

그래도 부연 설명을 좀 해볼까?

 

기본적으로 이 클래스는 나 외에 타인이 함부로 만지지 못하도록 'private' 으로 접근제한자를 걸어놨다.

그것을 다른 클래스에서 가져다가 쓰려면 *.getName() 이런 식으로 호출해서 써야 한다.

 

컬럼은 데이터베이스에서 열 하나 하나를 의미하는 값이다.

비어있으면 안되니까 (nullable == false)로 조건을 둬야겠지?

 

그 외에 궁금한 점은 코멘트를 참조하기 바란다.

 

3. [PersonRepository.java]

package com.sparta.server_run.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface PersonRepository extends JpaRepository<Person, Long> {
    // This page is Interface not a class
    // PersonRepository is abstract class
    // PersonRepository (child) inherit JAVA JpaRepository<> (parent)
}

해당 클래스는 일반적인 자바 클래스가 아니라 인터페이스이다.

기본적으로 추상 클래스이며 불완전한 상태의 설계도면이라고 생각하면 이해가 쉽다.

자식 클래스들이 해당 인터페이스를 상속받아 미완성된 구성요소들을 완성해서 쓰는 게 강요된다.

 

4. [PersonRequestDto.java]

package com.sparta.server_run.domain;

// Auto Import

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

@RequiredArgsConstructor // Lombok 기능을 사용하여 비어있는 타입의 생성자 자동생성
@Getter // Generate setter automatically using Lombok lib
@Setter // Generate setter automatically using Lombok lib

public class PersonRequestDto {
    // DTO: Data Transfer Object
    // Final is necessarily required data.

    private final Long id;
    private final String name;
    private final String sex;
    private final int age;
    private final String job;
    private final String addr;
    private final String hobby;

}

DTO, DTO, DTO...

Data Transfer Object!

즉, 데이터베이스 서버에 전송하기 위한 객체들이다.

 

접근제한자 앞에 굳이 final 타입을 지정해준 이유는 "너 이거 안가져다가 쓰면 죽어?" 의미 정도이다.

 

아! 참고로 PersonRequestDto 클래스를 쌩으로 생성해주면 빨간 줄과 함께 오류가 뜰 것이다.

기본생성자를 따로 만들어주지 않았기 때문이다.

@RequiredArgsConstructor 어노테이션을 선언해주면 Lombok이 알아서 생성해주는 편리한 기능이 있다.

 

IntelliJ 환경에서는 포르젝트를 생성할 때 라이브러리를 추가해주는 것만으로도 간단하게 쓸 수 있다.

이클립스는 아마 별도로 다운로드를 받아서 밀어넣어줘야 할 듯?

 

5. [PersonService.java]

package com.sparta.server_run.service;

// Auto Import

import com.sparta.server_run.domain.Person;
import com.sparta.server_run.domain.PersonRepository;
import com.sparta.server_run.domain.PersonRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service // Hey, Java! This page is Service Scope.
@RequiredArgsConstructor // lombok 기능을 활용하여 기본생성자 자동생성

public class PersonService {

    private final PersonRepository personRepository;
    // @RequiredArgsConstructor make it possible

    @Transactional // Hey, Java! there is SQL Query Request on this page.
    public Long update(Long id, PersonRequestDto requestDto) {
        Person per = personRepository.findById(id).orElseThrow(
                // SELECT ID FROM PERSONS
                // PERSONS 테이블에 해당 ID가 존재하지 않을 시 예외처리 기능 구현
                () -> new IllegalArgumentException("해당 테이블이 존재하지 않습니다!")
        );
        per.update(requestDto);
        return per.getId();
    }

}

SQL 요청을 처리하기 위한 서비스 기능단이다.

코멘트를 참조할 것..

 

6. [PersonController.java]

package com.sparta.server_run.controller;

// Auto Import

import com.sparta.server_run.domain.Person;
import com.sparta.server_run.domain.PersonRepository;
import com.sparta.server_run.domain.PersonRequestDto;
import com.sparta.server_run.service.PersonService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RequiredArgsConstructor // lombok lib 기능을 사용하여 기본생성자 자동생성
@RestController // Hey, Java! this page is optional REST Controller section.

public class PersonController {
    // Final is necessarily required data.
    private final PersonRepository personRepository;
    private final PersonService personService;

    @GetMapping("/api/persons")
    // READ
    public List<Person> getPersons() {
        return personRepository.findAll();
        // SELECT * FROM PERSONS;
    }

    @PostMapping("/api/persons")
    // CREATE
    public Person createPerson(@RequestBody PersonRequestDto requestDto) {
        // requestDto means Request Query.
        // PERSONS 테이블을 "생성"하기 위해서는 Person 클래스에서 선언한 변수들의 값이 요구된다.
        // 해당 데이터들을 load 하는 역활!

        Person person = new Person(requestDto);
        // Caution!: 저장되는 값은 requestDto 가 아니라 Person 이다.
        // 따라서 requestDto 의 데이터를 Person 에 저장해야 한다.
        // 초기화를 해주는 새로운 생성자 DIY!

        return personRepository.save(person);
        // JPA 기능을 활용하여 결과값을 DB에 저장하고, 값을 반환하는 역활
    }

    @PutMapping("/api/persons/{id}")
    // UPDATE
    // 특정 테이블만을 수정하기 위해 {id} 제한자를 둔다.
    public Long updatePerson(@PathVariable Long id, @RequestBody PersonRequestDto requestDto) {
        return personService.update(id, requestDto);
    }

    @DeleteMapping("/api/persons/{id}")
    // DELETE
    // 특정 테이블만을 삭제하기 위해 {id} 제한자를 둔다.
    public Long deletePerson(@PathVariable Long id) {
        personRepository.deleteById(id);
        // Caution!: 비몽사몽에 *.deleteAll() 메서드를 insert 해주면 돌이킬 수 없는 대참사가 일어날 수 있으니 주의할 것!
        return id;
    }

}

게시판의 C.R.U.D 기능을 실행하기 위한 자동응답기와 같은 자바 클래스이다.

 

이해를 돕기 위해 맥도날드를 생각해보자.

86번 손놈은 카운터를 통해서든, 키오스크를 통해서든 빅맥세트를 주문하고 싶다.

어떠한 경로로든 주문을 요청 (Request)하면, 거기에 대한 응답 (Response)으로 몇 분 내에 메뉴가 나와야 한다.

 

그 주문을 주방으로 전달하기 위한 매개체가 따로 필요하겠지?

그 매개체 역활을 하는 것이 바로 Controller단이다.

주방은 DB 서버 정도로 생각하면 이해가 빠를 것이다.

 

이 정도 개념을 잡고 코멘트와 함께 코드를 살펴보길 바란다.

 

이상으로 코드리뷰를 마치겠다!