반응형

https://devjunyeok.tistory.com/193

 

답변형 게시판 구현 (2)

https://devjunyeok.tistory.com/192 답변형 게시판 만들기 (1) 네이버 카페 등의 게시판을 주로 보면 질문에 대한 답글이 게시되어 있는 기능을 종종 볼 수 있습니다. 이번에는 답글을 달 수 있는 게시판을

devjunyeok.tistory.com

📝 실행결과

지난 글에 이어 이번에는 게시글 생성 기능구현을 해보겠습니다.

 

💻 프론트 작업

게시글 추가 페이지를 만들기 위해 AddReplyBoard.tsx 페이지를 생성합니다.

rfce 단축키를 이용해 함수를 생성하고, return 문 아래에 html 코드를 작성합니다.

// return문 아래에 작성
    <div className="row">
      {submitted ? (
        <div className="col-6 mx-auto">
          <h4>You submitted successfully!</h4>
          <button className="btn btn-success" onClick={newReplyBoard}>
            Add
          </button>
        </div>
      ) : (
        <>
          {/* 제목 start */}
          <TitleCom title="Add Reply Board" />
          {/* 제목 end */}

          <div className="col-6 mx-auto">
            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="boardTitle" className="col-form-label">
                  boardTitle
                </label>
              </div>

              <div className="col-9">
                <input
                  type="text"
                  id="boardTitle"
                  required
                  className="form-control"
                  value={replyBoard.boardTitle}
                  onChange={handleInputChange}
                  placeholder="boardTitle"
                  name="boardTitle"
                />
              </div>
            </div>

            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="boardContent" className="col-form-label">
                  boardContent
                </label>
              </div>

              <div className="col-9">
                <input
                  type="text"
                  id="boardContent"
                  required
                  className="form-control"
                  value={replyBoard.boardContent}
                  onChange={handleInputChange}
                  placeholder="boardContent"
                  name="boardContent"
                />
              </div>
            </div>

            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="boardWriter" className="col-form-label">
                  boardWriter
                </label>
              </div>

              <div className="col-9">
                <input
                  type="text"
                  id="boardWriter"
                  required
                  className="form-control"
                  value={replyBoard.boardWriter}
                  onChange={handleInputChange}
                  placeholder="boardWriter"
                  name="boardWriter"
                />
              </div>
            </div>

            <div className="row g-3 mt-3 mb-3">
              <button
                onClick={saveReplyBoard}
                className="btn btn-outline-primary ms-2 col"
              >
                Submit
              </button>
            </div>
          </div>
        </>
      )}
    </div>

변수 및 함수 정의

return 문 위쪽에 html에 사용된 변수와 함수들을 정의합니다.

// return 문 위에 작성

// todo: 변수 정의
  // todo: 객체 초기화
  const initialReplyBoard = {
    bid: null,
    boardTitle: "",
    boardContent: "",
    boardWriter: "",
    viewCnt: 0,
    boardGroup: null,
    boardParent: 0,
  };

  // replyBoard 객체
  const [replyBoard, setReplyBoard] = useState<IReplyBoard>(initialReplyBoard);
  // 저장버튼 클릭후 submitted = true 변경됨
  const [submitted, setSubmitted] = useState<boolean>(false);

  // todo: 함수 정의
  // input 태그에 수동 바인딩
  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target; // 화면값
    setReplyBoard({ ...replyBoard, [name]: value }); // 변수저장
  };

  // 저장 함수
  const saveReplyBoard = () => {
    // 임시 객체
    var data = {
      boardTitle: replyBoard.boardTitle,
      boardContent: replyBoard.boardContent,
      boardWriter: replyBoard.boardWriter,
      viewCnt: replyBoard.viewCnt,
      boardGroup: null,             // 입력시 제외
      boardParent: 0,               // 입력시 제외
    };

    ReplyBoardService.createBoard(data) // 게시물 저장 요청
      .then((response: any) => {
        setSubmitted(true);
        console.log(response.data);
      })
      .catch((e: Error) => {
        console.log(e);
      });
  };

  // 새폼 보여주기 함수 : 변수값 변경 -> 화면 자동 갱신(리액트 특징)
  const newReplyBoard = () => {
    setReplyBoard(initialReplyBoard); // replyBoard 초기화
    setSubmitted(false); // submitted 변수 초기화
  };

