강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

초보 초보 개발자님의 프로필 이미지
초보 초보 개발자

작성한 질문수

스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판

게시글 CRUD API 구현

게시판 CRUD 관련 오류

해결된 질문

작성

·

313

·

수정됨

0

  • 학습 관련 질문을 최대한 상세히 남겨주세요!

  • 고민 과정도 같이 나열해주셔도 좋습니다.

  • 먼저 유사한 질문이 있었는지 검색해보세요.

  • 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.

 

안녕하세요,

저와 비슷한 오류가 많은 것 같은데 해결이 안된것 같아서 질문드립니다.

13분쯤에 코드를 같이 따라 쳐보도 위와 같은 오류가 발생합니다.

 

이문제가 해결이 안되서 코드만 3번째 다시 치고 있습니다 ㅠㅠ...

 

 

500 Internal Server Error: "{"timestamp":"2025-03-03T03:54:49.747+00:00","status":500,"error":"Internal Server Error","path":"/v1/articles"}"
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error: "{"timestamp":"2025-03-03T03:54:49.747+00:00","status":500,"error":"Internal Server Error","path":"/v1/articles"}"
	at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102)
	at org.springframework.web.client.StatusHandler.lambda$defaultHandler$3(StatusHandler.java:89)
	at org.springframework.web.client.StatusHandler.handle(StatusHandler.java:146)
	at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.applyStatusHandlers(DefaultRestClient.java:698)
	at org.springframework.web.client.DefaultRestClient.readWithMessageConverters(DefaultRestClient.java:200)
	at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.readBody(DefaultRestClient.java:685)
	at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.body(DefaultRestClient.java:631)
	at kuke.board.article.api.ArticleApiTest.create(ArticleApiTest.java:29)
	at kuke.board.article.api.ArticleApiTest.createTest(ArticleApiTest.java:16)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

 

https://velog.io/@ghwns9991/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-3.2-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EC%9D%B4%EB%A6%84-%EC%9D%B8%EC%8B%9D-%EB%AC%B8%EC%A0%9C

스프링 3.2 부터 uri 관련 매개변수 어노테이션을 잘 인식하지 못한다고 하나 봅니다. 저는 윗 글의 두 번째(-parameters) 방법으로 해결했습니다.

 

 

위와 같이 해결했다고 하는 문구가 많은데,

저는 -parameters를 추가해도 같은 오류가 발생합니다.

 

 

image.png

 

혹시 추가 설정이 필요한 부분이나 추가적으로 말씀해주시면 업로드 하겠습니다 !

 

 


코드 추가

 

ArticleController

package kuke.board.article.controller;


import kuke.board.article.service.ArticleService;
import kuke.board.article.service.request.ArticleCreateRequest;
import kuke.board.article.service.request.ArticleUpdateRequest;
import kuke.board.article.service.response.ArticleResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
public class ArticleController {

    private final ArticleService articleService;

    @GetMapping("/v1/articles/{articleId}")
    public ArticleResponse read(@PathVariable Long articleId) {
        return articleService.read(articleId);
    }

    @PostMapping("/v1/articles")
    public ArticleResponse create(@RequestBody ArticleCreateRequest request) {
        return articleService.create(request);
    }

    @PutMapping("/v1/articles/{articleId}")
    public ArticleResponse update(@PathVariable Long articleId, @RequestBody ArticleUpdateRequest request) {
        return articleService.update(articleId, request);
    }


    @DeleteMapping("/v1/articles/{articleId}")
    public void delete(@PathVariable Long articleId) {
        articleService.delete(articleId);
    }

}

 

entity-Article

 

package kuke.board.article.entity;


import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.time.LocalDateTime;

@Table(name = "article")
@Getter
@Entity
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {

    @Id
    private Long articleId;
    private String title;
    private String content;
    private Long boardId;
    private Long writerId;
    private LocalDateTime createAt;
    private LocalDateTime modifiedAt;

    public static Article create(Long articleId, String title, String content, Long boardId, Long writerId) {
        Article article = new Article();
        article.articleId = articleId;
        article.title = title;
        article.content = content;
        article.boardId = boardId;
        article.writerId = writerId;
        article.createAt = LocalDateTime.now();
        article.modifiedAt = article.createAt;
        return article;
    }

    public void update(String title, String content) {
        this.title = title;
        this.content = content;
        modifiedAt = LocalDateTime.now();
    }
}

 

