Spring/Spring Boot

섹션 1. 프로젝트 환경설정 [실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발]

광터틀 2023. 12. 6. 21:59

이 포스트는 김영한 강사님의 [실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발] 을 바탕으로 작성되었습니다. 

 

섹션 1. 프로젝트 환경설정 

 

순서 

1) 프로젝트 생성 

2) 라이브러리 살펴보기 

3) View 환경 설정 

4) H2 데이터베이스 설치 

5) JPA와 DB 설정, 동작 확인 

 

 

1) 프로젝스 생성 

스프링부트 스타터 (https://start.spring.io/) 를 통해 프로젝트를 생성한다. 

환경 : Gradle-Groovy, groupId: jpabook, artifactId: jpashop 

dependencies : web, thymeleaf, jpa, h2, lombok, validation 

 

!주의! - 스프링부트 3.x 버전, 자바는 17 or 21 버전. 꼭꼭! 

자바 버전을 11로 쓰다가 20분 정도 날려먹었다... 

+ 중간에 한번 더 오류가 나서 또 무엇이 문제이지 했는데 자바를 17로 재설치만 하고 환경변수에서 path를 11에서 17로 안 바꿔줘서 또 날려먹었다... 

 

최근 IntelliJ 버전은 Gradle로 실행하는 것이 기본이나 이렇게 하면 실행속도가 느리다. Build Tools 의 Gradle 에서 Build and run using과 Run test using의 Gradle을 모두 IntelliJ IDEA로 변경해주면 자바로 바로 실행하기 때문에 더 빠르다. 

 

2) 라이브러리 살펴보기 

spring-boot-starter-web
spring-boot-starter-tomcat: 톰캣 (웹서버)
spring-webmvc: 스프링 웹 MVC
spring-boot-starter-thymeleaf: 타임리프 템플릿 엔진(View)
spring-boot-starter-data-jpa
spring-boot-starter-aop
spring-boot-starter-jdbc
HikariCP 커넥션 풀 (부트 2.0 기본)
hibernate + JPA: 하이버네이트 + JPA
spring-data-jpa: 스프링 데이터 JPA
spring-boot-starter(공통): 스프링 부트 + 스프링 코어 + 로깅
spring-boot
spring-core
spring-boot-starter-logging
logback, slf4j

 

테스트 라이브러리**
spring-boot-starter-test
junit: 테스트 프레임워크
mockito: 목 라이브러리
assertj: 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리
spring-test: 스프링 통합 테스트 지원
핵심 라이브러리
스프링 MVC
스프링 ORM
JPA, 하이버네이트
스프링 데이터 JPA
기타 라이브러리
H2 데이터베이스 클라이언트
커넥션 풀: 부트 기본은 HikariCP
WEB(thymeleaf)
로깅 SLF4J & LogBack
테스트

 

 

View 환경 설정 

thymeleaf 템플릿 엔진 

스프링 부트 thymeleaf viewName 매핑
resources:templates/ +{ViewName}+ .html 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package jpabook.jpashop;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
 
@Controller
public class HelloController {
 
    @GetMapping("hello")
    public String hello(Model model) {     //Model 은 컨트롤러에서 데이터를 받아 뷰에 넘김 
        model.addAttribute("data""hello!!!");
        return "hello";         //return "hello"의 hello는 화면 이름임. resources/templates 에 view name이 hello.html인 것을 반환 
    }
}
cs

 

 

hello.html 

 

 

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'안녕하세요. ' + ${data}" >안녕하세요. 손님</p>
</body>
</html>
cs

 

index.html 

 

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'안녕하세요. ' + ${data}" >안녕하세요. 손님</p>
</body>
</html>
cs

 

 

3) H2 데이터베이스 설치 

데이터베이스 파일 생성 방법
`jdbc:h2:~/jpashop` (최소 한번)
`~/jpashop.mv.db` 파일 생성 확인
이후 부터는 `jdbc:h2:tcp://localhost/~/jpashop` 이렇게 접속...........? 

 

 

4) JPA와 DB 설정, 동작 확인 

 

yml 파일과 properties 의 차이? 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/jpashop
    username: sa
    password:
    driver-class-name: org.h2.Driver
 
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
#       show_sql: true
      format_sql: true
 
logging.level:
  org.hibernate.SQL: debug
#   org.hibernate.type: trace #스프링 부트 2.x, hibernate5
#   org.hibernate.orm.jdbc.bind: trace #스프링 부트 3.x, hibernate6
cs

 

spring.jpa.hibernate.ddl-auto: create 
이 옵션은 애플리케이션 실행 시점에 테이블을 drop 하고, 다시 생성한다.
참고: 모든 로그 출력은 가급적 로거를 통해 남겨야 한다.
`show_sql` : 옵션은 `System.out` 에 하이버네이트 실행 SQL을 남긴다.
`org.hibernate.SQL` : 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.

... 이 둘 차이????? 

 

 

회원 엔티티 

 

1
2
3
4
5
6
7
8
9
@Entity
@Getter @Setter
public class Member {
 
    @Id @GeneratedValue
    private Long id;
    private String username;
    ...
}
cs

 

 

회원 리포지토리 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Repository
public class MemberRepository {
 
    @PersistenceContext
    EntityManager em;
    
    public Long save(Member member) {
        em.persist(member);
        return member.getId();
    }
    
    public Member find(Long id) {
        return em.find(Member.class, id);
    }
}
cs

 

 

회원 리포지토리 테스트 

 

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
26
27
28
29
30
31
32
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
 
import javax.persistence.EntityManager;
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class MemberRepositoryTest {
 
    @Autowired MemberRepository memberRepository;
 
    @Test
    @Transactional
    @Rollback(false)
    public void testMember() {
        Member member = new Member();
        member.setUsername("memberA");
        Long savedId = memberRepository.save(member);
 
        Member findMember = memberRepository.find(savedId);
 
        Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
        Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        Assertions.assertThat(findMember).isEqualTo(member); //JPA 엔티티 동일성 보장
    }
}
cs