보라코딩
[인프런] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 본문
MemberController에
회원목록 눌렀을때 나오는 기능을 추가한다.
전체 목록 조회이기에 List를 사용하고
model에 데이터 넘겨준다.

그럼 memberList.html 에 내용을 아래와 같이 넣어준다.
회원목록 클릭 시 볼수 있는 화면으로
타임리프라는 템플릿 엔진을 사용한다.

아래는 타임리프 문법으로 for문처럼 루프를 돌면서 데이터를 가져오고
이때 ${} 사용하면 model 안의 값을 꺼내서 가져온다.

데이터가 휘발성이기에 기록하기 위해 이제부터 DB를 사용한다!
h2가 가볍고 교육용으로 쓰기 좋다고 한다.

들어가면 이런화면이 나온다.

데이터베이스 파일 생성방법과 접속 방법은 아래와 같다.

테이블 생성하는 쿼리

강사님은 sql 폴더 만들어서 관리하신다고 한다.


JdbcMemeberRepository 클래스 내용이다. (순수 JDBC 이용하기!)
국비지원 자바 수업 들으면서 배운 내용이였는데
20년 전에 사용했던 것이라며... 지금은 이렇게 안한다고 해서 당황했다 ㅋㅋㅋ
나도 이걸 사용하면서 코드가 이렇게 길고 복잡하게 매번 하는게 맞을까..하는 의문이 들었는데
스프링에서는 역시 다른 방법이 있구나...!
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class JdbcMemberRepository implements MemberRepository{
private final DataSource dataSource;
public JdbcMemberRepository(DataSource dataSource) {
this.dataSource = dataSource;
// dataSource.getConnection();
}
@Override
public Member save(Member member) {
String sql = "insert into member(name) values(?)";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // 결과 받는 것
try {
conn = getConnection(); // Connection 가져와
pstmt = conn.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, member.getName());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
member.setId(rs.getLong(1));
} else {
throw new SQLException("id 조회 실패");
}
return member;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public Optional<Member> findById(Long id) {
String sql = "select * from member where id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
} else {
return Optional.empty();
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public Optional<Member> findByName(String name) {
String sql = "select * from member where name = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
rs = pstmt.executeQuery();
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
}
return Optional.empty();
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public List<Member> findAll() {
String sql = "select * from member";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
List<Member> members = new ArrayList<>();
while(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
members.add(member);
}
return members;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
private Connection getConnection() {
return DataSourceUtils.getConnection(dataSource);
}
private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
{
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null) {
close(conn);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void close(Connection conn) throws SQLException {
DataSourceUtils.releaseConnection(conn, dataSource);
}
}
.
SpringConfig을 사용하면
다형성을 이용해서 정말 간단하게
메모리에서 DB이용으로 변경할 수 있다!

바로 아래처럼 return 하는 것을 바꿔주면 되는데
이것이 바로 객체지향 다형성을 이용한 것이다.

또 기존 테스트파일에 스프링부트와 트랜잭션 애노테이션을 추가한다.
이렇게하면 before과 after같은 애노테이션을 사용하지 않아도 되어 매우 편리한데
다만 기본 단위테스트보다 스프링부트테스트는 시간이 오래걸려서
나중에 많은 테스트를 진행시 그리 좋지는 않다고 한다.
하지만 너무 편리해보임!!
특히 트랜잭션 ㅎ.ㅎ

스프링 JDBC Template
스프링 JdbcTemplate과 MyBatis 같은 라이브러리는 JDBC API에서 본 반복 코드를 대부분 제거해준다.
하지만 SQL은 직접 작성해야 한다.
JdbcTemplate을 사용한다.
우선 findByid 다음과 같이 작성
jdbcTemplate.query 이용한다.

이때 매퍼 작성해줘야하고

놀랍게도 람다식으로 알아서 변경해준다

이렇게 변경 완료!

솔직히..
처음 배우는 내용이고 어떻게 저 코드가 나왔는지 설명해주시진 않아서
이해가 되진 않는다 ㅠㅠ
추가 공부가 필요!!

최종적으로는 SpringConfig 이렇게 바꿔주면 완료!

JPA
JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.
JPA를 사용하면 개발 생산성을 크게 높일 수 있다.
build gradle에 내용추가

application.properties에 추가
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
이렇게 hybernate가 떠야함

Member에 @Entity 애노테이션 추가

EntityManager을 사용한다
쿼리문을 쓰지 않아도 된다는게 매우 신선한 충격!!

하지만 find는 쿼리문 필요
select m 이 특이한데
객체 전체를 가져오기 때문!

inline으로 변경하는것도 신기...! 코드 깔끔해짐!


@Transactional 추가해주고

똑같이 변경해주는데 이번엔 EntityManager 필요함!


스프링데이터JPA
스프링 부트와 JPA만 사용해도 개발 생산성이 정말 많이 증가하고, 개발해야할 코드도 확연히 줄어듭니다.
여기에 스프링 데이터 JPA를 사용하면, 기존의 한계를 넘어 마치 마법처럼, 리포지토리에 구현 클래스 없이
인터페이스 만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 스프링 데이터
JPA가 모두 제공합니다.
스프링 부트와 JPA라는 기반 위에, 스프링 데이터 JPA라는 환상적인 프레임워크를 더하면 개발이 정말
즐거워집니다. 지금까지 조금이라도 단순하고 반복이라 생각했던 개발 코드들이 확연하게 줄어듭니다.
따라서 개발자는 핵심 비즈니스 로직을 개발하는데, 집중할 수 있습니다.
실무에서 관계형 데이터베이스를 사용한다면 스프링 데이터 JPA는 이제 선택이 아니라 필수 입니다.
뒤로갈수록 이해도가 낮아지고 있는데
정말 코드는 심플해서 놀랍다.
일단 인터페이스 만들어주고

코드도 이거뿐이다.
이름으로 찾는 이유는 결국 이것이 아래 코드와 같게 작용하기 때문이다
select m from Member m where m.name = ?
JpaRepository를 상속받는다 (내가 만든 것이 아니다)

SpringConfig도 간결하게 작성해주었다.

'코딩 > Spring' 카테고리의 다른 글
Thymeleaf 문법정리 (0) | 2023.05.08 |
---|---|
Day91_230508_Spring 시작 (STS 3.9.13 설치, Legacy project 시작) (0) | 2023.05.08 |
[인프런] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (0) | 2023.03.05 |
코드로 배우는 스프링 웹 프로젝트 Part3 (ch11끝) (0) | 2023.03.05 |
코드로 배우는 스프링 웹 프로젝트 Part3 (ch11) (0) | 2023.02.26 |