๐œ Spring Boot ์˜ˆ์ œ3 (๊ฒŒ์‹œ๊ธ€ ๊ด€๋ฆฌ) โ—Ÿ( ห˜โ€ขฯ‰โ€ขห˜ )โ—ž

@Autowiredยท2022๋…„ 1์›” 17์ผ
1

Spring Boot

๋ชฉ๋ก ๋ณด๊ธฐ
11/11

Spring Boot์—์„œ ๊ฒŒ์‹œ๊ธ€ ๋Œ“๊ธ€ ๊ด€๋ฆฌ ํ•ด๋ณด๊ธฐ! ใƒฝ(โœฟ๏พŸโ–ฝ๏พŸ)ใƒŽ


Comment

์•ˆ๋…•ํ•˜์„ธ์š”:D
์˜ค๋Š˜์€ ๋Œ“๊ธ€ ๊ด€๋ฆฌ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค~~!!
๋Œ“๊ธ€์ž‘์„ฑ ๋ฐ ์ถœ๋ ฅ์€ ๊ธฐ์กด๊ณผ ๋‹ค๋ฅธ๊ฒŒ ์—†์œผ๋ฏ€๋กœ ๋Œ“๊ธ€ ์ €์žฅ ๋ฐ ์ถœ๋ ฅ์€ ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค :D
๊ทธ๋Œ€์‹  DB๊ด€๋ จ ๋‚ด์šฉ์ด ๋ณต์žกํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด์— ์„ค๋ช…์„ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!!
๊ทธ๋Ÿผ ๋ฐ”๋กœ ์‹œ์ž‘ํ•˜์‹œ์ฃ !(เน‘โ€ขฬ€ใ…‚โ€ขฬ)ูˆ


CommentEntity

๋Œ“๊ธ€ ์ž‘์„ฑ์„ ํ•˜๊ธฐ ์ „ 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

// 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

๋Œ“๊ธ€ ์ €์žฅ์šฉ 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

@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

@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๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ๋ณด๋Ÿฌ๊ฐ€์‹œ์ฃ !


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

profile
์ฆ๊ฒ๋‹ค!

0๊ฐœ์˜ ๋Œ“๊ธ€