본문 바로가기

기능이해

[JAVA | SPRING | MVC | CRUD] 게시물 수정 Update

게시물 수정

 



HTTP메서드 : POST

Endpoint URL : /api/update/posts/{post-id}

작업 내용 : 작성된 게시물 수정

게시물 수정 기본 설명과 예시 : 게시물 수정은 특정 게시물의 내용을 업데이트하는 기능이다. 클라이언트가 서버로 요청을 보내 특정 게시물의 일부 또는 전체 정보를 변경하고 서버는 이를 처리하고 결과를 반환한다.

 

 

 


요구 사항

 

 
  • 게시물의 id에 해당하는 게시물을 찾아 제목(title)과 내용(content)을 수정한다.
  • 클라이언트는 수정 요청을 JSON 형식으로 보내며, 서버는 성공 여부를 응답한다.
  • 잘못된 id로 요청 시 예외 처리 및 적절한 메시지를 반환해야 한다.
 

개념 정리

 



 
 

HTTP 메서드: POST

  • POST는 보통 새로운 데이터를 생성하는 데 사용되지만, 경우에 따라 수정 작업에 활용할 수도 있다.
  • RESTful하게 접근하려면 PATCH 또는 PUT을 사용하는 것이 일반적이다.

게시물 수정의 일반적인 과정

  • 클라이언트로부터 수정 요청 데이터 수신.
  • 서버에서 해당 id의 게시물 조회.
  • 조회된 게시물의 데이터를 수정.
  • 수정된 데이터를 저장 후 응답 반환.

JAVA 기본개념

  • 클래스와 객체: 게시물 데이터를 관리하기 위한 Post 클래스를 정의한다.
  • 컬렉션: 게시물을 관리하기 위한 리스트나 맵과 같은 자료구조를 활용할 수 있다.
  • 예외처리: 존재하지 않는 id로 요청 시 예외 처리 필요.

DB 연동 기술

  • JDBC: SQL을 직접 작성하여 DB와 통신.
  • MyBatis: SQL과 객체 매핑.
  • JPA: 객체와 관계형 데이터베이스를 매핑하여 처리
 
 
 
 

 


코드 설명

순수 JAVA로 구현

클래스 정의

public class Post {
    private int id;
    private String title;
    private String content;

    // 생성자
    public Post(int id, String title, String content) {
        this.id = id;
        this.title = title;
        this.content = content;
    }

    // getter, setter
    public int getId() { return id; }
    public void setTitle(String title) { this.title = title; }
    public void setContent(String content) { this.content = content; }
}

데이터 관리 클래스

import java.util.HashMap;
import java.util.Map;

public class PostService {
    private Map<Integer, Post> postStorage = new HashMap<>();

    // 초기 데이터 추가
    public PostService() {
        postStorage.put(1, new Post(1, "첫 번째 게시물", "내용1"));
        postStorage.put(2, new Post(2, "두 번째 게시물", "내용2"));
    }

    // 게시물 수정
    public boolean updatePost(int id, String newTitle, String newContent) {
        Post post = postStorage.get(id);
        if (post == null) {
            return false; // ID가 없는 경우
        }
        post.setTitle(newTitle);
        post.setContent(newContent);
        return true;
    }

    // 게시물 조회
    public Post getPost(int id) {
        return postStorage.get(id);
    }
}

요청 처리

import java.util.Scanner;

public class PostController {
    public static void main(String[] args) {
        PostService postService = new PostService();
        Scanner scanner = new Scanner(System.in);

        System.out.println("수정할 게시물 ID 입력:");
        int id = scanner.nextInt();
        scanner.nextLine(); // 버퍼 클리어

        System.out.println("새 제목 입력:");
        String newTitle = scanner.nextLine();

        System.out.println("새 내용 입력:");
        String newContent = scanner.nextLine();

        if (postService.updatePost(id, newTitle, newContent)) {
            System.out.println("게시물 수정 완료!");
            Post updatedPost = postService.getPost(id);
            System.out.println("수정된 게시물: " + updatedPost.getId() + ", " + updatedPost.getTitle() + ", " + updatedPost.getContent());
        } else {
            System.out.println("게시물 수정 실패: ID를 확인하세요.");
        }
    }
}

JDBC

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class PostDAO {
    public boolean updatePost(int id, String title, String content) {
        String url = "jdbc:mysql://localhost:3306/postdb";
        String user = "root";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            String sql = "UPDATE posts SET title = ?, content = ? WHERE id = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, title);
            pstmt.setString(2, content);
            pstmt.setInt(3, id);

            int rows = pstmt.executeUpdate();
            return rows > 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

 

 

MyBatis

Mapper Interface

public interface PostMapper {
    int updatePost(@Param("id") int id, @Param("title") String title, @Param("content") String content);
}

Mapper XML

<update id="updatePost" parameterType="map">
    UPDATE posts
    SET title = #{title}, content = #{content}
    WHERE id = #{id}
</update>

 

 

JPA

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;

@Repository
public class PostRepository {
    @PersistenceContext
    private EntityManager em;

    public boolean updatePost(int id, String title, String content) {
        Post post = em.find(Post.class, id);
        if (post != null) {
            post.setTitle(title);
            post.setContent(content);
            em.merge(post);
            return true;
        }
        return false;
    }
}

개발 중 생길 수 있는 기본적 의문들

Q: 수정기능에 POST를 사용하는 이유는 무엇인지? A:

  • POST는 리소스에 대한 상태를 변경하거나 서버에 작업을 요청할 때 사용되며, 그 결과가 꼭 리소스 생성에 한정되지 않는다.
  • 수정 작업이 복잡한 트랜잭션이나 추가적인 로직(예: 검증, 알림 발송 등)을 포함한다면 POST를 사용하는 것이 적절할 수 있다.
  • 수정 요청이 단일 리소스를 넘어 여러 리소스에 영향을 주거나, 부가적인 서버 처리 로직이 포함될 경우 POST가 적합하다. 예: 게시물 수정과 동시에 수정 내역 로그를 생성하거나 관련된 태그 데이터를 갱신하는 작업.

Q: 수정 권한에 대해서는 어떻게 확인하는지? A:

  • 인가(Authorization): 해당 사용자가 요청한 리소스에 접근 가능한지 확인. 사용자가 수정하려는 게시물이 자신의 소유인지, 특정 권한(Role)을 가지고 있는지 확인.
  • 데이터베이스에서 게시물의 작성자와 요청한 사용자의 ID를 비교. HTTP 응답: 403 Forbidden (권한 없음)
@PostMapping("/api/posts/{id}")
public ResponseEntity<?> updatePost(@PathVariable Long id, @RequestBody PostRequestDto request, Principal principal) {
    Post post = postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("게시물을 찾을 수 없습니다."));
    
    // 게시물 작성자와 현재 사용자 비교
    if (!post.getAuthor().equals(principal.getName())) {
        throw new AccessDeniedException("권한이 없습니다.");
    }

    post.setTitle(request.getTitle());
    post.setContent(request.getContent());
    postRepository.save(post);

    return ResponseEntity.ok("게시물이 수정되었습니다.");
}