<스프링부트> 02. 생성

박서연·2023년 7월 13일
0

Spring

목록 보기
10/10

0. 목표

게시판 만들기 => CRUD 과정 구현
Create, Read, Update, Delete

1. 폼 데이터

1. 폼데이터

🔸 HTML 요소인 form 태그에 담긴 데이터
🔸 폼데이터는 서버로 전송하고 controller가 이를 객체(DTO)에 담아 받음
🔸 어디로 보낼지(action) + 어떻게 보낼지(method) form 태그에 포함되어있어야 함

2. 코드 작성

1) 입력 폼 만들기

🔸 src/main/resources/templates에 articles 이름의 디렉토리 생성
🔸 articles 디렉토리에 new.mustache 파일 생성
🔸 bootstrap에서 form 검색 후 복사

2) controller 추가

🔸 main/java/com.example.firstProject/controller 디렉토리에 ArticleController 파일 생성

[ArticleController]

[new.mustache]

[결과]

3) 폼데이터 전송

🔸 (HTML 변경)
🔸 mustache 파일의 form 태그에 action과 method 추가
🔸 action은 어디로 보낼지, method는 어떻게 보낼지 결정

4) 폼데이터 수신

🔸 controller에 메소드 추가
🔸 이때 annotation이 GetMapping이 아니라 PostMapping => 앞에서 생성한 mustache 파일에서 post로 전송했기 때문
🔸 PostMapping의 주소는 앞의 mustache에서 action으로 보낸 주소와 일치해야함

5) DTO 작성

🔸 데이터를 객체로 받아야하므로 DTO 필요
🔸 main/java/com.example.firstProject에 dto 디렉토리 생성 (controller와 같은 레벨에 존재)
🔸 dto 디렉토리에 ArticleForm 이름의 자바 클래스 파일 생성
🔸 해당 dto/ArticleForm이 데이터를 받아올 그릇 역할
🔸 2개의 데이터를 가져올 것이므로 private으로 변수 지정 후 생성자 생성 (마우스 우클릭해 Generate -> Constructor)
🔸 데이터를 잘 받았는지 확인하기 위해서 toString 메소드 생성 (마우스 우클릭해 Generate -> toString)
🔸 controller에서 PostMapping으로 받은 메소드의 파라미터에 DTO를 넣어야함
🔸 데이터 값을 보기 위해 파라미터.toString()으로 변환해 출력
[dto/ArticleForm]

[controller/ArticleController]

6) 입력값 이름 지정

🔸 mustache 내의 input 태그와 textarea 태그 내에 dto의 필드명과 동일한 이름이 name으로 지정되어야 함 => data가 dto와 연결되어 전달

<input type="text" class="form-control" name="title">
<textarea class="form-control" rows="3" name="content"></textarea>

7) 최종 코드

[templates/articles/new.mustache]

[controller/ArticleController]

[dto/ArticleForm]

[페이지&결과]

[전송전페이지]

[전송후페이지]

2. 데이터 생성 with JPA

🔸 위까지의 과정은 client -> server 까지의 과정. 하지만 이 데이터가 DB까지 연결되야 함

1. Database

🔸 데이터를 관리하는 창고로 H2 사용
🔸 스프링부트는 자바를 사용하지만 데이터베이스는 자바가 아닌 SQL 사용 => JPA가 자바를 SQL로 바꿔주며 데이터 관리에 필요한 여러 기능 제공
🔸 JPA의 핵심 도구는 entity와 repository

1) Entity

자바 객체(DTO)를 DB가 잘 이해할 수 있게 규격화된 객체로 만듬

2) Repository

entity는 repository를 통해 DB에 전달 및 처리

2. 코드 작성

Controller에서 데이터를 객체로 받은 메소드에 작성

1) 객체 -> Entity 변환

Article이라는 타입에 entity 반환

Article article = form.toEntity();

  1. Article이라는 타입이 없으므로 Article class 생성: Article에 마우스 hover하면 생성되는 모달창에서 생성. main/java/com.example.firstProject에 entity라는 디렉토리를 생성해 그 안에 Article class 생성
  • entity/Article에 @Entity annotation 작성해 entity임을 나타냄 => DB가 해당 객체 인식 가능
  • dto에서 존재한 title과 content를 private으로 선언한 후 각각을 @Column annotation을 넣어 DB에서 관리하는 table과 연결되도록 함
  • 대표값을 하나 넣어줘야함 (주민등록번호 같은 고유 번호). 이때 annotation @Id를 넣어주며 자동 생성할 경우 그 아래에 @GeneratedValue도 작성
  • 생성자와 toString() 추가

[entity/Article]

  1. toEntity()가 없으므로 생성
  • toEntity()에 hover하면 모달 창에 이를 생성할 수 있음. 클릭 시 객체(form)가 존재하는 dto 파일로 넘어감
  • toEntity는 Article 타입을 반환하기 원하기에 Article을 만들어 리턴
  • Article은 Entity 클래스이므로 entity 클래스의 객체를 생성해야함 => 생성자 호출

2) Repository에게 Entity를 DB 안에 저장하게 함

  1. articleRepository라는 저장소가 있다고 가정하고 그곳에 article 데이터를 save한 값을 반환
Article saved = articleRepository.save(article);
  1. articleRepository 객체가 실제로는 존재하지 않으므로 필드에 선언
private ArticleRepository articleRepository;

