현재

[PP1] jpa + springboot + mysql + react (5)(댓글 입력, 댓글 출력) 본문

Java/여러가지프로그램구현연습

[PP1] jpa + springboot + mysql + react (5)(댓글 입력, 댓글 출력)

AAAge 2024. 4. 12. 15:08

[Board.jsx]

    import axios from "axios";
    import { useEffect, useState } from "react";
    import { useParams } from "react-router-dom";

    const Board = () =>{

        const [writer, setWriter] = useState('');
        const [content, setContent] = useState('');
        const [commentData , setCommentData] = useState([]);

        const a = (e)=>{
            console.log(e.target.value);
            setWriter(e.target.value);
        }
        const b = (e)=>{
            console.log(e.target.value);
            setContent(e.target.value);
        }

        const sendComment =()=>{
            const data = {
                boardId : `${id}`,
                commentWriter : writer,
                commentContents : content
            }
            const url = "/comment/save"
            axios.post(url,data)
            .then(res => {
                console.log(res.data);
                setCommentData(res.data);
            }).catch(err=>console.log(err)).then()
        }

        const [e , setArticle] = useState({});
        const { id } = useParams();

       

        const update = () => {
            window.location.href=`/board/update/${id}`
        }
        const deleteBtn = () => {
            axios.delete(`/board/delete/${id}`)
            .then(window.location.href="/").catch(err => console.log(err))
        }

        useEffect(() => {
            const url = `/board/${id}`
            axios.get(url)
            .then(res => {
                setArticle(res.data)
                console.log(res.data)
            })
            .catch(err => console.log(err))
        },[id]);

        useEffect(() => {
            const url =`/comment/${id}`
            axios.get(url)
            .then(res => {
                console.log(res.data);
                setCommentData(res.data);
            }).catch(err => console.log(err))
        },[id])

        return(
            <div className="Board">
               

                글번호 : {e.id} <br/>
                글제목 : {e.boardTitle} <br/>
                글내용 : {e.boardContent} <br/>
                조회수 : {e.boardHits} <br/>
                저장경로 : {e.storedFileName}
                {
                    e.storedFileName?.map((fileName,index) => (
                        <img key={index} src={`/uploadImages/${fileName}`} />
                    ))
                }
                <br/><br/>
                    <div>
                        -------------댓글-------------
                    </div>
                    <div>
                        댓글 출력
                    </div>
                    {
                        commentData.map((e,index) => (
                            <div key={index}>
                                댓글 번호 : {e.id} /
                                작성자 : {e.commentWriter} /
                                내용 : {e.commentContents} /
                                시간 : {new Date(e.commentCreatedTime).toLocaleDateString()}
                            </div>
                        ))
                    }
                   
                    작성자 : <input type="text" onChange={a}></input><br/>
                    내용 : <textarea cols={30} rows={2} onChange={b}></textarea><br/>
                    <button onClick={sendComment}>댓글 작성</button>
                <br/>
                <button onClick={update} >수정</button>&nbsp;
                <button onClick={deleteBtn}>삭제</button>&nbsp;
            </div>
           
        );
    }
    export default Board;

 

- 댓글을 작성할때 보내줘야 하는 부분은 작성자, 내용, 게시글 번호로 한정하였다.

sendComment함수를 통해서 데이터를 보내주었다. axios.post는 헤더를 따로 설정하지 않을시 json타입으로 데이터를 전송한다.

- 댓글을 작성하고 새로고침하는 형식과, 상세조회를 했을때 보는 댓글의 형식을 같이하여서 댓글 데이터를 commentData

로 설정하고 데이터가 변경될때마다 재랜더링 하는 방식으로 표기하였다.

 

[CommentController.jsx]

package com.board.practice.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.board.practice.DTO.CommentDTO;
import com.board.practice.service.CommentService;
import java.util.*;

import lombok.RequiredArgsConstructor;

@Controller
@RequestMapping("/comment")
@RequiredArgsConstructor
public class CommentController {

    private final CommentService commentService;

    @GetMapping("/{id}")
    public ResponseEntity comments(@PathVariable Long id){
        List<CommentDTO> commentDTOList = commentService.findAll(id);
        return new ResponseEntity<>(commentDTOList,HttpStatus.OK);
    }

    @PostMapping("/save")
    public ResponseEntity save(@RequestBody CommentDTO commentDTO){
        System.out.println("컨트롤러에서 받아온 DTO" + commentDTO);
        Long saveResult = commentService.save(commentDTO);
        if( saveResult != null){

            List<CommentDTO> commentDTOList = commentService.findAll(commentDTO.getBoardId());
           
            return new ResponseEntity<>(commentDTOList,HttpStatus.OK);

        } else {

            return new ResponseEntity<>("게시글 없음", HttpStatus.BAD_REQUEST);

        }

       
    }

}

 

반환타입을 ResponseEntity로 구현한 이유는, HTTP요청을 보냈을때 응답을 조금더 확실히 받기 위해서 ResponseEntity로 반환하였다.

 

[CommentService.jsx]

package com.board.practice.service;

import org.springframework.stereotype.Service;

import com.board.practice.DTO.CommentDTO;
import com.board.practice.entity.CommentEntity;
import com.board.practice.entity.boardEntity;
import com.board.practice.repository.BoardRepository;
import com.board.practice.repository.CommentRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import java.util.*;

@Service
@RequiredArgsConstructor
public class CommentService {

    private final CommentRepository commentRepository;
    private final BoardRepository boardRepository;
   
    @Transactional
    public List<CommentDTO> findAll(Long board_id){
        // select * from where comment_table where board_id = ? order by id desc;
        boardEntity boardEntity =  boardRepository.findById(board_id).get();
        List<CommentEntity> commentEntities = commentRepository.findAllByBoardEntityOrderByIdDesc(boardEntity);
        List<CommentDTO> commentDTOList = new ArrayList<>();
        for ( CommentEntity e : commentEntities ) {
            commentDTOList.add(CommentDTO.toCommentDTO(e)) ;
        }
        return commentDTOList;

    }

    public Long save(CommentDTO commentDTO){
        // CommentEntity commentEntity = new CommentEntity(); 한번에 CommentEntity에서 하는 이유는
        // 최대한 Entity객체를 보호하자는 의미가 있어서 인스턴스 생성을 하지 않는다.

        Optional<boardEntity> optionalBoardEntity = boardRepository.findById(commentDTO.getBoardId());
        if( optionalBoardEntity.isPresent() ){
            boardEntity boardEntity = optionalBoardEntity.get();
            CommentEntity commentEntity = CommentEntity.toSaveEntity(commentDTO, boardEntity);
            commentRepository.save(commentEntity);
            return commentRepository.save(commentEntity).getId();
        } else {
            return null;
        }
        // commentRepository.save();
    }

}

 

CommentEntity 와 CommentDto 는 이전에 작성했던 BoardFileDto,BoardFileEntity와 같이 방식으로 작성하여서 따로 첨부하지 않았다.