728x90
반응형
1. 동기와 비동기 차이점
1.1 동기(Synchronous)
- 작업의 순차적 실행:
- 동기 방식에서는 한 작업이 완료될 때까지 다음 작업이 시작되지 않습니다. 즉, 작업이 순차적으로 실행됩니다.
- 블로킹(Blocking):
- 동기 방식에서는 현재 작업이 완료될 때까지 시스템 자원을 차단(블로킹)합니다. 이로 인해 다른 작업이 대기 상태에 놓입니다.
- 단순한 흐름:
- 작업이 순차적으로 이루어지기 때문에 프로그램의 흐름을 이해하고 디버깅하기 쉽습니다.
- 예시:
- 함수 호출: result = functionA(); resultB = functionB(result); 여기서 functionB는 functionA가 완료된 후에 실행됩니다.
- 파일 읽기: readFileSync (동기 방식의 파일 읽기 함수로, 파일을 다 읽을 때까지 다음 코드가 실행되지 않습니다).
1.2 비동기(Asynchronous)
- 작업의 병렬적 실행:
- 비동기 방식에서는 한 작업이 진행되는 동안 다른 작업을 동시에 실행할 수 있습니다. 작업이 병렬적으로 실행됩니다.
- 논블로킹(Non-blocking):
- 비동기 방식에서는 현재 작업이 진행되는 동안 다른 작업이 차단되지 않습니다. 시스템 자원을 효율적으로 사용하여 여러 작업을 동시에 처리할 수 있습니다.
- 복잡한 흐름 관리:
- 비동기 작업의 흐름은 동기 작업보다 복잡할 수 있습니다. 콜백(callback), 프라미스(Promise), async/await와 같은 패턴을 사용하여 작업을 관리해야 합니다.
- 예시:
- 콜백 함수: functionA(result => { functionB(resultB => { /* ... */ }) }) 여기서 functionB는 functionA의 결과가 준비되면 실행됩니다.
- 파일 읽기: readFile (비동기 방식의 파일 읽기 함수로, 파일을 읽는 동안 다음 코드가 계속 실행됩니다).
1.3 동기와 비동기의 비교
- 작업 처리 순서:
- 동기: 작업이 순차적으로 처리됨.
- 비동기: 작업이 병렬적으로 처리될 수 있음.
- 자원 차단:
- 동기: 현재 작업이 완료될 때까지 시스템 자원이 차단됨.
- 비동기: 현재 작업이 진행되는 동안 다른 작업이 차단되지 않음.
- 코드의 복잡성:
- 동기: 코드가 단순하고 이해하기 쉬움.
- 비동기: 코드가 복잡할 수 있으며, 흐름 관리를 위해 추가적인 패턴이 필요함.
- 응답 시간:
- 동기: 작업 완료까지 기다려야 하기 때문에 응답 시간이 길어질 수 있음.
- 비동기: 대기 시간이 줄어들어 응답 시간이 단축될 수 있음.
- 동기: 순차적 작업, 블로킹, 단순한 흐름.
- 비동기: 병렬적 작업, 논블로킹, 복잡한 흐름 관리.요약
2. Reply CRUD(Service)
public interface ReplyService {
Long register(ReplyDTO replyDTO);
ReplyDTO read(Long rno);
void modify(ReplyDTO replyDTO);
void remove(Long rno);
PageResponseDTO getListOfBoard(Long bno, PageRequestDTO PageRequestDTO);
}
@Service // 해당 클래스가 서비스 클래스임을 나타냅니다.
@RequiredArgsConstructor // 생성자를 자동으로 생성해주는 Lombok 어노테이션입니다.
@Log4j2 // 로그를 사용하기 위한 Log4j2 어노테이션입니다.
public class ReplyServiceImpl implements ReplyService{
private final ReplyRepository replyRepository; // 댓글 데이터를 처리하는 리포지토리입니다.
private final ModelMapper modelMapper; // DTO와 엔티티 간 매핑을 처리하는 ModelMapper입니다.
@Override
public Long register(ReplyDTO replyDTO){
// ReplyDTO를 Reply 엔티티로 변환합니다.
Reply reply = modelMapper.map(replyDTO, Reply.class);
// 엔티티를 저장하고 생성된 댓글의 번호(rno)를 반환합니다.
Long rno = replyRepository.save(reply).getRno();
return rno;
}
@Override
public ReplyDTO read(Long rno){
// 댓글 번호로 Reply 엔티티를 조회합니다.
Optional<Reply> result = replyRepository.findById(rno);
// 결과가 없으면 예외를 발생시킵니다.
Reply reply = result.orElseThrow();
// 조회된 엔티티를 ReplyDTO로 변환하여 반환합니다.
return modelMapper.map(reply, ReplyDTO.class);
}
@Override
public void modify(ReplyDTO replyDTO){
// 수정할 댓글을 댓글 번호로 조회합니다.
Optional<Reply> result = replyRepository.findById(replyDTO.getRno());
// 결과가 없으면 예외를 발생시킵니다.
Reply reply = result.orElseThrow();
// 댓글 내용을 수정합니다.
reply.changeText(replyDTO.getReplyText());
// 수정된 댓글을 저장합니다.
replyRepository.save(reply);
}
@Override
public void remove(Long rno){
// 댓글 번호로 댓글을 삭제합니다.
replyRepository.deleteById(rno);
}
// bno가 일치하는 댓글들을 페이지 요청에 맞춰서 읽어오는 메서드입니다.
@Override
public PageResponseDTO getListOfBoard(Long bno, PageRequestDTO pageRequestDTO){
// 페이지 요청을 설정합니다.
Pageable pageable = PageRequest.of(
pageRequestDTO.getPage()<=0 ? 0 : pageRequestDTO.getPage()-1, // 페이지 번호는 0부터 시작합니다.
pageRequestDTO.getSize(), // 한 페이지에 보여줄 댓글 수입니다.
Sort.by("rno").ascending()); // rno를 기준으로 오름차순 정렬합니다.
// bno가 일치하는 댓글들을 페이지 요청에 맞춰서 조회합니다.
Page<Reply> result = replyRepository.listOfBoard(bno, pageable);
// 조회된 댓글 엔티티들을 ReplyDTO 리스트로 변환합니다.
List<ReplyDTO> dtoList = result.getContent().stream()
.map(reply -> modelMapper.map(reply, ReplyDTO.class))
.collect(Collectors.toList());
// 페이지 응답 DTO를 생성하여 반환합니다.
return PageResponseDTO.<ReplyDTO>withAll()
.pageRequestDTO(pageRequestDTO) // 페이지 요청 정보를 설정합니다.
.dtoList(dtoList) // 댓글 DTO 리스트를 설정합니다.
.total((int)result.getTotalElements()) // 전체 댓글 수를 설정합니다.
.build();
}
}
- 댓글 서비스 구현 코드입니다. 댓글 등록, 조회, 수정, 삭제 기능을 제공합니다. 또한 특정 게시글에 달린 댓글 목록을 페이지 요청에 맞춰 조회할 수 있습니다.
자세한 설명:
이 클래스는 댓글 서비스 구현체로서 다음과 같은 기능을 제공합니다:
- register(ReplyDTO replyDTO): 댓글을 등록하고, 생성된 댓글 번호를 반환합니다.
- read(Long rno): 댓글 번호로 댓글을 조회하고, 댓글 정보를 DTO로 반환합니다.
- modify(ReplyDTO replyDTO): 댓글을 수정합니다. 댓글 번호로 댓글을 조회한 후 내용을 수정하여 저장합니다.
- remove(Long rno): 댓글 번호로 댓글을 삭제합니다.
- getListOfBoard(Long bno, PageRequestDTO pageRequestDTO): 특정 게시글에 달린 댓글 목록을 페이지 요청에 맞춰 조회하고, 페이지 응답 DTO를 반환합니다.
- 이 클래스는 ReplyRepository를 사용하여 데이터베이스와 상호작용하고, ModelMapper를 사용하여 DTO와 엔티티 간 매핑을 처리합니다.
3. ReplyCotroller
@RestController // 이 클래스가 RESTful 웹 서비스의 컨트롤러임을 나타냅니다.
@RequestMapping("/replies") // 이 클래스의 기본 요청 경로를 "/replies"로 설정합니다.
@Log4j2 // 로그를 사용하기 위한 Log4j2 어노테이션입니다.
@RequiredArgsConstructor // 생성자를 자동으로 생성해주는 Lombok 어노테이션입니다.
public class ReplyController {
private final ReplyService replyService; // ReplyService 객체를 주입받습니다.
@PostMapping(value = "/", consumes = MediaType.APPLICATION_JSON_VALUE)
// 댓글 등록 요청을 처리하는 메서드입니다. JSON 형식의 데이터를 소비합니다.
public Map<String, Long> register(@Valid @RequestBody ReplyDTO replyDTO,
BindingResult bindingResult) throws BindException {
log.info(replyDTO); // replyDTO 객체의 내용을 로그에 출력합니다.
if (bindingResult.hasErrors()) { // 유효성 검사에서 오류가 발생하면
throw new BindException(bindingResult); // BindException을 발생시킵니다.
}
Map<String, Long> resultMap = new HashMap<>();
Long rno = replyService.register(replyDTO); // 댓글을 등록하고 댓글 번호를 반환받습니다.
resultMap.put("rno", rno); // 결과 맵에 댓글 번호를 저장합니다.
return resultMap; // 결과 맵을 반환합니다.
}
@GetMapping(value = "/list/{bno}")
// 특정 게시글에 달린 댓글 목록을 조회하는 메서드입니다.
public PageResponseDTO<ReplyDTO> getList(@PathVariable("bno") Long bno, PageRequestDTO pageRequestDTO) {
PageResponseDTO<ReplyDTO> responseDTO = replyService.getListOfBoard(bno, pageRequestDTO);
// replyService를 통해 댓글 목록을 조회하고, PageResponseDTO 객체를 반환받습니다.
return responseDTO; // 조회 결과를 반환합니다.
}
@GetMapping(value = "/{rno}")
// 특정 댓글을 조회하는 메서드입니다.
public ReplyDTO getReplyDTO(@PathVariable("rno") Long rno) {
ReplyDTO replyDTO = replyService.read(rno); // 댓글 번호로 댓글을 조회하고 ReplyDTO 객체를 반환받습니다.
return replyDTO; // 조회된 댓글 정보를 반환합니다.
}
@PutMapping(value = "/{rno}", consumes = MediaType.APPLICATION_JSON_VALUE)
// 특정 댓글을 수정하는 메서드입니다. JSON 형식의 데이터를 소비합니다.
public Map<String, Long> modify(@Valid @RequestBody ReplyDTO replyDTO,
@PathVariable("rno") Long rno,
BindingResult bindingResult) throws BindException {
if (bindingResult.hasErrors()) { // 유효성 검사에서 오류가 발생하면
throw new BindException(bindingResult); // BindException을 발생시킵니다.
}
// replyDTO.setRno(rno); // 주석 처리된 부분입니다. 필요시 사용할 수 있습니다.
replyService.modify(replyDTO); // 댓글을 수정합니다.
Map<String, Long> resultMap = new HashMap<>();
resultMap.put("rno", rno); // 결과 맵에 댓글 번호를 저장합니다.
return resultMap; // 결과 맵을 반환합니다.
}
@DeleteMapping("/{rno}")
// 특정 댓글을 삭제하는 메서드입니다.
public Map<String, Long> remove(@PathVariable("rno") Long rno) {
replyService.remove(rno); // 댓글을 삭제합니다.
Map<String, Long> resultMap = new HashMap<>();
resultMap.put("rno", rno); // 결과 맵에 댓글 번호를 저장합니다.
return resultMap; // 결과 맵을 반환합니다.
}
}
- 댓글 컨트롤러입니다. 댓글 등록, 조회, 수정, 삭제 기능을 제공하며, 특정 게시글에 달린 댓글 목록을 조회할 수 있습니다.
자세한 설명:
이 클래스는 댓글 관리를 위한 RESTful 컨트롤러로서 다음과 같은 기능을 제공합니다:
- register(ReplyDTO replyDTO, BindingResult bindingResult): 댓글을 등록하고, 댓글 번호를 반환합니다. 유효성 검사에서 오류가 발생하면 BindException을 발생시킵니다.
- getList(Long bno, PageRequestDTO pageRequestDTO): 특정 게시글에 달린 댓글 목록을 페이지 요청에 맞춰 조회하고, PageResponseDTO 객체를 반환합니다.
- getReplyDTO(Long rno): 댓글 번호로 댓글을 조회하고, 댓글 정보를 ReplyDTO 객체로 반환합니다.
- modify(ReplyDTO replyDTO, Long rno, BindingResult bindingResult): 댓글을 수정하고, 수정된 댓글 번호를 반환합니다. 유효성 검사에서 오류가 발생하면 BindException을 발생시킵니다.
- remove(Long rno): 댓글 번호로 댓글을 삭제하고, 삭제된 댓글 번호를 반환합니다.
이 컨트롤러는 ReplyService를 통해 비즈니스 로직을 처리하며, @Valid 어노테이션을 사용하여 입력 데이터를 검증합니다.
4. 부트스트랩 예제 코드(버튼 추가)
<div class="d-flex justify-content-end align-items-center">
<a href="/board/register" class="btn btn-outline-primary me-4">Register</a>
<ul class="pagination flex-wrap mb-0">
<li class="page-item" th:if="${responseDTO.prev}">
<a class="page-link" th:data-num="${responseDTO.start -1}">Previous</a>
</li>
<th:block th:each="i: ${#numbers.sequence(responseDTO.start, responseDTO.end)}">
<li th:class="${responseDTO.page == i}?'page-item active':'page-item'">
<a class="page-link" th:data-num="${i}">[[${i}]]</a>
</li>
</th:block>
<li class="page-item" th:if="${responseDTO.next}">
<a class="page-link" th:data-num="${responseDTO.end +1}">Next</a>
</li>
</ul>
</div>
- 페이지네이션(글 목록 페이지 보이는 곳) 왼쪽에 Register 버튼을 추가한다.
- d-flex: 요소를 플렉스 컨테이너로 만듭니다.
- justify-content-between: 플렉스 항목을 컨테이너의 양 끝에 정렬합니다.
- align-items-center: 플렉스 항목을 세로축(중앙)에 정렬합니다.
- mb-0: 하단 여백을 제거합니다. 페이지네이션이 다른 요소와 겹치지 않도록 합니다.
- me-4 : 오른쪽 여백을 추가합니다. 인텔리제이에 me-를 입력하면 여러가지 옵션이 있어 여백의 크기를 조절할 수 있습니다.
댓글