본문 바로가기

항해 99/Web

웹 미니 프로젝트 2일차

2.1 프로젝트 진행으로 인해 작성하지 못 했음.

 

웹 미니 프로젝트 2일차 진행

1. 각 파트 별 개발 시작

  • 게시글 수정 및 삭제 기능 추가
    • 게시글(카드) 하단에 삭제 버튼을 누르면 삭제 여부를 확인 할 수 있도록 모달 추가(모달에서 삭제 눌러야 게시글 삭제)
    • 삭제 버튼 옆에 게시글 수정 버튼을 생성하고 수정 버튼을 누르면 수정 모달을 통해 변경 내용을 입력 후 저장하면 해당 게시글 내용이 수정 반영
  • 기능 개발 간 생긴 문제
    • 수정 버튼을 눌러 모달을 통해 수정 내용을 입력 시 서버에 반영되지 않아 내용 변경 실패
      • 원인 분석 : POST 타입으로 보낸 수정 데이터를 서버에서 인식하지 못함
      • 해결 : 서버로 보내는 데이터를 PUT 타입으로 변경 → 서버에 반영되어 데이터가 수정 됨
    • PUT 타입으로 변경했을 때 수정하려는 카드 외에 다른 카드(게시글)도 내용이 수정되는 문제 발생
      • 원인 분석 : PUT 타입으로 데이터를 보내기 위해 카드 부분을 for 문으로 감싸게 되어 모든 카드 내용이 수정 됨
      • 해결 : POST 타입으로 서버로 데이터를 보내는 방식으로 돌아옴, 서버로 데이터를 보내는 javascript 코드를 다른 방식으로 수정

  • 문제 해결 후 서버(app.py) 파일의 수정 기능 코드

  • 문제 해결 후 수정 내용 전송하는 javascript 코드

 

해당 파트를 진행하면서 느낀 점

  • HTML에서 받은 데이터를 ajax를 통해 서버로 넘길 때 javascript 코드와 해당 데이터를 받을 서버의 route 코드를 잘 설계하는 것도 중요하지만 에러가 발생할 경우 어떤 이유로 에러가 발생했는지 파악하는 것도 중요
    • 에러 이유를 파악하는 것으로 문제가 발생한 부분에 대해 정확한 수정 작업을 진행할 수 있다.
  • javascript 코드 사용 시 해당 코드를 사용하기 위한 jQuery 코드를 불러오지 않을 경우 javacript 코드의 기능이 작동하지 않음
  • 코드에 문제가 없는데도 작동에 실패하는 경우 기존에 사용하던 방식과 다른 방식의 코드를 실험해보는 것이 좋음
    • POST 방식으로 데이터를 받는 코드를 GPT를 통해 초기에 사용한 코드와 다른 방식의 코드를 받는 것으로 수정 데이터가 서버에 반영되지 않는 문제를 해결했다.

 

 

2. 각 개발 파트를 GIT의 팀 branch에 push

  • 각자 개발한 파트를 Master 브랜치로 합치기 전에 테스트용 브랜치에 합쳐서 기능을 확인하는 작업 실시
  • 발생한 문제
    • 수정 및 삭제 기능이 내가 개발했던 웹 환경에서는 정상적으로 작동했으나, 합쳐진 환경에서는 기능이 작동하지 않았음.
      • 모듈화 작업이 필요했고, 데이터를 수정하는데 필요한 변수명의 차이, 서버로 데이터를 넘기는 javascript 코드에서 발생한 문제 등을 수정해야 했음
    • 로그인 세션 정보를 받아서 로그인 정보를 기준으로 수정 및 삭제 기능이 작동하도록 로직을 구현했으나 로직이 제대로 작동하지 않는 문제 발생
      • 로그인 세션 정보를 게시글이 있는 HTML 페이지로 전달되지 않아서 로그인 정보가 None 값으로 되어 수정 및 삭제 기능을 사용할 수 없었음
  • 해결
    • 수정 및 삭제 기능은 HTML 파일을 각각 분리하여 include를 통해 각 페이지에서 불러와서 사용할 수 있도록 모듈화 하였고, 서버로 데이터를 보내는 javascript 코드도 js 파일로 만들어 다른 페이지에서 불러와 사용할 수 있도록 함
    • 각 기능이 정상작동 되지 않는 부분은 에러 코드, 서버 로그 기록, 각 파일(HTML 파일, 서버 파일, js 코드 파일)에서 문제점을 찾아서 수정하는 작업을 통해 해결
  • 과제
    • 시간 부족으로 ID 기반 삭제 및 수정 기능 부여는 2일차에 완료하지 못함, 3일차에 해결이 필요하다.

 

