진도표 4일차와 연결됩니다
우리는 GET API와 POST API를 만드는 방법을 배웠습니다. 👍 추가적인 API 들을 만들어 보며 API 개발에 익숙해져 봅시다!
문제1 : "과일 정보" 저장하는 api 생성
FruitController, Fruit, FruitCreateRequest 파일을 아래와 같은 폴더 구조로 만들었다.
그런데 (문제2)에서 id 값이 필요한 것을 보고, primary key로 id 를 추가 설정하였다.
Fruit.java
package com.group.libraryapp.domain;
import java.time.LocalDate;
public class Fruit {
private String name;
private LocalDate warehousingDate;
private long price;
public Fruit(String name, LocalDate warehousingDate, long price) {
this.name = name;
this.warehousingDate = warehousingDate;
this.price = price;
}
public String getName() {
return name;
}
public LocalDate getWarehousingDate() {
return warehousingDate;
}
public long getPrice() {
return price;
}
}
FruitController.java
package com.group.libraryapp.controller.fruit;
import com.group.libraryapp.dto.fruit.FruiteCreateRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FruitController {
private final JdbcTemplate jdbcTemplate;
public FruitController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostMapping("/api/v1/fruit")
public void saveFruit(@RequestBody FruiteCreateRequest request){
String sql = "INSERT INTO fruits(name, warehousingDate, price) Values (?,?,?)";
jdbcTemplate.update(sql,request.getName(),request.getWarehousingDate(),request.getPrice());
}
}
FruitCreateRequest.java
package com.group.libraryapp.dto.fruit;
import java.time.LocalDate;
public class FruiteCreateRequest {
private String name;
private LocalDate warehousingDate;
private long price;
public String getName() {
return name;
}
public LocalDate getWarehousingDate() {
return warehousingDate;
}
public long getPrice() {
return price;
}
}
sql console 창에서는 아래와 같이 작성하였다. id와 문제2에서의 팔린 여부를 측정하는 saled (0이면 팔림, 1이면 안팔림) 을 추가했다.
sql_console
create table fruits
(
id bigint auto_increment,
name varchar(25),
warehousingDate date,
price long,
saled int,
primary key(id)
);
select * from fruit
문제1 결과>>
postman에서 실행 결과, 정상적으로 post api 가 작동이 되고, database에도 정상적으로 등록이 된 것을 볼 수 있다.
문제2
put api 실행결과,
위와 같이 database에서 saled 값 부분이 0으로 바뀐 것을 볼 수 있다.
문제3
문제 3 을 해결하기 위해 FruitController.java에 아래 코드를 추가하였고
//문제3
@GetMapping("/api/v1/fruit/stat")
public FruitOverviewResponse overviewFruit(@RequestParam String name){
String readSql = "SELECT * FROM fruits WHERE name = ?";
List<Fruit> list = jdbcTemplate.query(readSql, (rs,rowNum) -> {
String rs_name = rs.getString("name");
long rs_price = rs.getLong("price");
LocalDate rs_warehousingDate = rs.getDate("warehousingDate").toLocalDate();
int rs_saled = rs.getInt("saled");
return new Fruit(rs_name,rs_warehousingDate,rs_price,rs_saled);
}, name);
return fruitOverviewLogic(list);
}
//문제3 내의 서브 메서드
private FruitOverviewResponse fruitOverviewLogic(List<Fruit> list) {
long notsalesamount = 0;
long salesamount = 0;
for(Fruit e : list){
if (e.getSaled() == 1)
notsalesamount += e.getPrice();
else
salesamount += e.getPrice();
}
fruitOverviewResponse.setNotSalesAmount(notsalesamount);
fruitOverviewResponse.setSalesAmount(salesamount);
return fruitOverviewResponse;
}
문제3에서 바라는 응답을 반환하기 위해서 FruitOverviewResponse.java 라는 새로운 클래스를 dto 폴더에 만들었다. 이는 FruitController.java 의 서브 메서드 내에서 반환된다.
FruitOverviewResponse.java
package com.group.libraryapp.dto.fruit;
public class FruitOverviewResponse {
private long salesAmount;
private long notSalesAmount;
public long getSalesAmount() {
return salesAmount;
}
public long getNotSalesAmount() {
return notSalesAmount;
}
public void setSalesAmount(long salesAmount) {
this.salesAmount = salesAmount;
}
public void setNotSalesAmount(long notSalesAmount) {
this.notSalesAmount = notSalesAmount;
}
}
- 오류
- 그런데, 아래와 같이 Could not autowire. No beans of 'FruitOverviewResponse' type found. 라는 오류가 나와서 서칭을 해보았다. @Service 어노테이션을 안 붙여서 발생했고, FruitOverviewResponse 클래스에 어노테이션을 추가하니 해결되었다.
위와 같이 판매된 '사과' 가 얼마인지 볼 수 있다.
여기서 존재하지 않는 과일의 name을 입력한 경우에도 위 json 결과가 0,0 값으로 나오는데, 이를 15강,16강 에서 배운대로 FruitController.java에 에러처리를 추가했다.
//문제3
@GetMapping("/api/v1/fruit/stat")
public FruitOverviewResponse overviewFruit(@RequestParam String name){
String readSql = "SELECT * FROM fruits WHERE name = ?";
List<Fruit> list = jdbcTemplate.query(readSql, (rs,rowNum) -> {
String rs_name = rs.getString("name");
long rs_price = rs.getLong("price");
LocalDate rs_warehousingDate = rs.getDate("warehousingDate").toLocalDate();
int rs_saled = rs.getInt("saled");
return new Fruit(rs_name,rs_warehousingDate,rs_price,rs_saled);
}, name);
if (list.isEmpty())
throw new IllegalArgumentException();
return fruitOverviewLogic(list);
}
위와 같이 db에 있지 않은 '자갈치'를 name에 넣었을때, 에러 결과가 정상적으로 나오는 것을 볼 수 있다.
sql sum , groupby
SELECT column, 집계함수(column) FROM TABLE (WHERE column = data)GROUP BY column;
이를 이용해 문제3을 간단하게 sql 문에서 다루어 해결할 수도 있다.
이 부분은 시도를 했는데 계속 오류가 나서 다른 분이 하신 부분을 참고해서 작성하였다.
그 분이 작성하신 코드는 내가 작성한 코드와 구조적으로 달라 다시 작성해보았다.
[출처]
https://galid1.tistory.com/609
https://www.inflearn.com/blogs/6674
'spring' 카테고리의 다른 글
[인프런 워밍업 클럽 7차 과제-5/16] 백엔드 (0) | 2024.05.16 |
---|---|
[인프런 워밍업 클럽 6차 과제-5/11] 백엔드 (0) | 2024.05.11 |
[인프런 워밍업 클럽 3차 과제-5/3] (0) | 2024.05.03 |
[인프런 워밍업 클럽 1차 과제-4/29] (0) | 2024.04.29 |
[쿠석쿠석 프로젝트] 코드리뷰 #1 데이터베이스 구조 설계 (0) | 2024.04.04 |