Spring Boot - 7

현곤·2024년 12월 18일

@PostMapping

post 처리를 한다 = post는 CRUDCreate

그리고 Mapping은 @GetMapping과 동일하게 URL 매핑을 담당하지만

POST 요청을 처리하는 경우에 사용

그러고보니 GET은 읽는다인가????? 오 맞네

GET /api/v1/posts : 주세요 글들을
GET /api/v1/posts/3 : 3번 글 주세요
DELETE /api/v1/posts/3 : 3번 글 삭제해주세요

@PostMapping(value ="/create/{id}")

이렇게 안하고 value 생략 가능함

@PostMapping("/create/{id}")

^^bbbb

@RequsetParam << 저번에 사용했던 것 중 하나

그냥 콕 찝어서 이거다 라고 할 때 사용했던 것 같음


구성 요소 2가지

  • 내부처리 (눈에 보이지 않는 부분)

  • UI (눈에 보이는 부분)


앱을 만드는 방식 2가지

MPA 방식

백엔드 개발자가 스프링부트로 내부처리와 UI를 모두 구현 (둘 다 하기)

  • 결과물 : 웹 사이트
  • 멀티 페이지 앱(Multi Page Application)
  • 이때 UI를 구현하기 위해서 타임리프나 JSP 같은 템플릿 엔진을 사용한다.
  • 아래 방식(SPA)보다 백엔드 개발자가 해야할 일이 더 많다.
    - 왜냐하면, 백엔드 개발자가 UI도 작업하고 신경써야함

SPA 방식

백엔드 개발자는 스프링부트로 내부처리만 구현하고 UI는 프론트엔드 개발자가 구현

  • 결과물 : 앱 같은 웹 사이트
  • SPQ 방식에서 백엔드 부분의 구현을 REST API 구현 이라고 한다.
  • 프론트엔드 개발자는 보통 리액트, 뷰, 앵귤러, 스벨트 같은 프론트엔드 프레임워크
    (혹은 라이브러리)를 사용한다.
  • 위 방식(MPA)보다 백엔드 개발자가 해야할 일이 적다.
    - 백엔드 개발자가 UI 부분을 신경쓰지 않아도 됨

@REQUESTBODY

요건 스트링부트 입장에선 편지를 받은 것과 같음

Request : 클라이언트가 서버에게 보내는 요청 (편지)

Response : 서버(스프링부트)가 클라이언트에게 보내는 응답 (편지)


Request 헤더 : 요청에 대한 메타데이터(부가정보)를 담는 곳

예시 )
Content-Type:application/json

Request 바디 : 요청의 실제 내용을 담는 곳

예시 )
{"title" : "제목", "content" : "내용"}


API 양식 바꾸지마라

프론트엔드 개발자가 싫어한다

원래 숫자가 10, 20이었는데 이걸 내가 임의로 30, 40으로 수정해버리면

바뀐 API 양식으로 소스코드를 수정해야 한다.

나같아도 싫을듯

그래서 엔티티 객체를 REST API 를 통해 노출하지 않고

따로 DTO 클래스를 만들어 노출하는 것이 좋다.

DTO 를 사용하면 보안, 유지보수성, 성능 면에서 유리하고,
API 응답 구조를 유연하게 제어할 수 있다.

  1. DTO 클래스 정의

필요한 데이터만 담아 클라이언트에 전달하도록 설계된 클래스

보통 엔티티 클래스와 비슷한 구조를 가지지만, 엔티티와 1:1 매핑이 아닌 경우도 많다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class PostDto {
    private Long id;
    private String title;
    private String content;
    private LocalDateTime createdDate;
    private LocalDateTime modifiedDate;
}
  1. 서비스 계층에서 DTO 변환 로직을 추가하기

엔티티 객체를 DTO로 변환하는 작업은 일반적으로 서비스 계층에서 수행된다.

변환하기 위해 엔티티를 DTO로 변환하는 메서드를 작성한다.

@Service
@RequiredArgsConstructor
public class PostService {
    private final PostRepository postrepository;
    
