
java 파일 밑 step에 controller / dto / entity / repository / service 패키지를 만들었다.
각 패키지는 다음의 역할을 수행한다.
사용자가 프로필 카드를 생성하면
POST /profile-cards
라는 요청이 Controller로 들어온다. controller는 이 요청을 받은 후 필요한 데이터를 service로 전달하고 처리 결과를 다시 사용자에게 반환하는 역할을 수행한다.
-> 사용자와 서비스를 연결
ex) 프로필 카드 생성 / 프로필 카드 조회 / 입력값 검증
-> 프로그램의 핵심 기능 수행
JPA를 이용하여 저장 / 조회 / 수정 / 삭제 와 같은 작업을 한다.
-> 데이터베이스와 연결
JPA란?
JPA는 자바 객체와 데이터베이스를 연결해 주는 기술입니다. 개발자가 SQL을 직접 작성하지 않아도 JPA가 SQL을 자동으로 생성하여 데이터베이스와 통신할 수 있도록 도와줍니다.
ERD에 있는 profileCard 엔티티를 직접 profileCard 클래스로 표현한다.
각 속성은
private Long profileCardID;
private String introduce;
private String tag;
와 같이 변수로서 작용한다.
-> ERD 테이블과 매핑
Data Transfer Object
프로필 카드 생성 요청이 들어오면 데이터를 DTO에 담어 service로 전달한다.
entity를 직접 사용하는 것보다 필요한 데이터만 전달할 수 있어서 보안과 유지보수 측면에서 유리하다.
-> 계층 간 데이터를 전달하는 객체
왜 dto를 사용하는지에 대한 추가적인 설명
사용자가 프로필 카드를 생성하려고 할 때 보내는 데이터는 tag와 introduce이다.
하지만 entity를 그대로 사용하면 tag와 introduce 뿐만 아니라 profileCardID, userID 모두 받을 수 있게 된다. 따라서 불필요한 데이터의 노출을 막을 수 있고 역할을 분리하여 유지보수가 보다 쉬워진다.
package com.likelion.step.profilecard.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "profileCard")
public class profileCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long profileCardID;
private String tag;
private String introduce;
private Long userID;
}
데이터베이스의 어떤 테이블과 연결하도록 명시하는 역할
현재 profileCardID 를 기본키로 설정한 상태
: 데이터베이스가 자동으로 번호를 증가시켜주라는 뜻
private으로 보호되는 정보를 가져올 수 있는 매서드
그렇다면 왜 public을 쓰지 않고 private과 Getter를 쓸까?
public을 사용했을 시 어디서든 값을 마음대로 바꿀 수 있다. 하지만 private을 썼을시 그 클래스에서만 값을 다룰 수 있기 때문에 데이터가 보호된다.
-> 캡슐화 - 외부에서 함부로 접근하거나 수정하지 못하도록 보호하는 것
Lombok이 뭘까?
Lombok은 반복해서 작성하는 코드를 자동으로 만들어주는 라이브러리이다.
private String tag;
String인 이유 - ERD에서는 ENUM이지만 아직 Enum 클래스를 만들지 않았기 때문에 임시로 String으로 저장
private Long userID;
원래는
@ ManyToOne
private User user;
가 맞지만 아직 User 기능이 구현되지 않았으므로 임시로 회원 ID만 저장

객체를 만들때 처음 값을 넣어주는 코드
this는 현재 만들어지고 있는 객체 자기 자신을 의미한다(하나는 필드, 다른 하나는 생성자 매개변수)
ex) this.tag = tag; = 현재 객체의 tag 필드에 생성자로 들어온 tag 값을 넣겠다.
new ProfileCard("BACKEND","안녕하세요",1L);
생성자 실행
public ProfileCard(String tag, String introduce, Long Id)
따라서 값이 다음과 같이 들어온다.
tag = "BACKEND"
introduce = "안녕하세요"
userId = 1L

왜 class가 아닌 interface를 쓸까?
extends JpaRepository 때문
JpaRepository에는 데이터를 다룰 때 사용하는 기능(CRUD 기능)들이 이미 구현되어 있기 때문에
public interface ProfileCardRepository
extends JpaRepository<ProfileCard, Long>
만 써도 JPA가 실제로 동작하는 repository를 자동으로 만들어준다.
JpaRepository<ProfileCard, Long>
profileCard는 어떤 entity를 관리하는 repository인지를 의미
Long은 PK 타입을 의미

entity:

repository:

dto:


entity에서의 생성자 vs service에서의 생성자
entity에서는 객체를 생성하며 데이터를 초기화하기 위해
service(@RequiredArgsConstructor)에서는 repository 같은 의존성을 생성자를 통해 주입받기 위해
private final ProfileCardRepository profileCardRepository;
여기서 final은 한번만 초기화되고 이후에는 바뀌지 않음을 의미한다.
(값은 계속 바꿀 수 있지만 처리하는 repository는 처음 연결된 이것만 사용한다는 뜻)
package com.likelion.step.profilecard.sevice;
import com.likelion.step.profilecard.dto.ProfileCardCreateRequest;
import com.likelion.step.profilecard.entity.Certification;
import com.likelion.step.profilecard.entity.ProfileCard;
import com.likelion.step.profilecard.repository.CertificationRepository;
import com.likelion.step.profilecard.repository.ProfileCardRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class ProfileCardService {
private final ProfileCardRepository profileCardRepository;
private final CertificationRepository certificationRepository;
public Long createProfileCard(ProfileCardCreateRequest request){
ProfileCard profileCard = new ProfileCard(
request.getTag(),
request.getIntroduce(),
request.getUserId()
);
ProfileCard saveProfileCard = profileCardRepository.save(profileCard);
Certification certification = new Certification(
request.getCertification(),
saveProfileCard.getProfileCardId()
);
certificationRepository.save(certification);
return saveProfileCard.getProfileCardId();
}
}
public Long createProfileCard(ProfileCardCreateRequest request)
이 메서드가 프로필 카드 생성 기능이다.
request는 사용자 요청을 DTO에 담아서 service로 넘기는 역할을 수행한다.
ProfileCard profileCard = new ProfileCard(
request.getTag(),
request.getIntroduce(),
request.getUserId()
);
이 메서드는 entity를 새로 생성하는 역할을 수행한다.
DTO는 그냥 데이터를 전달하고 담아오는 객체이므로 DB에는 저장할 수 없다.
ProfileCard savedProfileCard =
profileCardRepository.save(profileCard);
데이터를 DB에 저장하기 위한 메소드이다. save()를 호출하면 JPA가 SQL을 자동 생성해서 DB에 저장한다.
Certification certification = new Certification(
request.getCertification(),
saveProfileCard.getProfileCardId()
);
certificationRepository.save(certification);
새로운 자격증 객체를 만든다. 어떤 프로필 카드의 자격증인지 연결하기 위해 savedProfileCard.getProfileCardId()를 사용한다. (FK로서 profileCardId를 사용하기 위해)


포트번호 불일치