✔ 설치

implementation 'org.springframework.data:spring-data-jdbc:3.3.1'
#인텔리제이 스프링프레임워크 day05
...
<servlet><!--스프링에는 단 한가지의 서블릿 클래스를 제공,
이 서블릿은 모든 요청의 창구가 된다. 서블릿은 초기화시 스프링 컨테이너를 만들어줌-->
<servlet-name>dispatcher</servlet-name> <!--서블릿 이름 정의-->
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param><!--어떤 스프링 컨테이너를 쓸 것인지 알려줘야한다.-->
<param-name>contextClass</param-name>
<param-value><!--handler,adapter등 담겨있는 웹전용 컨테이너-->
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name><!--스프링 설정 위치 지정-->
<param-value>
org.choongang.config.MvcConfig <!--Spring MVC와 관련된 설정을 정의하는 클래스-->
</param-value>
</init-param>
</servlet>
<servlet-mapping><!--서블릿과 URL패턴 매핑-->
<servlet-name>dispatcher</servlet-name> <!--매핑할 서블릿 이름 지정-->
<url-pattern>/</url-pattern><!--서블릿이 매핑될 URL 패턴을 지정-->
</servlet-mapping>
<!--모든 URL 패턴 (/)을 dispatcher 서블릿으로 매핑, 모든 요청이 DispatcherServlet을 통해 처리됨을 의미함-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern><!--모든 경로를 의미-->
</filter-mapping>
...
db설정
DBConfig
Datasource: 연결 + 커넥션 풀 설정
@Bean(destroyMethod = "close")//스프링 컨테이너가 소멸될때 자원도 같이 해제 된다.

JdbcTemplate
PlatformTransactionManager
@EnableTransactionManagement //트랜잭션 관련 설정 자동화

SqlSessionFactory
마이바티스 관련 설정
@MapperScan("org.choongang") //mapper 스캔 범위 설정

MvcConfig db 통합 설정
@Import(DBConfig.class)
👩🏫참고)
테스트 환경에서 @SpringJUnitWebConfig 애노테이션
ExtendWith + contextConfiguration + WebAppConfiguration 기능 포함되어있는 애노테이션


Spring쪽에서 정의된 Enum상수가 정의되어있다. (응답코드)
공통 예외처리 클래스
//공통 예외처리
public class CommonException extends RuntimeException{
private HttpStatus status; //스프링쪽에서 제공하는 응답코드 enum 상수 클래스
//응답코드 고정
public CommonException(String message) {
this(message, HttpStatus.INTERNAL_SERVER_ERROR);//500대 응답코드
}
public CommonException(String message, HttpStatus status){
super(message);
this.status = status;
}
//상수 조회 클래스
public HttpStatus getStatus() {
return status;
}
}
✔세팅 -> 설정 클래스 추가하기(설정 자동화)


@Id



🔼 mapper와 동일하게 dao을 가능하게함 (mapper역할)

쿼리를 작성하지 않았는데 실행될까 ?
MemberRepositorytest

만들어짐!
...
@Test
void test2(){
Member member = Member.builder()
.seq(1L)
.email("user01@test.org")
.password("12345678")
.userName("사용자06")
.build();
repository.save(member);
}

이미 있는거라 수정됨
//기본키로 조회
@Test
void test3(){
Member member = repository.findById(1L).orElse(null); //게시글이 없는 경우 등 null에 대한 처리를 많이 하기때문에 매개변수 Optional 형태로 반환값이 나옴
System.out.println(member);
}

//삭제
@Test
void test3(){
Member member = repository.findById(1L).orElse(null); //게시글이 없는 경우 등 null에 대한 처리를 많이 하기때문에 매개변수 Optional 형태로 반환값이 나옴
System.out.println(member);
repository.delete(member);
}

1삭제됨

인터페이스에 코드 추가
CrudRepository는 패턴을 가지고 입력하면 그거에 맞게 쿼리가 알아서 입력된다
find + (엔티티 이름) + By + 변수이름


이메일로 해당 쿼리 찾아서 조회 성공





List<Member> findByUserNameContainingAndEmailContainingOrderByRegDtDesc(String key1, String key2);//정렬 추가
....
@Test
void test6(){
List<Member> members = repository.findByUserNameContainingAndEmailContainingOrderByRegDtDesc("용자","user");
members.forEach(System.out::println);
}
메서드 명과 쿼리가 너무 긴 문제점이 있다...
위처럼 사용하지는 않음✖✖✖
이런 복잡한 형태 대신
애노테이션을 사용한다.
public interface MemberRepository extends CrudRepository<Member, Long> {
...
@Query("SELECT * FROM MEMBER WHERE USER_NAME LIKE :param1 AND EMAIL LIKE :param2 ORDER BY REG_DT DESC") //param이 대체되는 부분
List<Member> getMembers(@Param("param1")String key1, @Param("param2")String key2);
//param1 -> key1, param2 -> key2
...
}
...
@Test
void test7(){
List<Member> members = repository.getMembers("%용자%","%user%");
members.forEach(System.out::println);
}

🔹Pageable 인터페이스

🔹PageRequest (구현 클래스)
PageNumber: 0부터 시작
PageSize:한 페이지당 출력되는 개수
sort: 정렬/ 뒤에 자동으로 ORDER BY 붙음

🔹Page 자료형
Pageable 반환값 -> Page


SELECT * FROM BOARD WHERE ... ORDER BY ... LIMIT 시작번호, 레코드개수
...
@Test
void test8(){
Pageable pageable = PageRequest.of(1,3);
Page<Member> data = repository.findByUserNameContaining("용자",pageable);
}

@Test
void test8(){
Pageable pageable = PageRequest.of(0,3); //0 : 첫 페이지 부터
Page<Member> data = repository.findByUserNameContaining("용자",pageable);
List<Member> members = data.getContent();
long total = data.getTotalElements(); //조회된 전체 레코드 갯수(페이지 나누지 않은)
int pages = data.getTotalPages();
members.forEach(System.out::println);
System.out.printf("총 갯수: %d, 총 페이지 수 : %d\n",total,pages);
}



✅ 오름차순 내림차순
import static org.springframework.data.domain.Sort.Order.asc;
import static org.springframework.data.domain.Sort.Order.desc;
...
@Test
void test8(){
Pageable pageable = PageRequest.of(0, 3, Sort.by(desc("regDt"),asc("email")));
Page<Member> data = repository.findByUserNameContaining("용자", pageable);
//0 : 첫 페이지 부터 , desc: 내림차순
..
...
}
✅ @Table
@Table("CH_MEMBER") //클래스명과 테이블명을 다르게 써야할때 이 애노테이션을 사용하면 Member -> CH_MEMBER 테이블에 매칭된다.
✅ 컬럼명
