일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 좋은 코드 나쁜 코드
- 구현
- 수신자 대상 다르게
- 트랜잭샨
- 깊게 생각해보기
- 코드 계약
- BFS
- jwt 표준
- 완전탐색
- piplining
- 숫자 블록
- 이분탐색
- branch 전략
- 셀러리
- AWS
- 객체지향패러다임
- 검색어 추천
- 레디스 동시성
- 누적합
- prg 패턴
- 백준
- docker
- 쿠키
- 알람 시스템
- spring event
- gRPC
- 결제서비스
- 카카오
- 디버깅
- 프로그래머스
- Today
- Total
코딩관계론
[실무 역량 과제] 신규 유형 (BE) 본문
문제 이해하기
Get 요청으로 다음과 같은 URI가 있고, 쿼리 파람을 통해서 예약 상태를 조회하고자 한다. 이 때 주어지는 조건이 여러가지 있는데 모두를 만족시켜야 한다.
@GetMapping("/api/reservation/search")
문제 해결 방법
쿼리파람을 DTO 객체에 리플렉션하기
쿼리파람을 DTO 객체에 리플렉션을 하려면 객체의 기본생성자가 존제해야 한다. 그 이유는 Spring이 기본 생성자를 사용하는 이유는 리플렉션을 통한 객체 생성의 필요성, 객체 상태 초기화의 유연성, 데이터 바인딩의 일관성을 유지하기 위해서입니다. 기본 생성자가 없으면 이러한 과정을 수행할 수 없기 때문에, DTO 클래스에는 반드시 기본 생성자가 필요합니다.
1. 객체 생성의 일관성
기본 생성자를 통해 객체를 생성하면, Spring은 모든 파라미터를 가진 생성자와 독립적으로 객체를 생성할 수 있습니다. 이를 통해 데이터 바인딩 과정에서 다양한 요청 파라미터를 일관되게 처리할 수 있습니다.
2. 리플렉션(Reflection)을 통한 객체 생성
Spring의 데이터 바인딩 메커니즘은 리플렉션을 사용하여 객체를 생성하고 필드를 설정합니다. 리플렉션을 통해 객체를 생성하려면 기본 생성자가 필요합니다. 기본 생성자가 없으면 리플렉션을 사용하여 객체를 생성할 수 없습니다.
3. 객체 상태 초기화
기본 생성자는 객체를 초기화하는 데 사용됩니다. Spring은 기본 생성자를 호출하여 객체를 생성한 후, setter 메서드를 통해 각 필드를 초기화합니다. 이렇게 하면 객체의 초기 상태를 설정하고, 이후 요청 파라미터에 따라 필드 값을 설정할 수 있습니다.
4. 유연한 데이터 바인딩
기본 생성자를 사용하면 다양한 필드 조합을 유연하게 처리할 수 있습니다. 모든 필드를 초기화하는 생성자가 있는 경우, 특정 필드가 없는 요청을 처리하기 어렵습니다. 기본 생성자를 사용하면 모든 필드를 초기화한 후, 필요한 필드만 설정할 수 있습니다.
문자열 비교
자바에서는 동등성 및 동일성의 개념이 있다.
간단하게 말하면 동일성은 "=="비교를 통해 주소 값을 비교하는 것이고, 동일성은 equals함수를 통해서 값으로 판별한다.(오버라이딩을 수행했다고 가정)
우리는 all 일때 와 name이 들어올때를 구분해야 하는데 동등성 비교를 위해서 equals로 비교를 진행해야 한다. 파이썬만을 사용하다보니 "=="을 무의식적으로 사용하면 왜 안되는지 디버깅하는데 시간을 잡아 먹었다.
그 후 all일때는 정렬을 통해서 값들을 오름차순으로 반환해야 한다. SORT 함수는 다음과 같이 작성할 수 있다.
List<ReservationDTO> reservationsDTO = reqDTO.stream().sorted((r1, r2) ->
r1.getCheckIn().compareTo(r2.getCheckIn())).collect(Collectors.toList());
sort함수를 확인해보면 *Compator 함수형 인터페이스를 구현하도록 해놨다.
public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T> arg0);
public abstract interface Comparator<T> {
public abstract int compare(T arg0, T arg1);
}
우리는 이 compare함수를 람다로 구현했다. 왜냐면 함수형 인터페이스이기 때문이다.
코드
package project;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@RestController
public static class ApiController {
private final String DATA_DIR = "../data/input";
private final ObjectMapper objectMapper = new ObjectMapper();
@GetMapping("/api/reservation/search")
public ResponseEntity<?> login(RequestDTO dto) {
try {
List<ReservationDTO> reqDTO = objectMapper.readValue(
Files.readAllBytes(Paths.get(DATA_DIR, "reservation.json")),
new TypeReference<List<ReservationDTO>>() {}
);
// 정렬
List<ReservationDTO> reservationsDTO = reqDTO.stream().sorted((r1, r2) -> r1.getCheckIn().compareTo(r2.getCheckIn())).collect(Collectors.toList());
if (dto.getCustomerName().isEmpty()){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseErrorDTO("customerName is required"));
}
if (dto.getCustomerName().equals("all")){
return ResponseEntity.status(HttpStatus.OK).body(reservationsDTO);
}
List<ReservationDTO> result = reservationsDTO.stream().filter(e -> e.getCustomerName().contains(dto.getCustomerName())).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK).body(result);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
public static class RequestDTO {
public String customerName;
public RequestDTO(){
customerName="";
}
public RequestDTO(String customerName) {
this.customerName = customerName;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
public static class ResponseErrorDTO {
public String error;
public ResponseErrorDTO(String error) {
this.error = error;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
public static class ReservationDTO {
public Integer id;
@JsonProperty("customer_name")
public String customerName;
@JsonProperty("check_in")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public Date checkIn;
@JsonProperty("check_out")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public Date checkOut;
public String status;
// 기본 생성자 추가
public ReservationDTO() {
}
// Getters and Setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public Date getCheckIn() {
return checkIn;
}
public void setCheckIn(Date checkIn) {
this.checkIn = checkIn;
}
public Date getCheckOut() {
return checkOut;
}
public void setCheckOut(Date checkOut) {
this.checkOut = checkOut;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
}
코드 리뷰
DTO 매핑을 위해선 반듯이 기본생성자가 필수다.
배운점 정리하기
왜 필수냐 리플렉션을 사용하려면 기본생성자로 객체를 생성해야 하며, 기본 생성자로 생성하면 객체의 다양성을 제공한다.
함수형 인터페이스(Functional Interface)를 구현할 수 있습니다. 함수형 인터페이스는 하나의 추상 메서드만을 가지는 인터페이스를 말합니다.
'개발 > Java' 카테고리의 다른 글
Thread Safety하게 만들자 (0) | 2024.06.09 |
---|---|
static, final 어디까지 알아보고 왔는가? (0) | 2024.06.09 |
JVM 메모리 구조 (0) | 2024.06.08 |
자바 어떻게 실행되는가? (0) | 2024.06.02 |
Java에서 equals와 hashCode 메서드를 재정의해야 하는 이유 (0) | 2024.05.27 |