Post

[Spring Boot] 게시판 만들고 새 글 작성하기: Create

폼 데이터란?

HTML 요소인 <form> 태그에 실려 전송되는 데이터, 웹 브라우저에서 서버로 데이터를 전송할 때 사용

  • form 태그에 실어 보낸 데이터는 서버의 컨트롤러가 객체에 담아 받는다.
  • 이 객체를 DTO(Data Transfer Object)라고 한다.
  • DTO로 받은 데이터는 최종적으로 데이터베이스에 저장된다.

폼 데이터를 DTO로 받기

HTML에서 요청 보내기

  • 태그를 입력하려면 데이터를 어디로, 어떻게 보낼지에 대한 정보가 필요하다.
  • 어떻게 보낼지는 action 속성으로, 어떻게 보낼지는 method 속성으로 설정한다.
1
<form class="container" action="/articles/create" method="post">

action : URL 연결 주소를 적어 localhost:8080/URL 연결 주소 페이지로 폼 데이터를 보낸다는 의미다.

method : 속성 값으로 getpost를 설정할 수 있다.

Controller에서 요청 받기

1
2
3
4
5
6
7
@Controller
public class ArticleController {
    @PostMapping("/articles/create")
    public String createArticle() {
        return "";
    }
}

form에서 보낸 데이터를 Controller에서 받아준다.

뷰 페이지에서 post 방식으로 폼 데이터를 전송했으므로 받을 때도 @PostMapping으로 받아주어야 한다.

❔ @GetMapping과 @PostMapping의 차이

@GetMapping : HTTP GET 요청을 특정 핸들러 메소드에 매핑하기 위한 주석이다. 특히 특히 @GetMapping@RequestMapping(method = RequestMethod.GET)에 대한 바로가기 역할을 하도록 구성된 주석.

@PostMapping : HTTP POST 요청을 특정 핸들러 메소드에 매핑하기 위한 주석이다. 특히 특히 @PostMapping@RequestMapping(method = RequestMethod.POST)에 대한 바로가기 역할을 하도록 구성된 주석.

HTTP POST 요청은 GET 요청과 다르게 JSON과 FORM 등의 데이터 형식을 사용해 데이터를 보낼 수 있는 Body(본문)를 가진다.

DTO 만들기

폼 데이터를 받아올 그릇을 만든다.

  1. DTO는 com.example.firstproject.dto와 같이 dto 패키지를 만들어 보관한다.
  2. 전송할 내용에 따라 필드를 만들어 준다.
  3. 전송받은 내용을 필드에 저장하는 생성자와 폼 데이터를 잘 받았는지 확인하기 위한 toString() 메서드를 추가해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 + '\'' +
                '}';
    }
}

폼 데이터를 DTO에 담기

이제 폼 데이터를 담을 그릇이 준비되었으니, 데이터를 DTO에 담아 Controller로 가져온다. 만든 Controller의 매개변수로 DTO를 받도록 한다. toString()을 통해 받은 내용이 출력될 수 있도록 한다.

1
2
3
4
5
@PostMapping("/articles/create")
    public String createArticle(ArticleForm form) {
        System.out.println(form.toString());
        return "";
    }

입력 폼과 DTO 필드 연결하기

입력 폼에서 전송한 데이터를 DTO로 받기 위해서는 DTO의 필드명과 폼 데이터에 담긴 name 명이 일치해야 한다. name이 곧 키 값으로 사용되기 때문이다.

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

사용자로부터 입력받을 title, content 요소에 각각 name 속성을 추가한다.

서버를 재시작하고 제목과 내용을 입력한 후 Console을 확인하면 정상적으로 데이터가 보내지고 있음을 확인할 수 있다.

Form data to console

과정 요약

  1. 뷰 페이지를 만들고 <form> 태그의 action 속성으로 데이터를 어디로 보낼지, method 속성으로 데이터를 어떻게 보낼지 정의한다.
  2. 컨트롤러를 만들고 PostMapping 방식으로 URL 주소를 연결한다.
  3. 전송받은 데이터를 담아 둘 객체인 DTO를 만든다.
  4. 컨트롤러에서 폼 데이터를 전송받아 DTO에 담는다.

DTO를 데이터베이스에 저장하기

JPA와 H2 Database를 사용해 DTO를 데이터베이스에 저장할 수 있다. DTO를 엔티티로 변환하고, 리파지터리를 이용해 엔티티를 DB에 저장한다.