repository - ArticleRepository

package kuke.board.article.repository;

import kuke.board.article.entity.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {
}

 

Service - request - ArticleCreateRequest

package kuke.board.article.service.request;


import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class ArticleCreateRequest {
    private String title;
    private String content;
    private Long writerId;
    private Long boardId;
}

Service - request - ArticleUpdateRequest

package kuke.board.article.service.request;


import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class ArticleUpdateRequest {
    private String title;
    private String content;

}

 

Service - response - ArticleResponse

package kuke.board.article.service.response;


import kuke.board.article.entity.Article;
import lombok.Getter;
import lombok.ToString;

import java.time.LocalDateTime;

@Getter
@ToString
public class ArticleResponse {

    private Long articleId;
    private String title;
    private String content;
    private Long boardId;
    private Long writerId;
    private LocalDateTime createAt;
    private LocalDateTime modifiedAt;

    public static ArticleResponse from(Article article) {
        ArticleResponse response = new ArticleResponse();
        response.articleId = article.getArticleId();
        response.title = article.getTitle();
        response.content = article.getContent();
        response.boardId = article.getBoardId();
        response.writerId = article.getWriterId();
        response.createAt = article.getCreateAt();
        response.modifiedAt = article.getModifiedAt();

        return response;
    }
}

ArticleApplication

package kuke.board.article;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ArticleApplication {
    public static void main(String[] args) {
        SpringApplication.run(ArticleApplication.class, args);
    }
}

resources - application.yml

server:
  port: 9000

spring:
  application:
    name: kuke-board-article-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/article
    username: root
    password: root
  jpa:
    database-platform: org.hibernate.dialect.MySQLDialect
    open-in-view: false
    show-sql: false
    hibernate:
      ddl-auto: none

 

test - java - kuke.board.article.api

package kuke.board.article.api;

import kuke.board.article.service.request.ArticleCreateRequest;
import kuke.board.article.service.response.ArticleResponse;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.web.client.RestClient;

public class ArticleApiTest {
    RestClient restClient = RestClient.create("http://localhost:9000");

    @Test
    void createTest() {
        ArticleResponse response = create(new ArticleCreateRequest(
                "hi", "my contents", 1L, 1L
        ));

        System.out.println("response = " + response);

    }

    ArticleResponse create(ArticleCreateRequest request) {
        return restClient.post()
                .uri("/v1/articles")
                .body(request)
                .retrieve()
                .body(ArticleResponse.class);
    }

    @Test
    void readTest() {
        ArticleResponse response = read(1234L);
        System.out.println("response = " + response);
    }

    ArticleResponse read(Long articleId) {
        return restClient.get()
                .uri("/v1/articles/{articleId}")
                .retrieve()
                .body(ArticleResponse.class);
    }

    @Test
    void updateTest() {
        update(1234L);
        ArticleResponse response = read(1234L);
        System.out.println("response = " + response);
    }

    void update(Long articleId) {
        restClient.put()
                .uri("/v1/articles/{articleId}", articleId)
                .body(new ArticleUpdateRequest("hi 2", "my content 22"))
                .retrieve()
                ;

    }

    @Test
    void deleteTest() {
        restClient.delete()
                .uri("/v1/articles/{articleId}", 1234L)
                .retrieve();
    }

    @Getter
    @AllArgsConstructor
    static class ArticleCreateRequest {
        private String title;
        private String content;
        private Long writerId;
        private Long boardId;
    }

    @Getter
    @AllArgsConstructor
    static class ArticleUpdateRequest {
        private String title;
        private String content;

    }
}

article - build.gradle

 

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.mysql:mysql-connector-j'

    implementation project(':common:snowflake')
}

답변 6

2

전부 createAt이 아니라 createdAt으로 바꿔도 동일하신가용?

 return restClient.get() .uri("/v1/articles/{articleId}") .retrieve() .body(ArticleResponse.class);
여기 부분에서 uri("v1/articles/{articleId}", articleId) 이렇게 넘겨주셔야 하는데 인자 넘기는게 비어있는 것도 확인해보시면 좋을 것 같아요

