<댓글 수정(update) 구현 (spring boot)>
<replyUpdate>
@Transactional
public Reply replyUpdate(ReplyUpdateDto replyUpdateDto) {
Reply replyEntity = replyRepository.findById(replyUpdateDto.getId())
.orElseThrow(()->new IllegalArgumentException("이미 삭제된 댓글입니다."));
replyEntity.setContent(replyUpdateDto.getContent());
return replyEntity;
}
<replyUpdateDTO>
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReplyUpdateDto {
private Long id;
private String content;
}
<replyApiController>
@PutMapping("/api/reply/{id}/update") // 댓글 수정
public ResponseDto<?> replyUpdate (@RequestBody ReplyUpdateDto replyUpdateDto) {
return new ResponseDto<>(HttpStatus.OK.value(), replyService.replyUpdate(replyUpdateDto));
}
<react에서 수정, 삭제하기>
<board/Content 수정>
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { Button, Card, Form, InputGroup } from "react-bootstrap";
import ReplyItem from "../../components/ReplyItem";
const Content = () => {
const propsParam = useParams();
const id = propsParam.id;
const navigate = useNavigate();
const [board, setBoard] = useState({
//처음에 공백
data: [],
status: "",
});
const [replyList, setReplyList] = useState([]);
const [reply, setReply] = useState({
board_id: id,
content: "",
});
const [subCategoryName, setSubCategoryName] = useState({});
useEffect(() => {
fetch("http://localhost:8080/board/" + id) //id를 통해서 게시판 정보를 가져옴
.then((res) => res.json())
.then((res) => {
setBoard(res); //공백에 가져온 정보로 채워줌
setSubCategoryName(res.data.subCategory);
setReplyList(res.data.replies);
});
}, [id]);
const deleteBoard = () => {
//해당 게시글 삭제
fetch("http://localhost:8080/api/board/" + id + "/delete", {
method: "DELETE",
headers: {
AccessToken: localStorage.getItem("Tnut's accessToken"),
},
})
.then((res) => res.text())
.then((res) => {
if (res === "success delete!") {
navigate("/");
} else {
alert("삭제 실패");
}
});
};
const updateBoard = () => {
//함수 updateBoard 실행되면 /update/id로 이동
navigate("/board/updateForm/" + id);
};
const changeValue = (e) => {
setReply((reply) => ({
...reply,
content: e.target.value,
}));
};
const submitReply = (e) => {
e.preventDefault();
fetch("http://localhost:8080/api/reply/save", {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify(reply),
})
.then((res) => {
console.log(res);
if (res.status === 200) {
return res.json();
} else {
return null;
}
})
.then((res) => {
if (res !== null) {
window.location.reload();
} else {
alert("댓글 등록 실패!");
}
});
};
return (
<div>
<h1>{board.data.title}</h1>
<Button variant="secondary" onClick={() => updateBoard()}>
수정
</Button>{" "}
<Button variant="secondary" onClick={() => deleteBoard()}>
삭제
</Button>{" "}
<Button variant="secondary" onClick={() => navigate(-1)}>
돌아가기
</Button>
<hr />
<Card>
<Card.Body>Category: {subCategoryName.subCategoryName}</Card.Body>
</Card>
<Card>
<Card.Body>{board.data.content}</Card.Body>
</Card>
<hr />
<InputGroup className="mb-3">
<Form.Control
type="reply"
onChange={changeValue}
name="reply"
placeholder="댓글을 입력하세요"
/>
<Button
variant="outline-secondary"
id="button-addon2"
onClick={submitReply}
>
댓글 등록
</Button>
</InputGroup>
<hr />
<>
{replyList.map((comment) => {
return <ReplyItem key={comment.id} comment={comment} />;
})}
</>
</div>
);
};
export default Content;
<components/ReplyItem>
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { Button, Card, Form, InputGroup } from "react-bootstrap";
import ReplyItem from "../../components/ReplyItem";
const Content = () => {
const propsParam = useParams();
const id = propsParam.id;
const navigate = useNavigate();
const [board, setBoard] = useState({
//처음에 공백
data: [],
status: "",
});
const [replyList, setReplyList] = useState([]);
const [reply, setReply] = useState({
board_id: id,
content: "",
});
const [subCategoryName, setSubCategoryName] = useState({});
useEffect(() => {
fetch("http://localhost:8080/board/" + id) //id를 통해서 게시판 정보를 가져옴
.then((res) => res.json())
.then((res) => {
setBoard(res); //공백에 가져온 정보로 채워줌
setSubCategoryName(res.data.subCategory);
setReplyList(res.data.replies);
});
}, [id]);
const deleteBoard = () => {
//해당 게시글 삭제
fetch("http://localhost:8080/api/board/" + id + "/delete", {
method: "DELETE",
headers: {
AccessToken: localStorage.getItem("Tnut's accessToken"),
},
})
.then((res) => res.text())
.then((res) => {
if (res === "success delete!") {
navigate("/");
} else {
alert("삭제 실패");
}
});
};
const updateBoard = () => {
//함수 updateBoard 실행되면 /update/id로 이동
navigate("/board/updateForm/" + id);
};
const changeValue = (e) => {
setReply((reply) => ({
...reply,
content: e.target.value,
}));
};
const submitReply = (e) => {
e.preventDefault();
fetch("http://localhost:8080/api/reply/save", {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify(reply),
})
.then((res) => {
console.log(res);
if (res.status === 200) {
return res.json();
} else {
return null;
}
})
.then((res) => {
if (res !== null) {
window.location.reload();
} else {
alert("댓글 등록 실패!");
}
});
};
return (
<div>
<h1>{board.data.title}</h1>
<Button variant="secondary" onClick={() => updateBoard()}>
수정
</Button>{" "}
<Button variant="secondary" onClick={() => deleteBoard()}>
삭제
</Button>{" "}
<Button variant="secondary" onClick={() => navigate(-1)}>
돌아가기
</Button>
<hr />
<Card>
<Card.Body>Category: {subCategoryName.subCategoryName}</Card.Body>
</Card>
<Card>
<Card.Body>{board.data.content}</Card.Body>
</Card>
<hr />
<InputGroup className="mb-3">
<Form.Control
type="reply"
onChange={changeValue}
name="reply"
placeholder="댓글을 입력하세요"
/>
<Button
variant="outline-secondary"
id="button-addon2"
onClick={submitReply}
>
댓글 등록
</Button>
</InputGroup>
<hr />
<>
{replyList.map((comment) => {
return <ReplyItem key={comment.id} comment={comment} />;
})}
</>
</div>
);
};
export default Content;
<components/SubReplyItem>
import React, { useState } from "react";
import { Button, Card, Form, InputGroup } from "react-bootstrap";
const SubReplyItem = (props) => {
const { content, id } = props.subreply;
const [mode, setMode] = useState("read");
const [contentValue, setContentValue] = useState({
id: id,
content: content,
});
const changeValue = (e) => {
setContentValue((contentValue) => ({
...contentValue,
content: e.target.value,
}));
};
const deleteReply = () => {
fetch("http://localhost:8080/api/reply/" + id + "/delete", {
method: "DELETE",
})
.then((res) => res.text())
.then((res) => {
console.log(res);
if (res === "success delete!") {
window.location.reload();
} else {
alert("삭제 실패");
}
});
};
const updateReply = (e) => {
e.preventDefault();
fetch("http://localhost:8080/api/reply/" + id + "/update", {
method: "PUT",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify(contentValue),
})
.then((res) => {
if (res.status === 200) {
return res.json;
} else {
return null;
}
})
.then((res) => {
if (res !== null) {
window.location.reload();
} else {
alert("댓글 수정 실패!");
}
});
};
return (
<div>
<Card>
{mode === "read" ? (
<>
{content !== null ? (
<Card.Body>
{content}
{" "}
<Button variant="outline-secondary" onClick={deleteReply}>
삭제
</Button>{" "}
<Button
variant="outline-secondary"
onClick={() => setMode("update")}
>
수정
</Button>
</Card.Body>
) : (
<Card.Body>
"삭제된 댓글입니다."
{" "}
<Button variant="outline-secondary" onClick={deleteReply}>
삭제
</Button>{" "}
<Button
variant="outline-secondary"
onClick={() => setMode("update")}
>
수정
</Button>
</Card.Body>
)}
</>
) : (
<InputGroup className="mb-3">
<Form.Control
type="replyUpdate"
onChange={changeValue}
name="replyUpdates"
placeholder="글을 입력하세요"
value={contentValue.content}
/>
<Button
variant="outline-secondary"
id="button-addon2"
onClick={updateReply}
>
수정하기
</Button>
<Button
variant="outline-secondary"
id="button-addon2"
onClick={() => setMode("read")}
>
수정취소
</Button>
</InputGroup>
)}
</Card>
</div>
);
};
export default SubReplyItem;
<블로그에서 확인하기>
db에서 데이터가 지워진 것이 아니고 content가 null인것이기 때문에 만일 삭제된 댓글이 수정가능하도록 하려면 isDeletable도 함께 업데이트 시켜주거나 아니면 수정이 되지 않도록 리팩토링 해야겠다
앞으로 할 내용 : 댓글에 user정보를 담아서 해당 유저 + 관리자에 한해서 삭제하고 수정할 수 있게끔 만들 것임, 조건부 렌더링이 생각보다 재밌고 편해서 category부분도 리펙터링 할 예정
+ 삭제된 댓글은 수정 안되도록
728x90
반응형
'개인 프로젝트 > 블로그' 카테고리의 다른 글
댓글에 유저 정보를 담아보자 feat.@AuthenticationPrincipal (0) | 2022.08.02 |
---|---|
네이버 카카오 Oauth2.0 로그인 구현 (0) | 2022.08.01 |
댓글 삭제 구현 로직 생각 및 구현 (0) | 2022.07.29 |
대대ㅅ댓..글 구현(save) (2) | 2022.07.25 |
jpa 대댓글 삭제에 대한 고민 (0) | 2022.07.24 |