JPA(Java Persistence API)란?

  • 자바 언어로 DB에 명령을 내리는 도구로, 데이터를 객체 지향적으로 관리할 수 있게 해준다.
  • 자바 애플리케이션과 JDBC 사이에서 동작하며 자바 인터페이스로 정의되어 있다.
  • 자바에서 사용하는 ORM(Object-Relational Mapping) 기술 표준이다.
  • 핵심 도구로는 Entity와 repository가 있다.
    • entity : 자바 객체를 DB가 이해할 수 있게 만든 것으로, 이를 기반으로 테이블이 만들어진다.
    • repository : 엔티티가 DB 속 테이블에 저장 및 관리될 수 있게 하는 인터페이스

❔ ORM(Object-Relational Mapping, 객체 관계 매핑)

  • 객체와 관계형 데이터베이스의 데이터를 매핑하는 기술
  • ORM 프레임워크가 객체와 데이터베이스 중간에서 매핑
  • 객체와 테이블을 매핑하여 패러다임 불일치 문제 해결

DTO를 엔티티로 변환하기

  • Entity는 DTO와 같이 따로 관리해주어야 한다. 이는 다음과 같은 이유들 때문이다. 자세한 내용은 추후 포스팅으로 다루어 보겠다.
    • 유연한 응답
    • 상호 참조 이슈 해결
    • 보안 이슈 해결
    • Entity에 없는 값이 필요한 경우 불필요한 로직 생성 방지
  1. entity 패키지를 만들고 Entity 클래스를 생성한다.
    • @Entity : 이 클래스가 Entity임을 선언한다. 이 어노테이션이 붙은 클래스를 기반으로 DB에 테이블이 생성된다. 테이블 이름은 클래스 이름과 동일하다.
    • @Column : DB 테이블의 각 열과 연결된다.
    • @Id : Entity의 대표값을 지정한다.
    • @GeneratedValue : 대푯값을 자동으로 생성하게 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Entity
public class Article {
    @Id
    @GeneratedValue
    private Long id;
    @Column
    private String title;
    @Column
    private String content;

    public Article(Long id, String title, String content) {
        this.id = id;
        this.title = title;
        this.content = content;
    }

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}
  1. DTO 클래스에 toEntity() 메서드를 추가한다. toEntity() 메서드는 DTO인 form 객체를 엔티티 객체로 변환하는 역할을 한다. Entity 클래스의 생성자 형식에 맞게 작성한다.
1
2
3
    public Article toEntity() {
        return new Article(null, title, content);
    }
  1. Controller에 form 객체의 toEntity()라는 메서드를 호출해서 그 반환값을 Article 타입의 article 엔티티에 저장한다.
1
2
3
4
5
6
7
8
    @PostMapping("/articles/create")
    public String createArticle(ArticleForm form) {
        System.out.println(form.toString());
        // 1. DTO를 엔티티로 변환
        Article article = form.toEntity();
        // 2. 리파지터리로 엔티티를 DB에 저장
        return "";
    }

리파지터리로 엔티티를 DB에 저장하기

  1. repository 패키지를 만들고 ArticleRepository 인터페이스를 만든다. 사용자가 직접 구현할 수도 있지만, JPA에서 제공하는 리파지터리 인터페이스를 활용해 만들 수도 있다.

  2. CrudRepository 인터페이스를 상속받는다. <관리 대상 엔티티의 클래스 타입, 관리 대상 엔티티의 대푯값 타입>을 제네릭 요소로 받는다.

1
2
3
public interface ArticleRepository extends CrudRepository<Article, Long> {

}
  1. 스프링 부트에서는 객체를 만들지 않아도 스프링 부트가 알아서 객체를 만들어 준다. @Autowired 어노테이션을 붙이면 스프링 부트가 미리 생성해 놓은 객체를 가져다가 연결해 준다. 이를 의존성 주입(DI, Dependency Injection) 이라고 한다.
1
2
    @Autowired
    private ArticleRepository articleRepository;
  1. articleRepository.save() 메서드를 호출해 엔티티를 저장한다. save() 메서드는 저장된 엔티티를 반환하므로 이를 Article 타입의 saved라는 객체에 받아온다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller
public class ArticleController {
    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();
        // 2. 리파지터리로 엔티티를 DB에 저장
        Article saved = articleRepository.save(article);
        return "";
    }
}
  1. toString() 메소드를 통해 article이 DB에 잘 저장되는지 확인할 수 있다.

Article console

🔗 참고자료

📚 더 공부해야 할 것

  • 의존성 주입
  • DTO와 Entity 분리하는 이유와 장단점
  • JPA
This post is licensed under CC BY 4.0 by the author.