본문 바로가기
Dev/[프로젝트] 2022 Spring Boot + JSP

[프로젝트] Spring Boot + JSP를 이용한 함께 부산 여행할 사람을 구하는 웹 사이트-3-JPA

by javapp 자바앱 2022. 7. 31.
728x90

 

JPA 를 통해 Entity 생성

E-R Diagram

 

 

Member

@Getter@Setter@Entity
@NoArgsConstructor
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="userid")
	private int userid; //필수, 사용자 ID
	@Column(nullable=false)
	private String name; //필수, 성명
	private String nickName; //필수, 별명
	
	private String password; //필수, 패스워드
	
	private String gender; //필수, 성별
	
	private String email; //필수, 메일
	private String phone; //필수X, 연락처
	
	private String interField; //필수, 관심분야 한줄
	private String address; //필수X, 주소
	private String role; //필수, 권한역할    --> ADMIN_ROLE, USER_ROLE
	private String withdraw; //필수, 탈퇴여부
	
	// 리뷰보드 양방향
	@OneToMany(mappedBy="member")
	@JsonIgnoreProperties("member") // 양방향때 서로 호출되는 것을 방지
	private List<ReviewBoard> reviewBoards  = new ArrayList<>();
	
	//tourarea는 일단 단방향
	
	// 관심 보드
	@OneToMany(mappedBy="member")
	@JsonIgnoreProperties("member") // 양방향때 서로 호출되는 것을 방지
	private List<InterestBoard> interestBoards  = new ArrayList<>();
	
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@Column(name="regdate")
	private Date regdate; // 작성일자
}

@OneToMany(mappedBy="member") // FetchType 은 LAZY가 디폴트
@JsonIgnoreProperties("member") // 양방향때 서로 호출되는 것을 방지
private List<ReviewBoard> reviewBoards  = new ArrayList<>();

 

TourArea

// 여행 관광지
//touristarea는 콘텐츠ID   콘텐츠명   구군   테마   장소   제목     이미지URL   썸네일이미지URL 상세정보
@Getter @Setter
@Entity
public class TourArea 
{		
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="contents_id")
	private int contentsId;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="userid")
	@Getter @Setter
	private Member member;
	
	private String contentsName;
	private String area;
	private String divide; // 테마
	private String course;
	private String title;
	@Transient 
	private MultipartFile imageUrl; //05.23 추가. 이미지 업로드.
	private String imagefile;
	@Transient
	private MultipartFile thumimage_url; 
	private String thumimagefile;
	@Column(length = 1000)
	private String content;
	private String location; //장소
	
	
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@Column(name="regdate")
	private Date regdate; // 등록일자 

}

@Transient // sql 자동생성시 해당 속성은 제외
private MultipartFile thumimage_url; 

 

@ManyToOne(fetch = FetchType.LAZY) // .getMember(), 즉 호출시 쿼리문이 나간다.
@JoinColumn(name="userid") // Member 객체의 @Id 의 변수명
@Getter @Setter
private Member member;

 

InterestBoard

Member 와 TourArea의 관계형 테이블이고

Member : InterestBoard 와 1 : N 관계

InterestBoard : TourArea 와 1 : N 관계

 

@Getter  @Setter
@Entity
@IdClass(InterestBoardPK.class)
public class InterestBoard {
	@Id @ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="userid")
	private Member member; //필수, 사용자 ID
	
	
	@Id
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="contentsId")	
	private TourArea tourarea;
	
	
	private String interTitle; //필수X, 컨텐츠 제목
	private String interName; //필수X, 컨텐츠 명칭
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="regdate")
	private Date regdate; //필수X, 등록일자(자동생성)	
}

여기서 프라이머리 키가 2개로 복합키이다.

Member 객체의 아이디 userid, TourArea의 아이디 contentsId

 

그래서 복합키인 경우 해당 키를 모두 묶어주는 전용 클래스를 생성해서 이용해야된다.

@IdClass(InterestBoardPK.class)

 

InterestBoardPK

@Data
@NoArgsConstructor @AllArgsConstructor
public class InterestBoardPK implements Serializable{
	//테이블에 지정된 키값의 대상 필드
	//키 2개를 복합키로 만든다.
	private int member; // 키가 들어있는 클래스 이름
	private int tourarea; // 키가 들어있는 클래스 이름
	
}

 


 

ReviewBoard

 

리뷰보드 또한 복합키

TourArea(관광지) 에 대해 리뷰 데이터를 담는다.

@Getter
@Setter
@Entity
@IdClass(ReviewBoardPK.class)
public class ReviewBoard 
{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer num;
	
	@Id
	private int boardId;
	
	private String title;
	
	// fk
	@JoinColumn(name="userid")
	@ManyToOne(fetch=FetchType.LAZY)
	private Member member;
	
	//fk
	@JoinColumn(name="contentsid")
	@ManyToOne(fetch=FetchType.LAZY)
	private TourArea tourArea;

	
	private String contents;
	private String area1; //지역1
	private String divide; // 테마
	@Column(columnDefinition = "integer default 0")
	private int hitcount;
	@Column(columnDefinition = "integer default 0")
	private int replycnt;
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@Column(name="regdate")
	private Date regdate; // 등록일자
}

 

ReviewBoardPK

@Setter @Getter
@NoArgsConstructor 
public class ReviewBoardPK implements Serializable
{
	@Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer num;
	private int boardId;
}

 


 

MyBoard

Member 와 1 : N 관계

