블로그
전체 10#카테고리
- 백엔드
#태그
- 인프런
- 인프런워밍업클럽
- 스터디0기
- 백엔드
- 워밍업
2024. 03. 19.
3
[인프런 워밍업 클럽 0기] BE 후기
여느 때처럼 인프런 강의를 들으러 사이트에 들어왔더니 인프런 워밍업 클럽을 모집한다는 배너가 보였습니다. 혼자 공부를 하다 보니 목표를 세워도 미루기도 하는 식이였는데 인프런 워밍업 클럽에 참여하면 미션도 있고 미니 프로젝트도 있다고 하여 참여하였습니다. 앞부분은 아는 내용도 많아서 쉬웠지만 뒤로 갈 수로 공부하며 진행하였고 내가 궁금했던 부분들은 이미 다른 분들이 질문을 해서 답변을 얻은 것들을 보면서 공부했습니다. 중간중간 코치님의 라이브를 통해 현재 회사에서는 어떻게 일을 하고 어떤 것을 사용하고 문제를 어떻게 해결하는지 등 많은 내용을 공유해 주셨고 마지막 라이브 때는 열정적으로 2시간 40분 정도 라이브를 해주셨습니다. 열정적으로 알려주셔서인지 시간이 너무 빨리 간 느낌입니다. 수료식 때는 온라인으로 참여하였고 여기서도 많은 것을 알 수 있었고 많은 도움을 받을 수 있었습니다. 러너 분들이 포기하지 않고 완주 목표를 달성할 수 있게 도와주시고 배려 해주시는 운영진분들, 하나라도 더 알려주시는 코치님 그리고 열심히 참여하셨던 러너 분들과 함께할 수 있어서 뜻깊은 시간이 된 것 같습니다. 다음에도 기회가 된다면 참여하고 싶습니다.
백엔드
・
인프런
・
인프런워밍업클럽
・
스터디0기
2024. 03. 10.
0
[인프런 워밍업 클럽 0기] BE 3주차 회고
인프런 워밍업 클럽 0기 스터디 마지막 최종 회고 이 워밍업 클럽을 통해 다시 한번 스프링 공부를 할 수 있었고 JPA에 대해 공부할 수 있었습니다. 3주라는 시간동안 많은 것을 배울 수 있는 시간이였습니다. 코치님께서 해주신 라이브 중 가장 기억에 많이 남는 것은 마지막 라이브였던 것 같습니다. 마지막 라이브에서 코치님께서 하나라도 더 알려주시려고 하시는 것을 보고 더 집중에서 들었고 참여 하셨던 분들이 말씀하시 것 처럼 시간이 정말 빨리 가더군요. 거의 2시간 40분 정도 라이브를 해주셨는데 내용도 알차고 실무에서는 어떻게 일을 하는지 어떤것을 고려해야 하는지 알 수 있어서 많은 도움이 될 것 같습니다. 디스코드에 질문을 올리면 정성스러운 답변도 정말 많은 도움이 되었습니다. 하나라도 더 알려주고 싶어 하시는 마음이 느껴졌습니다.^^ 이렇게 많은 분들과 같이 공부할 수 있는 시간을 만들어 주신 인프런 관계자 분들과 열정적으로 라이브와 질문에 답변해주신 코치님 그리고 러너분들 모두 감사하다는 말씀을 드리고 싶습니다. 모두 응원하겠습니다!!!
백엔드
・
백엔드
・
워밍업
2024. 03. 03.
0
[인프런 워밍업 클럽 0기] BE 2주차 회고
2주차 학습 내용과 공부한 내용 정리 ORM(Object Relational Mapping)우리가 일반 적으로 알고 있는 애플리케이션 Class와 RDB(Relational DataBase)의 테이블을 매핑(연결)한다는 뜻이며, 기술적으로는 어플리케이션의 객체를 RDB 테이블에 자동으로 영속화 해주는 것이다. JPAJava 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스인터페이스 이기 때문에 Hibernate, OpenJPA 등이 JPA를 구현함 사용이유는?JPA를 사용하여 얻을 수 있는 가장 큰 장점은 SQL이 아닌 객체 중심으로 개발할 수 있다는 것이다. 이에 생산성이 좋아지고 유지보수 또한 수월해진다. 트랜잭션데이터베이스 트랜잭션은 데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위이다.데이터베이스의 상태를 변경시키기 위해 수행하는 작업 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산을 의미한다. 영속성 컨텍스트란?엔티티를 영구 저장하는 환경엔티티 매니저가 영속성 컨텍스트에 엔티티를 보관하고 관리한다.영속성 컨텍스트에 저장된 상태를 영속 상태, 저장되었다가 분리된 상태를 준영속 상태라고 한다. 마무리남은 한주에는 미니프로젝트를 완료하고 더 나아가서 기능을 추가한다거나 해서 더 발전된 프로그램을 만들고 싶습니다.
백엔드
・
백엔드
・
워밍업
2024. 02. 27.
0
[인프런 워밍업 클럽 0기] BE 7일차 과제
controller@RequestMapping("/api/v1") @RestController public class FruitController { private final FruitService fruitService; public FruitController(FruitService fruitService) { this.fruitService = fruitService; } @PostMapping("/fruit") public void saveFruit(@RequestBody FruitDTO request) { fruitService.save(request); } @PutMapping("/fruit") public void sellFruit(@RequestBody FruitDTO request) { fruitService.sell(request); } @GetMapping("/fruit/stat") public FruitResponse getStat(@RequestParam String name) { return fruitService.getStat(name); } @GetMapping("/fruit/count") public FruitCountResponse count(@RequestParam String name) { return fruitService.count(name); } @GetMapping("/fruit/list") public FruitListResponse getList(FruitListRequest fruitListRequest) { return fruitService.getList(fruitListRequest); } } service@Service public class FruitService { private final FruitRepository fruitRepository; public FruitService(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void save(FruitDTO request) { fruitRepository.save(new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice())); } public void sell(FruitDTO request) { Fruit fruit = fruitRepository.findById(request.getId()).orElseThrow(IllegalArgumentException::new); fruit.changeIs_sold(); fruitRepository.save(fruit); } public FruitResponse getStat(String name) { List salesList = fruitRepository.findByNameAndIsSoldIsFalse(name); List notSalesList = fruitRepository.findByNameAndIsSoldIsTrue(name); long salesAmount = salesList.stream().mapToLong(Fruit::getPrice).sum(); long notSalesAmount = notSalesList.stream().mapToLong(Fruit::getPrice).sum(); return new FruitResponse(salesAmount, notSalesAmount); } public FruitCountResponse count(String name) { return new FruitCountResponse(fruitRepository.countByNameAndIsSoldIsTrue(name)); } public FruitListResponse getList(FruitListRequest fruitListRequest) { if ("GTE".equals(fruitListRequest.getOption())) { return new FruitListResponse(fruitRepository.findAllByPriceGreaterThanEqualAndIsSoldIsFalse(fruitListRequest.getPrice())); } if ("LTE".equals(fruitListRequest.getOption())) { return new FruitListResponse(fruitRepository.findAllByPriceLessThanEqualAndIsSoldIsFalse(fruitListRequest.getPrice())); } throw new IllegalArgumentException("과일 리스트를 불러올 수 없습니다."); } } repository@Repository public interface FruitRepository extends JpaRepository { List findByNameAndIsSoldIsFalse(String name); List findByNameAndIsSoldIsTrue(String name); long countByNameAndIsSoldIsTrue(String name); List findAllByPriceGreaterThanEqualAndIsSoldIsFalse(Long price); List findAllByPriceLessThanEqualAndIsSoldIsFalse(Long price); } domain@Entity @Getter public class Fruit { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private LocalDate warehousingDate; @Column(nullable = false) private long price; @Column(nullable = false, columnDefinition = "boolean default false") private boolean isSold; public Fruit(String name, LocalDate warehousingDate, long price) { this.name = name; this.warehousingDate = warehousingDate; this.price = price; } public Fruit() { } public void changeIs_sold() { this.isSold = true; } } dto@Data @AllArgsConstructor @RequiredArgsConstructor public class FruitDTO { private Long id; private String name; private LocalDate warehousingDate; private long price; private boolean is_sold; @Data @AllArgsConstructor @RequiredArgsConstructor public static class FruitResponse { private long salesAmount; private long notSalesAmount; } @Data @AllArgsConstructor @RequiredArgsConstructor public static class FruitCountResponse { private long count; } @Data @AllArgsConstructor @RequiredArgsConstructor public static class FruitListRequest { private String option; private long price; } @Data @AllArgsConstructor @RequiredArgsConstructor public static class FruitListResponse { private List list; } }
백엔드
・
백엔드
・
워밍업
2024. 02. 26.
0
[인프런 워밍업 클럽 0기] BE 6일차 과제
문제 1을 해결하기 전에 과제4에서 했던 코드를 조금 수정을 한뒤 과제를 진행 하였다.문제1DTO@Data @AllArgsConstructor @RequiredArgsConstructor public class FruitDTO { private long id; private String name; private LocalDate warehousingDate; private long price; private boolean is_sold; @Data @AllArgsConstructor public static class FruitResponse { private long salesAmount; private long notSalesAmount; } } controller@RequestMapping("/api/v1") @RestController public class FruitController { private final FruitService fruitService; public FruitController(FruitService fruitService) { this.fruitService = fruitService; } @PostMapping("/fruit") public void saveFruit(@RequestBody FruitDTO request) { fruitService.save(request); } @PutMapping("/fruit") public void sellFruit(@RequestBody FruitDTO request) { fruitService.sell(request); } @GetMapping("/fruit/stat") public FruitResponse getStat(@RequestParam String name) { return fruitService.getStat(name); } } Service@Service public class FruitService { private final FruitMysqlRepository fruitRepository; public FruitService(FruitMysqlRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void save(FruitDTO request) { fruitRepository.save(request); } public void sell(FruitDTO request) { if (fruitRepository.isFruitNotExist(request)) { throw new IllegalArgumentException("존재하지 않는 과일 입니다."); } fruitRepository.sell(request); } public FruitResponse getStat(String name) { return fruitRepository.getStat(name); } }Repository@Repository public class FruitMysqlRepository implements FruitRepository { private final JdbcTemplate jdbcTemplate; public FruitMysqlRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void save(FruitDTO request) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice()); } public void sell(FruitDTO request) { String sql = "UPDATE fruit SET is_sold = 1 WHERE id = ?"; jdbcTemplate.update(sql, request.getId()); } public boolean isFruitNotExist(FruitDTO request) { String readSql = "SELECT * FROM fruit WHERE id = ?"; return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, request.getId()).isEmpty(); } public FruitResponse getStat(String name) { String salesSql = "select sum(price) from fruit where is_sold = 1 group by name having name = ?"; String notSalesSql = "select sum(price) from fruit where is_sold = 0 group by name having name = ?"; long salesAmount = jdbcTemplate.queryForObject(salesSql, Long.class, name); long notSalesAmount = jdbcTemplate.queryForObject(notSalesSql, Long.class, name); return new FruitResponse(salesAmount, notSalesAmount); } } 문제2FruitRepository interfacepublic interface FruitRepository { void save(FruitDTO request); void sell(FruitDTO request); FruitResponse getStat(String name); boolean isFruitNotExist(FruitDTO request); } 수정 된 Service@Service public class FruitService { private final FruitRepository fruitRepository; public FruitService(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void save(FruitDTO request) { fruitRepository.save(request); } public void sell(FruitDTO request) { if (fruitRepository.isFruitNotExist(request)) { throw new IllegalArgumentException("존재하지 않는 과일 입니다."); } fruitRepository.sell(request); } public FruitResponse getStat(String name) { return fruitRepository.getStat(name); } } FruitMemoryRepository@Primary @Repository public class FruitMemoryRepository implements FruitRepository { List fruitList = new ArrayList(); private long seq = 0L; @Override public void save(FruitDTO request) { fruitList.add(new FruitDTO( ++seq, request.getName(), request.getWarehousingDate(), request.getPrice(), false)); } @Override public void sell(FruitDTO request) { fruitList.get((int)request.getId()).set_sold(true); } public boolean isFruitNotExist(FruitDTO request) { return fruitList.size()
백엔드
・
백엔드
・
워밍업
2024. 02. 25.
0
[인프런 워밍업 클럽 0기] BE 1주차 회고
1일 차어노테이션과 API에 대해 생각해 볼 수 있었습니다.과제 : 어노테이션에 대해 찾아보며 몰랐던 내용을 정리하면 공부하였습니다. 2일 차API를 설계하여 통신하는 방법을 공부했습니다.과제 : 시간이 없어서 과제를 다 못해서 안 올렸지만 다음에 완성해서 올리려고 합니다. 3일 차익명 클래스와 람다에 관해 공부했습니다.개인적으로 익명 클래스와 람다 그리고 제네릭, collection 부분은 계속 반복해서 공부해야 될 것 같습니다. 코드를 보면 이해는 되지만 실제로 프로젝트 등에 적용을 해보는 연습이 필요할 것 같습니다.과제 : 이번 기회에 공부를 하면서 익명 클래스와 람다에 대해 좀 더 알 수 있는 시간이었습니다. 4일 차API를 설계하여 개발하고 postman으로 결과를 확인하며 공부하였습니다.과제 : 간단한 과일가게 API 개발이어서 큰 어려움은 없었지만 이런 기초를 단단히 쌓아야 나중에 도움이 될 것으로 생각합니다. 5일 차클린코드란 무엇인가 생각해 보는 시간이었습니다.과제 : 최대한 깔끔하게 작성해 보려고 했습니다. 1주 차 후기개인적으로 제일 좋았던 과제는 익명 클래스와 람다에 관해 공부할 수 있었던 과제였습니다.이번에 공부를 했으니 실제로 프로젝트나 다른 과제에 적용을 해보고 싶습니다.
백엔드
・
백엔드
・
워밍업
2024. 02. 23.
0
[인프런 워밍업 클럽 0기] BE 5일차 과제
코드class Dice { int numberOfSide; int count; Map map = new HashMap(); public void inputNumber() { System.out.println("주사위 면의 갯수를 입력하세요 : "); Scanner scanner = new Scanner(System.in); this.numberOfSide = scanner.nextInt(); System.out.println("주사위를 굴릴 총 횟수를 입력하세요 : "); scanner = new Scanner(System.in); this.count = scanner.nextInt(); } public void cal() { for (int i = 0; i
백엔드
・
백엔드
・
워밍업
2024. 02. 22.
0
[인프런 워밍업 클럽 0기] BE 4일차 과제
우리는 GET API와 POST API를 만드는 방법을 배웠습니다. 👍 추가적인 API 들을 만들어 보며 API 개발에 익숙해져 봅시다!Requestpublic class FruitRequest { private String name; private LocalDate warehousingDate; private long price; public String getName() { return name; } public LocalDate getWarehousingDate() { return warehousingDate; } public long getPrice() { return price; } } Controller@RequestMapping("/api/v1") @RestController public class FruitController { JdbcTemplate jdbcTemplate; public FruitController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @PostMapping("/fruit") public void saveFruit(@RequestBody FruitRequest request) { String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice()); } }postmanDBController@PutMapping("/fruit") public void putFruit(@RequestBody FruitSellRequest 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 is_sold = 1 WHERE id = ?"; jdbcTemplate.update(sql, request.getId()); } requestpublic class FruitSellRequest { private long id; public long getId() { return id; } }postmanDBController@GetMapping("/fruit/stat") public FruitStatResponse getStat(@RequestParam String name) { String salesSql = "select sum(price) from fruit where is_sold = 1 group by name having name = ?"; String notSalesSql = "select sum(price) from fruit where is_sold = 0 group by name having name = ?"; long salesAmount = jdbcTemplate.queryForObject(salesSql, Long.class, name); long notSalesAmount = jdbcTemplate.queryForObject(notSalesSql, Long.class, name); return new FruitStatResponse(salesAmount, notSalesAmount); } responsepublic class FruitStatResponse { private long salesAmount; private long notSalesAmount; public FruitStatResponse(long salesAmount, long notSalesAmount) { this.salesAmount = salesAmount; this.notSalesAmount = notSalesAmount; } public long getSalesAmount() { return salesAmount; } public long getNotSalesAmount() { return notSalesAmount; } } postmanDB
백엔드
・
백엔드
・
워밍업
2024. 02. 21.
0
[인프런 워밍업 클럽 0기] BE 3일차 과제
[질문]자바의 람다식은 왜 등장했을까?자바의 람다식은 불필요한 코드를 줄이고, 가독성을 높이기 위해서 등장하였다. 람다식의 이점코드의 간결함병렬처리의 가능과 안정적인 확장성 람다식과 익명 클래스는 어떤 관계가 있을까? 익명 클래스프로그램에서 일시적으로 한 번만 사용되고 버려지는 객체재사용이 없고 확장성을 활용하는 것이 유지보수하는 것에 있어 불리할 때 사용 람다식익명 함수의 한 형태로 볼 수 있으며 함수를 하나의 식으로 표현한 것을 말한다.장점- 코드의 간결함- 개발자의 의도가 명확히 드러나 좋은 가독성- 병렬 프로그래밍이 용이단점- 디버기의 어려움- 람다로 만든 익명함수의 재사용 불가능 FunctionalInterface추상 메소드가 오직 하나인 인터페이스를 의미(default method, static method는 여러개 존재해도 상관없다는 뜻이다.)@FunctionalInterface 어노테이션은 해당 인터페이스가 함수형 인터페이스 조건에 맞는지 검사해 준다. 람다식의 문법은 어떻게 될까? 람다식 기본 문법(타입 매개변수, ...) -> {실행문; ...} 매개 타입은 런타임시에 대입값에 따라 자동으로 인식하기 때문에 생략 가능(a) -> { System.out.println(a); } 하나의 매개변수만 있을 경우에는 괄호() 생략 가능a -> { System.out.println(a); } 하나의 실행문만 있다면 중괄호 {} 생략 가능a -> System.out.println(a); 매개변수가 없다면 괄호 ()를 생략할 수 없음( ) - > { 실행문; ... } 리턴값이 있는 경우 return 문을 사용(x, y) -> { return x + y; } 중괄호 {}에 return문만 있을 경우, 중괄호 생략 가능(x, y) -> x + y
백엔드
・
백엔드
・
워밍업
2024. 02. 19.
0
[인프런 워밍업 클럽 0기] BE 1일차 과제
[질문]- 어노테이션을 사용하는 이유 (효과) 는 무엇일까?컴파일러에게 코드 작성 문법 에러를 체크하도록 컴파일러에게 정보를 제공한다.소프트웨어 개발툴을 사용할 때 빌드 또는 배치 시 코드를 자동 생성할 수 있도록 정보 제공한다. 실행 시 특정 기능을 실행 하도록 정보제공한다.어노테이션사전적 의미로는'주석’을 뜻한다.메타 데이터의 일종메타 데이터 : application이 처리해야할 데이터가 아닌 컴파일 과정에서 코드를 어떻게 처리해야 하는지 알려주기 위한 추가 정보 어노테이션 종류메타어노테이션@Target : 어노테이션이 적용 가능한 대상을 지정@Retention : 어노테이션이 유지되는 기간을 지정@Documented : 해당 어노테이션을 javadoc에 포함 시킴@Inherited : 어노테이션의 상속을 가능하게 함@Repeatable : 어노테이션을 반복해서 적용할 수 있게 함표준 어노테이션(자바에서 기본으로 제공하는 어노테이션)@Override : 컴파일러에게 오버라딩하는 메소드라는 것을 알림@Deprecated : 앞으로 사용하지 않을 것을 권장하는 대상에 붙임@SuppressWarnings : 컴파일러의 특정 경고 메시지가 나타나지 않게 해 줌 @SafeVarargs : 제네릭 타입의 가변 인자에 사용@FunctionalInterface : 함수형 인터페이스라는 것을 알림@Native : native 메소드에서 참조되는 상수 앞에 붙임사용자 정의 어노테이션 사용자가 직접 정의하여 사용하는 어노테이션 - 나만의 어노테이션은 어떻게 만들 수 있을까? 나만의 어노테이션(커스텀 어노테이션)을 만들기 위해서는 @interface 를 사용하면 된다.지켜야할 조건어노테이션 타입은 자동적으로 java.lang.Annotation 인터페이스를 상속해서 다른 클래스나 인터페이스를 상속받지 않는다.파라미터 멤버들의 접근자는 public이거나 default 이다.파라미터 멤버들은 byte, short, char, int ,float, double, boolean의 기본 타입과 String, Enum, Class, 어노테이션만 사용할 수 있다. @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotation { String name() default "The name"; } public class MyAnnotationTest { @MyAnnotation(name = "커스텀 어노테이션") class Ano {} @Test @DisplayName("HelloWorld테스트") public void HelloWorldTest() throws Exception { Annotation[] annotations = Ano.class.getAnnotations(); for (Annotation annotation : annotations) { MyAnnotation myAnnotation = (MyAnnotation) annotation; System.out.println("helloWorldAnnotation = " + myAnnotation.name()); } } }
백엔드
・
백엔드
・
워밍업