728x90
반응형
1. list로 돌아가는 버튼 스크립트 예제 코드
const link = [[${pageRequestDTO.getLink()}]]; // 페이지 요청에 대한 링크 정보를 가져와 link 변수에 할당합니다.
const formObj = document.querySelector("#f1"); // id가 'f1'인 폼 요소를 찾아 formObj 변수에 할당합니다.
document.querySelector(".listBtn").addEventListener("click", function (e) { // .listBtn 클래스를 가진 요소에 클릭 이벤트 리스너를 추가합니다.
e.preventDefault(); // 기본 동작을 방지합니다. (여기서는 a 태그의 클릭 이벤트를 막습니다.)
e.stopPropagation(); // 이벤트의 전파를 중단합니다. (부모 요소로의 이벤트 전파를 막습니다.)
formObj.reset(); // formObj의 내용을 초기화합니다. (폼 요소 내의 입력값들을 초기화합니다.)
self.location = `/board/list?${link}`; // 현재 페이지를 새로운 URL로 이동합니다. (페이지 요청에 대한 링크를 포함한 새 URL로 이동합니다.)
}, false);
- 이 부분은 .listBtn 클래스를 가진 요소를 클릭할 때 실행되는 이벤트 핸들러입니다. 여기서 e.preventDefault()와 e.stopPropagation()를 호출하여 클릭 이벤트의 기본 동작과 이벤트의 전파를 막습니다. 그 후, formObj.reset()을 호출하여 폼 요소 내의 입력값을 초기화합니다. 마지막으로, self.location을 이용하여 현재 페이지를 새로운 URL로 이동시킵니다. 새 URL은 /board/list로 시작하며, 해당 페이지로 이동할 때 link 변수에 저장된 페이지 요청에 대한 링크 정보가 쿼리 문자열로 전달됩니다.
2. Controller method 방식(Http 메소드)
- 조회: GET
- 등록: POST
- 수정: PUT
- 삭제: DELETE
3. Board, Member, Reply 테이블 관계도
- Member
- member_id (PK)
- name
- Board
- board_id (PK)
- title
- content
- member_id (FK) -> Member(member_id)
- Reply
- reply_id (PK)
- content
- member_id (FK) -> Member(member_id)
- board_id (FK) -> Board(board_id)
관계
- Member와 Board: 일대다 관계 (한 명의 멤버가 여러 개의 게시글을 작성할 수 있음)
- Member와 Reply: 일대다 관계 (한 명의 멤버가 여러 개의 댓글을 작성할 수 있음)
- Board와 Reply: 일대다 관계 (한 개의 게시글에 여러 개의 댓글이 달릴 수 있음)
4. 추가된 코드1(삭제, 리스트로 돌아가기)
//Delete 버튼을 눌렀을 때, 이벤트 처리
document.querySelector(".removeBtn").addEventListener("click", function (e){
e.preventDefault()
e.stopPropagation()
formObj.action = `/board/remove`
formObj.method = 'post'
formObj.submit()
}, false)
- 삭제버튼에 대한 스크립트 코드
@PostMapping("/remove")
public String remove(Long bno, RedirectAttributes redirectAttributes){
boardService.remove(bno);
redirectAttributes.addFlashAttribute("result", "removed success!");
return "redirect:/board/list";
}
- 삭제 boardController 코드
@Override
public void remove(Long bno){
boardRepository.deleteById(bno);
}
- 삭제 BoardServiceImpl 코드
5. 추가된 코드2(댓글)
@RestControllerAdvice // @RestControllerAdvice 어노테이션은 전역적으로 컨트롤러에 적용되는 예외 처리기를 정의합니다.
@Log4j2 // @Log4j2 어노테이션은 로그 처리를 위해 Log4j2 라이브러리를 사용합니다.
public class CustomRestAdvice {
@ExceptionHandler(BindException.class) // @ExceptionHandler 어노테이션은 특정 예외 타입을 처리하는 메서드를 지정합니다. 여기서는 BindException을 처리합니다.
public ResponseEntity<Map<String, String>> handleBindException(BindException e) {
log.error(e); // 예외가 발생했을 때 예외 정보를 로그에 기록합니다.
Map<String, String> errorMap = new HashMap<>(); // 에러 메시지를 담을 Map 객체를 생성합니다.
if(e.hasErrors()){ // BindException 객체에 에러가 있는지 확인합니다.
BindingResult bindingResult = e.getBindingResult(); // 에러 정보를 가져옵니다.
bindingResult.getFieldErrors().forEach(fieldError -> { // 각 필드 에러에 대해 반복합니다.
errorMap.put(fieldError.getField(), fieldError.getCode()); // 필드 이름과 에러 코드를 Map에 추가합니다.
});
}
// 에러가 있을 때 CustomRestAdvice가 호출되므로 예외가 있는지 체크할 필요가 없다.
return ResponseEntity.badRequest().body(errorMap); // HTTP 상태 코드 400 (Bad Request)와 에러 메시지를 담은 Map 객체를 응답 본문에 포함하여 반환합니다.
}
}
요약 설명
- @RestControllerAdvice와 @Log4j2 어노테이션을 사용하여, 이 클래스가 전역 예외 처리와 로그 기록을 담당하도록 합니다.
- handleBindException 메서드는 BindException이 발생할 때 호출됩니다.
- 발생한 예외를 로그에 기록한 후, 에러 메시지를 담은 Map 객체를 생성합니다.
- BindException에 포함된 모든 필드 에러를 Map 객체에 추가합니다.
- 최종적으로, HTTP 400 상태 코드와 에러 메시지를 클라이언트에게 반환합니다.
@RestController // @RestController 어노테이션은 이 클래스가 RESTful 웹 서비스의 컨트롤러임을 나타냅니다.
@RequestMapping("/replies") // @RequestMapping 어노테이션은 이 컨트롤러의 기본 URL 경로를 "/replies"로 설정합니다.
@Log4j2 // @Log4j2 어노테이션은 로그 처리를 위해 Log4j2 라이브러리를 사용합니다.
public class ReplyController {
@PostMapping(value = "/", consumes = MediaType.APPLICATION_JSON_VALUE) // @PostMapping 어노테이션은 HTTP POST 요청을 처리합니다. 요청 경로는 기본 경로 "/replies"에 "/"를 더한 "/replies/"이며, 요청 본문은 JSON 형식이어야 합니다.
public Map<String, Long> register(@Valid @RequestBody ReplyDTO replyDTO, // @Valid 어노테이션은 ReplyDTO 객체를 유효성 검사합니다. @RequestBody 어노테이션은 요청 본문을 ReplyDTO 객체로 변환합니다.
BindingResult bindingResult) throws BindException { // BindingResult 객체는 유효성 검사 결과를 저장합니다. BindException을 던질 수 있습니다.
log.info(replyDTO); // replyDTO 객체의 정보를 로그에 기록합니다.
if (bindingResult.hasErrors()) { // 유효성 검사에서 에러가 발생했는지 확인합니다.
throw new BindException(bindingResult); // 에러가 발생한 경우 BindException을 던집니다.
}
Map<String, Long> resultMap = new HashMap<>(); // 결과를 담을 Map 객체를 생성합니다.
resultMap.put("rno", 10L); // "rno"라는 키로 10L 값을 Map에 추가합니다. (실제 구현에서는 등록된 댓글의 ID 값을 반환하도록 해야 합니다)
return resultMap; // 결과 Map을 반환합니다.
}
}
요약 설명
- @RestController, @RequestMapping, @Log4j2 어노테이션을 사용하여, 이 클래스가 RESTful 웹 서비스의 컨트롤러임을 나타내고, 기본 경로를 /replies로 설정하며, 로그 기록을 위해 Log4j2를 사용합니다.
- register 메서드는 HTTP POST 요청을 처리합니다.
- 요청 경로는 /replies/이고, 요청 본문은 JSON 형식이어야 합니다.
- @Valid 어노테이션으로 ReplyDTO 객체를 유효성 검사합니다.
- 유효성 검사 결과는 BindingResult 객체에 저장됩니다.
- 유효성 검사에서 에러가 발생하면 BindException을 던집니다.
- 유효성 검사를 통과하면, 결과를 담은 Map 객체를 생성하여 반환합니다. 여기서는 임시로 "rno" 키에 10L 값을 반환합니다.
@Entity // @Entity 어노테이션은 이 클래스가 JPA 엔티티임을 나타냅니다.
@Getter // @Getter 어노테이션은 Lombok 라이브러리를 사용하여 모든 필드에 대한 getter 메서드를 자동으로 생성합니다.
@Builder // @Builder 어노테이션은 Lombok 라이브러리를 사용하여 빌더 패턴을 적용합니다.
@AllArgsConstructor // @AllArgsConstructor 어노테이션은 Lombok 라이브러리를 사용하여 모든 필드를 인자로 받는 생성자를 자동으로 생성합니다.
@NoArgsConstructor // @NoArgsConstructor 어노테이션은 Lombok 라이브러리를 사용하여 인자가 없는 기본 생성자를 자동으로 생성합니다.
@ToString(exclude = "board") // @ToString 어노테이션은 Lombok 라이브러리를 사용하여 toString 메서드를 자동으로 생성합니다. "board" 필드는 toString 출력에서 제외됩니다.
public class Reply extends BaseEntity { // Reply 클래스는 BaseEntity를 상속받아 공통 엔티티 속성을 가집니다.
@Id // @Id 어노테이션은 이 필드가 엔티티의 기본 키임을 나타냅니다.
@GeneratedValue(strategy = GenerationType.IDENTITY) // @GeneratedValue 어노테이션은 기본 키 생성을 데이터베이스에 위임합니다. (자동 증가)
private Long rno; // rno 필드는 댓글의 고유 식별자입니다.
@ManyToOne(fetch = FetchType.LAZY) // @ManyToOne 어노테이션은 이 필드가 Board 엔티티와 다대일 관계임을 나타냅니다. fetch 속성은 지연 로딩을 사용합니다.
private Board board; // board 필드는 이 댓글이 속한 게시글을 나타냅니다.
private String replyText; // replyText 필드는 댓글의 내용을 나타냅니다.
private String replyer; // replyer 필드는 댓글 작성자를 나타냅니다.
}
요약 설명
- @Entity, @Getter, @Builder, @AllArgsConstructor, @NoArgsConstructor, @ToString 어노테이션을 사용하여 댓글(Reply) 엔티티를 정의합니다.
- @Entity: 이 클래스가 JPA 엔티티임을 나타냅니다.
- @Getter: 모든 필드에 대한 getter 메서드를 생성합니다.
- @Builder: 빌더 패턴을 적용합니다.
- @AllArgsConstructor: 모든 필드를 인자로 받는 생성자를 생성합니다.
- @NoArgsConstructor: 기본 생성자를 생성합니다.
- @ToString(exclude = "board"): toString 메서드를 생성하지만, board 필드는 제외합니다.
- Reply 클래스는 BaseEntity를 상속받아 공통 엔티티 속성을 가집니다.
- rno 필드는 댓글의 고유 식별자로, 기본 키로 설정되며 자동 증가합니다.
- board 필드는 이 댓글이 속한 게시글과의 다대일 관계를 나타내며, 지연 로딩을 사용합니다.
- replyText 필드는 댓글의 내용입니다.
- replyer 필드는 댓글 작성자입니다.
@Data // @Data 어노테이션은 Lombok 라이브러리를 사용하여 getter, setter, toString, equals, hashCode 메서드를 자동으로 생성합니다.
@Builder // @Builder 어노테이션은 Lombok 라이브러리를 사용하여 빌더 패턴을 적용합니다.
@AllArgsConstructor // @AllArgsConstructor 어노테이션은 Lombok 라이브러리를 사용하여 모든 필드를 인자로 받는 생성자를 자동으로 생성합니다.
@NoArgsConstructor // @NoArgsConstructor 어노테이션은 Lombok 라이브러리를 사용하여 인자가 없는 기본 생성자를 자동으로 생성합니다.
public class ReplyDTO {
private Long rno; // 댓글의 고유 식별자
@NotNull // @NotNull 어노테이션은 이 필드가 null이 아니어야 함을 나타냅니다.
private Long bno; // 댓글이 속한 게시글의 고유 식별자
@NotEmpty // @NotEmpty 어노테이션은 이 필드가 비어 있지 않아야 함을 나타냅니다.
private String replyText; // 댓글의 내용
@NotEmpty // @NotEmpty 어노테이션은 이 필드가 비어 있지 않아야 함을 나타냅니다.
private String replyer; // 댓글 작성자
private LocalDateTime regDate, modDate; // 댓글의 생성 시간과 수정 시간
}
요약 설명
- @Data, @Builder, @AllArgsConstructor, @NoArgsConstructor 어노테이션을 사용하여 댓글(Reply)의 데이터 전송 객체를 정의합니다.
- @Data: Lombok 라이브러리를 사용하여 getter, setter, toString, equals, hashCode 메서드를 자동으로 생성합니다.
- @Builder: 빌더 패턴을 적용합니다.
- @AllArgsConstructor: 모든 필드를 인자로 받는 생성자를 생성합니다.
- @NoArgsConstructor: 기본 생성자를 생성합니다.
- rno 필드는 댓글의 고유 식별자입니다.
- bno 필드는 댓글이 속한 게시글의 고유 식별자입니다. @NotNull 어노테이션으로 null이 아닌 값만 허용합니다.
- replyText 필드는 댓글의 내용입니다. @NotEmpty 어노테이션으로 빈 값이 허용되지 않습니다.
- replyer 필드는 댓글 작성자입니다. @NotEmpty 어노테이션으로 빈 값이 허용되지 않습니다.
- regDate와 modDate 필드는 댓글의 생성 시간과 수정 시간을 나타냅니다.
댓글