show databases ;
CREATE DATABASE warehouse default CHARACTER SET UTF8;
USE warehouse;
show tables;
CREATE TABLE warehouse (
id bigint auto_increment,
name VARCHAR(20),
warehousingDate DATE,
price long,
sell BOOLEAN,
primary key (id)
);
SELECT * FROM warehouse;
import java.time.LocalDate;
public class Fruit {
private long id;
private String name;
private LocalDate warehousingDate;
private long price;
private boolean sell;
public Fruit(String name, LocalDate warehousingDate, long price) {
if (name == null || name.isBlank()){
throw new IllegalArgumentException("잘못된 name(%s)이 들어왔습니다.");
}
if (price < 0){
throw new IllegalArgumentException("잘못된 price(%s)가 들어왔습니다.");
}
this.name = name;
this.warehousingDate = warehousingDate;
this.price = price;
this.sell = false;
}
public Fruit(long id, String name, long price, boolean sell) {
this.id = id;
this.name = name;
this.price = price;
this.sell = sell;
}
public Fruit(long price, boolean sell){
this.price = price;
this.sell = sell;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public LocalDate getWarehousingDate() {
return warehousingDate;
}
public long getPrice() {
return price;
}
public boolean isSell() {
return sell;
}
}
package com.example.Todomate.dto.fruit.request;
public class FruitUpdateRequest {
private long id;
public long getId() {
return id;
}
}
@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 warehouse (name, warehousingDate, price) VALUES (?,?,?)";
jdbcTemplate.update(sql, request.getName(),request.getWarehousingDate(), request.getPrice());
}
}
강의 내용 중 int의 숫자범위를 넘어가는 경우를 만날 수 있으니 long을 사용해서 수의 범위를 최대한 넓힌다는 내용이 있었다.
package com.example.fruit.dto.fruit.request;
public class FruitUpdateRequest {
private long id;
public long getId() {
return id;
}
}
@PutMapping("api/v1/fruit")
public void putFruit(@RequestBody FruitUpdateRequest request){
String readSql = "SELECT * FROM warehouse WHERE id = ?";
boolean isFruitNotExist = jdbcTemplate.query(readSql, (rs, rowNum)-> 0, request.getId()).isEmpty();
if(isFruitNotExist){
throw new IllegalArgumentException();
}
String sql = "UPDATE warehouse SET sell = true WHERE id = ?";
jdbcTemplate.update(sql, request.getId());
}
public class FruitResponse {
private final long salesAmount;
private final long notSalesAmount;
public FruitResponse(long salesAmount, long notSalesAmount) {
this.salesAmount = salesAmount;
this.notSalesAmount = notSalesAmount;
}
public long getSalesAmount() {
return salesAmount;
}
public long getNotSalesAmount() {
return notSalesAmount;
}
}
@GetMapping("api/v1/fruit/stat")
public FruitResponse getFruitTotalPrice(@RequestParam String name){
long sellPrice=0;
long notSellPrice=0;
String sql = "SELECT * FROM warehouse WHERE name = ?";
List<Fruit> fruits = jdbcTemplate.query(sql, (rs, rowNum) -> {
long price = rs.getLong("price");
boolean sell = rs.getBoolean("sell");
return new Fruit(price, sell);
}, name);
for (Fruit fruit : fruits){
if ( fruit.isSell() ){
sellPrice += fruit.getPrice();
}
else{
notSellPrice += fruit.getPrice();
}
}
return new FruitResponse(sellPrice, notSellPrice);
}
SQL의 sum은 SUM은 SQL의 집계 함수로, 특정 열의 모든 값을 합산하는 데 사용되는 쿼리이고 group by는 집계함수의 결과를 특정 컬럼을 기준으로 묶어 결과를 출력해주는 쿼리이다.
이걸 이용해서 코드를 작성했고, query 코드 안의 람다식을 완성하기 위해 long이 아니라 AtomicLong 객체를 사용했다. long을 사용하면 람다식 내에서 long 로컬 변수에 접근할 수 없어서 이다.
@GetMapping("api/v1/fruit/stat")
public FruitResponse getFruitTotalPrice(@RequestParam String name){
String sql = "SELECT sell, SUM(price) AS TotalPrice FROM warehouse WHERE name = ? GROUP BY sell;";
AtomicLong sellPrice = new AtomicLong();
AtomicLong notSellPrice = new AtomicLong();
jdbcTemplate.query(sql, (rs,rowNum)->{
boolean sell = rs.getBoolean("sell");
if (rs.wasNull() ||!sell){
notSellPrice.addAndGet(rs.getLong("TotalPrice"));
}
else{
sellPrice.addAndGet(rs.getLong("TotalPrice"));
}
return null;
},name);
return new FruitResponse(sellPrice.get(), notSellPrice.get());
}
문제 발견 1 : Fruit를 저장할 때 request 형식에 맞지 않아도 저장되는 오류가 생김.
수정 ->
@PostMapping("/api/v1/fruit")
public ResponseEntity<Void> saveFruit(@RequestBody FruitRequest request){
if (request.getName() == null || request.getWarehousingDate() == null || request.getPrice() == null) {
return ResponseEntity.badRequest().build();
}
String sql = "INSERT INTO warehouse (name, warehousingDate, price) VALUES (?,?,?)";
jdbcTemplate.update(sql, request.getName(),request.getWarehousingDate(), request.getPrice());
return ResponseEntity.ok().build();
}
문제 발견 2 : 처음 DB 테이블을 생성할 때 default 값을 설정하지 않아서 sell의 처음값이 null이었다.
수정 -> null값을 확인할 수 있는 조건문 추가