투로드
Coder ToLoad
투로드
전체 방문자
오늘
어제

블로그 메뉴

  • 홈
  • 알고리즘
  • CS
  • GITHUB
  • 태그
  • 분류 전체보기 (69)
    • Toy Project (0)
      • EternalSNS (0)
    • Algorithm (46)
      • BaekJoon (38)
      • Programmers (7)
      • Code Tree (1)
    • Computer Science (13)
      • JAVA (7)
      • DataBase (4)
    • Backend (7)
      • Spring (2)
      • JPA (2)
      • Django (3)
    • Mobile (2)
      • Android (2)
    • Unity (1)

인기 글

최근 글

hELLO · Designed By 정상우.
투로드

Coder ToLoad

[JPA] JPA로 복합키로 구성된 테이블 생성 및 삭제하기
Backend/JPA

[JPA] JPA로 복합키로 구성된 테이블 생성 및 삭제하기

2022. 1. 22. 19:12

현재 진행 중인 프로젝트에서 회원 고유번호와 팬미팅 고유 번호 두 개만을 외래 키로 받아서 구성된 테이블이 하나 있는데 해당 테이블을 만들면서 오류 폭탄을 받으면서 배운 정보를 기록해두려고 한다.

 


 

 

구성하려는 테이블

 

 

사용한 방법 (@IdClass)

 

1. 식별자 클래스 생성

 

신청자 테이블의 복합 키를 담고 있는 식별자 클래스 ApplicantID 를 먼저 생성한다.

 

식별자 클래스는 생성 시에 조건이 몇 개 있다.

  • 식별자 클래스를 생성할 때 Entity클래스와 동일한 변수명으로 생성해야 한다.
  • 기본 생성자가 있어야 한다.
  • 접근 지정자는 public 이어야 한다.
  • Serializable 상속받아야 한다.
  • equals, hashCode 를 구현

 

위 조건에 맞게 아래와 같이 구성하였다.

// ApplicantID.java	

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data               // equals, hashCode 생성용 Lombok Annotation
@NoArgsConstructor  // 기본 생성자 생성용 Lombok Annotation
@AllArgsConstructor
public class ApplicantID implements Serializable {
    private int meetingId;
    private int memberId;
}

 

2. Entity 클래스 생성

 

식별자 클래스를 생성한 이후에 Entity 클래스를 생성해준다.

변수명은 식별자 클래스와 동일해야 한다.

추가적으로 테이블에 applicant_warn_count 라는 컬럼이 있어서 추가해주었다.

// Applicant.java

import lombok.*;

import javax.persistence.*;

@Entity
@Getter
@Setter
@IdClass(ApplicantID.class)
@Table(name = "applicant")
public class Applicant {
    @Id
    @Column(name = "meeting_id")
    private int meetingId;

    @Id
    @Column(name = "member_id")
    private int memberId;

    @Column(name = "applicant_warn_count")
    private int applicantWarnCount;
}

 

3. Repository 생성

 

보통 JPA Repository는 JpaRepository<Entity명, 기본키 타입> 을 상속받아서 사용한다.

하지만 우리는 복합 키를 사용하므로 아래와 같이 구성하면 된다.

// ApplicantRepository.java

import com.ssafy.yourstar.domain.meeting.db.entity.Applicant;
import com.ssafy.yourstar.domain.meeting.db.entity.ApplicantID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface ApplicantRepository extends JpaRepository<Applicant, ApplicantID> {
}

 


 

컬럼 생성 및 삭제 테스트 (Spring JAVA)

 

1. Request와 Response 클래스 파일 생성

// MeetingApplyByUserPostReq.java

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@ApiModel(value = "MeetingApplyByUserPostReq", description = "팬이 팬미팅 신청시 필요한 정보")
public class MeetingApplyByUserPostReq {
    @ApiModelProperty(value = "팬미팅 구분 번호", required = true, example = "3")
    int meetingId;

    @ApiModelProperty(value = "회원 구분 번호", required = true, example = "23")
    int memberId;
}
// BaseResponseBody.java

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@ApiModel("BaseResponseBody")
public class BaseResponseBody {
	@ApiModelProperty(name="응답 메시지", example = "정상")
	String message = null;
	@ApiModelProperty(name="응답 코드", example = "200")
	Integer statusCode = null;
	
	public BaseResponseBody() {}
	
	public BaseResponseBody(Integer statusCode){
		this.statusCode = statusCode;
	}
	
	public BaseResponseBody(Integer statusCode, String message){
		this.statusCode = statusCode;
		this.message = message;
	}
	
	public static BaseResponseBody of(Integer statusCode, String message) {
		BaseResponseBody body = new BaseResponseBody();
		body.message = message;
		body.statusCode = statusCode;
		return body;
	}
}

 

2. Service 구성

 

생성과 삭제에 사용할 메서드를 구성 및 구현

// MeetingService.java

import com.ssafy.yourstar.domain.meeting.request.MeetingApplyByUserPostReq;

