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 요약

  1. JavaScript 객체의 키: axios를 통해 보내는 객체의 키는 서버의 DTO 필드와 일치해야 합니다. 예를 들어, replyObj의 키인 bno, rno, replyText, replyer는 모두 ReplyDTO의 필드와 일치합니다.
  2. 서버의 DTO 클래스: 서버의 DTO 클래스는 JavaScript 객체의 키와 일치하는 필드를 가져야 하며, 이를 통해 JSON 객체의 각 필드를 DTO의 각 필드에 매핑할 수 있습니다.
  3. 매핑: Spring Boot는 @RequestBody 어노테이션을 사용하여 JSON 요청 바디를 DTO에 매핑합니다. 이 과정에서 JSON 객체의 키와 DTO 필드 이름이 일치해야 매핑이 올바르게 이루어집니다.

따라서, 키 값이 DTO의 필드 이름과 일치하도록 JavaScript 객체를 구성하는 것이 중요합니다. 이렇게 하면 데이터가 서버로 올바르게 전달되고 처리될 수 있습니다.