activity/인프런 워밍업 클럽

[인프런 워밍업 클럽 0기] 네 번째 과제 - API 개발하기

dani0312 2024. 2. 22. 15:40

강의

데이터베이스를 사용해 만드는 API

`@PutMapping`과 `@DeleteMapping` 을 이용해 데이터베이스 테이블에 저장된 데이터를 수정, 삭제하는 API를 만드는 것에 대하여 학습하였다. 또한 삭제 시 존재하는 유저가 없을 경우 응답으로 오는 상태코드가 200OK가 아닌 500 Error가 발생하도록 에러 처리를 해주었다.


과제

우리는 GET API와 POST API를 만드는 방법을 배웠습니다. 👍 추가적인 API 들을 만들어 보며 API 개발에 익숙해져 봅시다! 

◾문제1

 

 

◾풀이

데이터베이스에서 fruit테이블을 우선 수정해주어야한다. 기존에는 아래처럼 이렇게 3개의 컬럼이 있었지만 

 

name, stocked_date,age → name, waringhousingDate, price 로 변경을 해주어야한다! 만일 fruit테이블이 없는 경우라면 지금처럼 컬럼을 변경하는 것이 아니라 새로 만들어주어야한다.

 

stocked_date와 age 컬럼을 지워준다.

ALTER TABLE fruit
DROP COLUMN stocked_date,
DROP COLUMN age;

 

waringhousingDate, price 컬럼을 추가해준다.

ALTER TABLE fruit
ADD COLUMN warehousingDate DATE,
ADD COLUMN price long;

 

테이블 변경 성공!

쿼리문 작성 후 데이터베이스에 들어가 새로고침해보니 성공적으로 컬럼이 잘 변경이 되었다. (처음에 분명 쿼리가 성공적으로 실행되었는데 db에서 새로고침을 몇 번해도 바로 반영이 안되서 당황했는데.. 조금 지나니 반영이 되었다.)

 

 

💡테이블명이 빨간색?

그리고 컨트롤러 안에서 String형으로 쿼리를 작성 시에 테이블 명이 빨간색으로 떠서 당황할 수 있는데 이는 alt+enter를 눌러 스키마를 선택해주면 된다. 자세한 내용은 아래 작성하였다.

2024.02.23 - [웹 개발/error] - [java] 쿼리 작성 시 테이블명이 빨간 색일 때 해결법

 

[java] 쿼리 작성 시 테이블명이 빨간 색일 때 해결법

테이블이 빨간색으로 표기되는 현상 에러는 아닌 듯 하지만 자바 코드 안에서 JdbcTemplate을 이용하여 mysql과 연동하여 사용하기 위해 쿼리를 작성하던 중 아래와 같이 테이블명에 빨간색이 들어

dani0312.tistory.com

 

 

🔻controller

@RestController
@RequestMapping("/api/v1")
public class FruitController {
    JdbcTemplate jdbcTemplate;

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

    // 과일 정보 저장 API
    @PostMapping("/fruit")
    public void saveFruit(@RequestBody FruitCreateRequest request){
        String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
        jdbcTemplate.update(sql,request.getName(),request.getWarehousingDate(),request.getPrice());
    }
}

 

🔻dto

public class FruitCreateRequest {
    private String name;
    private LocalDate warehousingDate;
    private long price;

    public String getName() {
        return name;
    }

    public LocalDate getWarehousingDate() {
        return warehousingDate;
    }

    public long getPrice() {
        return price;
    }
}

 

 

POSTMAN 요청 결과 200OK코드를 받았다. 데이터베이스에도 데이터가 잘 들어갔는지 살펴보니 입력한대로 데이터가 잘 들어가있다. (id가 2번부터인것은 auto_increment가 원래 이전데이터 삭제여부 상관없이 계속 증가하는 속성이기 때문이다.)

 

💡Id가 계속 증가한다? Auto_increment
데이터베이스에 값을 넣고, 삭제하고 다시 넣는 작업을 하다보니 이런 점을 발견했다. 
분명 데이터를 삭제하고 빈 테이블인 상태에서 값을 넣었는데 아래와 같이 이전에 삭제여부와 관계없이 ID값은 계속 증가하는 값이 들어가게 된다. 

Auto_increment설정은 알아보니 원래 이처럼 삭제 여부 관계 없이 계속해서 증가하는 숫자의 값이 들어가게 된다고 한다. 이것이 기본값인데, 만일 다시 데이터를 넣었을 때 1부터 증가하도록 설정하거나 빈 숫자를 채우려면 따로 설정을 해주면 가능하다고 한다. 그렇다면 실무에서는 어떤 방식을 쓸까? 이에 대해 코치님께 질문을 드렸다.

실무에서는 auto_increment 기본값을 사용하는 편이라고 한다. 왜냐하면 유저를 기록할 시 id는 유저를 구분하는 수단으로 사용이 되고(이름과 같은 속성은 중복이 될 수 있기 때문에), 이를 통해 추가 정보도 저장을 한다. 
그런데 만일 1번 유저를 지우고 새 유저를 그 유저가 가져던 Id인 1번을 할당한다면 이전 유저의 추가정보를 새 유저 1번이 가지게 된다..? 이슈가 발생하는 것이다. 

그래서 보통 계속 증가시켜주는 기본값을 사용하는 것이고 id는 int 대신 long형을 사용하는 편이라고 한다.

 

 

