본문 바로가기
스터디/인프런

[인프런 워밍업 스터디 클럽 0기- BE] 4일차 과제

by 행복한라이언 2024. 3. 11.
728x90
반응형

공통

spring:
  datasource:
    url: "jdbc:mysql://localhost/library"
    username: "root"
    password: ""
    driver-class-NAME: com.mysql.cj.jdbc.Driver
  • 기존의 application.yml 파일 활용
    • library 라는 database에 fruit 테이블 생성
create table fruit (
    id bigint auto_increment,
    name VARCHAR(25),
    warehousingDate DATE,
    price long,
    status VARCHAR(20),
    primary key (id)
);
  • id: '과일 판매'라는 이벤트가 발생할 때 백엔드가 받는 값은 id이다. 따라서 id를 컬럼을 추가했다. id는 과일 고유 번호이므로 auto_increment와 primary key 설정을 한다.
  • name: String 타입
  • warehousingDate: "2024-03-12"타입의 데이터를 받으므로 DATE 타입 
  • price: long 타입
    • 왜 int를 사용하지 않고 long 타입을 사용하였는가?
  • status: 과일의 판매 상태 기록
    • SELL - 판매 / NOT SELL - 미판매
    • fruit 테이블에 작성한 이유: 문제 2번에서 과일이 판매 발생하면 id가 넘어오면서 기록해야한다. 원래 history table을 하나 더 작성해서 기록한 후에 join을 하는 것이 적절해 보인다. 
    • 하지만 과제 요구사항은 과일이 판매될 때 사용해야하는 HTTP Method는 PUT이다. PUT은 수정을 의미하므로 history table에 기록을 생성하는 것과는 맞지 않다.
    • 따라서 방법은 2가지이다. saveFruit할 때 history table에 같이 기록을 한다. 또는 fruit table에 status를 기록한다. 나는 두 번째 방법을 사용한다.
    private final JdbcTemplate jdbcTemplate;

    public ThirdAssignmentController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
  • DB를 사용하기 위해서 JdbcTemplate 가져오고 ThirdAssignmentController에 jdbcTemplate를 파라매터로 받는 기본 생성자 생성

1.  문제 1번

 

    @PostMapping("/api/v1/fruit")
    public void saveFruit(@RequestBody FruitCreateRequest request) {
        String sql = "insert into fruit (name, warehousingDate, price, status) values (?, ?, ?, ?)";
        jdbcTemplate.update(sql, request.getName(), request.getWarehosuingDate(), request.getPrice(), "NOT SELL");

    }
  • HTTP Method: POST
  • PATH: /api/v1/fruit
  • SQL: insert into fruit (name, warehousingData, price, status) values (?, ?, ?, ?)
  • JdbcTemplate - update: SQL연산을 통해 DB갱신할 때(INSERT, DELETE, UPDATE) 사용하는 메서드 
    • DTO - FruitCreateRequest 생성 - name. warehousingDate, price를 가진 객체
    • status - 'NOT SELL'


2. 문제 2번

 

    @PutMapping("/api/v1/fruit")
    public void updateFruit(@RequestBody FruitUpdateRequest request) {

        String sql = "update fruit set status=? where id=?";
        jdbcTemplate.update(sql, request.getStatus(), request.getId());
    }

 

  • HTTP Method: PUT
  • HTTP Path: /api/v1/fruit
  • SQL: update fruit set status=? where id=?
    • 판매된 과일의 id를 통해서 status 업데이트
  • JdbcTemplate - update: SQL연산을 통해 DB갱신할 때(INSERT, DELETE, UPDATE) 사용하는 메서드 
    • DTO - FruitUpdateRequest - id와 Status를 가진 객체


3. 문제 3번

    @GetMapping("api/v1/fruit/stat")
    public SalesAmountResponse getSalesAndNonSalesAmount(@RequestParam String name) {
        String readSql = "select status, sum(price) as PRICE from fruit where name=? group by status";
        List<StatusAndAmountResponse> result = jdbcTemplate.query(readSql, new Object[]{name}, new RowMapper<StatusAndAmountResponse>() {
            @Override
            public StatusAndAmountResponse mapRow(ResultSet rs, int rowNum) throws SQLException {
                String status = rs.getString("status");
                long price = rs.getLong("PRICE");
                return new StatusAndAmountResponse(status, price);
            }
        });

        Map<String, Long> salesAmount = new HashMap<>();
        for (StatusAndAmountResponse response : result) {
            salesAmount.put(response.getStatus(), response.getAmount());
        }
        SalesAmountResponse response = new SalesAmountResponse(salesAmount.getOrDefault("SELL", 0L), salesAmount.getOrDefault("NOT SELL", 0L));

        return response;

    }
  • HTTP Method: GET 
    • GET이므로 qurey로 요청
    • DTO 생성 대신 @RequestParam 으로 요청 : name 만 받으므로 DTO 생성까지 할 필요는 없어보인다.
  • HTTP Path: api/v1/fruit/stat
  • SQL: select status, sum(price) as PRICE from fruit where name=? group by status
    • 해석: status로 group by를 한 후에 sum을 통해서 각 상태(SELL, NOT SELL)의 price를 sum한다.
  • ★JdbcTemplate - query - SELECT 시 여러 row를 처리할 수 있는 메서드
    • 한 개의 row 씩 처리한 후에 List에 담는다.
    • 한 개의 row 처리 → 결과(status, price) new StatusAndAmountResponse(status, price) DTO 생성
    • List<StatusAndAmountResponse> result라는 리스트에 DTO들이 들어간다!
    • 여기서는 status가 SELL, NOT SELL 이므로 row 2개다. 따라서 result에는 2개의 객체 존재
    • 결론: RowMapper에서 만들어진 StatusAndAmountResponse 객체는 JdbcTemplate에 의해서 List에 추가되며 작업을 모두 마치면 모든 row를 처리한 결과가 담긴 List<StatusAndAmountResponse> result가 생성된다.
  • HTTP Response Body의 예시처럼 만들어야 한다.
    • 현재 result 안에 StatusAndAmountResponse 객체는 status필드와 amount필드로 존재한다.
    • 우리가 필요한건 SELL과 NOT SELL의 amount 한 번에 조회해야한다.
    • 이를 위해서 SalesAmount DTO 객체 생성 - salesAmount필드와 noSalesAmount를 가지고 있다.
    • result를 For문을 돌려 Map 콜렉션 생성 - key(sell) - value(amount)로 구성
      • SELL - salesAmount필드
      • NOT SELL - nonSalesAmount필드
728x90
반응형