프로젝트 환경설정

LeeKyoungChang·2022년 2월 24일
0
post-thumbnail

스프링 부트와 JPA 활용 1 - 웹 애플리케이션 개발 수업을 듣고 정리한 내용입니다.

 

📚 1. 프로젝트 생성

스크린샷 2022-02-23 오후 12 55 40
  • 강의는 JUnit4를 기준으로 하기 때문에 build.gradle 에 있는 다음 부분을 꼭 직접 추가해야한다. 해당 부분을 입력하지 않으면 JUnit5로 동작한다.
//JUnit4 추가 
testImplementation("org.junit.vintage:junit-vintage-engine") {
         exclude group: "org.hamcrest", module: "hamcrest-core"
}
  • Enable annotation processing 체크
  • Intellij IDEA로 변경
  • UTF-8로 변경

 

📚 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, slf4

 

✔️ 테스트 라이브러리
spring-boot-starter-test

  • junit : 테스트 프레임워크
  • mockito : 목 라이브러리
  • assertj : 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리
  • spring-test : 스프링 통합 테스트 지원

 

핵심 라이브러리

  • 스프링 MVC
  • 스프링 ORM
  • JPA, 하이버네이트
  • 스프링 데이터 JPA

 

기타 라이브러리

  • H2 데이터베이스 클라이언트
  • 커넥션 풀: 부트 기본은 HikariCP
  • WEB(thymeleaf)
  • 로깅 SLF4J & LogBack
  • 테스트

 

💡 참고

  • 스프링 데이터 JPA는 스프링과 JPA를 먼저 이해하고 사용해야 하는 응용기술이다.

 

📚 3. View 환경 설정

🔔 thymeleaf 템플릿 엔진

 

HelloController

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에 데이터를 담아서 view에 넘길 수 있다.
        model.addAttribute("data", "hello!");
        // key : data, value : hello!
        return "hello";
        // return : 화면 이름 (resources -> templates -> hello.html
    }
}
  • model에 데이터를 담아서 view에 넘길 수 있다.
  • key : data, value : hello!
  • return : 화면 이름 (resources -> templates -> hello.html), 스프링 부트가 반환 값 뒤에 .html을 붙여준다.

 

hello.html

  • thymeleaf 템플릿엔진 동작 확인(hello.html)
<!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>
<p th:text="'안녕. ' + ${data}" >안녕하세요. 손님</p>
  • 순수 html 인 경우 : 안녕하세요. 손님이 출력된다.
  • 서버 사이드 렌더링을 탈 경우(서버 실행할 경우) : th:text="'안녕. ' + ${data}" 결과 값이 >여기(안녕하세요. 손님)< 으로 들어간다.

➡️ 이것이 thymeleaf의 장점이다!

 

순수 html일 경우, static 디렉터리에 준다.
index.html : 웹 사이트 접속할 때 실행되는 첫 화면이다. (localhost:8080 == localhost:8080/index.html)

static/index.html

<!DOCTYPE HTML>
<html>
<head>
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
Hello
<a href="/hello">hello</a>
</body>
</html>
  • hello를 눌렸을 경우, 현재 경로 + /hello 경로로 이동

 

실행 결과
스크린샷 2022-02-23 오후 5 26 22

스크린샷 2022-02-23 오후 5 26 26

 

💡 참고
html파일에서 화면 수정했을 때, 실행 상태에서 업데이트가 적용되도록 하기 위해 spring-boot-devtools 라이브러리를 추가한다.

스크린샷 2022-02-23 오후 5 24 54

View file 변경 후,

스크린샷 2022-02-23 오후 5 02 05

Recompile hello.html 클릭한다.
이제 웹 사이트에서 f5를 눌릴 시 변경된 내용이 출력된다.

➡️ 시행시, 서버 재시작 없이 브라우저에서 새로고침만 하면 View 파일 변경이 가능하다.

 

📚 4. H2 데이터베이스 설치

  • 개발이나 테스트 용도로 가볍고 편리한 DB, 웹 화면 제공
  • 윈도우, 맥, 리눅스 실행 버전 다운로드 : https://h2database.com/h2-2019-10-14.zip
  • 공식 사이트 : https://www.h2database.com

 

✔️ h2 설치전

스크린샷 2022-04-04 오후 12 47 45
  • Intellij의 Gradle h2 version을 확인한 후, 설치를 해야 한다.
  • SELECT H2VERSION() FROM DUAL : h2 version 확인
스크린샷 2022-04-04 오후 12 59 48

 

✔️ 다운로드 및 설치
먼저 https://h2database.com/h2-2019-10-14.zip 설치한다.

스크린샷 2022-02-23 오후 6 04 08

사진에서 h2디렉터리가 해당된다.

 

터미널에서

  • 터미널에서 h2가 있는 곳으로 이동한다. (이동할 때 띄워쓰기가 있다면 " "으로 경로지정)
  • h2Database 실행 방법 : ./h2.sh
  • h2Database 종료 방법 : ^ + c
스크린샷 2022-02-23 오후 6 09 37

 