개발에 사용한 코드 목록

<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="editModalLabel">게시물 수정</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="editForm" method="POST">
                    <input type="hidden" name="postID" id="editPostID">
                    <div class="mb-3">
                        <label for="editTypeSelect" class="form-label">타입</label>
                        <select class="form-control" id="editTypeSelect" name="type">
                            <option value="music">음악</option>
                            <option value="movie">영화</option>
                            <option value="instagram">인스타그램</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label for="editUserID" class="form-label">유저 ID</label>
                        <input type="text" class="form-control" id="editUserID" name="userID">
                    </div>
                    <div class="mb-3">
                        <label for="editTitle" class="form-label">제목</label>
                        <input type="text" class="form-control" id="editTitle" name="title">
                    </div>
                    <div class="mb-3">
                        <label for="editImageUrl" class="form-label">이미지 URL</label>
                        <input type="text" class="form-control" id="editImageUrl" name="image_url">
                    </div>
                    <div class="mb-3">
                        <label for="editContent" class="form-label">내용</label>
                        <textarea class="form-control" id="editContent" rows="3" name="content"></textarea>
                    </div>
                    <div class="mb-3">
                        <label for="editUrl" class="form-label">URL</label>
                        <input type="text" class="form-control" id="editUrl" name="url">
                    </div>
                    <button type="submit" class="btn custom-button">수정하기</button>
                </form>
            </div>
        </div>
    </div>
</div>
  • 수정 기능 모달 : 수정 버튼을 누르면 수정할 내용을 입력하는 창
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="deleteModalLabel">게시글 삭제 확인</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                정말로 삭제하시겠습니까?
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
                <button type="button" class="btn btn-danger" id="confirmDelete">삭제</button>
            </div>
        </div>
    </div>
</div>
  • 삭제 확인 모달 : 삭제 버튼을 누르면 게시글을 삭제할 건지 확인하는 창
$(document).ready(function () {
    $('.edit-btn').on('click', function () {
        var postId = $(this).data('post-id'); // 'data-post-id' 속성을 통해 게시물 ID를 가져옵니다.
        // AJAX를 통해 서버에서 해당 게시물 정보를 가져옵니다.
        $.get('/get-post-info/' + postId, function (postData) {
            $('#editPostID').val(postData.postID);
            // $('#editUserID').val(postData.userID);
            $('#editTypeSelect').val(postData.type);
            $('#editTitle').val(postData.title);
            $('#editImageUrl').val(postData.image_url);
            $('#editContent').val(postData.content);
            $('#editUrl').val(postData.url);
        });
    });

    $('#editForm').on('submit', function (e) {
        e.preventDefault();
        var postId = $('#editPostID').val();
        var data = {
            userID: $('#editUserID').val(),
            type: $('#editTypeSelect').val(),
            title: $('#editTitle').val(),
            image_url: $('#editImageUrl').val(),
            content: $('#editContent').val(),
            url: $('#editUrl').val()
        };
        $.ajax({
            url: '/edit-post/' + postId,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(data),
            success: function (result) {
                // UI 업데이트, 예를 들어 페이지 새로고침 없이 변경된 정보를 표시
                $('#editModal').modal('hide'); // 모달 닫기
                // 변경된 게시물 정보를 페이지에 반영하는 로직을 추가할 수 있습니다.
                location.reload(); // 단순하게 페이지를 새로고침하여 변경사항 반영
            },
            error: function (error) {
                console.error('Error updating post: ', error);
                alert('게시물 수정 중 오류가 발생했습니다. 다시 시도해주세요.');
            }
        });
    });
});
  • 수정 javascript 코드 : 모달에서 입력한 변경 내용을 서버로 보내주는 역할
