ToString 사용시 순한 참조 조심해야 합니다.
package com.puzzlix.solid_task.domain.comment;
import com.puzzlix.solid_task.domain.issue.Issue;
import com.puzzlix.solid_task.domain.user.User;
import jakarta.persistence.*;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@ToString(exclude = {"issue", "writer"}) // 순한 참조 방지(양방향 매핑시 조심해야 될 부분)
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
// 어디 이슈에 댓글이 달렸는가
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "issue_id")
private Issue issue;
// 누가작성했는가?
// 이걸전략, 레이지 전략
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "writer_id")
private User writer;
}
package com.puzzlix.solid_task.domain.user;
import com.puzzlix.solid_task.domain.issue.Issue;
import jakarta.persistence.*;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "user_table")
@ToString(exclude = "issues")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
@OneToMany(mappedBy = "reporter")
private List<Issue> issues = new ArrayList<>();
}
package com.puzzlix.solid_task.domain.project;
import com.puzzlix.solid_task.domain.issue.Issue;
import jakarta.persistence.*;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@ToString(exclude = {"issues"})
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
// 나는 fk 주인이 아니야
@OneToMany(mappedBy = "project")
private List<Issue> issues = new ArrayList<>();
}
package com.puzzlix.solid_task.domain.issue;
import com.puzzlix.solid_task.domain.comment.Comment;
import com.puzzlix.solid_task.domain.project.Project;
import com.puzzlix.solid_task.domain.user.User;
import jakarta.persistence.*;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@ToString(exclude = {"project", "reporter", "assignee", "commnets"})
public class Issue {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String tittle;
private String description;
@Enumerated(EnumType.STRING)
private IssueStatus issueStatus;
// 추후 연관관계 필드
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id")
private Project project;
// 누가 요청(보고)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "reporter_id")
private User reporter;
// 담당자(누군가에게 할당 되어 처리 됩니다)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assignee_id")
private User assignee;
// 댓글
// 이슈 너는 댓글에 외래키 주인이 아니야!
@OneToMany(mappedBy = "issue", cascade = CascadeType.ALL)
private List<Comment> commnets = new ArrayList<>();
}
package com.puzzlix.solid_task.domain.comment;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CommentRepository extends JpaRepository<Comment, Long> {
// 수십개의 메서드 쿼리를 지원한다.
}
package com.puzzlix.solid_task.domain.project;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProjectRepository extends JpaRepository<Project, Long> {
}
package com.puzzlix.solid_task.domain.user;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
package com.puzzlix.solid_task.domain.issue;
import com.puzzlix.solid_task.domain.issue.dto.IssueRequest;
import com.puzzlix.solid_task.domain.project.Project;
import com.puzzlix.solid_task.domain.project.ProjectRepository;
import com.puzzlix.solid_task.domain.user.User;
import com.puzzlix.solid_task.domain.user.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.NoSuchElementException;
@Service // IoC
@RequiredArgsConstructor
@Transactional
public class IssueService {
// 구체 클래스가 아닌, IssueRepository 라는 역할(인터페이스)에만 의존한다.
private final IssueRepository issueRepository;
private final UserRepository userRepository;
private final ProjectRepository projectRepository;
// 이슈 생성 로직
public Issue createIssue(IssueRequest.Create request) {
// 보고자 ID -> 실제 회원이 있는가?
User reporter = userRepository.findById(request.getReporterId())
.orElseThrow(() -> new NoSuchElementException("해당 ID의 사용자를 찾을 수 없습니다"));
// 프로젝 ID 검증
Project project = projectRepository.findById(request.getProjectId())
.orElseThrow(() -> new NoSuchElementException("해당 ID의 프로젝트를 찾을 수 없습니다"));
Issue newIssue = new Issue();
newIssue.setTittle(request.getTitle());
newIssue.setDescription(request.getDescription());
newIssue.setReporter(reporter);
newIssue.setProject(project);
newIssue.setIssueStatus(IssueStatus.TODO); // 시스템에서 설정 (최초 등록)
return issueRepository.save(newIssue);
}
// 모든 이슈 조회
@Transactional(readOnly = true)
public List<Issue> findIssues() {
return issueRepository.findAll();
}
}'JAVA' 카테고리의 다른 글
| [3단계] 데이터베이스 연동과 JPA (DIP) (0) | 2025.11.14 |
|---|---|
| [2단계] CRUD API 구현과 계층형 아키텍처 (SRP) (0) | 2025.11.14 |
| 컴포넌트 스캔 (0) | 2025.11.14 |
| 리플렉션(+어노테이션) (0) | 2025.11.14 |
| 우당탕탕 소셜로그인 구현(for kakao) -- 진행중 (0) | 2025.11.11 |