h2에서
첫 실행시

스크린샷 2022-02-23 오후 6 12 00

이렇게 뜨는데, 이제 경로 지정해줘야함

스크린샷 2022-02-23 오후 5 42 39

➡️

스크린샷 2022-02-23 오후 6 13 18

경로가 뜨는데, JDBC URL 경로가 무엇이냐면 이제 JDBC 파일 저장되는 경로이다.

스크린샷 2022-02-23 오후 6 14 56

 

연결버튼을 눌렸을 때 실행화면
스크린샷 2022-02-23 오후 6 15 46

 

h2DB를 종료하려면 그림으로 체크되어 있는 부분을 클릭하면 된다.

스크린샷 2022-02-23 오후 5 56 06

 

이제 터미널에서 ./h2.sh로 실행한 후, 시작 경로를 입력하면(tcp 네트워크 모드로 접근) h2DB가 실행된다.
나의 경로 : jdbc:h2:tcp://localhost//Users/leekyoungchang/Desktop/Study/Computer/Spring/JPA(pdf, ppt)/스프링 부트와 JPA 활용 1/자료/db/jpashop

 

📚 5. JPA와 DB 설정, 동작확인

main/resources/application.yml

spring: #띄어쓰기 없음
  datasource: #띄어쓰기 2칸
    url: jdbc:h2:tcp://localhost//Users/leekyoungchang/Desktop/Study/Computer/Spring/JPA(pdf, ppt)/스프링 부트와 JPA 활용 1/자료/db/jpashop  # 여기해결해야함 14:01분
    username: sa
    password:
    driver-class-name: org.h2.Driver
  jpa: #띄어쓰기 2칸
    hibernate: #띄어쓰기 4칸
      ddl-auto: create #띄어쓰기 6칸
    properties:
      hibernate:
#        show_sql: true
        format_sql: true #띄어쓰기 8칸

logging:
  level:
    org.hibernate.SQL: debug
#    org.hibernate,type: trace

spring.jpa.hibernate.ddl-auto: create : 이 옵션은 애플리케이션 실행 시점에 테이블을 drop 하고, 다시 생성한다.

💡 참고

  • 모든 로그 출력은 가급적 로거를 통해 남겨야 한다.
  • show_sql : 옵션은 System.out 에 하이버네이트 실행 SQL을 남긴다.
  • org.hibernate.SQL : 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.

 

⚠️ 주의
application.yml 같은 yml 파일은 띄어쓰기(스페이스) 2칸으로 계층을 만든다. 따라서 띄어쓰기 2칸을 필수로 적어주어야한다.

 

📖 A. 실제 동작하는지 확인하기

Member

package jpabook.jpashop;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Getter @Setter
public class Member {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

}

 

MemberRepository - 회원 리포지토리

package jpabook.jpashop;

import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class MemberRepository {

    @PersistenceContext
    private EntityManager em;

    public Long save(Member member) {
        em.persist(member);
        return member.getId();
    }

    public Member find(Long id) {
        return em.find(Member.class, id);
    }
}
  • 현재 스프링 컨테이너 위에서 동작하게 된다.
  • @PersistenceContext EntityManager : 자동으로 엔티티 매니저를 주입해준다.
스크린샷 2022-04-04 오후 4 36 40

implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 사용 시, 엔티티 매니저가 자동으로 생성되고 application.yml에 있는 jpa: 설정을 읽고 엔티티 매니저 팩토리 관련 모든 것들이 자동으로 생성되고 실행된다.

 

MemberRepositoryTest - 테스트

package jpabook.jpashop;

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.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;

import javax.transaction.Transactional;

import static org.assertj.core.api.Assertions.*;


@RunWith(SpringRunner.class)
@SpringBootTest
public class MemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

    @Test
    @Transactional
    @Rollback(false)
    public void testMember() throws Exception{
        // given
        Member member = new Member();
        member.setName("memberA");

        // when
        // 엔티티를 수정하기 위해서는 트랜잭션안에서 실행되어야 한다.
        Long saveId = memberRepository.save(member);
        Member findMember = memberRepository.find(saveId);

        // then
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getName()).isEqualTo(member.getName());
        assertThat(findMember).isEqualTo(member);

        System.out.println("findMember == member: " + (findMember = member));

    }

}
  • @Transactional : 엔티티는 트랜잭션안에서 실행되기 때문에, 엔티티 데이터들을 수정할 때는 @Transactional 애노테이션을 사용해야 한다.
  • @Rollback(false) : Test 끝난 후, Rollback을 하게 된다. (원래는 auto로 해주지만, 그렇지 않을 경우가 있기 때문에 직접 삽입하는 것이 좋고, Rollback을 하지 않고 커밋을 할려면 이와 같이 삽입하면 된다.)

 

⚠️ 주의

  • @TestJUnit4를 사용하면 org.junit.Test를 사용해야한다.
  • Entity, Repository 동작 확인
  • jar 빌드해서 동작 확인

 

오류

테스트를 실행했는데 다음과 같이 테스트를 찾을 수 없는 오류가 발생하는 경우