public interface MeetingService {
    void meetingApplyByUser(MeetingApplyByUserPostReq meetingApplyByUserPostReq); // 생성용
    boolean meetingRemoveByUser(int memberId, int meetingId);                     // 삭제용
}
// MeetingServiceImpl.java

import com.ssafy.yourstar.domain.meeting.db.entity.Applicant;
import com.ssafy.yourstar.domain.meeting.db.entity.ApplicantID;
import com.ssafy.yourstar.domain.meeting.db.repository.ApplicantRepository;
import com.ssafy.yourstar.domain.meeting.request.MeetingApplyByUserPostReq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MeetingServiceImpl implements MeetingService {
    @Autowired
    ApplicantRepository applicantRepository;

    @Override
    public void meetingApplyByUser(MeetingApplyByUserPostReq meetingApplyByUserPostReq) {
        Applicant applicant = new Applicant();

        applicant.setMeetingId(meetingApplyByUserPostReq.getMeetingId());
        applicant.setMemberId(meetingApplyByUserPostReq.getMemberId());
        applicant.setApplicantWarnCount(0); // 신청 했을 때 경고 횟수는 0이다.

        applicantRepository.save(applicant);
    }

    @Override
    public boolean meetingRemoveByUser(int memberId, int meetingId) {
        // 복합키이기 때문에 ID에 내용을 등록 후 사용
        ApplicantID applicantID = new ApplicantID();
        applicantID.setMemberId(memberId);
        applicantID.setMeetingId(meetingId);

        // 해당 팬미팅이 존재하는지 조회 후 있을 때 삭제
        if (applicantRepository.findById(applicantID).isPresent()) {
            applicantRepository.deleteById(applicantID);

            return true;
        }
        return false;
    }
}

 

3. Controller 구성

// MeetingController.java

import com.ssafy.yourstar.domain.meeting.request.MeetingApplyByUserPostReq;
import com.ssafy.yourstar.domain.meeting.service.MeetingService;
import com.ssafy.yourstar.global.model.response.BaseResponseBody;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Api("팬미팅 관련 API")
@Slf4j
@RestController
@RequestMapping("/api/meetings")
public class MeetingController {

    @Autowired
    MeetingService meetingService;

    @ApiOperation(value = "팬이 팬미팅 신청")
    @PostMapping("/fan-applicant")
    public ResponseEntity<? extends BaseResponseBody> meetingApplyByUser
            (@RequestBody MeetingApplyByUserPostReq meetingApplyByUserPostReq) {
        log.info("meetingApplyByUser - Call");

        meetingService.meetingApplyByUser(meetingApplyByUserPostReq);

        return ResponseEntity.status(201).body(BaseResponseBody.of(201, "Success"));
    }

    @ApiOperation(value = "팬이 신청한 팬미팅 취소")
    @DeleteMapping("/fan-applicant/{memberId}/{meetingId}")
    public ResponseEntity<? extends BaseResponseBody> meetingRemoveByUser
            (@ApiParam(value = "회원 구분 번호") @PathVariable("memberId") int memberId,
             @ApiParam(value = "팬미팅 번호") @PathVariable("meetingId") int meetingId) {
        log.info("meetingRemoveByUser - Call");

        if (meetingService.meetingRemoveByUser(memberId, meetingId)) {
            return ResponseEntity.status(200).body(BaseResponseBody.of(200, "Success"));
        } else {
            log.error("meetingRemoveByUser - This MeetingId or MemberId doesn't exist");
            return ResponseEntity.status(400).body(BaseResponseBody.of(400, "This MeetingId or MemberId doesn't exist"));
        }
    }
}

 

4. 확인

 

Swagger 를 통해 생성 확인

DB에도 문제없이 잘 들어간 것을 확인

 

삭제는 아래와 같이 Swaager을 이용 Success 메시지를 잘 반환하는 것을 확인하였다.

 


글보다 코딩한 내용을 보는 게 이해가 더 잘되는 편이라 참고한 블로그 글을 참고해 현재 프로젝트에서 작성한 코드를 가지고 설명했는데 도움이 되었으면 좋겠다.

 

코딩이 늘 그렇듯 문제를 만나면 막막하지만, 해결하고 나면 재밌다고 느껴진다.

JPA를 처음 사용해보면서 익숙하지 않아서 문제가 발생하면 어떻게 해결해야 할지 막막하다고 많이 느끼는데 계속 사용하면서 익숙해지니까 MyBatis를 쓸 때 보다 훨씬 편하다고 느껴진다.

 

JPA에 대해 어느 정도 이해하고 잘 다루게 되면 JPA가 무엇인지 기본 사용법은 어떤지도 작성해보려고 한다.

 

참고한 블로그 : https://jforj.tistory.com/84

저작자표시 (새창열림)

'Backend > JPA' 카테고리의 다른 글

[JPA] 특정 날짜 기준으로 조회 및 정렬하기  (0) 2022.02.21
    'Backend/JPA' 카테고리의 다른 글
    • [JPA] 특정 날짜 기준으로 조회 및 정렬하기
    투로드
    투로드
    훌륭한 프로그래머가 되어가는 과정을 담아보는 중입니다.

    티스토리툴바