기록방
3장 : 게시판 만들고 새 글 작성하기: Create 본문
길벗 IT도서에서 주관하는 코딩 자율학습단 8기 : Spring Boot 파트에 참여한 기록입니다 [ 목록 ]
3.1 폼 데이터란
- 폼 데이터(form data)란 HTML 요소인
<form>
태그에 실려 전송되는 데이터- 게시판 내용 작성 후 [전송] 버튼 누를 때, 데이터를 서버로 전송할 때 사용 됨
- 택배처럼 어디로, 어떻게 보낼지 작성함
<form>
태그에 실어 보낸 데이터는 서버의 컨트롤러가 객체에 담아 받음.
이 객체를 DTO(Data Transfer Object)라고 함- DTO로 받은 데이터는 최종적으로 데이터베이스(DB, Database)에 저장 됨
3.2 폼 데이터를 DTO로 받기
3.2.1 입력 폼 만들기
{{>layouts/header}}
<form action="">
<input type="text">
<textarea></textarea>
<button type="submit">Submit</button>
</form>
{{>layouts/footer}}
3.2.2 컨트롤러 만들기
package com.example.firstproject.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ArticleController {
@GetMapping("/articles/new")
public String newArticleForm() {
return "articles/new";
}
}
⇒ CSS 수정하기
{{>layouts/header}}
<form class="container">
<div class="mb-3">
<label class="form-label">제목</label>
<input type="text" class="form-control">
</div>
<div class="mb-3">
<label class="form-label">내용</label>
<textarea class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{{>layouts/footer}}
3.2.3 폼 데이터 전송하기
<form>
태그에 action과 method 지정하기<form class="container" action="/articles/create" method="post">
3.2.4 폼 데이터 받기
ArticleContorller
에 메서드 추가@PostMapping("/articles/create") public String createArticle(){ return ""; }
3.2.5 DTO 만들기
package com.example.firstproject.dto;
public class ArticleForm {
private String title; // 제목을 받을 필드
private String content; // 내용을 받을 필드
public ArticleForm(String title, String content) {
this.title = title;
this.content = content;
}
@Override
public String toString() {
return "ArticleForm{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
3.2.6 폼 데이터를 DTO에 담기
@PostMapping("/articles/create")
public String createArticle(ArticleForm form){
System.out.println(form.toString());
return "";
}
3.2.7 입력 폼과 DTO 필드 연결하기
{{>layouts/header}}
<form class="container" action="/articles/create" method="post">
<div class="mb-3">
<label class="form-label">제목</label>
<input type="text" class="form-control" name="title">
</div>
<div class="mb-3">
<label class="form-label">내용</label>
<textarea class="form-control" rows="3" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{{>layouts/footer}}
🚀 1분 퀴즈
다음 중 옳지 않은 것을 고르세요.
- <form> 태그의 action 속성에는 데이터를 전달할 URL 주소가 담긴다.
- <form> 태그의 method 속성에는 get만 사용할 수 있다.
- @PostMapping 애노테이션은 post 방식으로 전달된 요청을 받아 컨트롤러의 메서드에 전달한다.
- 폼 데이터를 자동으로 받으려면 입력 폼에서 <input>, <textarea> 태그의 name 속성과 DTO 클래스의 필드명이 같아야 한다.
⇒ b. method 속성에는 get 뿐만 아니라 post, delete, put 과 같은 HTTP 메서드를 지정 할 수 있다.
3.3 DTO를 데이터베이스에 저장하기
3.3.1 데이터베이스와 JPA
- 데이터베이스란 데이터를 관리하는 창고.
- DB의 모든 데이터를 행과 열로 구성된 테이블(table)에 저장해 관리
- 실습에서는 H2 DB 사용
- DB에 명령을 내리기 위해서는 SQL(Structured Query Language)라는 언어 필요
- Java를 이용해 SQL을 쉽게 사용하기 위해서 JPA(Java Persistence API) 사용
- JPA를 사용해 데이터를 객체 지향적으로 관리 가능
- JPA의 핵심 도구는 엔티티(entitiy)와 레포지토리(repository)
- 엔티티 : 자바 객체를 DB가 이해할 수 있게 만든 것
- 이를 기반을 ㅗ테이블이 만들어짐
- 레포지토리 : 엔티티가 DB 속 테이블에 저장 및 관리될 수 있게 하는 인터페이스
- 엔티티 : 자바 객체를 DB가 이해할 수 있게 만든 것
3.3.2 DTO를 엔티티로 변환하기
@Controller
public class ArticleController {
@GetMapping("/articles/new")
public String newArticleForm() {
return "articles/new";
}
@PostMapping("/articles/create")
public String createArticle(ArticleForm form){
System.out.println(form.toString());
// 1. DTO를 엔티티로 변환
Article article = form.toEntity();
// 2. 레포지토리로 엔티티를 DB에 저장
return "";
}
}
- createArticle() 수정
Article
클래스 (엔티티) 만들어주기ArticleForm
DTO에toEntity()
메서드 만들어주기
package com.example.firstproject.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity // 엔티티 선언
public class Article {
@Id // 엔티티의 대푯값 지정
@GeneratedValue // 자동 생성 기능 추가(숫자가 자동으로 매겨짐)
private Long id;
@Column // title 필드 선언. DB 테이블의 title 열과 연결
private String title;
@Column // content 필드 선언. DB 테이블의 content 열과 연결
private String content;
public Article(Long id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
public Article() {
}
@Override
public String toString() {
return "Article{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
- JPA의 엔티티인 Article 클래스 생성
- 엔티티 선언은
@Entity
- 엔티티 대푯값 지정
@Id
- 숫자 자동 증가 생성
@GeneratedValue
- JPA 필드 선언
@Column
- 엔티티 선언은
- id, title, content 를 받는 생성자 필요
- 추가로 책에는 안 나온 것 같은데 JPA는 아무 매개변수가 없는 기본 생성자도 필요
- toString() 메서드 추가
public Article toEntity() {
return new Article(null, title, content);
}
ArticleForm
DTO에toEntity()
메서드 추가
3.3.3 리파지터리로 엔티티를 DB에 저장하기
1. 컨트롤러에서 리포지토리 사용
@Controller
public class ArticleController {
@Autowired
private ArticleRepository articleRepository;
@GetMapping("/articles/new")
public String newArticleForm() {
return "articles/new";
}
@PostMapping("/articles/create")
public String createArticle(ArticleForm form){
System.out.println(form.toString());
// 1. DTO를 엔티티로 변환
Article article = form.toEntity();
System.out.println(article.toString());
// 2. 레포지토리로 엔티티를 DB에 저장
Article saved = articleRepository.save(article);
System.out.println(saved.toString());
return "";
}
}
2. 리포지토리 생성
- 리포지토리 인터페이스를 JPA에서 제공하는 CrudRepository<T, ID> 인터페이스를 상속해 생성
- T는 관리 대상인 엔티티 클래스, Long은 대푯값(id)의 타입
- DB 데이터의 생성 읽기 수정 삭제의 CRUD 기본 동작을 제공해줌
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.data.repository;
import java.util.Optional;
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAllById(Iterable<? extends ID> ids);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
}
3. 객체 주입은 별도의 구현체 클래스 없이 @Autowired
사용
- 스프링 부트에서 제공하는 어노테이션으로, 스프링 부트가 만들어 놓은 객체를 가져와 주입해주어 구현체를 만들 필요 없음
- 이를 의존성 주입(DI, Dependency Injection) 이라고 부름
4. 출력해보면 DTO, 엔티티, DB 저장 데이터 모두 잘 나오는 모습
🚀 1분 퀴즈
- 다음 빈칸에 들어갈 용어를 쓰세요
- (
@Entity
)(이)란 JPA에서 제공하는 어노테이션으로, 이를 부여받은 클래스를 기반으로 DB 속 테이블이 생성됩니다. - (
CrudRepository<T, ID>
)(이)란 JPA에서 제공하는 인터페이스로, 이를 상속해 엔티티를 관리(생성, 조회, 수정, 삭제)할 수 있습니다. 해당 인터페이스는 2개의 제네릭 요소를 받습니다. 하나는 관리할 대상 엔티티의 클래스 타입이고, 또 다른 하나는 그 엔티티의 대푯값 타입입니다. - (
@Autowired
)은/는 스프링 부트에서 제공하는 어노테이션으로, 이를 컨트롤러의 필드에 부여할 수 있습니다. 해당 어노테이션은 스프링 부트가 만들어 놓은 객체를 가져와 주입해 줍니다.
- (
3.4 DB 데이터 조회하기
- DB의 테이블(table)은 행(row)와 열(column)으로 구성
- 현재 DB에 저장된 Article 테이블은 id, title, content라는 3개의 열로 구성
- DB의 데이터는 CRUD(생성, 조회, 수정, 삭제)를 기본 조작으로 하는데, SQL 에서 INSERT, SELECT, UPDATE, DELETE 문이 사용 됨
3.4.1 H2 DB 접속하기
1. application.properties
수정
server.servlet.encoding.force=true
spring.h2.console.enabled=true
- H2 DB에 웹 콘솔로 접근 허용
2. 서버 재실행 후 http://localhost:8080/h2-console 접속
- JDBC URL에 적힌 값이 DB 접근 주소인데 서버를 실행 할 때마다 바뀜
3. 인텔리제이 Run 탭에서 주소 찾기
- JDBC 검색하면 h2주소가 나옴
- 메모리 주소는 컴퓨터마다 다르고 서버 재시작 할 때마다 바뀜
4. Connect
3.4.2 데이터 조회하기
- 왼쪽 탭에서 ARTICLE 누르면
SELECT * FROM ARTICLE
문 나오고 Run 누르면 조회 성공
🚀 1분 퀴즈
- 다음 빈칸에 들어갈 용어를 쓰세요
- ( 테이블 ) : DB에서 데이터를 저장하는 틀
- ( 레코드 ) : 테이블의 행(row)을 표현하는 또 다른 말
- ( CRUD ) : 데이터의 생성/조회/수정/삭제를 뜻하는 말
- ( INSERT ) : 테이블에 데이터를 생성하는 SQL 문
- ( SELECT ) : 테이블에 데이터를 조회하는 SQL 문
✅ 셀프 체크
- 회원 가입 페이지 만들기
🏓 더 알아 볼 내용
1. @PostMapping
- HTTP POST 요청을 처리하기 위한 애노테이션으로 @RequestMapping(method = RequestMethod.*POST) 과 정확히 같은 역할을 수행한다.
- HTTP POST 요청은 GET 요청과 다르게 Body(본문)을 가질 수 있다.
- Body에 데이터를 넣어 보내겠다는 의미
- Body의 데이터 형식으로는 JSON 혹은 FORM 등을 사용
2. DTO와 Entity 분리의 장점
- 유연하지 못한 응답
- 만약 엔티티의 특정 필드를 보이면 안된다면, 필드와 연관 된 메서드를 모두 수정해야함
- 즉 응답과 모델 간의 분리가 힘들어짐
- 상호 참조 이슈
- SpringDataJPA를 사용하고 DB 테이블 간 상호 외래키 참조를 하고 있는 상황에서 모델을 View로 내 보내면 상호 참조 시 에러가 발생해 올바르지 못한 응답을 출력
- 보안 이슈
- Password 같은 정보를 저장하는 User 테이블이 있다면, Password 값이 응답으로 내 보내면 안됨
- 이런 정보들을 숨기기 위해서 응답용 DTO 클래스를 따로 사용하기도 함
- Entity에 없는 값이 필요한 경우
- DB에 저장하지 않고 비즈니스 로직에서 얻어서 내 보내야 하는 값이 있을 때
- Entity를 응답으로 사용한다면 Entity 클래스에 지나치게 많은 Getter가 생성될 수도 있고, 불필요한 로직이 존재할 수도 있게 됨
728x90
'FrameWork > Spring' 카테고리의 다른 글
5장 : 게시글 읽기: Read (0) | 2024.03.29 |
---|---|
4장 : 롬복과 리팩터링 (0) | 2024.03.22 |
2장 : MVC 패턴 이해와 실습 (0) | 2024.03.10 |
1장 : 스프링 부트 시작하기 (0) | 2024.03.06 |
코딩 자율학습단 8기 : 스프링 부트3 (0) | 2024.03.06 |