$(document).ready(function () {
    $('.delete-btn').on('click', function () {
        // 삭제하려는 게시물의 ID를 저장
        var postIdToDelete = $(this).data('post-id');
        $('#deleteModal').modal('show');
        $('#confirmDelete').data('post-id', postIdToDelete);
    });

    $('#confirmDelete').on('click', function () {
        var postID = $(this).data('post-id');
        $.ajax({
            url: '/delete_post/' + postID,
            type: 'POST',
            success: function (response) {
                $('#deleteModal').modal('hide'); // 모달 숨기기
                
                // 서버 요청이 성공한 후에 페이지 새로고침
                window.location.reload();
            },
            error: function (error) {
                console.log(error);
                alert('Error deleting post');
            }
        });
    });
});
  • 삭제 javascript 코드 : 모달에서 삭제 확인 버튼을 누르면 서버에서 해당 게시글을 삭제하도록 명령을 보내는 역할
@app.route("/delete_post/<int:postID>", methods=['POST'])
def delete_post(postID):
    post_to_delete = Posts.query.get_or_404(postID)
    db.session.delete(post_to_delete)
    db.session.commit()
    return jsonify({'success': 'Post deleted successfully'}), 200

@app.route('/edit-post/<int:postID>', methods=['POST'])
def edit_post(postID):
    post = db.session.get(Posts, postID)
    if not post:
        return jsonify({'error': 'Post not found'}), 404

    data = request.json
    title = data.get('title')
    content = data.get('content')
    type = data.get('type')
    image_url = data.get('image_url')

    if type is None:
        return jsonify({'error': '`type` is a required field'}), 400

    post.title = title
    post.content = content
    post.type = type
    post.image_url = image_url

    try:
        db.session.commit()
        return jsonify({'success': 'Post updated successfully'}), 200
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500
  • 수정 및 삭제 데이터를 서버에서 처리할 수 있게 하는 함수
    • delete_post : 게시글 삭제 신호를 받으면 DB에서 해당 게시글의 데이터를 삭제하는 역할
    • edit_post : 수정된 데이터를 받아서 DB에서 데이터를 업데이트 시키는 역할
      • 게시글 검색: 먼저, 함수는 db.session.get(Posts, postID)를 사용하여 데이터베이스에서 주어진 postID를 가진 게시글을 검색합니다.
      • 게시글 존재 여부 확인: 게시글이 존재하지 않을 경우, 404 상태 코드와 함께 "Post not found" 오류 메시지를 반환합니다.
      • 데이터 추출: 요청 본문에서 JSON 형식의 데이터를 추출합니다. 이 데이터에는 게시글을 업데이트하기 위한 새로운 title, content, type, image_url 정보가 포함됩니다.
      • 필수 필드 검증: type 필드가 누락된 경우, 400 상태 코드와 함께 오류 메시지를 반환합니다. 이는 type 필드가 필수적임을 나타냅니다.
      • 게시글 업데이트: 검증 후, 게시글 객체의 속성을 새로운 값으로 설정하고, db.session.commit()을 호출하여 변경 사항을 데이터베이스에 저장합니다.
      • 예외 처리: 업데이트 과정에서 예외가 발생하면, db.session.rollback()을 호출하여 변경 사항을 롤백(취소)하고, 500 상태 코드와 함께 오류 메시지를 반환합니다.

 

프로젝트 2일차 느낀 점

  • 기능을 개발할 때 여러 곳에서 같은 기능을 사용하게 될 경우 모듈화해서 작업하는 것이 편하다는 것을 배움
  • 기능이 정상적으로 작동하지 않을 경우 에러 코드, 서버 로그, 코드 파일 등을 검토하여 수정하는 것이 문제를 해결하는데 크게 작용한다
  • GPT 등을 잘 활용하면 개발에 들어가는 시간을 줄이거나 문제 해결에 도움을 받을 수 있음
  • 다른 팀원과 소통을 통해 어떤 식으로 개발할 것인지 정보를 알고 내 파트를 개발하는 것이 추후에 파트를 전체적으로 합칠 때 수정하는 문제를 덜 겪을 것 같다.