본문 바로가기
스터디공부/인프런 워밍업

인프런 워밍업 0기 여섯 번째 과제! (진도표 6일차)

by 파덕 2024. 2. 26.

문제 1

4일차 과제의 Controller를 Controller/Service/Respsitory로 분리하기

Controller

package com.group.libraryapp.controller.homework;

import com.group.libraryapp.service.fruit.FruitService;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;

@RestController
public class FruitController {

    private final FruitService fruitService;

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

    @PostMapping("/api/v1/fruit")
    public ResponseEntity<Object> saveFruit(@RequestBody CreateFruitRequest request) {
        Assert.notNull(request.getName(), "이름필수");
        Assert.notNull(request.getWarehousingDate(), "이름필수");
        Assert.isTrue(request.getPrice() > 0, "금액은 0보다 큽니다.");

        fruitService.saveFruit(request.getName(), request.getWarehousingDate(), request.getPrice());
        return ResponseEntity.ok().build();
    }

    public static class CreateFruitRequest {
        private String name;
        private LocalDate warehousingDate;
        private long price;

        public CreateFruitRequest() {
        }

        public String getName() {
            return name;
        }

        public LocalDate getWarehousingDate() {
            return warehousingDate;
        }

        public long getPrice() {
            return price;
        }
    }

    @PutMapping("/api/v1/fruit")
    public FruitSellResponse sellFruit(@RequestBody SellFruitRequest request) {
        Assert.isTrue(request.getId() > 0, "과일 정보 고유번호는 0 보다 큽니다.");
        long sellId = fruitService.sellFruit(request.getId());
        return new FruitSellResponse(sellId);
    }

    public static class FruitSellResponse {
        private long id;

        public FruitSellResponse(final long id) {
            this.id = id;
        }

        public long getId() {
            return id;
        }
    }

    public static class SellFruitRequest {
        private long id;

        public long getId() {
            return id;
        }
    }

    @GetMapping("/api/v1/fruit/stat")
    public FruitSalesResponse getSalesInfo(@RequestParam("name") String fruitName) {
        return fruitService.getSalesInfo(fruitName);
    }

    public static class Fruit {
        private long id;
        private String name;
        private long price;
        private String status;
        private String sell_status;

        private LocalDate warehousingDate;


        public Fruit(final String name, final long price, final String status,final String sell_status) {
            this.name = name;
            this.price = price;
            this.status = status;
            this.sell_status = sell_status;
        }

        public Fruit(final String name, final LocalDate warehousingDate, final long price) {
            this.name = name;
            this.warehousingDate = warehousingDate;
            this.price = price;
        }

        public String getName() {
            return name;
        }

        public long getPrice() {
            return price;
        }

        public String getStatus() {
            return status;
        }

        public String getSell_status() {
            return sell_status;
        }

        public void assignId(long id) {
            this.id = id;
        }

        public long getId() {
            return id;
        }

        public void selling() {
            this.sell_status = "SELLING";
        }
    }

    public static class FruitSalesResponse {
        private long salesAmount;
        private long notSalesAmount;

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

        public long getSalesAmount() {
            return salesAmount;
        }

        public long getNotSalesAmount() {
            return notSalesAmount;
        }

    }
}

Service

package com.group.libraryapp.service.fruit;

import com.group.libraryapp.controller.homework.FruitController;
import com.group.libraryapp.repository.fruit.FruitRepository;
import com.group.libraryapp.repository.fruit.FruitRepositoryInterface;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingLong;

@Service
public class FruitService {

//    private final FruitRepository fruitRepository;
//    public FruitService(FruitRepository fruitRepository) {
//        this.fruitRepository = fruitRepository;
//    }
    private final FruitRepositoryInterface fruitRepository;


    public FruitService(FruitRepositoryInterface fruitRepository) {
        this.fruitRepository = fruitRepository;
    }

    public void saveFruit(String name, LocalDate warehousingDate, long price) {
        fruitRepository.save(name, warehousingDate, price);
    }

    public long sellFruit(long id) {
        fruitRepository.updateSellStatus(id);
        return id;
    }

