Spring Boot/STUDY

[Spring Boot] React연동 프로젝트(4) - 상세 화면

코맹 2024. 7. 4. 16:29

 

🔽 이전 글

 

[Spring Boot] React연동 프로젝트(2) - 페이징 기능 구현

🔽이전 글 [Spring Boot] React연동 프로젝트프로젝트 실행하기 위해 Spring Boot 웹서버, React 프론트 웹 서버도 함께 실행시킨다.  1. 리액트 프로젝트 생성- /spring03/frontboard 폴더 생성cd spring03npx cre

iieunji023.tistory.com

 

 

(Backend) RestBoardController.java detail() 메서드 생성
  • /controller/BoardController.java에서 detail() GET 메서드 복사한 후 수정
@GetMapping("/detail/{bno}")
  public BoardDto detail(@PathVariable("bno") Long bno, HttpServletRequest request) {
    
    String prevUrl = request.getHeader("referer");//이전 페이지 변수 담기
    log.info(String.format("현재 이전 페이지: %s", prevUrl));
    Board _board = this.boardService.hitBoard(bno);    // 조회수 증가하고 리턴
    BoardDto board = BoardDto.builder()
                             .bno(_board.getBno())
                             .title(_board.getTitle())
                             .content(_board.getContent()).createDate(_board.getCreateDate())
                             .modifyDate(_board.getModifyDate())
                             .writer(_board.getWriter() != null ? _board.getWriter().getUsername() : "")
                             .build();

    List<ReplyDto> replyList = new ArrayList<>();
    if(_board.getReplyList().size() > 0) {
      _board.getReplyList().forEach(rpy -> replyList.add(ReplyDto.builder().content(rpy.getContent())
                                                                          .createDate(rpy.getCreateDate()).modifyDate(rpy.getModifyDate())
                                                                          .rno(rpy.getRno())
                                                                          .writer(rpy.getWriter() != null ? rpy.getWriter().getUsername() : "" )
                                                                          .build()));

    }
    

    board.setReplyList(replyList);

    return board;

  }

 

(Frontend) /BoardList.js 제목 수정
<Link to={`/boardDetail/${board.bno}`}>{board.title}</Link>

 

 

/routes/BoardDetail.js 생성
import { useState } from 'react';
import { useParams } from 'react-router-dom';

function BoardDetail() {
  // const [bid, setBid] = useState(0);

  const params = useParams();
  console.log(params.bno);
  // setBid(params.bno);
  
  return (
    <div className='container main'>
      <h1>boardDetail {params.bid} </h1>
    </div>
  );
}

export default BoardDetail;

 

App.js에서 링크 연결
  • App.js
import BoardDetail from './routes/BoardDetail';

<Route path='/boardDetail/:bno' element={<BoardDetail />} />

 

(Back) RestBoardController.java detail() 리턴값 변경
@GetMapping("/detail/{bno}")
  public Header<BoardDto> detail(@PathVariable("bno") Long bno, HttpServletRequest request) {
    try{
      String prevUrl = request.getHeader("referer");//이전 페이지 변수 담기
      log.info(String.format("현재 이전 페이지: %s", prevUrl));
      Board _board = this.boardService.hitBoard(bno);    // 조회수 증가하고 리턴
      BoardDto board = BoardDto.builder()
                               .bno(_board.getBno())
                               .title(_board.getTitle())
                               .content(_board.getContent()).createDate(_board.getCreateDate())
                               .modifyDate(_board.getModifyDate())
                               .writer(_board.getWriter() != null ? _board.getWriter().getUsername() : "")
                               .build();
  
      List<ReplyDto> replyList = new ArrayList<>();
      if(_board.getReplyList().size() > 0) {
        _board.getReplyList().forEach(rpy -> replyList.add(ReplyDto.builder().content(rpy.getContent())
                                                                            .createDate(rpy.getCreateDate()).modifyDate(rpy.getModifyDate())
                                                                            .rno(rpy.getRno())
                                                                            .writer(rpy.getWriter() != null ? rpy.getWriter().getUsername() : "" )
                                                                            .build()));
  
      }
      
  
      board.setReplyList(replyList);
      return Header.OK(board);

    } catch (Exception e) {
      return Header.OK(e.getMessage());

    }

  }
  • 404 error가 뜨지 않도록, Header를 리턴으로 넘김

 

(Front) BoardDetail.js에서 axios로 가져오기
// URL에 넘어온 매개변수
import React, { useState, useEffect, useInsertionEffect } from 'react';
import { Link, useParams } from "react-router-dom";
//RestAPI
import axios from 'axios';
// 공통함수 추가
import * as common from '../common/CommonFunc'; 

function BoardDetail() {
  const [board, setBoard] = useState({});   // 딕셔너리 한번에!
  const [replyList, setReplyList] = useState([]);
  const params = useParams(null);
  console.log(params.bno);

  const getBoardDetail = async (bno) => {
    const resp = (await axios.get("http://localhost:8080/api/board/detail/" + bno));

    const resultCode = resp.data.resultCode;
    // console.log(resultCode);
    console.log(resp.data.data);
    if(resultCode == 'OK') {
      setBoard(resp.data.data);   // data 내용 한번에
    }

    if(resp.data.data.replyList.length > 0) {
      setReplyList(resp.data.data.replyList);
    }
  }

  // 상세 RestAPI 요청
  useEffect(() => {
    getBoardDetail(params.bno);
 
  }, []);   // useEffect를 사용하지 않으면 무한로딩 발생!!
  
  return (
    <div className="container main">
            <h4 className="border-bottom py-2">{board.title}</h4>
            <div className="card my-3">
                <div className="card-body">
                    <div className="card-text">{board.content}</div>
                    <div className="d-flex justify-content-end">
                        {/* <div className="badge bg-light text-dark p-2 text-start mx-3">
                            <div className="mb-2">modified at</div>
                            <div></div>
                        </div> */}
                        <div className="badge bg-light text-dark p-2 text-start">
                            <div className="mb-2">
                                <span>{board.writer}</span>
                            </div>
                            <div>{common.formatDate(board.createDate)}</div>
                        </div>
                    </div>
                    <div className="my-3">
                    </div>
                </div>
            </div>
            <h5 className="border-bottom my-3 py-2">{`${replyList.length}개의 댓글이 있습니다.`}</h5>
            {replyList && replyList.map((reply) => (
                <div className="card my-3" key={reply.rno}>                    
                    <div className="card-body">
                        <div className="card-text">{reply.content}</div>
                        <div className="d-flex justify-content-end">                            
                            <div className="badge bg-light text-dark p-2 text-start">
                                <div className="mb-2">
                                    <span>{reply.writer}</span>
                                </div>
                                <div>{common.formatDate(reply.createDate)}</div>
                            </div>
                        </div>
                    </div>
                </div>
            ))}
        </div>
  );
}

export default BoardDetail;