개발천재

[Spring Boot] JpaRepository 사용하기 본문

개발 준비/Spring Boot

[Spring Boot] JpaRepository 사용하기

세리블리 2025. 2. 21. 21:59
반응형

JpaRepository 이해하기

JpaRepository<T, ID>는 Spring Data JPA에서 제공하는 인터페이스다. 이걸 사용하면 SQL을 직접 작성하지 않아도 기본적인 데이터베이스 작업(조회, 저장, 삭제 등)을 자동으로 처리할 수 있다.

 


 

JpaRepository의 역할

JpaRepository는 기본적으로 CRUD 기능을 제공하는데, 이걸 사용하면 INSERT, SELECT, UPDATE, DELETE 같은 SQL 쿼리를 직접 작성하지 않고 사용할 수 있다.

public interface MemberRepository extends JpaRepository<Member, Long> {
}

 

JpaRepository를 쓰면 @Repository를 선언하지 않아도 되는 이유

Spring Data JPA에서 JpaRepository를 상속받으면, 자동 컴포넌트 스캔을 통해 JpaRepository를 상속받은 인터페이스를 자동으로 감지하고, 구현체(프록시 객체)를 만들어 스프링 빈으로 등록해 준다. 따라서 @Repository를 붙이지 않아도 정상적으로 동작한다.

하지만 일반적인 DAO 클래스를 직접 만들 경우에는 @Repository를 붙여야 한다. 직접 만든 클래스는 Spring이 자동으로 감지할 수 없기 때문에 @Repository 붙여줘야 빈으로 등록할 수 있다.

 

 


 

 

JpaRepository가 제공하는 기본 메서드

Spring Data JPA에서 JpaRepository를 상속받으면, 아래와 같은 CRUD 메서드들을 자동으로 사용할 수 있다.

메서드 이름 설명
save(T entity) 엔티티 저장 (INSERT, UPDATE)
findById(ID id) ID로 엔티티 조회
findAll() 모든 데이터 조회
deleteById(ID id) ID로 데이터 삭제
delete(T entity) 엔티티 삭제
existsById(ID id) 해당 ID가 존재하는지 확인
count() 총 데이터 개수 조회

 

 


 

 

JpaRepository 사용하기

JpaRepository를 사용하기 위해서는 인터페이스로 만들고 JpaRepository를 상속하면, 기본적인 데이터 조작 메서드들이 자동으로 생성된다. JpaRepository<> 여기 괄호 안에는 Entity 클래스 명과 Entity의 기본 키 타입(Primary Key)를 의미한다.

 

MemberRepository

import org.springframework.data.jpa.repository.JpaRepository;
public interface MemberRepository extends JpaRepository<Member, Long> {
}



이렇게 JpaRepository<Member, Long>을 상속하면, 기본적인 CRUD 메서드를 자동으로 사용할 수 있다.
MemberService

@Autowired
private MemberRepository memberRepository;

public void example() {
    // 1. 회원 저장
    Member member = new Member();
    member.setId("user1");
    member.setPassword("1234");
    memberRepository.save(member); // 저장됨

    // 2. 특정 회원 조회
    Optional<Member> findMember = memberRepository.findById(1L);
    
    // 3. 전체 회원 조회
    List<Member> members = memberRepository.findAll();
    
    // 4. 회원 삭제
    memberRepository.deleteById(1L);
    
    // 5. 회원 존재 여부 확인
    boolean exists = memberRepository.existsById(1L);
}

 

 


 

 

 

실제 적용 예시

MemberController

MemberController에서 MemberService로 회원 저장, 조회, 수정, 삭제 등을 요청한다.

@Controller
@RequestMapping("/member")
@Slf4j
public class MemberController {
    // 생성자 주입
    private final MemberService memberService;
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

	// 회원 입력 폼
    @GetMapping("insertForm")
    public String insertFormView(Model model) {
        model.addAttribute("memberDto", new MemberDto());
        return "insertMember";
    }
	
    // 회원 저장
    @PostMapping("insert")
    public String insert(
            @Valid MemberDto dto,
            BindingResult bindingResult,
            RedirectAttributes redirectAttributes
    ) {
        // validation check 진행
        if(bindingResult.hasErrors()) {
            // 오류 있을 때
            log.info("####### validation Error!");
            return "insertMember";
        }

        // 받은 dto를 service에 넘겨주고 저장 요청
        memberService.saveMember(dto);
        redirectAttributes.addFlashAttribute("msg", "신규데이터가 입력되었습니다");
        return "redirect:/member/view";
    }

	// 회원 목록 보기
    @GetMapping("view")
    public String showMember(Model model) {
        List<MemberDto> memberList = memberService.findAllMembers();
        model.addAttribute("list", memberList);
        System.out.println(memberList);
        return "showMember";
    }

	// 회원 삭제
    @GetMapping("delete/{id}")
    public String deleteMember(@PathVariable("id")Long id, RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("msg", "선택한 자료가 삭제되었습니다.");
        memberService.deleteById(id);
        return "redirect:/member/view";
    }