    public FruitController.FruitSalesResponse getSalesInfo(String fruitName) {
        List<FruitController.Fruit> result = fruitRepository.getSalesInfo(fruitName);
        Map<String, Long> collect = sumPriceByStatus(result);

        long selling = collect.get("SELLING") == null ? 0 : collect.get("SELLING");
        long having = collect.get("HAVING") == null ? 0 : collect.get("HAVING");
        return new FruitController.FruitSalesResponse(selling, having);
    }

    private Map<String, Long> sumPriceByStatus(List<FruitController.Fruit> result) {
        return result.stream()
                .filter(it -> it.getSell_status() != null)
                .collect(groupingBy(
                        FruitController.Fruit::getSell_status,
                        summingLong(FruitController.Fruit::getPrice)));
    }

}

Repository

package com.group.libraryapp.repository.fruit;

import com.group.libraryapp.controller.homework.FruitController;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;

@Repository
public class FruitRepository {

    private final JdbcTemplate jdbcTemplate;

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

    public void save(String name, LocalDate warehousingDate, long price) {
        String sql = "INSERT INTO fruit (name,warehousing_date,price) VALUES (?,?,?)";
        jdbcTemplate.update(sql, name, warehousingDate, price);
    }

    public void updateSellStatus(long id) {
        String sql = "UPDATE fruit SET sell_status = 'SELLING' WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }

    public List<FruitController.Fruit> getSalesInfo(String fruitName) {
        String sql = "SELECT * FROM fruit WHERE name = ?";
        return jdbcTemplate.query(sql
                , (rs, rowNum) -> new FruitController.Fruit(rs.getString("name"),
                        rs.getLong("price"),
                        null,
                        rs.getString("sell_status"))
                , fruitName);
    }
}

문제 2

기존에 작성한 FruitRepository를 FruitMemoryRepository와 FruitMySQLRepository로 나누고
@Primary 어노테이션을 활용해서 Repository를 변경하면서 동작할 수 있도록 코드를 변경하기

Interface

public interface FruitRepositoryInterface {

    public void save(String name, LocalDate warehousingDate, long price);
    public void updateSellStatus(long id) ;
    public List<FruitController.Fruit> getSalesInfo(String fruitName);

}

MemoryRepository

@Primary
@Repository
public class FruitMemoryRepository implements FruitRepositoryInterface{

    private static final Map<Long,FruitController.Fruit> memory = new HashMap<>();
    private static long sequence = 0L;

    @Override
    public void save(String name, LocalDate warehousingDate, long price) {
        FruitController.Fruit fruit = new FruitController.Fruit(name, warehousingDate, price);
        fruit.assignId(++sequence);
        memory.put(fruit.getId(),fruit);
    }

    @Override
    public void updateSellStatus(long id) {
        FruitController.Fruit fruit = memory.get(id);
        fruit.selling();
    }

    @Override
    public List<FruitController.Fruit> getSalesInfo(String fruitName) {
        return memory.values().stream()
                .filter(fruit -> fruit.getName().equals(fruitName))
                .collect(Collectors.toList());
    }

}

MySQLRepository

@Repository
public class FruitMySQLRepository implements FruitRepositoryInterface{
    private final JdbcTemplate jdbcTemplate;

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

    @Override
    public void save(String name, LocalDate warehousingDate, long price) {
        String sql = "INSERT INTO fruit (name,warehousing_date,price) VALUES (?,?,?)";
        jdbcTemplate.update(sql, name, warehousingDate, price);
    }

    @Override
    public void updateSellStatus(long id) {
        String sql = "UPDATE fruit SET sell_status = 'SELLING' WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }

    @Override
    public List<FruitController.Fruit> getSalesInfo(String fruitName) {
        String sql = "SELECT * FROM fruit WHERE name = ?";
        return jdbcTemplate.query(sql
                , (rs, rowNum) -> new FruitController.Fruit(rs.getString("name"),
                        rs.getLong("price"),
                        null,
                        rs.getString("sell_status"))
                , fruitName);
    }
}