본문 바로가기

개발 일지

[TIL]이노베이션 캠프 17일차

Spring 입문 주차 8.12(금) ~ 8.18(목)

1. 개인 과제: 게시판 CRUD 기능을 하는 백엔드 서버 만들기, AWS 배포
2. 팀 과제: Spring 핵심 키워드 정리(필수 4개, 선택 4개)

 

진행 계획

- 12일(금) Spring 핵심 키워드 정리

- 13일(토) Spring 핵심 키워드 정리

- 14일(일) 개인과제에 필요한 강의 수강 및 공부

- 15일(월) API 명세서 작성, Use Case 그리기

- 16일(화) 게시판 CRUD 기능 코드 작성

- 17일(수) 게시판 CRUD 기능 코드 작성

- 18일(목) 게시판 CRUD 기능 코드 작성 및 AWS 배포

 

 

1. 개인 과제 진행 상황

 

1) 게시글 수정 및 삭제 기능 구현 

  • PostController 수정
@RequiredArgsConstructor  // final로 선언된 멤버 변수 자동 생성
@RestController // JSON으로 응답 반환
public class PostController {

    private final PostRepository postRepository; // postRepository를 멤버 변수로 하고, 필수로 필요하니까 final

    // 전체 게시글 목록 조회  
    @GetMapping("/api/posts") // /api/posts Get요청
    public List<Post> getPost() { // Post에 List를 반환하는 getPost()메소드를 실행해라
        return postRepository.findAll(); //postRepository에서 findAll해서 전부 찾아 반환
    }
        
    // 게시글 작성
    @PostMapping("/api/posts") // /api/posts Post요청, PostMapping으로 같은 주소라도 방식이 다름을 구분
    public Post createPost(@RequestBody PostRequestDto requestDto) { //  RequestBody: 요청 받는 형태
        Post post = new Post(requestDto); // 저장은 Dto가 아니라 Post, Dto의 정보를 post에 담아야 합니다.
    return postRepository.save(post); // JPA를 이용하여 DB에 저장하고, 그 결과를 반환합니다.
    }
    
    // 게시글 조회
    @GetMapping("/api/posts/{id}") // /api/posts/{id} Get요청
    public Post getPost(@PathVariable Long id)
       return postService.getPost(id)
        
    // 게시글 수정
    @PutMapping("/api/posts/{id}") // 이 주소로 수정 요청이 오면 updatePost메소드 실행해라, "{변수명}"은 값이 유동적일 때 사용
    public Long updatePost(@PathVariable Long id, @RequestBody PostRequestDto requestDto) { // @PathVariable는 위 "{중괄호}" 유동적 값
    return courseService.update(id, requestDto);
    }

    // 게시글 삭제
    @DeleteMapping("/api/posts/{id}") //이 주소로 삭제 요청이오면 deletePost메소드 실행
    public Long deletePost(@PathVariable Long id) {
        postRepository.deleteById(id);
    return id;
    }
    
    // 게시글 비밀번호 확인
    @PostMapping("/api/posts/{id}")
    public ResponseDto<?> validateAuthorByPassword(@PathVariable Long id, @RequestBody String password) {
        return postService.validateAuthorByPassword(id, password);
    }
}

 

  • 응답 데이터를 전달할 Dto 생성: ResponseDto
@Getter
@AllArgsConstructor
public class ResponseDto<T> {
    private boolean success;
    private T data;
    private Error error;

    public static <T> ResponseDto<T> success(T data) {
        return new ResponseDto<>(true, data, null);
    }

    public static <T> ResponseDto<T> fail(String code, String message) {
        return new ResponseDto<>(false, null, new Error(code, message));
    }

    @Getter
    @AllArgsConstructor
    static class Error {
        private String code;
        private String message;
    }

}

 

 

  • 실제 비즈니스 로직이 실행되는 서비스 생성: PostService
@Service // 스프링에게 이 클래스는 서비스임을 명시
public class PostService {

    // final: 서비스에게 꼭 필요한 녀석임을 명시(final은 한번 값이 부여되면 변경 불가)
    private final CourseRepository courseRepository;