    public List<PostDto> findAllPosts() {
        return postrepository.findAllByOrderByIdDesc()
                .stream()
                .map(this::convertToDto)
                .collect(Collector.toList());
    }
    
    public PostDto findPostById(long id) {
        Post post = postrepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Post not found"));
        return convertToDto(post);
    }
    
    private PostDto convertToDto(Post post) {
        return new PostDto(
                post.getId(),
                post.getTitle(),
                post.getContent(),
                post.getCreatedAt(),
                post.getModifiedAt()
        );
    }
  1. 컨트롤러에서 DTO 반환하기

컨트롤러는 DTO를 반환하도록 변경,

서비스 게층에서 반환된 DTO를 반환받아 클라이언트에게 전달

@RestController
@RequestMapping("/api/v1/posts")
@RequiredArgsConstructor
public class ApiV1PostController {
    private final PostService postService;

    @GetMapping
    public List<Post> getItems() {
        return postService.findAllPosts();
    }

    @GetMapping("/{id}")
    public Post getItem(
            @PathVariable long id
    ) {
        return postService.findPostById(id);
    }
  1. 요청 처리시 DTO 사용하기

클라이언트가 데이터를 전달할 때도 DTO를 사용한다.

이렇게 하면 API 인터페이스와 내부 도메인 간의 명확한 분리가 가능하다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PostCreateRequsetDto {
	@NotBlank
    @Length(min = 2)
    private String title;
    
    @NotBlank
    @Length(min = 2)
    private String content;
@PostMapping
public RsData createItem(@RequestBody @Valid PostCreateRequestDto requestDto) {
	Post post = postService.createPost(
    requestDto.getTitle(),
    requestDto.getContent()
    );
    
    return new RsData("200-1", "%d번 글이 작성되었습니다.".formatted(post_getId()));
}
  1. DTO 변환 자동화 (Optinal)

ModelMapper 또는 MapStruct 사용

수동으로 변환 메서드를 작성하는 대신, DTO와 엔티티 간의 변환을 자동화할 수 있다.

  • ModelMapper
@Bean
public ModelMapper modelMapper() {
	return new ModelMapper();
}

// 변환
PostDto postDto = modelMapper.map(post, PostDto.class);
  • MapStruct
@Mapper
public interface PostMapper {
	PostMapper INSTANCE = Mappers.getMapper(PostMapper.class);
    
    PostDto toDto(Post post);
    Post toEntity(PostDto postDto);
}

이렇게 하면 뭐가 좋은가

  1. 보안 : 엔티티에 민감한 정보(비밀번호 등)가 포함되어 있어도 DTO에 포함되지 않음으로써 노출을 방지

  2. API 구조 유연성 : 클라이언트 요구에 맞게 DTO를 설계 가능

  3. 유지보수성 : 엔티티 변경이 API에 영향을 미치지 않음

  4. 데이터 최적화 : 필요한 데이터만 클라이언트로 전송하여 성능을 향상


인터넷 (Internet)

Local Area Network (LAN)

  • 근거리 통신망, 구내 정보 통신망은 네트워크 매체를 이용하여
    집, 사무실, 학교 등의 건물과 같은 가까운 지역을 한데 묶는 컴퓨터 네트워크

MAN(Metropolitan Area Network), WAN(Wide Area Network) 등이 있다

그러면 학교에 있던 컴퓨터들도 다 랜으로 묶여있었다 라고 생각하면 되겠다

인터넷 (Internet)컴퓨터 네트워크들을 서로 연결 지여주는 범지구적 네트워크

(= Inter-Network = 컴퓨터 네트워크들의 네트워크)

인터넷 안에 컴퓨터 네트워크가 있는 거??

이렇게 구축이 된 인터넷이라는 거대한 네트워크 위에서
우리가 사용하는 다양한 서비스들이 동작한다.

이메일도 보내고 웹도 사용하고 등등

인터넷이라는 네트워크 인프라가 갖춰졌기 때문에,
이를 활용한 서비스들이 동작할 수 있는 것

웹이 없어도 인터넷은 존재하지만 인터넷이 없으면 웹은 존재하지 않는다

profile
코딩하는 곤쪽이

0개의 댓글