Computer Science/Database

[Database] Spring Boot 프로젝트와 MySQL DB 연결 (MVC, DTO)

Bay Im 2024. 4. 6. 12:59

MySQL 데이터베이스 연동 MVC

  • application.properties 추가
    • spring.jpa.hibernate.ddl-auto=
      • none
        • 기본 값, 데이터베이스 구조는 변경되지 않는다.
      • update
        • Hibernate 주어진 엔터티 구조에 따라 데이터베이스를 변경한다.
      • create
        • 매번 데이터베이스를 생성하지만 닫을 때 DROP 하지 않는다.
      • create-drop
        • 데이터베이스를 생성하고 SessionFactory가 닫힐 때 삭제합니다.
      • validate
        • 엔티티와 스키마가 다르다면 예외발생
    • 예시
      • # thymeleaf
        spring.thymeleaf.cache=false
        
        # jpa
        spring.jpa.hibernate.ddl-auto=none
        spring.jpa.generate-ddl=false
        spring.jpa.show-sql=true
        spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
        
        # pretty sql format
        spring.jpa.properties.hibernate.format_sql=true
        spring.jpa.properties.hibernate.use_sql_comments=true
        
        # mysql
        spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
        spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/mydb?characterEncoding=UTF-8&serverTimezone=Asia/Seoul
        spring.datasource.username=root
        spring.datasource.password=root
        
        # logging
        logging.level.org.hibernate.type.description.sql.BasicBinder=trace
        logging.level.org.hibernate.SQL=debug
        # Hibernate 6.1.5 updated in springboot 3.x
        logging.level.org.hibernate.orm.jdbc.bind=trace
  • 엔티티 클래스 작성
    • 클래스 어노테이션 주입
      • @Entity
      • @Table(name = “테이블명”)
      • @Getter
        • 엔티티는 @Data 사용은 지양하고, @Getter을 사용하도록 하자
        • @Setter 사용을 지양하고 자체 setter 메소드를 사용하도록 하자
      • @AllArgsConstructor
      • @NoArgsConstructor
        • @ModelAttribute, @RequestBody 매핑시 필요하다.
      • @Builder
    • 멤버 변수 어노테이션 주입
      • @Id
        • primary key 변수에 주입한다.
      • @GeneratedValue(strategy = GenerationType.IDENTITY)
        • primary key 변수에 주입한다.
      • @Column(name = “컬럼명”)
      • @DateTimeFormat(pattern = “yyyy-mm-dd”)
        • Date 형식을 맞춰준다.
  • Repository 인터페이스 작성
    • 클래스에 @Repository 어노테이션 주입
    • JpaRepository<엔티티클래스, Long> 상속받기 (extends)
    • 기본 메소드
      • findAll(): SELECT *
      • findById(): SELECT * WHERE id = :id
      • count(): SELECT COUNT(*)
      • save(): UPDATE, INSERT
      • delete(): DELETE
  • Controller 클래스 작성
    • 클래스 어노테이션 주입
      • @Controller
      • @RequiredArgsConstructor
        • 생성자 주입을 위한 어노테이션
    • Repository 생성자 주입
      • final 엔티티Repository 엔티티Repository;
    • @GetMapping, @PostMapping 등으로 경로 설정 후 Model, @RequestBody 등을 사용하여 메소드 작성
    • 예시
      • @Controller
        @RequiredArgsConstructor
        public class MainController {
            // 생성자 주입
            final MemberRepository memberRepository;
        
            @GetMapping("/")
            public String main(Model model) {
                List<MemberEntity> list = memberRepository.findAll();
                model.addAttribute("list", list);
                return "index";
            }
        }
  • html 작성
    • 타임리프 사용을 위한 추가
    • ${변수명} 형태로 값 가져오기 가능
       
      • <!DOCTYPE html>
        <html lang="ko" xmlns:th="http://www.thymeleaf.org">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>회원목록조회</title>
        </head>
        <body>
            <h2 th:text="|회원목록 (총 ${list.size()}명)|">회원 목록</h2>
            <table border="1">
                <thead>
                    <tr align="center">
                        <td>일련번호</td>
                        <td>ID</td>
                        <td>아이디</td>
                        <td>비밀번호</td>
                        <td>이름</td>
                        <td>권한</td>
                        <td>가입일</td>
                        <td>단건조회</td>
                        <td>삭제</td>
                    </tr>
                </thead>
                <tbody>
                <tr th:each="member, status : ${list}" align="center">
                    <td><span th:text="${status.count}"></span></td>
                    <td><span th:text="${member.id}"></span></td>
                    <td><span th:text="${member.userId}"></span></td>
                    <td><span th:text="${member.userPw}"></span></td>
                    <td><span th:text="${member.userName}"></span></td>
                    <td><span th:text="${member.userRole}"></span></td>
                    <td><span th:text="${member.joinDate}"></span></td>
                    <td>
                        <!-- http://localhost:8080/viewMember?id=${member.id} -->
                        <button type="button" th:onclick="|location.href='@{viewMember(id=${member.id})}'|">단건조회</button>
                    </td>
                    <td>
                        <!-- http://localhost:8080/deleteMember?id=${member.id} -->
                        <button type="button" th:onclick="|location.href='@{deleteMember(id=${member.id})}'|">삭제</button>
                    </td>
                </tr>
                </tbody>
            </table>
        </body>
        </html>
  • 엔티티 DTO 클래스 생성
    • 클래스 어노테이션 주입
      • @Getter
      • @Setter
      • @AllArgsConstructor
      • @NoArgsConstructor
      • @Builder
    • 엔티티와 매핑되는 멤버 변수 작성
      • 엔티티에 없는 멤버 변수도 추가 가능하다.
    • DTO를 엔티티로 변환해주는 메소드 추가
      • builder를 사용하여 DTO 값을 엔티티로 변환하여 저장한다.
      • 예시
        •     // DTO 클래스
              
              public MemberEntity toSaveEntity() {
                  return MemberEntity.builder()
                          .userId(userId)
                          .userPw(userPw)
                          .userName(userName)
                          .userRole(userRole)
                          .joinDate(joinDate)
                          .build();
              }
    • 엔티티를 DTO로 변환해주는 메소드 추가 (엔티티 클래스)
      • 엔티티 클래스에도 DTO로 변환해주는 메소드 추가해준다.
      • 예시
        •    // 엔티티 클래스  
              
              public MemberSaveDTO toSaveDTO() {
                  return MemberSaveDTO.builder()
                          .id(id)
                          .userId(userId)
                          .userPw(userPw)
                          .userName(userName)
                          .userRole(userRole)
                          .joinDate(joinDate)
                          .build();
              }