[인프런 워밍업 클럽 1기] BE 4일차

[인프런 워밍업 클럽 1기] BE 4일차

[인프런 워밍업 클럽 1기] BE 4일차

본 게시글은 다음 강의 내용을 진행하고 있습니다.

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] - https://inf.run/XKQg

문제 1

구현 과정

  • 구현 목표 : 과일 정보를 입력해 요청하면 상태코드 반환하여 응답함.

  • 메서드 타입 : POST

  • 경로 : /api/v1/fruit

  • HTTP 요청 Body : { "name" : String, "warehousingDate" : LocalDate, "price" : long }

     

SQL 쿼리문

create table fruit
(
    id              bigint auto_increment,
    name            varchar(30),
    warehousingDate date,
    price           bigint,
    status          boolean default false,
    primary key (id)
);

FruitController.java

package com.group.libraryapp.controller.assingment2.fruit;

import com.group.libraryapp.dto.assignment2.request.FruitRequest;
import com.group.libraryapp.dto.assignment2.request.SoldRequest;
import com.group.libraryapp.dto.assignment2.response.SalesSumResponse;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
public class FruitController {

    private final JdbcTemplate jdbcTemplate;

    public FruitController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/api/v1/fruit")
    public void saveFruit(@RequestBody FruitRequest request) {
        String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
        jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice());
    }

FruitRequest.java

package com.group.libraryapp.dto.assignment2.request;

import java.time.LocalDate;

public class FruitRequest {

    private long id;
    private String name;
    private LocalDate warehousingDate;
    private long price;

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public LocalDate getWarehousingDate() {
        return warehousingDate;
    }

    public long getPrice() {
        return price;
    }
}

한 걸음 더 

API에서 long을 사용한 이유

  • null을 사용할 수 있다.

int를 사용할 경우 기본값이 0이여서 값이 없어서 0으로 초기화 된건지, 실제 값이 0인지 데이터만 보고 판별하기 어려운 문제점이 있다.

반면 Long을 사용할 경우 값이 없으면 null로 초기화되고, 실제 값이 0이면 0으로 저장되기 때문에 값의 유무를 쉽게 판별할 수 있다는 점에서 Long을 주로 사용한다.

  • int보다 더 넓은 범위의 값을 제공한다.

정수형 타입 : 데이터의 표현 범위

Int : -2,147,483,648 ~ 2,147,483,647

Long : -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

대규모 데이터를 처리하는 경우 데이터의 범위가 중요한데, long 자료형은 int 자료형 보다 월등히 더 넓은 범위의 값을 제공한다.

문제 2

구현 과정

  • 구현 목표 : id를 입력해 요청하면 상태코드 반환하여 응답함.

  • 메서드 타입 : PUT

  • 경로 : /api/v1/fruit

  • HTTP 요청 Body : { "id" : long }

SoldRequest.java

package com.group.libraryapp.dto.assignment2.request;

public class SoldRequest {
    private long id;

    public long getId() {
        return id;
    }
}

++FruitController.java

 ...
    @PutMapping("/api/v1/fruit")
    public void updateFruit(@RequestBody SoldRequest request) {
        String readSql = "SELECT * FROM fruit WHERE id = ?";

        boolean isFruitNotExist = jdbcTemplate.query(readSql, (rs, rowNum) -> 0, request.getId()).isEmpty();
        if (isFruitNotExist) {
            throw new IllegalArgumentException();
        }

        String updateSql = "UPDATE fruit SET is_sold  = true WHERE id = ?";
        jdbcTemplate.update(updateSql, request.getId());
    }
...

문제 3

구현 과정

  • 구현 목표 : 과일 정보를 입력해 요청하면 팔린 금액, 팔리지 않은 금액을 반환하여 응답함.

  • 메서드 타입 : GET

  • 경로 : /api/v1/fruit/stat

  • HTTP 요청 Body : { "salesAmount" : long, "notSalesAmount" : long }

SalesSumResponse.java

package com.group.libraryapp.dto.assignment2.response;

public class SalesSumResponse {

    private long salesAmount;
    private long notSalesAmount;

    public SalesSumResponse(long salesAmount, long notSalesAmount) {
        this.salesAmount = salesAmount;
        this.notSalesAmount = notSalesAmount;
    }

    public long getSalesAmount() {
        return salesAmount;
    }

    public long getNotSalesAmount() {
        return notSalesAmount;
    }
}

++FruitController.java

@GetMapping("/api/v1/fruit/stat")
public SalesSumResponse getAmountInfo(@RequestParam String name) {
    String sql = "SELECT * FROM fruit WHERE name = ?";
    List<SumResponse> list = jdbcTemplate.query(sql, (rs, rowNum) ->
            new SumResponse(rs.getLong("price"), rs.getBoolean("status")), name);

    long salesAmount = list.stream()
            .filter(SumResponse::status)
            .mapToLong(SumResponse::getPrice)
            .sum();

    long notSalesAmount = list.stream()
            .filter(res -> !res.status())
            .mapToLong(SumResponse::getPrice)
            .sum();

    return new SalesSumResponse(salesAmount, notSalesAmount);
}

한 걸음 더

sum, group by 키워드를 사용해 구현하기

++FruitController.java

...
    @GetMapping("/api/v1/fruit/stat")
    public SalesSumResponse statFruit(@RequestParam String name) {

        String salesSql = "SELECT sum(price) FROM fruit WHERE is_sold = true GROUP BY name HAVING name = ?";
        String notSalesSql = "SELECT sum(price) FROM fruit WHERE is_sold = false GROUP BY name HAVING name = ?";

        long salesAmount = jdbcTemplate.queryForObject(salesSql, long.class, name);
        long notSalesAmount = jdbcTemplate.queryForObject(notSalesSql, long.class, name);

        return new SalesSumResponse(salesAmount, notSalesAmount);
    }
...

JPA Entity클래스에서 id를 int가 아닌 Long 타입으로 하는 이유 (tistory.com)

댓글을 작성해보세요.