	// 회원 수정 폼
    @GetMapping("update/{id}")
    public String updateFormView(
            @PathVariable("id")Long id,
            Model model
    ) {
        MemberDto dto = memberService.findById(id);
        log.info("=== dto : " + dto);
        model.addAttribute("member", dto);
        return "/updateMember";
    }

	// 회원 수정 요청
    @PostMapping("update")
    public String update(
            @Valid @ModelAttribute("member") MemberDto member
            , BindingResult bindingResult
            , RedirectAttributes redirectAttributes
    ) {
            // Validation
            if(bindingResult.hasErrors()) {
                return "updateMember";
            }
            // 수정요청
            log.info("### DTO : " + member);
            memberService.updateMember(member);

            // 메세지 전송
            redirectAttributes.addFlashAttribute("msg", "정상적으로 수정되었습니다.");
            return "redirect:/member/view";
    }

	// 회원 찾기
    @GetMapping("search")
    public String search(
            @RequestParam("type")String type,
            @RequestParam("keyword")String keyword,
            Model model
    ) {
      log.info("========== type" + type, ", keyword : " + keyword);
        List<MemberDto> searchList = new ArrayList<>();
        switch (type) {
            case "name" :
                searchList = memberService.searchName(keyword);
                break;
            case "address" :
                searchList = memberService.searchAddress(keyword);
                break;
            default:
                searchList = memberService.searchAll();
                break;
        }
        model.addAttribute("list", searchList);
        return "showMember";
    }
}

 

 

MemberService

MemberController의 요청을 받은 MemberService는 MemberRepository로 회원 저장, 조회, 수정, 삭제를 요청한다.

package com.my.basicCRUD.service;

import com.my.basicCRUD.dto.MemberDto;
import com.my.basicCRUD.entity.Member;
import com.my.basicCRUD.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

import static java.util.Arrays.stream;

@Service
public class MemberService {
    @Autowired
    MemberRepository memberRepository;

	// 회원 조회
    public List<MemberDto> findAllMembers() {
        List<Member> memberList = memberRepository.findAll();
        System.out.println(memberList);

        // Entity Class => DTO Class 변경
        return memberList.stream().map(MemberDto::fromEntity).toList();
    }
	
    // 회원 저장
    public void saveMember(MemberDto dto) {
        // DTO -> Entity로 변환
        Member member = MemberDto.fromDto(dto);

        // 저장 요청
        memberRepository.save(member);
    }

	// 회원 삭제
    public void deleteById(Long id) {
        memberRepository.deleteById(id);
    }

	// 회원 찾기
    public MemberDto findById(Long id) {
        // id로 db에서 검색하기
        Member member = memberRepository.findById(id).orElse(null);

        // DTO로 변환
        if(!ObjectUtils.isEmpty(member)) {
            return MemberDto.fromEntity(member);
        } else {
            return null;
        }
    }

	// 회원 정보 수정(업데이트)
    public void updateMember(MemberDto dto) {
        // dto -> entity로 변환
        Member member = MemberDto.fromDto(dto);

        // 수정처리
        // save() : 해당 ID가 존재하면 수정, 없으면 신규로 입력
        memberRepository.save(member);
    }

	// 회원 조회(이름으로 찾기)
    public List<MemberDto> searchName(String keyword) {
        return memberRepository.searchName(keyword)
        .stream()
                .map(x -> MemberDto.fromEntity(x))
                .toList();
    }

	// 회원 조회(주소로 찾기)
    public List<MemberDto> searchAddress(String keyword) {
        List<Member> memberList = memberRepository.searchAddress(keyword);
        List<MemberDto> dtoList = new ArrayList<>();
        for(int i = 0; i < memberList.size(); i++) {
            MemberDto dto = new MemberDto(
                    memberList.get(i).getMemberId(),
                    memberList.get(i).getName(),
                    memberList.get(i).getAge(),
                    memberList.get(i).getAddress()
            );
            dtoList.add(dto);
        }
        return dtoList;
    }

	// 회원 검색
    public List<MemberDto> searchAll() {
        return memberRepository.searchAll()
                .stream()
                .map(MemberDto::fromEntity)
                .toList();
    }
}

 

 

MemberReposity

MemberService의 요청을 받은 MemberRepository는 JpaRepository를 상속받았기 때문에 별도의 구현 없이 JPA에서 제공하는 메서드를 이용해 요청을 처리할 수 있다.

 

JPA에서 기본적인 CRUD 기능은 제공하지만, 그 외의 다른 로직이 필요한 경우 @Query를 이용해서 데이터베이스에 접근해 조회할 수 있다.

package com.my.basicCRUD.repository;

import com.my.basicCRUD.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    // 전체 검색
    @Query(value = "SELECT * FROM member ORDER BY member_id ASC", nativeQuery = true)
    // 엔티티가 List로 들어감
    List<Member> searchAll();

    // 이름으로 검색
    @Query(value="SELECT * FROM member WHERE member_name LIKE %:keyword% ORDER BY address DESC;", nativeQuery = true)
    List<Member> searchName(@Param("keyword") String keyword);

    // 주소로 검색
    @Query(value="SELECT * FROM member WHERE address LIKE '%:keyword%' ORDER BY member_name DESC;", nativeQuery = true)
    List<Member> searchAddress(@Param("keyword") String keyword);
}
반응형