<aside> ❗
스프링 부트 플러그인
<aside> ❗
./gradlew dependencies → 의존관계를 출력해준다.
스프링 부트 라이브러리 살펴보기
spring-boot-starter-web
spring-boot-starter-tomcat: 톰캣 (웹서버)
spring-webmvc: 스프링 웹 MVC
** 웹이 톰캣과 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
→ slf4j - 로거를 찍는 인터페이스 모음, 구현체로 logback 등을 사용
spring-boot-starter-test
junit: 테스트 프레임워크
mockito: 목 라이브러리
assertj: 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리
spring-test: 스프링 통합 테스트 지원
스프링 MVC
스프링 ORM
JPA, 하이버네이트
스프링 데이터 JPA
H2 데이터베이스 클라이언트
커넥션 풀: 부트 기본은 HikariCP
WEB(thymeleaf)
로깅 SLF4J & LogBack
테스트
**
기본적으로 스프링 부트가 버전에 맞는 라이브러리를 세팅해둠
스프링 부트가 지원하지 않는 라이브러리들은 뒤에 버전 정보를 적어줘야 한다.
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'
</aside>
<aside> ❗
thymeleaf 템플릿 엔진
thymeleaf 공식 사이트: https://www.thymeleaf.org/
스프링 공식 튜토리얼: https://spring.io/guides/gs/serving-web-content/
스프링부트 메뉴얼: https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/
boot-features-developing-web-applications.html#boot-features-spring-mvc-template-engines
resources:templates/
+{ViewName}+ .html
java
@Controller
public class HelloController {
@GetMapping("hello")
public String hello(Model model) {
model.addAttribute("data", "hello!!");
return "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>
위치: resources/templates/hello.html
** index.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>
Hello
<a href="/hello">hello</a>
</body>
</html>
[참고]
spring-boot-devtools
라이브러리를 추가하면,
html
파일을 컴파일만 해주면 서버 재시작 없이
View 파일 변경이 가능하다.
인텔리J 컴파일 방법: 메뉴 build Recompile
정적인 콘텐츠는 static 폴더에 - 렌더링 안 하는 HTML
동적인 콘텐츠는 templates 폴더에 - 렌더링 할 HTML
implementation 'org.springframework.boot:spring-boot-devtools'
→ 캐시도 없애주고, 리로딩 되도록 해줌 (더 많은 기능 제공)
→ 실행 시 restartedMain이라고 뜨면 devtools가 잘 적용된 것
→ build → recompile(cmd + shift + F9)
</aside>
<aside> ❗
<aside> ❗
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 # System.out에 출력
format_sql: true
logging:
level:
org.hibernate.SQL: debug # 하이버네이트가 남기는 로그가 다 보임(모든 SLQ 보임)
# 로거를 통해서 출력한다.
# 로그는 System.out이 아닌 로거를 통해서 찍어야 한다.
#org.hibernate.orm.jdbc.bind: trace
[참고]
show_sql
: 옵션은 System.out
에 하이버네이트 실행 SQL을 남긴다.
org.hibernate.SQL
: 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.[주의!!]
</aside>
<aside> ❗
회원 리포지토리
package jpabook.jpashop;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
@Repository
public class MemberRepository {
// 스프링 부트는. 스프링 컨테이너 위에서 모든 것이 동작
// 스프링 부트가 @PersistenceContext가 있으면 EntityManager를 주입을 해준다.
// @PersistenceContext는 EntityManager의 생명 주기 컨테이너가 관리도록 설정 - EntityManger 주입, 영속 컨텍스트 관리
@PersistenceContext
private EntityManager em;
// 커맨드랑 쿼리를 분리해라
// 저장 후, side effect를 일으키는 커맨드성이기 때문에
// 리턴값을 만들지 않는다.
// ID 값이 있으면 다음에 다시 조회할 수 있도록 할 수 있도록 설계
public Long save(Member member) {
em.persist(member);
return member.getId();
}
public Member find(Long id) {
return em.find(Member.class, id);
}
}
테스트 코드
package jpabook.jpashop;
import org.assertj.core.api.Assertions;
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 org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
//JUnit한테 스프링과 관련된 걸로 테스트할 것이라는 걸 알려줘야 한다.
@RunWith(SpringRunner.class)
// 스프링 부트로 테스트 할 거야.
@SpringBootTest
public class MemberRepositoryTest {
@Autowired MemberRepository memberRepository;
@Test
// 스프링 트랜잭션 애너테이션 권장
// 트랜잭션 애너테이션이 테스트 코드에 있으면 실행 후 바로 롤백
@Transactional
// @Rollback(false)를 테스트 코드에 넣으면 롤백하지 않는다.
// @Rollback(false)
public void testMember() throws Exception{
// EntityManager를 통한 모든 데이터 변경은 항상 트랜잭션 안에서 이루어져야 한다.
//given
Member member = new Member();
member.setUserName("memberA");
//when
Long saveId = memberRepository.save(member);
Member findMember = memberRepository.find(saveId);
//then
Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
Assertions.assertThat(findMember.getUserName()).isEqualTo(member.getUserName());
Assertions.assertThat(findMember).isEqualTo(member);
System.out.println("findMember = " + findMember);
System.out.println("member = " + member);
// findMember == member가 true인 이유
// 같은 트랜잭션 안에서 영속성 컨텍스트가 동일하다.
// 같은 영속성 컨텍스트 안에서는 식별자가 같으면 같은 엔티티로 인식
}
}
// 지우고 깔끔하게 빌드 - jpashop 폴더에서 실행
./gradlew clear build
[참고]
persistence.xml
도 없고,
LocalContainerEntityManagerFactoryBean
도 없다.
스프링 부트를 통한 추가 설정은 스프링 부트 메뉴얼을 참고하고,
스프링 부트를 사용하지 않고 순수 스프링과 JPA 설정 방법은
자바 ORM 표준 JPA 프로그래밍 책을 참고하자.</aside>
<aside> ❗
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
**
로그를 어떻게 찍을지 옵션 설정하는 것은
[참고]
스프링 부트 3.0 이상을 사용하면 라이브러리 버전을 1.9.0 이상을 사용해야 한다.
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'
</aside>