Spring Boot์์ ๊ฒ์๊ธ ๋๊ธ ๊ด๋ฆฌ ํด๋ณด๊ธฐ! ใฝ(โฟ๏พโฝ๏พ)ใ
- ์ฌ์ฉ IDE : IntelliJ IDEA Ultimate
- ์ฌ์ฉ DB : MySQL
- ์ฌ์ฉ ์ธ์ด & SDK : Java & Amazon correto 11
- ์ ๋ฆฌ๋ณธ์ ๋๋ค ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ๋ด์ฃผ์ธ์ :D
- ๊ฒ์๊ธ ๋๊ธ ์์ฑ์ ๋ํด ์์๋ณด๊ธฐ!! (ใฃใปโใป๏ผใฃ
์ด์ ๊ธ
๐ Spring Boot ์์ 1 (๊ฒ์๊ธ ๊ด๋ฆฌ) ใฝ(โฟ๏พโฝ๏พ)ใ
๐ SpringBoot ์์ 2 (๊ฒ์๊ธ ๊ด๋ฆฌ) (ใฃใปโใป๏ผใฃ
์๋ ํ์ธ์:D
์ค๋์ ๋๊ธ ๊ด๋ฆฌ์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค~~!!
๋๊ธ์์ฑ ๋ฐ ์ถ๋ ฅ์ ๊ธฐ์กด๊ณผ ๋ค๋ฅธ๊ฒ ์์ผ๋ฏ๋ก ๋๊ธ ์ ์ฅ ๋ฐ ์ถ๋ ฅ์ ์๋ตํ๊ฒ ์ต๋๋ค :D
๊ทธ๋์ DB๊ด๋ จ ๋ด์ฉ์ด ๋ณต์กํ ์ ์์ผ๋ฏ๋ก ์ด์ ์ค๋ช ์ ํ๊ฒ ์ต๋๋ค!!
๊ทธ๋ผ ๋ฐ๋ก ์์ํ์์ฃ !(เนโขฬใ โขฬ)ู
๋๊ธ ์์ฑ์ ํ๊ธฐ ์ Spring Framework์์์ ๊ฐ์ด table์ ์์ฑํด์ผํฉ๋๋ค.
์ด๋ฒ์ JPA๋ก ๋๊ธ ๊ด๋ฆฌ๋ฅผ ํ ์์ ์ด๊ธฐ ๋๋ฌธ์ Entity Class๋ฅผ ํ๋ ์์ฑํด์ค๋๋ค.
@Entity
@Getter
@Setter
@Table(name = "comment_table")
public class CommentEntity extends BaseEntity {
// ์๊ฐ์ BaseEntity๊ฐ ์์ฑํ๊ฒ ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ BaseEntity๋ฅผ ์์๋ฐ๋ ํด๋์ค๋ก ์ ์ธ!
// ๋ง๋ค ์ปฌ๋ผ : ๋๊ธ๋ฒํธ, ์์ฑ์, ๋ด์ฉ, ์๊ธ ๋ฒํธ
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "comment_id")
private Long id;
// JPA์์ ์ฐธ์กฐ๊ด๊ณ ๋งบ๊ธฐ
// JPA ๋ฌธ๋ฒ์ด๊ธฐ ๋๋ฌธ์ ์ธ์ฐ๊ธฐ
// ์๊ธ์ ๊ฒ์๊ธ ๋ฒํธ๋ฅผ ์ฐธ์กฐํ๊ธฐ ์ํ ์ค์
// ๋๊ธ๊ณผ ๊ฒ์๊ธ์ ๊ด๊ณ์์ ๋๊ธ ์
์ฅ์์ -> N : 1 ๊ด๊ณ, ๊ฒ์๊ธ ์
์ฅ์์ 1 : N
@ManyToOne(fetch = FetchType.LAZY) // @ManyToOne : N : 1 ๊ด๊ณ๋ก ์ค์ (ํ์ฌ ์ํฐํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒฐ์ , ๋๊ธ์ฉ ์ํฐํฐ์ด๋ฏ๋ก N : 1)
@JoinColumn(name = "board_id") // ๋ถ๋ชจ ํ
์ด๋ธ(์ฐธ์กฐํ๊ณ ์ ํ๋ ํ
์ด๋ธ)์ pk ์ปฌ๋ผ ์ด๋ฆ
private BoardEntity boardEntity; // ์ฐธ์กฐํ๊ณ ์ ํ๋ ํ
์ด๋ธ์ ๊ด๋ฆฌํ๋ ์ํฐํฐ
// LAZY : ๋ค๋ฅธ Entity๋ฅผ ์ธ ๋ ๋ง ์์ฒญํด์ ๊ฐ์ ธ์ด
// EAGER : ๋ค๋ฅธ Entity๋ฅผ ์ฐ๋ ๋ง๋ ๋ฌด์กฐ๊ฑด ๊ฐ์ ธ์ด.
// EAGER๋ ๋ฐ์ดํฐ์ ์์ด ์ปค ๋ถ๋ด์ด ํฌ๊ธฐ ๋๋ฌธ์ ์ ์ฌ์ฉํ์ง ์๋๋ค.
@Column
private String commentWriter;
@Column
private String commentContents;
// ์ฐจํ์ ์จ์ผํ๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ฒ ์ต๋๋ค.
public static CommentEntity toSaveEntity(CommentSaveDTO commentSaveDTO, BoardEntity boardEntity) {
CommentEntity commentEntity = new CommentEntity();
commentEntity.setCommentWriter(commentSaveDTO.getCommentWriter());
commentEntity.setCommentContents(commentSaveDTO.getCommentContents());
commentEntity.setBoardEntity(boardEntity);
// jpa๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ํ์ฉํ๊ธฐ ์ํด Entity๋ฐ์ดํฐ ์์ฒด๋ฅผ ๋ฃ์.
return commentEntity;
}
}
์์ ๋ณด์๋ค์ํผ ๋ค๋ฅธ ํ ์ด๋ธ์ ์ปฌ๋ผ์ ์ฐธ์กฐํ๊ธฐ ์ํด์ ๋จผ์ ERD์ ๊ฐ๋ ์ ์์์ผํฉ๋๋ค.
DB ์์ฑ ํ DataBase์์ ์ญ์ค๊ณ๋ฅผ ํด ERD๋ฅผ ๋ง๋ค์ด์ ๋ณด๋ฉด >----| |- ์ด๋ฐ์์ผ๋ก ์ ์ด ์๋๊ฑธ ๋ณผ ์ ์์ต๋๋ค.
์ด ์ ์ด ๋ฐ๋ก 1:1, 1:N, N:1, N:N ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ ์ ์ ๋๋ค. ์์ธํ ๋ด์ฉ์ ๊ตฌ๊ธ๋ง... :D
์๋ฌดํผ DB์์ ์ง์ ํ ์ด๋ธ ์์ฑ ์ ์ฐธ์กฐํค๋ฅผ ์ค์ ํ๋ฉด ๋ฌธ์ ๊ฐ ์์ง๋ง JPA๋ฅผ ์ด์ฉํ๋ค๋ฉด ๋ง์ด ๋ฌ๋ผ์ง๋๋ค.
์ง์ Entity์์ ์ค์ ์ ํด์ค์ผํ๋๋ฐ์, ์ ์ด๋ ธํ ์ด์ ๊ณผ ๊ฐ์ด ๋จผ์ ์ด๊ฒ ๋ช๋๋ช ๊ด๊ณ์ธ์ง ์ ํด๋๊ณ ,
@ManyToOne, @OneToMany ๋ฑ ๋ง๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ค์ผํฉ๋๋ค.
๊ทธ๋ผ CommentEntity๋ฅผ ์์ฑํ์ผ๋ BoardEntity์๋ ์ด ๋ด์ฉ์ ๋ง๋ค๋ฌ ๊ฐ์ผํฉ๋๋ค
๊ทธ๋ผ ๊ฐ๋ณด์์ฃ !!
// BoardEntity์ ์๋ ๋ด์ฉ ์ถ๊ฐ
// ๋๊ธ ์ฐ๊ด๊ด๊ณ
@OneToMany(mappedBy = "boardEntity", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<CommentEntity> commentEntityList = new ArrayList<>();
// ๊ฒ์๊ธ ํ๋์ ๋๊ธ์ด ์ฌ๋ฌ๊ฐ ๋ถ๊ธฐ ๋๋ฌธ์ ๋ฆฌ์คํธ ํ์
์ผ๋ก ์ ์ธํด์ผํจ.
// ๋ฆฌ์คํธ ํ์
์ผ๋ก๋ ์์ํ
์ด๋ธ์ ์ํฐํฐ๊ฐ ๋ค์ด๊ฐ.
์ด๋ ๊ฒ ์ ์์ ํด์ผ ์์ฑ์ด ๋ฉ๋๋ค.
cascade, orphanRemoval์ ์ฐธ์กฐํค์ delete on cascade๋ผ๊ณ ์๊ฐํ์๋ฉด ์ดํดํ๊ธฐ ์ฌ์ธ๊ฒ๋๋ค!!
๋ํ ๊ฒ์๊ธ ํ๋์๋ ๋๊ธ์ด ์ฌ๋ฌ๊ฐ๊ฐ ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ Listํ์ ์ผ๋ก ์ ์ธ์ ํด์ผํฉ๋๋ค.
List ํ์ ์ผ๋ก๋ ์์ํ ์ด๋ธ์ ์ํฐํฐ๋ฅผ ๋ฃ์ด์ผํฉ๋๋ค!!
๋ง์ด ์ข ๊ธธ์์ง๋ง ์ค์ํ ๋ด์ฉ์ด๊ธฐ ๋๋ฌธ์ ์ด์ฉ ์ ์์ต๋๋ค ลฬฅฬฅฬฅฬฅืลฬฅฬฅฬฅฬฅ
๊ทธ๋ผ DTO๋ฅผ ์์ฑํ๋ฌ ๊ฐ๋ณผ๊น์??
๋๊ธ ์ ์ฅ์ฉ DTO ์์ฑ
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentSaveDTO {
private Long boardId;
private String commentWriter;
private String commentContents;
}
๋๊ธ ์ถ๋ ฅ์ฉ DTO ์์ฑ
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentDetailDTO {
private Long commentId;
private Long boardId;
private String commentWriter;
private String commentContents;
private LocalDateTime createTime;
// ์ฐจํ์ ์จ์ผํ๋๊น ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ฒ ์ต๋๋ค!
public static CommentDetailDTO toCommentDetailDTO(CommentEntity commentEntity) {
CommentDetailDTO commentDetailDTO = new CommentDetailDTO();
commentDetailDTO.setCommentId(commentEntity.getId());
commentDetailDTO.setBoardId(commentEntity.getBoardEntity().getId());
commentDetailDTO.setCommentWriter(commentEntity.getCommentWriter());
commentDetailDTO.setCommentContents(commentEntity.getCommentContents());
commentDetailDTO.setCreateTime(commentEntity.getCreateTime());
return commentDetailDTO;
}
}
๋ค ์ด๋ ๊ฒ ๋๊ธ์ ๋ฌ ์ค๋น๋ ๋ชจ๋ ๋๋ฌ์ต๋๋ค.
html์ ์๋ตํ๊ณ Controller์ Service๋ง ๋ง๋ค๊ณ , Test์ฝ๋๋ก๋ง ์งํํ๊ฒ ์ต๋๋ค:D
Service Interface์ ๋ํ ๋ด์ฉ์ ์๋ตํ๊ฒ ์ต๋๋ค!
html์ ajaxํ์์ผ๋ก ์ง์ ํ๋ฒ ํด๋ณด์๋๊ฒ๋...ใ
๊ทธ๋ผ ๋ฐ๋ก ๊ฐ์์ฃ ~!
@Controller
@RequiredArgsConstructor
@RequestMapping("/comment")
public class CommentController {
private final CommentService cs;
@PostMapping("/save")
public @ResponseBody List<CommentDetailDTO> save(@ModelAttribute CommentSaveDTO commentSaveDTO) {
Long commentId = cs.save(commentSaveDTO);
List<CommentDetailDTO> commentList = cs.findAll(commentSaveDTO.getBoardId());
return commentList;
}
}
@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService{
private final CommentRepository cr;
private final BoardRepository br;
@Override
public Long save(CommentSaveDTO commentSaveDTO) {
BoardEntity boardEntity = br.findById(commentSaveDTO.getBoardId()).get();
CommentEntity commentEntity = CommentEntity.toSaveEntity(commentSaveDTO, boardEntity);
return cr.save(commentEntity).getId();
}
@Override
public List<CommentDetailDTO> findAll(Long boardId) {
BoardEntity boardEntity = br.findById(boardId).get();
List<CommentEntity> commentEntityList = boardEntity.getCommentEntityList();
List<CommentDetailDTO> commentList = new ArrayList<>();
for (CommentEntity c: commentEntityList) {
CommentDetailDTO commentDetailDTO = CommentDetailDTO.toCommentDetailDTO(c);
commentList.add(commentDetailDTO);
}
return commentList;
}
}
์ด๋ ๊ฒ๋ง ์ ๋ฐ๋ผ์๋ค๋ฉด ๋๊ธ ์์ฑ ๋ฐ ๋๊ธ ๋ชฉ๋ก์ ๋ถ๋ฌ์ค๋๋ฐ๋ ํฐ ์ง์ฅ์ด ์์ต๋๋ค.
๋ฌผ๋ก ํ๋ก ํธ์์ ์ฌ์ฉํ๊ธฐ ์ํด์ html์ ํด๋น ๋ด์ฉ์ ์์ฑํด์ผํ์ง๋ง ์ ๋ ์๋ตํ์ต๋๋ค... :D
๊ทธ๋ผ Test๊ฐ ์ ์๋ํ๋์ง ๋ณด๋ฌ๊ฐ์์ฃ !
@SpringBootTest
public class CommentTest {
@Autowired
private BoardService bs;
@Autowired
private CommentService cs;
@Autowired
private CommentRepository cr;
@Test
@Transactional // ์ฐธ์กฐ๊ด๊ณ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ๋ @Transactional ์ ์ฌ์ฉํด์ผํจ. ๊ทธ๋์ผ ๋์ค์ ์ฌ๋ฌ๊ฐ์ง์ ์ฌ์ฉ ๊ฐ๋ฅ
@Rollback(value = false) // Rollback์ ํ์ง ์๊ฒ ๋ค๋ ์๋ฏธ
@DisplayName("๋๊ธ์์ฑ ํ
์คํธ")
public void commentTest() {
// Long boardId = bs.save(new BoardSaveDTO("ํ
์คํธ์์ฑ์", "ํ
์คํธ๋น๋ฐ๋ฒํธ", "ํ
์คํธ์ ๋ชฉ", "ํ
์คํธ๋ด์ฉ"));
// Long commentId = cs.save(new CommentSaveDTO(boardId, "๋๊ธ์์ฑ์", "๋๊ธ๋ด์ฉ"));
// assertThat(commentId).isNotNull();
assertThat(cs.save(new CommentSaveDTO(bs.save(new BoardSaveDTO("ํ
์คํธ์์ฑ์", "ํ
์คํธ๋น๋ฐ๋ฒํธ", "ํ
์คํธ์ ๋ชฉ", "ํ
์คํธ๋ด์ฉ")), "๋๊ธ์์ฑ์", "๋๊ธ๋ด์ฉ"))).isNotNull();
}
@Test
@Transactional
@DisplayName("๋๊ธ ์กฐํ ํ
์คํธ")
public void findByIdTest() {
CommentEntity commentEntity = cr.findById(1L).get();
// ์๋ Longํ์
์ ๋งค๊ฐ๋ณ์๋ก ๋ณด๋ผ ๋ ๋ค์ L์ ๋ถ์ฌ์ ๋ณด๋ด์ผํ๋ค.
System.out.println("commentEntity.toString() = " + commentEntity.toString());
System.out.println("commentEntity.getId() = " + commentEntity.getId());
System.out.println("commentEntity.getCommentWriter() = " + commentEntity.getCommentWriter());
System.out.println("commentEntity.getCommentContents() = " + commentEntity.getCommentContents());
System.out.println("commentEntity.getBoardEntity() = " + commentEntity.getBoardEntity());
System.out.println("commentEntity.getBoardEntity().getBoardTitle() = " + commentEntity.getBoardEntity().getBoardTitle());
// ์ด๋ ๊ฒ board_table์ ์ํ ์ปฌ๋ผ๋ ๊ฐ๊ณ ์ฌ ์ ์๋ค.
}
@Test
@Transactional
@DisplayName("๋๊ธ ๋ชฉ๋ก ์กฐํ ํ
์คํธ")
public void findByAllTest() {
List<CommentDetailDTO> commentDetailDTOList = cs.findAll(1L);
for (CommentDetailDTO c: commentDetailDTOList) {
System.out.println("c.toString() = " + c.toString());
}
}
}
์ด๋ ๊ฒ ๋๊ธ์ ๊ดํ ๋ด์ฉ๋ ๋์ ๋๋ค!!
์๊น Entityํ์ ์ผ๋ก ๋ณํํ๋ ๋ฉ์๋์์ boardEntity๋ฅผ ๊ทธ๋๋ก ๋ด์๊ฒ์ ๋ํด ์์ํด ํ์ จ์ํ ๋ฐ
์ด๋ ๊ฒ ๋๊ธ ํ ์ด๋ธ์์ ์ฐธ์กฐํ ๊ฒ์๊ธ ํ ์ด๋ธ์ ์ํ ์ปฌ๋ผ์ ๊ฐ์ ธ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ค์์๊ฐ์๋ ํ์์ ๊ฒ์ํ์ ๋ํด ์์๋ณผ ์์ ์ด๋ ๋ค์์ ๊ฑด๊ฐํ ๋ชจ์ต์ผ๋ก ๋ง๋์~!! :D