    // 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록 스프링에게 알려줌
    // 클래스에 @RequiredArgsConstructor을 쓰면 생략 가능
    public CourseService(CourseRepository courseRepository) {
        this.courseRepository = courseRepository;
    }

    @Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌
    public Long update(Long id, Post post) {
        Post post = postRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
        );
        post.update(post);
        return post.getId();
    }
    
    // 비밀번호 확인
    @Transactional(readOnly = true)
    public Long validateAuthorByPassword(Long id, String password) {
        Optional<Post> optionalPost = postRepository.findById(id);

        if (optionalPost.isEmpty()) {
            return ResponseDto.fail("NOT_FOUND", "post id is not exist");
        }

        Post post = optionalPost.get();

        if (!post.getPassword().equals(password)) {
            return ResponseDto.fail("PASSWORD_NOT_CORRECT", "password is not correct");
        }

        return post.getId();
    }
}

 

 

2) 개인 과제 코드 관련 질문과 답변

  1. 수정, 삭제 API의 request를 어떤 방식으로 사용하셨나요? (param, query, body)

👉🏻  수정의 게시글 id값은 @PathVariable, 수정 할 내용은 @RequestBody를 이용해서 받음

👉🏻  삭제 할 게시글 id를 @PathVariable를 이용해서 받음

 

  1. 어떤 상황에 어떤 방식의 request를 써야하나요?

👉🏻 param: id값을 받아서 id값에 관한 기능을 구현하기 위해서 사용

👉🏻 query: 검색, 정렬을 해야 하는 경우 사용

👉🏻 body: 데이터가 많거나, 인수가 길 때, urI에 노출하면 안되는 정보일 경우 사용

 

  1. RESTful한 API를 설계했나요? 어떤 부분이 그런가요? 어떤 부분이 그렇지 않나요?

👉🏻   요청하는 URI를 보면 직관적으로 어떤 기능에 대한 로직을 처리 할 지 예상 가능하고, 같은 URI이지만 메소드(GET, POST, PUT, DELETE)에 따라 어떤 다른 기능을 함

 

  1. 적절한 관심사 분리를 적용하였나요? (Controller, Repository, Service)

👉🏻  컨트롤러에서 처리할 수 있는 로직은 바로 컨트롤러에서 처리하고, 수정이나 조회가 필요한 부분은 서비스에서 기능이 구현되도록 하였음, 데이터는 리포지토리에서 관리되도록 함, 하지만 컨트롤러는 창구 역할을 하기 때문에 서비스에 구현했어도 좋았을 것 같다.

 

  1. 작성한 코드에서 빈(Bean)을 모두 찾아보세요!

👉🏻  @Controller, @Service, @Repository 어노테이션을 달고 있는 것은 모두 @Component를 상속받기 때문에 빈으로 등록된다.

 

  1. API 명세서 작성 가이드라인을 검색하여 직접 작성한 명세서와 비교해보세요!

👉🏻  URI 설계 시 주의사항

  1) 슬래시 구분자(/)는 계층 관계를 나타내는데 이용한다.
  2) URI 마지막 문자 뒤에 슬래시 구분자(/)를 포함하지 않는다.
  3) URI 경로에는 대문자보다 소문자를 사용하여 나타낸다.
  4) 파일 확장자의 구호를 포함하지 않는다.

 

2. 개발 중 발생한 이슈와 해결

  • ARC URL연결 문제

The requested URL can’t provide a secure connection The URL sent an invalid response.

Learn more about this problem. net::ERR_SSL_PROTOCOL_ERROR

The requested URL can&rsquo;t provide a secure connection에러

해결방법: URL https://localhost8080/api/courses에서 http로 변경해서 연결

 

3. 새로 배운 것

ARC(Advanced REST Client): API를 만들고 나서 테스트 및 기능 확인하는 툴 종류 중 하나

 

 

4. 오늘 한 일 / 회고

- 개인 과제: 게시글 수정, 삭제 기능 구현, 비밀번호 조회 기능 구현

 

 

5. TO-DO LIST

- 개인 과제: 테스트 코드 구현

- AWS 배포 완료

- Spring 입문 주차 과제 제출 완료