진진
수강평 작성수
-
평균평점
-
블로그
전체 7#카테고리
- 백엔드
![[인프런 워밍업 클럽 1기] 세번째 발자국](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 05. 19.
0
[인프런 워밍업 클럽 1기] 세번째 발자국
학습 내용 요약SQL 직접 사용할 때의 단점문자열을 작성하기 때문에 실수 가능성 존재특정 데이터베이스에 종속적반복작업 증가테이블과 객체는 패러다임이 다름 JPA(Java Persistence API)데이터를 영구적으로 보관하기 위해 Java 진영에서 정해진 규칙객체와 관계형 데이터베이스의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙영속성 : 서버의 생사와 무관하게 데이터가 저장되도록 하는 것 트랜잭션쪼갤 수 없는 업무의 최소 단위여러 SQL을 사용해야 할 때 한 번에 성공시키거나 하나라도 실패하면 모두 실패시키는 기능start transaction; 회고어느덧 3주차가 지났다.처음에는 꾸준히 하겠다는 마음가짐이었는데 현생과 병행하다보니 마음만큼 잘되지 않아서 아쉬웠다.이제부터라도 조금씩 밀렸던 강의를 듣고, 미니 프로젝트에 집중해야겠다고 다짐했다.
![[인프런 워밍업 클럽 1기] 두번째 발자국](https://cdn.inflearn.com/public/files/blogs/8e557f81-9e4a-49b4-9a86-8f3a11e31c2a/fd.png?w=260)
2024. 05. 12.
0
[인프런 워밍업 클럽 1기] 두번째 발자국
수업 내용 정리함수는 최대한 작게 만들고 한 가지 일만 수행하는 것이 좋다.클래스는 작아야 하며 하나의 책임만을 가져야 한다. Controller|Service|Repository 스프링 컨테이너에 의해 생성되고 관리되는 객체일반적으로 자바 클래스들이 빈으로 등록된다. 이를 통해 스프링은 이들을 인스턴스화하고 관리한다.특정한 스프링 인터페이스를 구현할 필요 없이 단순한 자바 객체로 정의될 수 있다.주로 애플리케이션의 비즈니스 로직, 데이터 액세스 객체, 서비스 등과 같은 요소들을 나타낸다. 스프링 애플리케이션의 핵심이며, 빈을 관리컨테이너는 빈의 라이프사이클을 관리하고, 빈의 의존성을 주입해주며, 필요에 따라 빈을 생성하거나 소멸시킨다. 회고시간에 쫓겨서 과제를 급하게 했던 기억이 있다. 좀 더 시간을 길게 잡고 과제를 해야할 것 같다고 느꼈다. 좋은 코드가 무엇인지에 대해 생각해보면서 코드 한 줄 한 줄의 의미를 다시금 생각해보는 기회가 되었다.
![[인프런 워밍업 클럽 1기] 첫번째 발자국](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 05. 05.
0
[인프런 워밍업 클럽 1기] 첫번째 발자국
01_네트워크와 API☾ Network데이터를 주고 받는 것(=택배)☾ IP각 컴퓨터의 고유 주소(=집 주소)256를 넘지 않는 4개의 숫자로 이루어짐ex. 대한시 민국구 서울동☾ Domain NameIP는 외우기 어려우니까 외우기 쉽게 별칭을 달아준 것ex. 빨간집☾ port number컴퓨터에서 돌아가는 여러 프로그램 중 한 프로그램을 특정하는 것ex. 홍길동☾ HTTP컴퓨터 간의 데이터를 주고 받는 표준(=운송장)ex. 내놓아라 파란집 둘째, 빨간포션 2개HTTP 요청GET /portion?color=red&count=2 Host: spring.com:3000 HTTP method(GET) : HTTP 요청을 받는 컴퓨터에게 요구하는 행위(데이터를 달라)path(/portion) : HTTP 요청을 받는 컴퓨터에게 원하는 자원Query(?color=red&count=2) : 자원을 요구할 때 필요한 조건Host : HTTP 요청을 받는 컴퓨터와 프로그램 정보POST /oak/leather Host: spring.com:3000 오크가죽정보 HTTP method(POST) : HTTP 요청을 받는 컴퓨터에게 요구하는 행위(데이터 저장해라)path(/oak/leather) : HTTP 요청을 받는 컴퓨터에게 원하는 자원Body(오크가죽정보) : 실제 저장할 정보Host : HTTP 요청을 받는 컴퓨터와 프로그램 정보정보를 보내는 2가지 방법Query : GET, DELETE에서 사용body : POST, PUT에서 사용HTTP 응답HTTP/1.1 200 OK Content-Type: application/json { "name":"A", "age":null } 💡 첫째줄 - 상태코드 여러줄 - 헤더 (한 줄 띄기) 여러줄 - 바디상태코드200 OK : 정상적으로 수행300 Moved Permanently : 다른 곳으로 옮겨가라404 Not Found : 요청을 찾을 수 없다500 Internal Server Error : 내부에 문제가 생김☾ API(Application Programming Interface)정해진 약속을 하여 특정 기능을 수행하는 것 💡 첫째줄 - Method path Query여러줄 - 헤더(여러 줄 가능)(한 줄 띄기)여러줄 - 바디(여러 줄 가능)☾ URL(Uniform Resource Locator) 주소창http : 사용하고 있는 프로토콜spring.com:3000 : 도메인 이름. 포트, 도메인 이름은 IP로 대체 가능portion : pathcolor=red&count=2 : 쿼리. 추가 정보02_GET APIQuery를 사용하여 데이터 요청☾ 덧셈 API 명세서HTTP Method HTTP Path Query(key, value) API의 반환 결과 GET /add int number1, int number2 int - 두 숫자의 덧셈 결과☾ @RequestParamcontroller/calculator/CalculatorControllerpackage com.group.libraryapp.controller.calculator; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; // @RestController : 주어진 클래스를 Controller(API의 진입 지점)으로 만들어 준다. API를 개발하려고 하는 클래스에 작성. 이 어노테이션이 있어야 클래스 안에 함수를 만들고 API 호출됐을 때 이 함수로 연결 @RestController public class CalculatorController { // @GetMapping("/add") : GET /add. 아래 함수를 HTTP Method가 GET이고 HTTP path가 /add인 API로 지정한다. @GetMapping("/add") public int addTwoNumbers(@RequestParam int number1, @RequestParam int number2) { // @RequestParam : Query를 통해서 넘어온 데이터를 함수 파라미터에 넣을 때 사용 return number1 + number2; } } @RequestParam 문제점 : Query가 늘어나면 함수의 파라미터도 길어짐☾ DTO해결책 : 객체를 받아서 사용dto/calculator/request/CalculatorAddRequestpackage com.group.libraryapp.dto.calculator.request; public class CalculatorAddRequest { private final int number1; private final int number2; public CalculatorAddRequest(int number1, int number2) { this.number1 = number1; this.number2 = number2; } public int getNumber1() { return number1; } public int getNumber2() { return number2; } } controller/calculator/CalculatorControllerpackage com.group.libraryapp.controller.calculator; import com.group.libraryapp.dto.calculator.request.CalculatorAddRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; // @RestController : 주어진 클래스를 Controller(API의 진입 지점)으로 만들어 준다. API를 개발하려고 하는 클래스에 작성. 이 어노테이션이 있어야 클래스 안에 함수를 만들고 API 호출됐을 때 이 함수로 연결 @RestController public class CalculatorController { // @GetMapping("/add") : GET /add. 아래 함수를 HTTP Method가 GET이고 HTTP path가 /add인 API로 지정한다. @GetMapping("/add") public int addTwoNumbers(CalculatorAddRequest request) { // API 호출될 때 주어진 Query가 이 객체에 있는 값에 들어가게 됨 return request.getNumber1() + request.getNumber2(); } } DTO(Data Transfer Object) : 정보를 전달하는 역할의 객체03_POST APIHTTP body를 사용하여 데이터 받음JSON(JavaScript Object Notation)객체 표기법HTTP body에서 사용됨{ "key": value } ☾ 곱셈 API 명세서HTTP Method HTTP Path HTTP Body API의 반환 결과 POST /multiply { “number1”:숫자, “number2”:숫자 } 숫자(곱셈 결과)☾ 코드로 구현dto/calculator/request/CalculatorMultiplyRequestpackage com.group.libraryapp.dto.calculator.request; public class CalculatorMultiplyRequest { private int number1; private int number2; public int getNumber1() { return number1; } public int getNumber2() { return number2; } } controller/calculator/CalculatorControllerpackage com.group.libraryapp.controller.calculator; import com.group.libraryapp.dto.calculator.request.CalculatorAddRequest; import com.group.libraryapp.dto.calculator.request.CalculatorMultiplyRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; // @RestController : 주어진 클래스를 Controller(API의 진입 지점)으로 만들어 준다. API를 개발하려고 하는 클래스에 작성. 이 어노테이션이 있어야 클래스 안에 함수를 만들고 API 호출됐을 때 이 함수로 연결 @RestController public class CalculatorController { @PostMapping("/multiply") // POST /multiply public int multiplyTwoNumbers(@RequestBody CalculatorMultiplyRequest request) { // @RequestBody : POST API에서 HTTP body 안에 담긴 json을 DTO 객체로 변환시킬 수 있음. DTO 객체 앞에 작성. return request.getNumber1() *request.getNumber2(); } } 04_유저 생성 API☾ 도서관 사용자 등록 API 명세서HTTP Method HTTP Path HTTP Body(JSON) 결과 반환 POST /user { “name”: String(null 불가능), “age”: Integer } x (HTTP 상태코드 200 OK면 충분)☾ POST API 구현dto/user/request/UserCreateRequestpackage com.group.libraryapp.dto.user.request; public class UserCreateRequest { private String name; private Integer age; public String getName() { return name; } public Integer getAge() { return age; } } domain/user/Userpackage com.group.libraryapp.domain.user; // saveUser API가 사용돼서 유저가 저장되면 이 객체를 만들어서 실제 리스트에 저장 public class User { private String name; private Integer age; public User(String name, Integer age) { // API 통해서 들어온 name 값이 null이거나 비어있을 경우 예외 던짐 if (name == null || name.isBlank()) { throw new IllegalArgumentException(String.format("잘못된 name이 들어왔습니다.", name)); } this.name = name; this.age = age; } } controller/user/UserControllerpackage com.group.libraryapp.controller.user; import com.group.libraryapp.domain.user.User; import com.group.libraryapp.dto.user.request.UserCreateRequest; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class UserController { // Instance 생성 private final List users = new ArrayList(); @PostMapping("/user") // 1. POST /user가 실행되면 public void saveUser(@RequestBody UserCreateRequest request) { // 2. 함수 실행. json 형식으로 HTTP Body에 name과 age가 들어오면 DTO로 값이 매핑 users.add(new User(request.getName(), request.getAge())); // 3. 유저 생성. 만들어진 유저 객체는 Users 리스트에 저장된다. } // 4. 200 OK 반환 } 05_유저 조회 API☾ 유저 조회 API 명세서HTTP Method HTTP Path Query 결과 반환 GET /user 없음 { “id”: Long, “name”: String(null 불가능), “age”: Integer }Id : 유저 별로 겹치지 않는 유일한 번호(Primary Key). 여기서는 저장할 때 List에 담겨 있는 유저의 순서를 id로 지정Controller에서 getter가 있는 객체를 반환하면 JSON이 된다.package com.group.libraryapp.domain.user; public class Fruit { private String name; private int price; public Fruit(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } } package com.group.libraryapp.controller.user; import com.group.libraryapp.domain.user.Fruit; import com.group.libraryapp.domain.user.User; import com.group.libraryapp.dto.user.request.UserCreateRequest; import com.group.libraryapp.dto.user.response.UserResponse; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class UserController { @GetMapping("/fruit") public Fruit fruit() { return new Fruit("바나나", 2000); } } JSON 형식으로 반환☾ GET API 구현domain/user/Userpackage com.group.libraryapp.domain.user; // saveUser API가 사용돼서 유저가 저장되면 이 객체를 만들어서 실제 리스트에 저장 public class User { private String name; private Integer age; public User(String name, Integer age) { // API 통해서 들어온 name 값이 null이거나 비어있을 경우 예외 던짐 if (name == null || name.isBlank()) { throw new IllegalArgumentException(String.format("잘못된 name이 들어왔습니다.", name)); } this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } } dto/user/response/UserResponsepackage com.group.libraryapp.dto.user.response; import com.group.libraryapp.domain.user.User; public class UserResponse { private long id; private String name; private Integer age; public UserResponse(long id, User user) { this.id = id; this.name = user.getName(); this.age = user.getAge(); } public long getId() { return id; } public String getName() { return name; } public Integer getAge() { return age; } } controller/user/UserControllerpackage com.group.libraryapp.controller.user; import com.group.libraryapp.domain.user.Fruit; import com.group.libraryapp.domain.user.User; import com.group.libraryapp.dto.user.request.UserCreateRequest; import com.group.libraryapp.dto.user.response.UserResponse; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class UserController { // Instance 생성 private final List users = new ArrayList(); @PostMapping("/user") // 1. POST /user가 실행되면 public void saveUser(@RequestBody UserCreateRequest request) { // 2. 함수 실행. json 형식으로 HTTP Body에 name과 age가 들어오면 DTO로 값이 매핑 users.add(new User(request.getName(), request.getAge())); // 3. 유저 생성. 만들어진 유저 객체는 Users 리스트에 저장된다. } // 4. 200 OK 반환 @GetMapping("/user") public List getUsers() { // UserResponse 반환 List responses = new ArrayList(); // 빈 UserResponse 리스트 생성 for (int i = 0; i users를 userResponse로 변환 } return responses; } } 현재 API의 문제점서버 재시작하면 데이터 사라짐유저 정보가 메모리에서만 유지되고 있기 때문 일주일 간의 학습 내용에 대한 간단한 회고를 작성해 주세요.API 제작을 어느 정도 알고 있다고 생각했는데 직접 해보니 아직 부족하다는 생각이 들었다. 복습 시간을 더 가져야겠다고 생각했다. 초반부에는 내용 정리를 꾸준히 하다가 점차 미루게 됐다. 주말에 남은 내용을 정리하고 다음주부터는 다시 일정에 맞게 내용 정리를 해야겠다. 미션을 해결하는 과정을 요약해 주세요.강의에서 작성한 코드와 주석을 읽으면서 내용을 복습하고, 이를 바탕으로 미션을 해결했다.다른 사람이 작성한 코드도 함께 읽어보며 미션을 했다. 미션 해결에 대한 간단한 회고를 작성해 주세요.API 만드는 미션이 생각보다 쉽지 않았다. 우선 제출은 했지만 추후에 수정할 필요가 있을 것 같다.
![[인프런 워밍업 클럽 0기] 6일차 과제](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 02. 26.
0
[인프런 워밍업 클럽 0기] 6일차 과제
문제 1. 과제 #4 에서 만들었던 API를 강의 내용처럼 Controller - Service - Repository로 분리해보세요!FruitControllerpackage com.group.libraryapp.controller.assignment; import com.group.libraryapp.dto.fruit.FruitCreateRequest; import com.group.libraryapp.dto.fruit.FruitUpdateRequest; import com.group.libraryapp.service.assignment.FruitService; import org.springframework.web.bind.annotation.*; @RestController public class FruitController { private final FruitService fruitService; public FruitController(FruitService fruitService) { this.fruitService = fruitService; } @PostMapping("/api/v1/fruit") public void saveFruit(@RequestBody FruitCreateRequest request) { fruitService.saveFruit(request); } @PutMapping("/api/v1/fruit") public void updateFruit(@RequestBody FruitUpdateRequest request) { fruitService.updateFruit(request); } } FruitServicepackage com.group.libraryapp.service.assignment; import com.group.libraryapp.dto.fruit.FruitCreateRequest; import com.group.libraryapp.dto.fruit.FruitUpdateRequest; import com.group.libraryapp.repository.assignment.FruitRepository; import org.springframework.stereotype.Service; @Service public class FruitService { private final FruitRepository fruitRepository; public FruitService(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void saveFruit(FruitCreateRequest request) { fruitRepository.saveFruit(request.getName(), request.getWarehousingDate(), request.getPrice()); } public void updateFruit(FruitUpdateRequest request) { boolean isFruitNotExist = fruitRepository.isFruitNotExist(request.getId()); if (isFruitNotExist) { throw new IllegalArgumentException(); } fruitRepository.updateFruit(request.getName(), request.getWarehousingDate(), request.getPrice(), request.getId()); } } FruitRepositorypackage com.group.libraryapp.repository.assignment; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.time.LocalDate; @Repository public class FruitRepository { private final JdbcTemplate jdbcTemplate; public FruitRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void saveFruit(String name, LocalDate warehousingDate, long price) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, name, warehousingDate, price); } public boolean isFruitNotExist(long id) { String readSql = "SELECT * FROM fruit WHERE id = ?"; return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty(); } public void updateFruit(String name, LocalDate warehousingDate, long price, long id) { String sql = "UPDATE fruit SET name = ?, warehousingDate = ?, price = ? WHERE id = ?"; jdbcTemplate.update(sql, name, warehousingDate, price, id); } } 문제 2. 문제 1에서 분리되면 FruitController / FruitService / FruitRepository가 생겼을 것입니다. 기존에 작성했던 FruitRepository를 FruitMemoryRepository와 FruitMySqlRepository로 나누고 @Primary 어노테이션을 활용해 두 Repository를 바꿔가며 동작시킬 수 있도록 코드를 변경해보세요! FruitRepositorypackage com.group.libraryapp.repository.assignment; public interface FruitRepository { void saveFruit(); boolean isFruitNotExist(); void updateFruit(); } FruitMemoryRepositorypackage com.group.libraryapp.repository.assignment; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.time.LocalDate; @Repository public class FruitMemoryRepository { private final JdbcTemplate jdbcTemplate; public FruitMemoryRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void saveFruit(String name, LocalDate warehousingDate, long price) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, name, warehousingDate, price); } public boolean isFruitNotExist(long id) { String readSql = "SELECT * FROM fruit WHERE id = ?"; return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty(); } public void updateFruit(String name, LocalDate warehousingDate, long price, long id) { String sql = "UPDATE fruit SET name = ?, warehousingDate = ?, price = ? WHERE id = ?"; jdbcTemplate.update(sql, name, warehousingDate, price, id); } } FruitMySqlRepository(이 repository를 사용한다고 가정)package com.group.libraryapp.repository.assignment; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.time.LocalDate; @Primary @Repository public class FruitMySqlRepository { private final JdbcTemplate jdbcTemplate; public FruitMySqlRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void saveFruit(String name, LocalDate warehousingDate, long price) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, name, warehousingDate, price); } public boolean isFruitNotExist(long id) { String readSql = "SELECT * FROM fruit WHERE id = ?"; return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty(); } public void updateFruit(String name, LocalDate warehousingDate, long price, long id) { String sql = "UPDATE fruit SET name = ?, warehousingDate = ?, price = ? WHERE id = ?"; jdbcTemplate.update(sql, name, warehousingDate, price, id); } }
백엔드
![[인프런 워밍업 클럽 0기] 첫 번째 발자국](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 02. 25.
0
[인프런 워밍업 클럽 0기] 첫 번째 발자국
일주일 동안 학습했던 내용을 요약해주세요.용어 정의서버(Server) : 기능을 제공하는 것. 기능하는 컴퓨터 자체클라이언트(Client) : 요청을 한 컴퓨터네트워크(Network) : 데이터 주고받음포트(Port) : 특정 프로그램도메인 이름 : IP(244.66.51.9)를 외우기 쉽게 spring.com 변환한 것HTTP : 데이터를 주고받는 표준HTTP Method : 요구하는 행위, 방법Host : Http 요청을 받는 컴퓨터와 프로그램 정보Path : Http 요청을 받는 컴퓨터에게 원하는 자원Query : 데이터를 요구할 때 원하는 조건. GET. DELETEbody : 데이터를 저장할 때 보내는 것. POST. PUTAPI : 정해진 약속을 하여 특정 기능을 수행하는 것 스프링 프로젝트 생성JDK 설치 : 2.xx 버전 사용 시 JDK 11 버전 설치 / 3.xx 버전 사용 시 JDK 17 버전 설치스프링 부트 스타터 사이트로 이동(https://start.spring.io)기본 메인 클래스 실행 -> http://localhost:8080 이동 API 개발HTTP 요청은 HTTP Method (GET, POST) 와 Path(/portion) 가 핵심!요청에서 데이터를 전달하기 위한 2 가지 방법은 쿼리와 바디HTTP Method 종류에는 POST(생성), GET(조회), PUT(수정), DELETE(삭제)가 존재 MySQL 사용법 및 연동MySQL 8.0Command Line Client - Unicode 로 이동비밀번호 입력mysql> 이 뜨면 사용 가능 -연동법create database [데이터베이스 이름]; // 데이터베이스 생성 use [데이터베이스 이름]; // 데이터베이스 내부로 이동 create table [테이블 이름] ( // 테이블 생성 [필드1 이름] [타입] [부가조건], [필드2 이름] [타입] [부가조건], ... primary key ([필드 이름]) ); -데이터 조작법// 데이터 생성 INSERT INTO [테이블 이름] (필드1 이름, 필드2이름, ...) VALUES (값1, 값2, ...) // 데이터 조회 SELECT * FROM [테이블 이름]; // 데이터 수정 UPDATE [테이블 이름] SET 필드1이름=값1, 필드2이름=값2, ... WHERE [조건]; // 데이터 삭제 DELETE FROM [테이블 이름] WHERE [조건]; 클린 코드 일주일 간의 학습 내용에 대한 간단한 회고를 작성해 주세요.강의를 미루는 것이 가장 큰 걱정이었는데 프로젝트 와중에도 강의를 매일매일 챙겨들었다는 점을 칭찬하고 싶다.그러나 과제를 고민하는 시간을 오래 갖지 못한 점이 아쉽다. 다음주부터는 온전히 스터디에만 몰두할 수 있기에 과제를 오랫동안 고민하고 시도해볼 예정이다.또한, 이번주에는 기술블로그에 내용 정리를 하지 못하였는데 다음주부터는 매일 짧게라도 기술 블로그도 작성하고 싶다. 미션을 해결하는 과정을 요약해 주세요.티스토리와 chat GPT를 사용하여 '찾아보기' 과제를 해결하였다. 내용을 복사 붙여넣기 하는 것이 아닌 내가 이해한 내용을 바탕으로 내용을 정리하였다. 강의에서 작성한 코드를 다시 한 번씩 읽어보며 코드를 작성하였다. 모르는 문제가 나온 경우, 다른 사람의 제출물을 참고해서 다시 작성해보고, 내가 작성한 코드랑 비교하였다. 미션 해결에 대한 간단한 회고를 작성해 주세요.미션 시작을 저녁부터 한 경우가 많아서 충분히 고민할 시간이 적었던 것이 아쉽다. 또한, 2일차 과제를 완성시키지 못하고 제출 시간을 넘겨버린 것이 아쉽다. 다음주에는 과제를 할 시간을 미리 확보할 예정이다.
백엔드
![[인프런 워밍업 클럽 0기] 4일차 과제](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 02. 22.
0
[인프런 워밍업 클럽 0기] 4일차 과제
문제 1. 우리는 작은 과일 가게를 운영하고 있습니다. 과일 가게에 입고된 "과일 정보"를 저장하는 API를 만들어 봅시다.[조건]HTTP method : POSTHTTP path : /api/v1/fruitHTTP 요청 Body{ "name": String, "warehousingDate": LocalDate, "price": long } [예시]{ "name": "사과", "warehousingDate": "2024-02-01", "price": 5000 }응답 : 성공 시 200 OK [문제 풀이]FruitControllerpackage com.group.libraryapp.controller.assignment; import com.group.libraryapp.dto.fruit.FruitCreateRequest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; 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 FruitCreateRequest request) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice()); } } FruitRequestpackage com.group.libraryapp.dto.fruit; import java.time.LocalDate; public class FruitCreateRequest { private String name; private LocalDate warehousingDate; private long price; public FruitCreateRequest(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; } } 문제 2. 과일이 팔리게 되면, 우리 시스템에 팔린 과일 정보를 기록해야 합니다.[조건]HTTP method : PUTHTTP path : /api/v1/fruitHTTP 요청 Body{ "id": long } [예시]{ "id": 3 }응답 : 성공 시 200 OK [문제 풀이]FruitController@PutMapping("/api/v1/fruit") public void updateFruit(@RequestBody FruitUpdateRequest request) { String readSql = "SELECT * FROM fruit WHERE id = ?"; boolean isFruitNotExist = jdbcTemplate.query(readSql, (rs, rowNum) -> 0, request.getId()).isEmpty(); if (isFruitNotExist) { throw new IllegalArgumentException(); } String sql = "UPDATE fruit SET name = ?, warehousingDate = ?, price = ? WHERE id = ?"; jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice(), request.getId()); } FruitUpdateRequestpackage com.group.libraryapp.dto.fruit; import java.time.LocalDate; public class FruitUpdateRequest { private long id; private String name; private LocalDate warehousingDate; private long price; public FruitUpdateRequest(long id, String name, LocalDate warehousingDate, long price) { this.id = id; this.name = name; this.warehousingDate = warehousingDate; this.price = price; } public long getId() { return id; } public String getName() { return name; } public LocalDate getWarehousingDate() { return warehousingDate; } public long getPrice() { return price; } } 문제 3. 우리는 특정 과일을 기준으로 팔린 금액, 팔리지 않은 금액을 조회하고 싶습니다.[조건]HTTP method : GETHTTP path : /api/v1/fruit/statHTTP queryname : 과일 이름HTTP 응답 body{ "salesAmount": long, "notSalesAmount": long } [예시]GET /api/v1/fruit/stat?name=사과{ "salesAmount": 6000, "notSalesAmount": 4000 } [문제 풀이]FruitController@GetMapping("api/v1/fruit/stat") public FruitResponse getSalesTotalPrice(@RequestParam("name") String fruitName) { String sql = "SELECT * FROM fruit WHERE name = ?"; List result = jdbcTemplate.query(sql, new Object[]{fruitName}, (RowMapper) (rs, rowNum) -> { return new Fruit(rs.getString("name"), rs.getLong("price"), rs.getString("sell_status")); }); long sellingPrice = 0L; long havingPrice = 0L; for (final Fruit fruit : result) { if (fruit.getStatus().equals("HAVING")) { havingPrice+= fruit.getPrice(); } else if (fruit.getStatus().equals("SELLING")) { sellingPrice+= fruit.getPrice(); } } return new FruitResponse(sellingPrice, havingPrice); } Fruitpublic static class Fruit { private String name; private long price; private String status; public Fruit(final String name, final long price, final String status) { this.name = name; this.price = price; this.status = status; } public String getName() { return name; } public long getPrice() { return price; } public String getStatus() { return status; } } FruitResponsepublic static class FruitResponse { private long salesAmount; private long notSalesAmount; public FruitResponse(final long salesAmount, final long notSalesAmount) { this.salesAmount = salesAmount; this.notSalesAmount = notSalesAmount; } public long getSalesAmount() { return salesAmount; } public long getNotSalesAmount() { return notSalesAmount; } }
![[인프런 워밍업 클럽 0기] 1일차 과제](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2024. 02. 19.
0
[인프런 워밍업 클럽 0기] 1일차 과제
어노테이션을 사용하는 이유 (효과) 는 무엇일까?어노테이션이란?어노테이션은 특별한 의미, 기능을 자동으로 해주는 기술로, 주석과 같은 의미를 가진다.소스 코드 내에 추가적인 정보를 제공하는 태그이다.Java 5부터 도입되었다.어노테이션은 @를 사용하여 작성한다. 어노테이션을 사용하는 이유(효과)컴파일러에게 코드 문법 에러를 체크하도록 정보 제공별도의 구성 파일 없이도 의존성 주입(dependency injection)과 같은 작업 수행Spring이 관리해야 할 클래스를 쉽게 지정(ex. @Component, @Service, @Repository) 나만의 어노테이션은 어떻게 만들 수 있을까?@interface 키워드 사용 설정할 수 있는 요소Retention Policy : 어노테이션이 언제까지 유지될 것인지 결정Target : 어노테이션이 적용될 수 있는 Java 요소(메소드, 필드, 클래스) 지정Member : 어노테이션 내에서 메소드 형태로 멤버 정의 가능 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // Retention Policy (런타임에도 유지) @Retention(RetentionPolicy.RUNTIME) // Target (여기서는 메소드에만 적용) @Target(ElementType.METHOD) public @interface MyCustomAnnotation { // Member(기본값을 가질 수 있음) String description() default "No description"; int value() default 0; } public class MyAnnotatedClass { @MyCustomAnnotation(description = "This is a custom annotation", value = 10) public void myMethod() { } }
백엔드