감사합니다 ! 다 바꾼줄 알았는데 하나 안바꿨었네요 !!

2

혹시 아티클 엔티티에 createAt이라고 하셨는데 쿠케님이 올려주신 DDL에는 created_at으로 되어있습니다. 이 부분에서 컬럼 매핑이 정상적으로 안되는 것은 아닐지.....

오타 ㅠㅠ 수정했습니다 ㅠ 그래도 똑같네여..

쿠케님의 프로필 이미지
쿠케
지식공유자

서버 애플리케이션에서 발생한 에러 로그를 올려주시겠어요?

서버 로그에서

 

org.hibernate.exception.SQLGrammarException: JDBC exception executing SQL [select a1_0.article_id,a1_0.board_id,a1_0.content,a1_0.create_at,a1_0.modified_at,a1_0.title,a1_0.writer_id from article a1_0 where a1_0.article_id=?] [Unknown column 'a1_0.create_at' in 'field list'] [n/a]
	

와 같은 로그를 찾아서 필드명 다시 확인했습니다. 감사합니다 !

1

쿠케님의 프로필 이미지
쿠케
지식공유자

초보 초보 개발자님, 안녕하세요!

올려주신 에러 로그는 테스트 코드가 서버에게 응답 받은 에러 로그입니다!

그래서 클라이언트 입장에서 서버의 응답 코드를 받기만 한거라 자세한 로그가 남지 않습니다.

테스트 코드의 실행 로그를 봐야하는 것이 아니라, 실행 중인 서버 애플리케이션의 로그를 봐야 합니다.

서버 애플리케이션의 에러 로그를 확인해보시겠어요?!

감사합니다 ! 서버 애플리케이션 로그 보니 오류를 찾았습니다.

1

작성하신 코드도 올려주셔야할 것 같은데용

1

안녕하세요, 인프런 AI 인턴입니다. 초보 초보 개발자님.

스프링 부트 기반으로 게시판 CRUD 작업을 하시면서 “500 Internal Server Error”가 발생하고 있어 어려움을 겪고 계신 것 같습니다. 이 오류는 서버 코드에서 발생하는 문제를 의미하며, 디버깅을 통해 문제의 근본 원인을 찾아야 합니다.

오류 해결을 위한 검토 사항:

  1. 서버 로그 확인:

    • 콘솔이나 로그 파일에서 자세한 예외 메시지를 확인해보세요. Java에서는 stack trace를 통해 문제의 원인을 파악할 수 있습니다. 특히 어디에서 예외가 발생했는지를 찾아보는 것이 중요합니다.
  2. 애플리케이션 설정 파일 확인:

    • application.yml 또는 application.properties에서 설정이 잘못되거나 누락된 부분이 없는지 확인하세요. 특히 데이터베이스 연결 정보와 서버 포트 설정이 올바른지 재확인해보세요.
  3. @PathVariable 및 @RequestParam 어노테이션 확인:

    • 엔드포인트의 컨트롤러 메소드에서 사용하는 어노테이션이 올바르게 적용되어 있는지 확인합니다. URI 경로 변수와 메소드 인자간의 매칭이 정확한지 확인하세요. -parameters 옵션은 매개 변수 정보를 런타임에 사용할 수 있도록 하는 역할을 합니다.
  4. 디버깅 및 예외 핸들링:

    • 실행 시 예외가 발생할 수 있는 부분에서 try-catch를 이용해 보다 구체적인 예외를 핸들링해보세요. 이를 통해 어떤 입력 혹은 상태에서 문제가 발생하는지 확인할 수 있습니다.
  5. 관련 문제 참고:

위의 방법으로도 문제가 해결되지 않는다면, 테스트 코드가 호출하는 API의 경로와 데이터 구조까지 함께 검토해보시는 것을 추천합니다. 추가적인 로그나 예외 메시지를 제공해주시면 더 많은 도움을 드릴 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

0

쿠케님의 프로필 이미지
쿠케
지식공유자

잘 해결되었다니 다행입니다!

wisehero님도 함께 도움 주셔서 감사합니다!

초보 초보 개발자님의 프로필 이미지
초보 초보 개발자

작성한 질문수

질문하기