[ArticleController]

  • main/java/com.example.firstProject에 repository 디렉토리 생성 후 ArticleRepository 이름의 interface 파일 생성: repository를 직접 생성할 수도 있지만, JPA가 제공하는 인터페이스 사용

  • (repository) extends CrudRepository<관리대상 entity, 관리대상 entity의 대표값의 타입> => 해당 프로젝트에서 관리 대상 entity는 Article, 관리 대상 entity의 대표값은 @Id로 annotation한 것이므로 타입은 Long.
    위를 통해 crud(생성, 읽기, 수정, 삭제) 기능을 별도의 코드 작성 없이 사용 가능
    [repository/ArticleRepository]

  • save는 CrudRepository의 기본 기능이므로 오류 없이 사용 가능

  • ArticleController에 있는 ArticleRepository 위에 @Autowired를 하면 객체 생성을 하지 않아도 스프링부트가 미리 생성해놓은 객체를 가져와 자동 연결시킴

3. 결과

[controller/ArticleController]

[entity/Article]

[repository/ArticleRepository]

[실제 데이터 전송]

ㄴcontroller에서 dto, entity, repository를 출력한 것이 차례대로 나타남 (ArticleForm -> Article(entity) -> Article(repository))

3. DB 테이블과 SQL

1. 테이블 구조

🔸 DB에 저장된 데이터는 테이블이라는 틀에 관리

🔸 이전에 우리가 구현한 entity Article

2. SQL과 CRUD

🔸 CRUD는 DB 내에서 SQL 언어로 처리되는데, Insert(create), Select(read), Update(update), Delete(delete기능)

3. H2 DB 접속 설정

🔸src/main/java/resources/application.properties에 아래 코드 작성 => H2 DB를 웹 콘솔로 접근 허용

spring.h2.console.enabled=true

🔸 웹브라우저에 localhost:8080/h2-console로 검색

🔸 JDBC URL이라는 데이터베이스 접근 주소가 매번 바뀌기 때문에 찾아서 수정해야함 => IntelliJ 콘솔에서 ctrl+F 누른 후 jdbc 검색 => jdbc:h2:mem:a2212fad-07c4-4602-a375-c88ccdfbba9d 와 같이 jdbc부터 끝까지 복사

🔸 JDBC URL 붙여넣기 후 연결 완료

4. 테이블 조회

🔸 ARTICLE 클릭하면 SQL문으로 SELECT * FROM ARTICLE 나타남:ARTICLE 테이블에 있는 모든 것 조회 => Run 눌러 실행

🔸 위에는 현재 데이터가 없다고 뜨는데 이유는 memory에 저장되기 때문에 서버를 재시작하면 이전의 데이터가 모두 삭제됨

🔸 localhost:8080/articles/new에서 데이터 전송 후 table 확인


🔸 하나 더 추가

5. insert 데이터 생성

🔸 직접 작성해 DB에 추가 가능 => 이때 큰 따옴표(")가 아닌 작은 따옴표(') 사용해야함

insert into article(id, title, content)
values(3, 'cccc', '3333')


🔸 정상적으로 성공

🔸 테이블 조회

select * from article

4. 리팩터링 with 롬복

1. 롬복

🔸 코드를 간소화시켜주는 라이브러리
🔸 getter(), setter(), constructor(), toString() 등 필수 메소드의 반복을 간소화할 수 있음
🔸 로깅 기능을 통해 println도 개선(리팩토링)할 수 있음
🔸 리팩토링: 코드의 구조와 성능을 개선하는 작업, 로깅은 프로그램의 수행 과정을 기록으로 남기는 것

2. 목표

🔸 기존 코드: controller, dto, entity, repository
🔸 목표: 롬복을 통해 코드 간소화 & println 메소드를 로깅으로 변환

3. 롬복 라이브러리 설치

🔸 (코끼리 아이콘) build.gradle의 dependencies가 중요 => 라이브러리 존재
🔸 dependencies 안에 아래 코드 추가 후 위의 코끼리 버튼 클릭해 인터넷으로부터 해당 라이브러리 다운받아옴

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

🔸 오른쪽 Gradle 클릭하면 추가된 라이브러리 확인 가능

4. 롬복 플러그인 설치

🔸 Help > Find action > plugins 검색 후 Marketplace 클릭 후 lombok 검색 및 설치 => 현재 IntelliJ는 롬복이 자체 내장되어있어 설치할 필요 X

5. 로깅

🔸 실제 서버에서 println으로 검증하면 기록 남지도 않고 서버 성능에도 악영향을 미치므로 절대 사용 X => logging 사용
🔸 로깅: 서버에서 일어나는 모든 일을 모두 기록
🔸 controller에서 주로 사용하며 @Slf4j annotation 사용

6. 코드 변환

🔸 롬복: 기존 코드에는 생성사와 toString 메소드가 존재
1. 생성자 코드 삭제 -> public class ArticleForm {} 위에 @AllArgsConstructor 작성
2. toString 메소드 삭제 -> public class ArticleForm {} 위에 @ToString 작성
이후 잘 동작하는지 테스트
🔸 로깅:
1. @Slf4j annotation 작성
2. println 코드 삭제 후 log.info()
3. info의 파라미터로 출력을 원하는 값(println의 파라미터와 동일) 넣기

1) DTO 리팩토링

[기존dto]

[롬복 사용 dto]

2) Entity 리팩토링

[기존 entity]

[롬복 사용 entity]

3) Controller에서의 logging

🔸 @Slf4j annotation 사용

[기존 Controller] => 오타 존재. 아래의 logging 사용 controller의 주석 처리된 값이 맞음

[logging 사용 Controller]

🔸 logging으로 기록할 경우 앞의 시간과 같은 추가 정보도 나타남

0개의 댓글