Springboot + JPA 날짜(LocalDate)를 활용한 Json 변환 및 조회

김도훈 - DevOps Engineer·2022년 4월 20일
0

Spring Boot

목록 보기
3/3
post-thumbnail
post-custom-banner

Json을 입력받아 LocalDate 타입으로 변환 후 컨트롤러 로직을 실행


  • Controller
 @PostMapping("/revenueExpenditure")
    public ResponseEntity<CreateRevenueExpenditureResponse> addRevenueExpenditure(@RequestBody CreateRevenueExpenditureRequest request) {
        return ResponseEntity.ok(new CreateRevenueExpenditureResponse(assetService.addRevenueExpenditure(request)));
    }

  • RequestDto
@AllArgsConstructor
public class CreateRevenueExpenditureRequest {

    @ApiModelProperty(value = "수익, 지출 타입", example = "REVENUE", required = true)
    private RevenueExpenditureType revenueExpenditureType;

    @ApiModelProperty(value = "해당 년월일", example = "2022-04-19", required = true)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "Asia/Seoul")
    private LocalDate date;

    @ApiModelProperty(value = "카테고리 이름", example = "월급", required = true)
    private String categoryName;

    @ApiModelProperty(value = "결제 수단", example = "신용 카드")
    private String paymentMethod;

    @ApiModelProperty(value = "금액", example = "6500", required = true)
    private int cost;

    @ApiModelProperty(value = "내용", example = "신전 떡볶이")
    private String content;

}

  • Service
    @Transactional
    public Long addRevenueExpenditure(CreateRevenueExpenditureRequest request) {
        User user = userUtil.findCurrentUser();

        return revenueExpenditureRepository.save(RevenueExpenditure.builder()
                .revenueExpenditureType(request.getRevenueExpenditureType())
                .content(request.getContent())
                .cost(request.getCost())
                .date(request.getDate())
                .categoryName(request.getCategoryName())
                .paymentMethod(request.getPaymentMethod())
                .user(user)
                .build()).getId();
    }

  • RequestBody 에서 시간을 다음과 같이 보낼 수 있다.

  • date : 2022-05-30

위와 같이 LocalDate는 해당년도, 월, 일 까지 지원한다.
그냥 Json으로 보낸다고 되는게 아니고 위의 RequestDto 에서 다음과 같이 포맷팅 설정을 해줘야한다.

   @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "Asia/Seoul")
    private LocalDate date;

이번엔 날짜를 QueryString 으로 보내서 조회


  • Controller
@ApiOperation(value = "수익 지출 내역 조회", notes = "해당 년 월, page, size 를 입력받아 한달 수익 지출 내역을 조회하는 API")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "해당 수익 지출 내역을 정상적으로 조회한 경우"),
            @ApiResponse(responseCode = "404", description = "회원 Id OR 예산 금액 Id를 찾지 못한 경우")
    })
    @ApiImplicitParam(name = "month", value = "해당 년 월", example = "2022-04", required = true)
    @GetMapping("/revenueExpenditure")
    public ResponseEntity<RevenueExpenditureSumResponse> getRevenueExpenditures(@RequestParam String month, Pageable pageable) {
        return ResponseEntity.ok(assetService.findRevenueExpenditureByMonth(month, pageable));
    }
  • 필자는 한 달 단위로 모든 정보를 가져오는 API를 만드는데, LocalDate 타입은 해당 년, 월, 일을 다 적어줘야 하기 때문에 String으로 값을 받았다.

  • Service
public RevenueExpenditureSumResponse findRevenueExpenditureByMonth(String month, Pageable pageable) {
        User user = userUtil.findCurrentUser();

        Page<RevenueExpenditureResponse> revenueExpenditure = revenueExpenditureRepository.findRevenueAndExpenditureByMonth(LocalDate.parse(month + "-01"), pageable, user.getId());

        Budget budget = budgetRepository.findBudgetAmountByUserId(user.getId())
                .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_BUDGET));

        List<RevenueExpenditure> revenueExpenditureList = revenueExpenditureRepository.findRevenueExpenditure(LocalDate.parse(month + "-01"), user.getId());

        int revenue = getRevenueExpenditure(revenueExpenditureList, TYPE_REVENUE);
        int expenditure = getRevenueExpenditure(revenueExpenditureList, TYPE_EXPENDITURE);
        int remainingBudget = budget.getBudgetAmount() - expenditure;

        return RevenueExpenditureSumResponse.of(revenue, expenditure, remainingBudget, revenueExpenditure);

    }

    /**
     * 수익 지출 타입을 받아서 합을 반환해주는 메소드
     */
    private int getRevenueExpenditure(List<RevenueExpenditure> revenueExpenditureList, String type) {
        return revenueExpenditureList
                    .stream()
                    .filter(r -> r.getRevenueExpenditureType().toString().equals(type))
                    .mapToInt(RevenueExpenditure::getCost)
                    .sum();
    }
  • Service 로직에서 String 받은 파라미터를 LocalDate.parse를 이용해서 바인딩 해주었다.

  • QueryDSL 코드
public Page<RevenueExpenditureResponse> findRevenueAndExpenditureByMonth(LocalDate month, Pageable pageable, Long userId) {

        List<RevenueExpenditureResponse> content = queryFactory
                .select(new QRevenueExpenditureResponse(
                        revenueExpenditure.date,
                        revenueExpenditure.categoryName,
                        revenueExpenditure.content,
                        revenueExpenditure.paymentMethod,
                        revenueExpenditure.cost
                ))
                .from(revenueExpenditure)
                .innerJoin(revenueExpenditure.user, user)
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .where(revenueExpenditure.date
                        .between(month.withDayOfMonth(1), month.withDayOfMonth(month.lengthOfMonth()))
                        .and(user.id.eq(userId)))
                .orderBy(revenueExpenditure.date.desc())
                .fetch();

        long countQuery = queryFactory
                .selectFrom(revenueExpenditure)
                .where(revenueExpenditure.date
                        .between(month.withDayOfMonth(1), month.withDayOfMonth(month.lengthOfMonth()))
                        .and(user.id.eq(userId)))
                .fetchCount();

        return PageableExecutionUtils.getPage(content, pageable, () -> countQuery);

    }
  • LocalDate 타입으로 넘겨받은 후 between으로 1일부터 말일까지의 데이터를 가져왔다.

Postman 테스트 결과

  • 위와 같이 해당 년, 월 까지만 받으려면 LocalDate를 사용할 수 없어서 어쩔 수 없이 컨트롤러에서 String으로 받아서 Service 로직에서 파싱을 해주었다.
profile
Email:ehgns5669@gmail.com
post-custom-banner

0개의 댓글