@Getter @Setter 
@Service
@Entity
public class MyBoard {
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long num;
	private String title;
	private String writer;
	private String content;
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="regdate")
	private Date regdate;
	private Long hitcount;
	private Long replycnt;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="member_id")
	private Member member;
	
	@PrePersist
	public void prePerist()	{
		this.hitcount = this.hitcount==null? 0 : this.hitcount;
		this.replycnt = this.replycnt==null? 0 : this.replycnt;
	}
	
}

@PrePersist // 엔티티(Entity)가 비영속(new/transient) 상태에서 영속(managed) 상태가 되는 시점 이전에 실행
public void prePerist() {
this.hitcount = this.hitcount==null? 0 : this.hitcount;
this.replycnt = this.replycnt==null? 0 : this.replycnt;
}

 


 

TakeRoom

여행 참여 모임방

Member와 TourArea 의 관계테이블

@Getter @Setter
@Entity
public class TakeRoom 
{
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Long num;
	
	@Column(nullable=false)
	private String title;

	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="startDate")
	private Date startDate;
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP)
//	@JsonFormat(pattern="yyyy-MM-dd")
	@Column(name="endDate")
	private Date endDate;
	
	//fk
//	@JsonBackReference
	@ManyToOne(fetch = FetchType.LAZY)
//	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name="userid")
	private Member member;
	//fk
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="contentsId")
	private TourArea tourarea;
//	private int contentsid;
	
	@Column(columnDefinition = "Integer default 0")
	private int membercnt;
	private String openyn; // OPEN/CLOSE여부
	private String nickname;  // 참여오픈방 개설자
	private String guider;  // 참여오픈방 개설자이름
	private String content;
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@JsonFormat(pattern="yyyy-MM-dd")
	@Column(name="regdate")
	private Date regdate; // 등록일자
	
	@OneToMany(mappedBy ="takeroom", fetch=FetchType.LAZY)
	private List<TakeMember> takemembers;
	
	@OneToMany(mappedBy ="takeroom", fetch=FetchType.LAZY)
	@JsonIgnoreProperties("takeroom")
	private List<TakeComment> takecomments;
	
//	@PrePersist
//	public void prePerist() {
//	  this.membercnt = this.membercnt==null?0:this.membercnt;
//	}
	
}

 

 

TakeMember

Member와 TakeRoom의 관계테이블

여행 참여방에 참여한 멤버를 저장

@Getter @Setter
@Entity
@IdClass(TakeMemberPK.class)
public class TakeMember 
{
	@Id
//	@JsonBackReference
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="num")
	private TakeRoom takeroom;
	
	@Id
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="userid")
	private Member member; //사용자 ID
	private String entrant;  // 참여오픈방 참여자 nickname
	
	private String takeyn; //참여자의 의견참여 여부값
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@JsonFormat(pattern="yyyy-MM-dd")
	@Column(name="regdate")
	private Date regdate; // 등록일자,참가일자
}

복합키로 구성

 

TakeMemberPK

@Data 
public class TakeMemberPK implements Serializable {
	private Long takeroom; // 외래키 일 경우 클래스명
	private int member;
}

 


 

TakeComment

Member와 TakeRoom의 관계형 테이블

여행 참여방에 대한 참여 댓글을 달 수 있다.

@Getter @Setter
@Entity
public class TakeComment 
{
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Long cnum;

//	@ManyToOne(fetch = FetchType.LAZY)
	@ManyToOne
	@JoinColumn(name="num")
	private TakeRoom takeroom;
	
	@ManyToOne
	@JoinColumn(name="userid")
	private Member member;  
	private String nickname; // 댓글 작성자 nickname
	private String content;
	
	@CreationTimestamp
	@Temporal(TemporalType.TIMESTAMP) // 날짜형
	@JsonFormat(pattern="yyyy-MM-dd")
	private Date regdate; // 작성일자

}

 


 

 

RecommenedService

추천 여행지

@ToString
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class RecommenedService 
{
	@Id
	String uc_seq;
	String main_title;
	String gugun_nm;
	String cate2_nm;
	String lat; //위도
	String lng; //경도
	String main_place;
	String title;
	String main_img_normal;
	String main_img_thumb;
	@Lob	String itemcntnts;
}

 

 

 

 

 

 

 


참고 사이트

 

https://cjh5414.github.io/jpa-use-composite-key-to-foreign-key/

 

JPA Composite key(복합키)를 foreign key(외래키)로 사용하기

Jihun's Development Blog

cjh5414.github.io

 

https://m.blog.naver.com/yjhyjh5369/221997271213

 

JPA] 컬럼의 기본값 설정 - Setting default values for columns

JPA에서 컬럼의 기본값을 설정하는 방법은 크게 두 가지가 있습니다. 방법 1. 엔티티 속성 값 직접 설정...

blog.naver.com

 

 

https://programmer-chocho.tistory.com/80

 

JPA에서 save할때 select 쿼리가 먼저 실행되는 이유

스프링 데이터 JPA의 JpaRepository로 save를 해보다가 이상한 점을 발견했다. MEMBER 테이블에 회원 객체를 저장하는 테스트 코드를 작성했다. @Test @DisplayName("회원 객체 등록 테스트") void insertMemberTe..

programmer-chocho.tistory.com

 

https://cobbybb.tistory.com/18

 

[JPA] 일반 Join과 Fetch Join의 차이

JPA를 사용하다 보면 바로 N+1의 문제에 마주치고 바로 Fetch Join을 접하게 됩니다. 처음 Fetch Join을 접했을 때 왜 일반 Join으로 해결하면 안되는지에 대해 명확히 정리가 안된 채로 Fetch Join을 사용했

cobbybb.tistory.com

 

 

댓글