No tests found for given includes: [jpabook.jpashop.MemberRepositoryTest] (filter.includeTestsMatching)

해결 : 스프링 부트 2.1.x 버전을 사용하지 않고, 2.2.x 이상 버전을 사용하면 Junit5가 설치된다. 이때는 build.gradle 마지막에 다음 내용을 추가하면 테스트를 인식할 수 있다. Junit5 부터는 build.gradle 에 다음 내용을 추가해야 테스트가 인식된다.

 

build.gradle 마지막에 추가

tasks.named('test') {
	useJUnitPlatform()
}

 

💡 참고

  • 스프링 부트를 통해 복잡한 설정이 다 자동화 되었다.
  • persistence.xml 도 없고, LocalContainerEntityManagerFactoryBean 도 없다.
  • 스프링 부트를 통한 추가 설정은 스프링 부트 메뉴얼을 참고하고, 스프링 부트를 사용하지 않고 순수 스프링과 JPA 설정 방법은 자바 ORM 표준 JPA 프로그래밍 책을 참고하자!

 

✔️ MemberRepositoryTest 실행했을 때

drop : 테이블 날림

스크린샷 2022-02-24 오후 12 04 03

create

스크린샷 2022-02-24 오후 12 04 11

Entity

스크린샷 2022-02-24 오후 12 11 58

➡️ 위 실행시, Entity 정보를 보고 생성한다.

 

Test에서 데이터 입력 db에 저장되었는지 체크할 때
@Rollback(false) 사용한다.

  • memberA 추가
스크린샷 2022-02-24 오후 12 10 17
  • memberA 출력됨
스크린샷 2022-02-24 오후 12 10 21

 

✔️build를 clean 하려고했는데 안됨(가상서버를 실행시켜야 함)
./gradlew clean buildbuildclean하려고 했다.

하지만, 이와 같은 오류가 발생한다.

스크린샷 2022-02-24 오후 12 50 46

어 그런데

test도 갑자기 실행이 안된다.

스크린샷 2022-02-24 오후 12 53 48

 

BUILD FAILED이 왜 발생하는 걸까?

  • 이는 가상서버를 실행하지 않은 상태에서 build 정리 및 test를 실행하려고 했기 때문에, 발생한 오류이다.
스크린샷 2022-02-24 오후 12 55 16

application.yml datasource에서 url을 실행했는데 가상서버가 close되어 있으니, 실행에서 오류가 발생한 것 같다. (개인적 생각)

그러므로 ./h2.sh 실행하여 가상서버를 켜주면, 위 발생했던 오류들이 해결된다.

스크린샷 2022-02-24 오후 12 59 05 스크린샷 2022-02-24 오후 12 58 56 스크린샷 2022-02-24 오후 12 59 13 스크린샷 2022-02-24 오후 12 59 34

 

터미널에서 Intellij대신 실행

위와 같이 가상 서버 open한 상태에서 실행해야 한다.

스크린샷 2022-02-24 오후 1 04 34

 

📖 B. 쿼리 파라미터 로그 남기기

스크린샷 2022-04-04 오후 5 12 43

이전부터 이런 형식으로 출력되면 답답했었다.

 

✔️ 꿀팁

(1) 로그에 다음을 추가하기 org.hibernate.type : SQL 실행 파라미터를 로그로 남긴다.

스크린샷 2022-04-04 오후 5 15 03

 

(2) 외부 라이브러리 사용 : https://github.com/gavlyukovskiy/spring-boot-data-source-decorator

  • 스프링 부트를 사용하면 이 라이브러리만 추가하면 된다.
    • implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
스크린샷 2022-04-04 오후 5 21 19

커넥션을 얻어오는 것도 모니터링이 가능하다. 현재 테이블에 입력된 내용들이 무엇인가도 알 수 있다.
추가적 설정들은 https://github.com/gavlyukovskiy/spring-boot-data-source-decorator 여기를 참고하여 추가하면 된다.

 

💡 참고
build.gradle에서

스크린샷 2022-04-04 오후 5 17 18
  • springboot 2.1.7부터는 나에게 잘맞는 버전을 궁합하여 맞추어준다.
  • 그러므로 2.1.7이후 버전부터는 뒤에 버전을 적지 않아도 된다.
  • 그러나, 이전 버전까지는 직접 버전을 입력해줘야 한다.

 

💡 참고

  • 쿼리 파라미터를 로그로 남기는 외부 라이브러리는 시스템 자원을 사용하므로, 개발 단계에서는 편하게 사용해도 된다.
  • 하지만 운영시스템에 적용하려면 꼭 성능테스트를 하고 사용하는 것이 좋다.
    • 지금은 개발 단계이므로 마음 껏 사용해도 된다.
    • 나중에 운영에서는 성능테스트가 중요해서 쿼리 파라미터 로그 남기기 설정들이 성능테스트에 문제가 없으면 사용하면 된다.
profile
"야, (오류 만났어?) 너두 (해결) 할 수 있어"

0개의 댓글