Coding 공부/IntelliJ
[IntelliJ_Springboot_MariaDB] read.html 코드, reply.js 코드, Axos 매개변수의 타입
CBJH
2024. 5. 29. 15:30
728x90
반응형
1. read.html 코드 추가
1.1 모달창 추가
<div class="modal registerModal" tabindex="-1"> <!-- 댓글등록 모달 -->
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Register Reply</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<span class="input-group-text">Reply Text</span>
<input type="text" class="form-control replyText" >
</div>
<div class="input-group mb-3">
<span class="input-group-text">Replyer</span>
<input type="text" class="form-control replyer">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary registerBtn">Register</button>
<button type="button" class="btn btn-outline-dark closeRegisterBtn" >Close</button>
</div>
</div>
</div>
</div>
<div class="modal modifyModal" tabindex="-1"> <!-- 댓글 읽기, 수정 모달 -->
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title replyHeader">Modify Reply</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<span class="input-group-text">Reply Text</span>
<input type="text" class="form-control modifyText" >
</div>
<div class="input-group mb-3">
<span class="input-group-text">Replyer</span>
<input type="text" class="form-control modifyReplyer" readonly>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary modifyBtn">Modify</button>
<button type="button" class="btn btn-danger removeBtn">Remove</button>
<button type="button" class="btn btn-outline-dark closeModifyBtn" >Close</button>
</div>
</div>
</div>
</div>
- registerBtn, closeRegisterBtn 같이 클래스를 추가해주고 스크립트에서 querySelect해서 버튼에 이벤트를 등록하도록 코드를 작성한다.
- 부트 스트랩이 제공하는 다양한 클래스를 사용해 UI를 꾸며준다.
1.2 스크립트 부분
<script layout:fragment="script" th:inline="javascript">
// 템플릿 엔진(예: Thymeleaf)을 사용하여 dto.bno 값을 JavaScript 변수 bno에 할당
const bno = [[${dto.bno}]]
// 댓글 목록과 페이징 요소를 선택
const replyList = document.querySelector('.replyList')
const replyPaging = document.querySelector('.replyPaging')
~~
let page = 1
let size = 10
// replyPaging 요소에 클릭 이벤트 리스너 추가
replyPaging.addEventListener("click", function (e) {
e.preventDefault()
e.stopPropagation()
const target = e.target
if(!target || target.tagName != 'A'){ // 클릭된 요소가 a 태그인지 확인, target이 비어있는지 확인
return
}
const pageNum = target.getAttribute('data-page') // data-page 속성 값 가져오기
page = parseInt(pageNum)
printReplies(page, size) // printReplies 함수 호출, 페이지 번호를 정수로 변환하여 첫 번째 매개변수로 전달
}, false)
//registerModal
//댓글 모달 관련 DOM 객체 변수
const replyText = document.querySelector('.replyText')
const replyer = document.querySelector('.replyer')
const registerModal = new bootstrap.Modal(document.querySelector('.registerModal'))
const registerBtn = document.querySelector('.registerBtn')
const closeRegisterBtn = document.querySelector('.closeRegisterBtn')
//ADD 버튼 누르면 모달 창 띄우는 이벤트 리스너
document.querySelector('.addReplyBtn').addEventListener('click', function (e){
registerModal.show()
}, false)
//CLOSE 버튼 누르면 모달 창 끄기
closeRegisterBtn.addEventListener('click', function (e){
registerModal.hide()
}, false)
registerBtn.addEventListener('click', function (e){
const replyObj = {bno:bno, replyText:replyText.value, replyer:replyer.value}
addReply(replyObj).then(result=>{
alert("rno값: " + result.rno)
registerModal.hide()
replyText.value=''
replyer.value=''
printReplies(1,10,true) //3번째 인자가 true면 마지막 페이지로 이동, 댓글 목록 갱신
}).catch(e=>{
alert("Reply Register Excetion....")
})
}, false)
//modifyModal
const modifyModal = new bootstrap.Modal(document.querySelector('.modifyModal'))
const replyHeader = document.querySelector('.replyHeader')
const modifyText = document.querySelector('.modifyText')
const modifyReplyer = document.querySelector('.modifyReplyer')
const modifyBtn = document.querySelector('.modifyBtn')
const removeBtn = document.querySelector('.removeBtn')
const closeModifyBtn = document.querySelector('.closeModifyBtn')
replyList.addEventListener("click", function (e) {
e.preventDefault()
e.stopPropagation()
const target = e.target
if(!target || target.tagName != 'SPAN'){ // 클릭된 요소가 span 태그인지 확인, target이 비어있는지 확인
return
}
const rno = target.getAttribute('data-rno') // data-rno 속성 값 가져오기
if(!rno){
return
}
getReply(rno).then(reply=>{ //then은 return 값을 reply에 반환 받아 콜백 함수 실행
replyHeader.innerHTML = reply.rno ///replyHeader에 reply.rno값을 보내 다른 페이지로 전달하겠다.
modifyText.value = reply.replyText
modifyReplyer.value = reply.replyer
modifyModal.show()
}).catch(e=>alert('ModifyModal Open error'))
}, false)
modifyBtn.addEventListener("click", function (e){
const replyObj = {bno:bno, rno:replyHeader.innerHTML, replyText:modifyText.value, replyer:modifyReplyer.value}
console.log(replyObj)
modifyReply(replyObj).then(result=>{
alert(result.rno+'수정됨')
replyText.value=''
replyer.value=''
modifyModal.hide()
printReplies(page, size)
}).catch(e=>{console.log(e)})
},false)
closeModifyBtn.addEventListener('click', function (e){
modifyModal.hide()
}, false)
removeBtn.addEventListener('click', function (e){
removeReply(replyHeader.innerHTML).then(result=>{
alert(result.rno+"(이)가 삭제 되었습니다.")
replyText.value = ''
replyer.value=''
modifyModal.hide()
page = 1 //댓글 첫번째 페이지로 이동
printReplies(page, size)
}).catch(e=>{console.log(e)})
}, false)
</script>
2. reply.js 코드 추가 부분
//reply.js 코드
// 비동기 함수 get1 정의, 게시물 번호(bno)를 매개변수로 받음
async function getList({bno,page,size,goLast}){
const result = await axios.get(`/replies/list/${bno}`,{params:{page,size}})
if(goLast){
const total = result.data.total
const lastPage = parseInt(Math.ceil(total/size))
return getList({bno:bno, page:lastPage, size:size})
}
return result.data
}
async function addReply(replyObj){
const response = await axios.post('/replies/', replyObj)
return response.data //Map이 전달되므로 .data는 밸류 값을 반환한다. rno값이 들어있다.
}
async function getReply(rno){
const response = await axios.get(`/replies/${rno}`)
return response.data
}
async function modifyReply(replyObj){
const response = await axios.put(`/replies/${replyObj.rno}`,replyObj)
return response.data
}
async function removeReply(rno){
const response = await axios.delete(`/replies/${rno}`)
return response.data
}
- axios를 사용해서 비동기로 get, put, delete, post 방식으로 컨트롤러를 호출한다.
- 첫번째 인자엔 호출할 url 주소를 넣고, 두번째 인자부턴 컨트롤러로 전달할 매개변수를 넣는다.
- replyObj가 컨트롤러에서 ReplyDTO 클래스 타입으로 @RequestBody로 처리되어 값이 넘어가므로, 자바스크립트 객체의 키 값과 DTO 필드 이름을 같게 맞춰준다.
3. Axos 매개변수의 타입
일반적으로 axios를 통해 JavaScript 객체를 서버의 컨트롤러로 전달할 때, 키 값은 서버에서 매개변수로 받는 DTO(Data Transfer Object)의 필드 이름과 일치해야 합니다. 이는 서버가 JSON 객체의 각 필드를 DTO의 각 필드에 정확하게 매핑할 수 있도록 하기 위함입니다.
3.1 클라이언트 코드 (JavaScript)
axios를 사용하여 POST 요청을 보내는 예시입니다. 여기서 replyObj의 키는 서버 DTO의 필드 이름과 일치해야 합니다.
// JavaScript 객체 생성
const replyObj = {
bno: 123,
rno: 456,
replyText: "This is a reply text",
replyer: "user123"
};
// POST 요청
axios.post('/replies', replyObj)
.then(response => {
console.log('Reply added:', response.data);
})
.catch(error => {
console.error('Error adding reply:', error);
});
3.2 서버 코드 (Java, Spring Boot)
DTO 클래스는 Java에서 다음과 같이 정의할 수 있습니다. @RequestBody 어노테이션을 사용하여 JSON 요청 바디를 이 DTO로 매핑합니다.
// DTO 클래스 정의
public class ReplyDTO {
private Long bno;
private Long rno;
private String replyText;
private String replyer;
~
}
컨트롤러에서는 이 DTO를 매개변수로 받아서 처리합니다.
@RestController
@RequestMapping("/replies")
public class ReplyController {
@PostMapping
public ResponseEntity<String> addReply(@RequestBody ReplyDTO replyDTO) {
// replyDTO를 이용하여 비즈니스 로직 처리
return new ResponseEntity<>("Reply added successfully", HttpStatus.CREATED);
}
}
3.3 요약
- JavaScript 객체의 키: axios를 통해 보내는 객체의 키는 서버의 DTO 필드와 일치해야 합니다. 예를 들어, replyObj의 키인 bno, rno, replyText, replyer는 모두 ReplyDTO의 필드와 일치합니다.
- 서버의 DTO 클래스: 서버의 DTO 클래스는 JavaScript 객체의 키와 일치하는 필드를 가져야 하며, 이를 통해 JSON 객체의 각 필드를 DTO의 각 필드에 매핑할 수 있습니다.
- 매핑: Spring Boot는 @RequestBody 어노테이션을 사용하여 JSON 요청 바디를 DTO에 매핑합니다. 이 과정에서 JSON 객체의 키와 DTO 필드 이름이 일치해야 매핑이 올바르게 이루어집니다.
따라서, 키 값이 DTO의 필드 이름과 일치하도록 JavaScript 객체를 구성하는 것이 중요합니다. 이렇게 하면 데이터가 서버로 올바르게 전달되고 처리될 수 있습니다.