◾한 걸음 더 - long형을 쓰는 이유

자바에서 정수를 다루는 대표적인 두 가지 `int`형과 `long`형 중에 `long`형을 사용한 이유는 무엇일까?

 

실무에서도 보통 int형보다는 long형으로 필드를 선언해 사용한다고 한다. 이는 아래와 같이 long형이 더 큰 데이터까지 담을 수 있기 때문이다. 

 

int형 vs long형

int형의 범위:  -2,147,483,648에서 2,147,483,647 (약 21억)

long형의 범위: -9,223,372,036,854,775,808에서 9,223,372,036,854,775,807 (약 92억)

 

데이터베이스에서 사용되는 식별자(ID)는 일반적으로 `long`형을 사용한다. 이는 레코드 수가 많아질수록 `int`형의 범위를 초과할 수 있기 때문이다.


◾문제2

팔린 과일 정보의 id를 Body를 통해 요청하면 이르르 서버에서 fruit테이블의 정보를 변경해주어야하는 문제이다. fruit테이블에 과일이 팔린 정보를 추가해야하기 때문에 컬럼을 추가해주어야한다!

 

테이블에  'is_sold'  컬럼을 팔린 여부를 기록하기 위해 boolean형태의 값을 저장해야한다. 이를 mysql에서는 TINYINT(1)을 사용하여 boolean형태의 컬럼을 흔히 구현한다고 한다. 1또는 0값을 사용하여 참과 거짓을 표현한다.

ALTER TABLE fruit
ADD COLUMN is_sold TINYINT(1) NOT NULL DEFAULT 0;

 

테이블을 확인해보면 is_sold 컬럼이 잘 추가가 되었다.

 

 

◾풀이

🔻controller

이어진 문제이므로 문제1과 같이 FruitController에서 진행하고 있다.

@RestController
@RequestMapping("/api/v1")
public class FruitController {

	...
	// 과일 정보 변경 API
    @PutMapping("/fruit")
    public void updateFruit(@RequestBody FruitUpdateRequest request) {
        String sql = "UPDATE fruit SET is_sold = 1 WHERE id = ?";
        jdbcTemplate.update(sql, request.getId());
    }

 

🔻dto

public class FruitUpdateRequest {
    private long id;

    public long getId() {
        return id;
    }
}

 

POSTMAN에서 요청을 보내보니 다른 에러없이 200OK를 받았다

 

db를 확인해보니 is_sold의 값이 0에서 1로 성공적으로 바뀌었다!

 

 


 

◾문제3

 

 

◾풀이

특정 과일에 해당하는 데이터들 중 팔린 금액의 합, 팔리지 않은 금액의 합을 응답해주는 API를 만들어야한다. 우선 데이터베이스에 현재 데이터가 1개만 있으므로 데이터를 늘려주자.

INSERT INTO fruit (name,warehousingDate,price) values ('사과','2024-01-01',2000)
INSERT INTO fruit (name,warehousingDate,price) values ('사과','2024-03-12',1500)

 

 

DB테이블을 확인해보니 데이터가 잘 들어간 것을 확인할 수 있었다. 

\

 

🔻controller

쿼리를 이용해 Fruit객체를 List로 받아 이것을 반복문 처리하는 방법도 있겠지만, 아래처럼 쿼리에서 직접 합을 구하는 방법을 사용해보았다. 

    // 특정 과일의 팔린 총액과 팔리지 않은 총액 조회 API
    @GetMapping("/fruit/stat")
    public GetSalesAmountResponse getSalesAmount(@RequestParam String name){

        long soldPrice = jdbcTemplate.queryForObject("SELECT SUM(price) FROM fruit WHERE name = ? AND is_sold = 1",long.class,name);
        long notSoldPrice = jdbcTemplate.queryForObject("SELECT SUM(price) FROM fruit WHERE name = ? AND is_sold = 0", long.class, name);

        return new GetSalesAmountResponse(soldPrice,notSoldPrice);
    }

 

🔻dto

public class GetSalesAmountResponse {
    private long salesAmount;
    private long notSalesAmount;

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

    public long getNotSalesAmount() {
        return notSalesAmount;
    }

    public long getSalesAmount() {
        return salesAmount;
    }
}

 

POSTMAN에서 확인 결과 제대로 성공적으로 팔린금액과 팔리지 않은 금액의 합이 각각 제대로 출력되는 것을 확인할 수 있다.

 

 

 

🔨리팩토링

처음에는 값을 받아오는 것을 DTO를 따로 선언하여 요청 값을 받아오게 하였지만, 단일 파라미터이고 String값이기 때문에 아래처럼 @RequestParam을 사용하여 요청 데이터를 받아오도록 변경하였다. (String은 권장되지만, long형과 같은 값은 권장되지 않고 DTO를 사용하는 것이 좋다고 알고있다.)

	public GetSalesAmountResponse getSalesAmount(GetSalesAmountRequest request){  //before
	public GetSalesAmountResponse getSalesAmount(@RequestParam String name){  //after

 

 

 

 

 

잘못된 내용이 있다면 댓글로 알려주시면 감사하겠습니다❤️

좋은 하루 되세요😊 


Reference

자바와 스프링 부트로 생애 최초 서버 만들기 [서버 개발 올인원 패키지] / 최태현 / 인프런 강의