프론트 서버를 재시작 후 화면을 테스트합니다.

 

 

💻 백엔드 작업

ReplyBoardRepository.java 파일에 게시물 생성(수정) 함수 작성

// 게시물 저장함수 : 최초 생성(board_group(그룹번호)), board_parent(부모번호))
//  => board_group(부모번호 == 자식번호(bid)), board_parent(최초생성시 0, 댓글이 달리면 부모 번호가 들어감)
// todo : JPA insert문 직접 작성(DML : 테이블 데이터 변경, 트랜잭션을 동반)
//  =>  @Transactional, @Modifying
//  => 예 ) 변수 전달  : :#{#replyBoard.boardTitle}
@Transactional
@Modifying
@Query(value = "INSERT INTO TB_REPLY_BOARD " +
        "VALUES(sq_reply_board.nextval, :#{#replyBoard.boardTitle}, " +
        ":#{#replyBoard.boardContent}, " +
        ":#{#replyBoard.boardWriter}, " +
        "0, sq_reply_board.CURRVAL, 0, 'N', " +
        "        TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL, NULL)", nativeQuery = true)
int insertByBoard(@Param("replyBoard") ReplyBoard replyBoard);

JPA insert 문을 직접 작성하기 위해서는 @Transactional, @Modifying 어노테이션을 함수위에 붙여줍니다.

그리고 쿼리문을 작성해야 하는데 먼저 SQL Developer에서 테스트 후 정상적으로 데이터가 나오는 것을 확인하여 쿼리문을 복사하여 붙여넣기 합니다.

 

INSERT INTO TB_REPLY_BOARD
VALUES(sq_reply_board.nextval, '제목', '내용', '홍길동', 0, sq_reply_board.CURRVAL, 0, 'N',
        TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL, NULL);

 

정상적으로 쿼리문을 작성하였다면 위 처럼 메세지가 나옵니다. 테스트용으로 데이터를 insert 하였으므로 ROLLBACK을 시켜줍니다.

        ROLLBACK;

SQL Developer의 쿼리문을 ;을 제외한 모든 문장을 복사하여 @Query(value = " ")의 " " 사이에 붙혀넣기합니다.

// 게시물 저장함수 : 최초 생성(board_group(그룹번호)), board_parent(부모번호))
//  => board_group(부모번호 == 자식번호(bid)), board_parent(최초생성시 0, 댓글이 달리면 부모 번호가 들어감)
// todo : JPA insert문 직접 작성(DML : 테이블 데이터 변경, 트랜잭션을 동반)
//  =>  @Transactional, @Modifying
//  => 예 ) 변수 전달  : :#{#replyBoard.boardTitle}
@Transactional
@Modifying
@Query(value = "INSERT INTO TB_REPLY_BOARD " +
        "VALUES(sq_reply_board.nextval, :#{#replyBoard.boardTitle}, " +
        ":#{#replyBoard.boardContent}, " +
        ":#{#replyBoard.boardWriter}, " +
        "0, sq_reply_board.CURRVAL, 0, 'N', " +
        "        TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL, NULL)", nativeQuery = true)
int insertByBoard(@Param("replyBoard") ReplyBoard replyBoard);

 

변수를 전달하기 위해 '제목', '내용', '홍길동' 부분을 아래와 같이 수정합니다.

 

ReplyBoardService에 함수 추가

// 게시물 저장
public int saveBoard(ReplyBoard replyBoard) {
    int insertCount = replyBoardRepository.insertByBoard(replyBoard);

    return insertCount;
}

 

ReplyBoardController에 함수추가

// 게시글 저장
    @PostMapping("/reply-board")
    public ResponseEntity<Object> createBoard(@RequestBody ReplyBoard replyBoard) {

        try {
            int insertCount = replyBoardService.saveBoard(replyBoard);  // db 저장

            return new ResponseEntity<>(insertCount, HttpStatus.OK);
        } catch (Exception e) {
//            DB 에러가 났을경우 : INTERNAL_SERVER_ERROR 프론트엔드로 전송
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

 

💻 프론트 + 백엔드 테스트

 

 

반응형

+ Recent posts