Repository
Repository란?
엔티티에 의해 생성된 데이터베이스 테이블에 접근하는 메서드들(findAll, save 등)을 사용하기 위한 인터페이스이다. 데이터 처리를 위해 테이블에 어떤 값을 넣거나 조회하거나 업데이트하거나 삭제시키는 등의 CRUD(Create, Read, Update, Delete)가 필요하다. 이때 CRUD를 어떻게 처리할지 정의하는 계층이 Repository이다.
CRUD
데이터 조회하기
api 모듈에 새로운 패키지인 repository를 만들고 MemberRepository 인터페이스를 생성한다.
repository/MemberRepository
package com.seungh1024.repository;
import com.seungh1024.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MemberRepository extends JpaRepository<Member, Integer> {
//사용자 이메일로 조회 -> 하나만 매칭
Member findMemberByMemberEmail(String memberEmail);
//사용자 pk로 조회
Member findMemberByMemberId(int memberId);
}
MemberRepository는 JpaRepository인터페이스를 상속하여 repository로 만들었다.
JpaRepository를 상속할 때는 <Member, Integer>처럼 repository의 대상이 되는 엔티티의 타입(Member)을 첫 번째 인자로, 해당 엔티티의 PK 속성 타입(Integer)을 두 번째 인자로 지정해 주어야 한다.
인터페이스 생성 후 JpaRepository <Entity 클래스, PK 타입>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성이 된다(findAll(), save(), delete() 등)
이는 JpaRepository를 생성하기 위한 규칙으로 반드시 이렇게 해야 한다.
특정 컬럼을 사용한 조회 등은 위의 코드처럼 특정 규칙을 통해 쉽게 만들 수 있으며 자동완성이 되므로 어렵지 않게 만들 수 있을 것이다.
findMemberByMemberEmail → 말 그대로 사용자 이메일로 사용자를 찾는다는 메소드이다.
findMemberByMemberId → 이번엔 PK로 찾는 것이다.
이 외에도 And, Like 등을 활용하여 여러 쿼리를 만들 수 있다.
아래는 예시이다
예제에서 없는 컬럼의 경우 있다고 가정한 후 작성하였다.
항목 | 예제 | 설명 |
And | findMemberByMemberEmailAndMemberName(String memberEmail, String memberName) | 두 조건을 모두 만족시키며 검색 |
Or | findMemberByMemberEmailOrMemberName(String memberEmail, String memberName) | 둘 중 하나만 만족하면서 검색 |
Between | findMemberByCreateDateBetween(LocalDateTime fromDate, LocalDateTime toDate) | 해당 기간 사이의 값 검색 |
LessThan | findMemberByMemberIdLessThan(int id) | id 보다 작은 값 검색 |
GreaterThanEqual | findMemberByMemberIdGreaterThanEqual(int id) | id 보다 크거나 같은 값 검색 |
Like | findMemberByMemberEmailLike(String word) | like 검색. word에는 “ttt%”, “%ttt”, “%ttt%” 와 같이 사용하면 된다. |
In | findMemberByMemberEmailIn(String[] word) | 여러 값 중에 해당하는 항목을 검색한다. |
OrderBy | findMemberByMemberEmailOrderByMemberIdAsc(String MemberEmail) | 검색 결과를 정렬하여 전달한다. 여기선 MemberId를 ASC로 정렬 |
데이터 저장, 수정, 삭제하기
여기서부터는 서비스 클래스, 컨트롤러 클래스를 만들어서 작성했다.
각자 service 패키지, controller 패키지를 만들어서 클래스를 작성해 준다.
service/MemberService
package com.seungh1024.service;
import com.seungh1024.entity.Member;
import com.seungh1024.repository.MemberRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
//사용자 등록
public boolean createMember(Member member){
try{
memberRepository.save(member);
return true;
}catch(Exception e){
return false;
}
}
//전체 사용자 조회
public List<Member> allMemberList(){
return memberRepository.findAll();
}
//사용자 이메일로 검색
public Member findMemberByEmail(String email){
return memberRepository.findMemberByMemberEmail(email);
}
//사용자 비밀번호 업데이트
public boolean updateMemberPassword(int pk,String password){
try{
Member member = memberRepository.findMemberByMemberId(pk);
member.updatePassword(password);
memberRepository.save(member);
return true;
}catch(Exception e){
// e.printStackTrace();
return false;
}
}
//사용자 삭제
public boolean deleteMember(int pk){
try{
Member member = memberRepository.findMemberByMemberId(pk);
memberRepository.delete(member);
return true;
}catch(Exception e){
return false;
}
}
}
사용자 등록 메소드인 createMember를 보면 만들어준 JPA Repository에서 save() 메서드를 호출한다.
위에서 언급한 기본적으로 제공해 주는 메소드로 엔티티 객체를 넣어서 호출하면 create문이 실행된다.
마찬가지로 findAll()도 따로 작성하지 않고 호출이 되는 모습을 볼 수 있다.
JPA Repository를 생성하여 직접 만든 메소드인 findMemberByMemberEmail 등도 호출한 것을 볼 수 있다.
업데이트의 경우 생성과 마찬가지로 save()를 사용하여 수정할 수 있다. setter를 사용하면 간단하게 set메소드를 호출하여 변경 후 save()하면 되지만 setter를 사용하지 않기로 했으므로 Member 클래스에 update가 필요한 값만을 받는 메소드를 따로 생성해 그것을 명시적으로 사용하면 된다.
entity/Member(추가 코드)
public void updatePassword(String memberPassword){
this.memberPassword = memberPassword;
}
해당 메소드를 보면 비밀번호 변경을 위해 누가 봐도 비밀번호 변경인 메소드를 작성하고 해당 객체의 비밀번호만 변경하는 것을 알 수 있다.
이걸 JPA가 인식하고 같은 save()라도 create, update를 판별하여 실행해 준다. 실제로 업데이트의 경우 아래와 같은 결과가 나왔다.

삭제의 경우 삭제할 객체를 찾아서 delete() 메소드를 호출해 주면 된다.
마찬가지로 findAll(), save()와 같이 바로 호출해서 사용할 수 있다.
다음으로 서비스 객체를 호출할 컨트롤러를 작성해 준다.
MemberController
package com.seungh1024.controller;
import com.seungh1024.Response;
import com.seungh1024.entity.Member;
import com.seungh1024.service.MemberService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/member")
public class MemberController {
private final MemberService memberService;
public MemberController(MemberService memberService){
this.memberService = memberService;
}
@PostMapping("/signup")
public Response<?> signup(@RequestBody Member member){
boolean result = memberService.createMember(member);
if(result){
return new Response<>().builder()
.code(200)
.message("성공")
.data(null)
.build();
}else{
return new Response<>().builder()
.code(400)
.message("실패")
.data(null)
.build();
}
}
@GetMapping("/search/all")
public Response<?> searchAll(){
List<Member> result = memberService.allMemberList();
if(result.size() >0 ){
return new Response<>().builder()
.code(200)
.message("성공")
.data(result)
.build();
}else{
return new Response<>().builder()
.code(404)
.message("찾는 데이터가 없습니다")
.data(null)
.build();
}
}
@GetMapping("/search/{email}")
public Response<?> searchByEmail(@PathVariable("email") String email){
Member member = memberService.findMemberByEmail(email);
if(member != null){
return new Response<>().builder()
.code(200)
.message("성공")
.data(member)
.build();
}else{
return new Response<>().builder()
.code(404)
.message("검색한 사용자가 없습니다")
.build();
}
}
@PatchMapping("/update")
public Response<?> updateByPk(@RequestBody Member member){
boolean result = memberService.updateMemberPassword(member.getMemberId(), member.getMemberPassword());
if(result){
return new Response<>().builder()
.code(200)
.message("업데이트 성공")
.build();
}else{
return new Response<>().builder()
.code(400)
.message("업데이트 실패")
.build();
}
}
@DeleteMapping("/delete/{pk}")
public Response<?> deleteByPk(@PathVariable("pk") int pk){
boolean result = memberService.deleteMember(pk);
if(result){
return new Response<>().builder()
.code(200)
.message("삭제 성공")
.build();
}else{
return new Response<>().builder()
.code(400)
.message("삭제 실패")
.build();
}
}
}
공통 응답 객체를 만들어서 응답을 해보았다.
아직 완성이 덜 되고 공부가 부족한 것 같아 다음에 해당 내용을 추가할 것이다.
code는 status code, message는 응답 메세지, data는 보내줄 데이터라고 생각하고 보면 된다.
이제 모든 API를 테스트해 보면
등록

전체 조회

이메일로 조회

데이터가 하나만 있어서 전체 조회와 이메일 조회가 무슨 차이인가 싶지만 자세히 보면 전체 조회는 List형태로 반환되고 이메일로 조회는 단건 조회라 하나의 데이터만 담겨있는 것을 볼 수 있다.
전체 조회에서 더 많은 데이터가 있다면 여러 개의 데이터가 List형태로 반환된다.
비밀번호 변경 및 결과


잘 적용된 것을 볼 수 있다.
사용자 삭제 및 결과


간단하게 CRUD 테스트를 해보았는데 앞으로 Spring Security, JWT 등을 활용하여 로그인 기능을 구현할 예정이다.
'Java > Spring boot 프로젝트' 카테고리의 다른 글
@ControllerAdvice를 사용한 예외 처리,에러 핸들링 - 게시판 만들기 (6) (0) | 2023.03.16 |
---|---|
Spring 공통 응답 만들기(Enum, 제네릭 타입) - 게시판 만들기(5) (0) | 2023.02.20 |
Spring Boot JPA 설정, 테이블 생성(Entity) - 게시판 만들기(3) (2) | 2023.02.19 |
Spring Boot Mysql 연결, 민감한 정보 관리하기(환경 변수 설정하기)- 게시판 만들기(2) (0) | 2023.02.18 |
Multi Module Project 생성하기 - 게시판 만들기(1) (0) | 2023.02.07 |