블로그

유원준

[인프런 워밍업 클럽(백엔드, 0기)] - 개별 정리 : 자바 어노테이션

스프링으로 프로젝트를 하면서 자바 어노테이션을 항상 사용해 왔지만 아직 잘 모르는 부분이 많은 것 같아서 1일 차에 대한 과제 제출 기간은 지났지만, 추가적으로 인프런 블로그를 통해 다시 한 번 정리해 보고자 한다. (1) https://twojun-space.tistory.com/178본인 블로그에 내용을 별도로 정리했지만 한 번 더 리마인드해 보고자 한다.   1. 자바 어노테이션(Java Annotation)1-1. 정의(1) 어노테이션은 사전적 정의로는 "주석"이라는 의미를 가지고 있지만 자바에서의 어노테이션은 소스 코드에 추가할 수 있는 일종의 메타 데이터라고 볼 수 있다.(2) 애플리케이션 레벨에서 처리되어야 하는 대상이 아닌, 컴파일, 런타임 시점에 코드를 어떻게 처리해야 할지 알려주기 위한 정보로 볼 수 있겠다.  1-2. 장점(1) 코드 가독성, 컴파일 시점에서의 오류 체크코드 레벨에서 동일하게 작성되기 때문에 코드의 가독성이 좋고, 일부 어노테이션의 경우 컴파일 시점에 문법 에러(아래에서 설명할 @Override, @FunctionalInterface)를 잡아주기도 한다. (2) 중복 코드 제거중복되는 어노테이션의 경우 공통화시킬 수 있고 재사용이 가능하기 때문에 코드의 중복을 줄이고 효율적인 코드 작성이 가능하다. (3) 커스텀 어노테이션 (사용자 정의 어노테이션) 사용 가능직접 용도에 맞게 커스텀 어노테이션을 작성할 수 있다. 프로젝트를 진행함에 따라 각각 필요한 제약사항들을 별도로 정리해서 커스텀 어노테이션 구성이 가능하다.  1-3. 단점(1) 런타임 시 발생할 수 있는 오버헤드만약 런타임 시점에 자바의 리플렉션(Reflection) 등을 사용해서 처리되는 어노테이션이라면 이 부분을 처리하기 위한 별도의 오버헤드가 발생할 수 있다 (성능 상 문제)    2. 어노테이션의 종류살펴볼 어노테이션의 종류로 총 2가지가 있다.(1) 표준 어노테이션(빌트 인 어노테이션)(2) 메타 어노테이션    3. 표준 어노테이션(1) 표준 어노테이션의 경우 자바에서 기본적으로 제공하고 있는 어노테이션이다. 대표적으로 아래와 같이 3가지가 있다. 3-1. @Override(1) 현재 메서드가 부모 타입 클래스 또는 인터페이스의 메서드를 오버라이딩했음을 컴파일러에게 명시하는 역할을 수행한다. 만약 형식에 맞지 않게 오버라이딩되었다면, 컴파일러가 이를 인지하고 오류를 발생시킨다.  3-2. @Deprecated(1) 현재 메서드를 사용하지 않도록 유도한다. 만약 해당 어노테이션이 붙은 메서드를 사용하면 컴파일러가 오류를 발생시킨다.  3-3. @FunctionalInterface(1) 해당 인터페이스가 함수형 인터페이스임을 명시한다. 함수형 인터페이스의 경우 추상 메서드가 반드시 1개 존재해야 한다. 추상 메서드가 존재하지 않거나 2개 이상이라면 컴파일러가 오류를 발생시킨다.    4. 메타 어노테이션(Meta Annotation)(1) 메타 어노테이션이란 다른 어노테이션에서 사용될 수 있는 어노테이션을 의미하며 아래에서 작성할 커스텀 어노테이션(사용자 정의 어노테이션)을 생성할 때 주로 사용되는 어노테이션이다.   4-1. @Target(1) 어노테이션을 적용할 위치를 알려주는 어노테이션이다. (2) 예를 들어 @Target(ElementType.TYPE)의 경우 해당 어노테이션을 다른 어노테이션의 대상으로 사용할 수 있다는 의미이다. (3) 메타 어노테이션을 선언해 줄 때 사용되는 일반적인 방법 중 하나다.@Target({ ElementType.PACKAGE, // 패키지 선언 ElementType.TYPE, // 타입 선언 ElementType.CONSTRUCTOR, // 생성자 선언 ElementType.FIELD, // 멤버 변수 선언 ElementType.METHOD, // 메소드 선언 ElementType.ANNOTATION_TYPE, // 어노테이션 타입 선언 ElementType.LOCAL_VARIABLE, // 지역 변수 선언 ElementType.PARAMETER, // 매개 변수 선언 ElementType.TYPE_PARAMETER, // 매개 변수 타입 선언 ElementType.TYPE_USE // 타입 사용 })  4-2. @Retention(1) @Retention의 경우 어노테이션이 적용되고 유지되는 범위를 설정하기 위해 사용되는 메타 어노테이션이다.@Retention(RetentionPolicy.RUNTIME) // 컴파일 이후에도 JVM에 의해서 참조가 가능하다. @Retention(RetentionPolicy.CLASS) // 컴파일러가 클래스를 참조할 때까지 유효하다. @Retention(RetentionPolicy.SOURCE) // 어노테이션 정보는 컴파일 이후 없어진다.  4-3. @Inherited(1) 해당 어노테이션이 적용된 경우 자식 클래스가 해당 어노테이션을 상속받을 수 있게 된다.(2) 따라서 부모 클래스에 선언된 @Inherited 어노테이션은 하위 클래스에서 자동으로 상속받는다.  4-4. @Repeatable(1) 반복 가능한 어노테이션을 정의할 때 사용될 수 있는 어노테이션이다.    5. 커스텀 어노테이션(Custom Annotation, 사용자 정의 어노테이션) 5-1. 정의, 사용 방법public @interface SimpleAnnotation { }(1) 자바에서는 위와 같이 @interface 키워드를 통해 커스텀 어노테이션을 정의할 수 있다.   5-2. 실제로 커스텀 어노테이션 적용해 보기@Retention(RetentionPolicy.RUNTIME) @Inherited @Target(ElementType.TYPE) @RestController @RequestMapping("/new") public @interface CustomMyAnnotation { String name() default "MemberController"; String value(); } @CustomMyAnnotation(name = "MemberController", value = "MemberController") @RequiredArgsConstructor public class MemberController { private final MemberService memberService; @GetMapping("/list") public List<MemberListResponseDto> getAllMemberList() { List<Member> allMemberList = memberService.findAllMembersList(); return allMemberList.stream() .map(member -> new MemberListResponseDto(member)) .collect(Collectors.toList()); } }  5-3. 자바의 리플렉션(Reflection)(1) 현재 어노테이션을 사용해서 코드의 가독성이 좋아짐은 물론 어노테이션 자체가 되게 많은 일을 대신 해주고 있는 것을 확인해 볼 수 있다. 이 부분은 자바의 리플렉션 기술들이 해결해 주고 있는데 추후에 리플렉션에 관한 내용을 블로그에 다시 한 번 정리해 볼 예정이다.  마지막으로 부족하지만 글을 읽어주신 분들께 감사드립니다!!  

백엔드백엔드인프런워밍업자바어노테이션스프링

[인프런 워밍업 클럽 스터디] 13일차 - Spring Boot 설정, 버전업 이해하기

build.gradle빌드 스크립트라고도 불리며, gradle을 이용해 프로젝트를 빌드하고 의존성을 관리하기 위해 작성되었다.groovy 언어를 사용해 작성되었고, Kotlin이라는 언어를 사용할 수도 있다. org.springframework.boot 플러그인 역할스프링을 빌드했을 때 실행가능한 jar 파일이 나오게 도와주고스프링 애플리케이션을 실행할 수 있게 도와주고또 다른 플러그인들이 잘 적용될 수 있게 해준다. Spring 과 Spring Boot 의 차이점1. 간편한 설정2. 간단한 의존성 관리3. 강력한 확장성MSA에 적합한 모니터링  Lombokgetter, setter, 생성자와 같은 반복되는 보일러 플레이트 코드(boiler plate code)를 제거할 수 있다.lombok 의존성 추가IntelliJ lombok 플러그인 추가IntelliJ Annotation Processor 설정   Spring Boot 2.7.x 에서 3.0.x 로 업데이트 하기Java 최소 버전이 17로 업그레이드 되었다.많은 스프링 프로젝트, Thrid-party Library 가 버전업 되었다.AOT 기초 작업이 이루어졌다. AOT(Ahead of Time) 빌드를 할 때 스프링 애플리케이션을 분석하고 최적화하는 도구애플리케이션 시작 시간과 메모리 사용량을 줄일 수 있게 해준다.javax 대신 jakarta 패키지를 사용하게 된다.모니터링 기능들의 강화외의 다양한 세부적인 변경사항이 많음   

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 12일차 - AWS와 EC2 배포

Section 7. 생애 최초 배포하기[목표]EC2에 접속하는 방법을 알아보고, EC2에 접속해 리눅스 명령어를 다뤄본다.개발한 서버의 배포를 위해 환경 셋팅을 리눅스에서 진행하고, 실제 배포를 진행한다.foreground와 background의 차이를 이해하고 background 서버를 제어한다.도메인 이름을 사용해 사용자가 IP 대신 이름으로 접속할 수 있도록 한다.[리눅스 기본 명령어]mkdir : 폴더를 만드는 명령어ls : 현재 위치에서 폴더나 파일을 확인하는 명령어ls -l : 조금 더 자세한 정보를 확인할 수 있다.cd : 폴더 안으로 들어가는 명령어pwd : 현재 위치를 확인하는 명령어cd .. : 상위 폴더로 올라가는 명령어rmdir : 비어있는 폴더(디렉토리)를 제거하는 명령어 sudo yum update : 관리자의 권한으로 설치되어 있는 여러 프로그램을 최신화한다.sudo yum install [프로그램이름] : 관리자의 권한으로 프로그램을 설치한다.sudo systemctl status [프로그램이름] : 프로그램의 상태를 확인한다.suto systemctl restart [프로그램이름] : 프로그램을 재시작한다.chmod : 파일이나 폴더의 권한을 변경한다.ctrl + c : foreground로 실행중인 프로그램을 중단하는 신호nohup [명령어] & : [명령어]를 background에서 동작하게 만드는 명령어rm : 파일을 제거하는 명령어 ps aux : 현재 실행중인 프로그램 목록을 확인할 수 있다. kill -9 [프로그램번호] : 해당 프로그램을 종료시킨다. vi : 리눅스 편집기인 vim을 사용하여 파일을 연다.cat : 파일에 있는 내용물을 모두 출력하는 명령어 tail : 현재 파일의 끝 부분을 출력하는 명령어 tail -f : 현재 파일의 끝 부분을 실시간으로 출력해준다.      

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 10일차 - 객체지향과 JPA 연관관계

[1 : 1 관계][연관관계의 주인]Table을 보았을 때 누가 관계의 주도권을 가지고 있는가연관관계의 주인이 아닌 쪽에 mappedBy 옵션을 달아 주어야 한다.연관관계의 주인의 값이 설정되어야만 진정한 데이터가 저장된다.객체가 연결되는 기준이 된다. [연관관계의 주인 효과]상대 테이블을 참조하고 있으면 연관관계의 주인연관관계의 주인이 아니면 mappedBy를 사용연관관계의 주인의 setter가 사용되어야만 테이블 연결 [N : 1 관계] - @ManyToOne 과 @OneTOMany@JoinColumn연관관계의 주인이 활용할 수 있는 어노테이션.필드의 이름이나 null 여부, 유일성 여부, 업데이트 여부 등을 지정 [N : M 관계] - @ManyToMany구조가 봅잡하고, 테이블이 직관적으로 매핑되지 않아 사용하지 않는 것을 추천 cascade 옵션 : 한 객체가 저장되거나 삭제될 때, 그 변경이 폭포처럼 흘러 연결되어 있는 객체도 함께 저장되거나 삭제되는 기능orphanRemoval 옵션: 객체간의 관계가 끊어진 데이터를 자동으로 제거하는 옵션  [연관관계 정리]상대 테이블을 가리키는 테이블이 연관관계의 주인이다. 연관관계의 주인이 아닌 객체는 mappedBy를 통해 주인에게 매여 있음을 표히새 주어야 한다.양쪽 모두 연관관계를 갖고 있을 때는 양쪽 모두 한 번에 맺어주는게 좋다.cascade 옵션을 활용하면, 저장이나 삭제를 할 때 연관관계에 놓인 테이블까지 함께 저장 또는 삭제가 이루어진다.orphanRemoval 옵션을 활용하면, 연관관계가 끊어진 데이터를 자동으로 제거해준다.  [연관관계를 사용하면 무엇이 좋을까?]각자의 역할에 집중하게 된다.(응집성)새로운 개발자가 코드를 읽을 때 이해하기 쉬워진다.테스트 코드 작성이 쉬워진다.[연관관계를 사용하는 것이 항상 좋을까?]지나치게 사용하면, 성능상의 문제가 생길 수도 있고 도메인 간의 복잡한 연결로 인해 시스템을 파악하기 어려워질 수 있다.또한 너무 얽혀 있으면, A를 수정했을 때 B, C, D 까지 영향을 받을 수 있다.그렇기 때문에 비즈니스 요구사항, 기술적인 요구사항, 도메인 아키텍처 등 여러 부분을 고민해서 연관관계 사용을 선택해야 한다.  Section 5. 정리책 생성, 대출, 반납 API를 온전히 개발하며 지금까지 다루었던 모든 개념을 실습해본다.객체지향적으로 설계하기 위한 연관관계를 이해하고, 연관관계의 다양한 옵션에 대해 이해한다.JPA에서 연관관계를 매핑하는 방법을 이해하고, 연관관계를 사용해 개발할 때와 사용하지 않고 개발할 때의 차이점을 이해한다.   

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 7일차 - Spring Data JPA를 사용한 데이터베이스

Section 4. 생애 최초 JPA 사용하기[목표]문자열 SQL을 직접 사용하는 것의 한계를 이해하고, 해결책인 JPA, Hibernate, Spring Data JPA가 무엇인지 이해한다.Spring Data JPA를 이용해 데이터를 생성, 조회, 수정, 삭제할 수 있다.트랜잭션이 왜 필요한지 이해하고, 스프링에서 트랜잭션을 제어하는 방법을 익힌다.영속성 컨텍스트와 트랜잭션의 관계를 이해하고, 영속성 컨텍스트의 특징을 알아본다.[SQL을 직접 작성하면 아쉬운 점]문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다.특정 데이터베이스에 종속적이게 된다.반복 작업이 많아진다. 테이블을 하나 만들 때 마다 CRUD 쿼리가 항상 필요하다.데이터베이스의 테이블과 객체는 패러다임이 다르다.===> 그렇기 때문에 등장한 것이 JPA(Java Persistence API) [JPA란?]객체와 관계형 DB의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙이것을 코드로 구현한 것이 Hibernate. Hibernate는 JDBC를 내부적으로 사용한다. [JPA 어노테이션]@Entity : 스프링이 User 객체와 user 테이블을 같은 것으로 바라본다.  기본생성자 꼭 필요함.@Id : 이 필드를 primary key로 간주한다.@GeneratedValue : primary key는 자동 생성되는 값이다.@Column : 객체의 필드와 Table의 필드를 매핑한다. 이름이 같을 시 생략 가능. [spring.jpa.hibernate.ddl-auto]create: 기존 테이블이 있다면 삭제 후 다시 생성create-drop: 스프링이 종료될 때 테이블을 모두 제거update: 객체와 테이블이 다른 부분만 변경validate: 객체와 테이블이 동일한지 확인none: 별다른 조치를 하지 않는다 [지금까지 사용한 JPA Repository 기능]save: 주어지는 객체를 저장하거나 업데이트 시켜준다.findAll: 주어지는 객체가 매핑된 테이블의 모든 데이터를 가져온다.findById: id를 기준으로 특정한 1개의 데이터를 가져온다. [Spring Data JPA]복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리 [JPA Repository에서 By 앞에 들어갈 수 있는 구절 정리]find: 1건을 가져온다. 반환 타입은 객체가 될 수도 있고, Optional<타입>이 될 수도 있다.findAll: 쿼리의 결과물이 N개인 경우 사용. List<타입> 반환.exists: 쿼리 결과가 존재하는지 확인. 반환 타입은 boolean.count: SQL의 결과 개수를 센다. 반환 타입은 long. [JPA Repository에서 By 뒤에 들어갈 수 있는 구절 정리]GraterThan: 초과GraterThanEqual: 이상LessThan: 미만LessThanEqual: 이하Between: 사이에StartsWith: ~로 시작하는EndsWith: ~로 끝나는  [과제]진도표 7일차와 연결됩니다우리는 JPA라는 개념을 배우고 유저 테이블에 JPA를 적용해 보았습니다. 몇 가지 문제를 통해 JPA를 연습해 봅시다! 🔥 

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 6일차 - 스프링 컨테이너의 의미와 사용 방법

[정리] Section 3. 역할의 분리와 스프링 컨테이너좋은 코드가 왜 중요한지 이해하고, 원래 있던 Controller 코드를 보다 좋은 코드로 리팩토링 한다.스프링 컨테이너와 스프링 빈이 무엇인지 이해한다.스프링 컨테이너가 왜 필요한지, 좋은 코드와 어떻게 연관이 있는지 이해한다.스프링 빈을 다루는 여러 방법을 이해한다.  클래스 : 객체를 정의해놓은 설계도. 객체를 생성하기 위해 사용된다.객체 : 클래스에 정의된 내용이 인스턴스화되어 실제로 생성된 것. 설계도를 통해 만들어진 집.인스턴스(화) : 클래스를 실제로 사용할 수 있도록 생성하는 것. 스프링 빈 (UserController에 @RestController를 붙여줌으로써 스프링 빈이 됨)서버가 시작되면 스프링 서버 내부에 거대한 컨테이너(클래스 저장소)를 만든다.컨테이너 안에는 클래스가 들어간다.이 때 다양한 정보도 함께 들어있고, 인스턴스화도 이루어진다.이때 스프링 컨테이너 안으로 들어간 클래스를 스프링 빈이라고 한다.JdbcTemplate도 스프링 빈으로 등록되어 있다. (Dependency가 등록해 주고 있음)스프링 컨테이너는 필요한 클래스를 연결해준다.  서버가 시작되면 일어나는 일스프링 컨테이너(클래스 저장소)가 시작된다.기본적으로 많은 스프링 빈들이 등록된다.우리가 설정해 준 스프링 빈이 등록된다.이 때 필요한 의존성이 자동으로 설정된다. 스프링 빈을 등록하는 방법@Configuration클래스에 붙이는 어노테이션@Bean을 사용할 때 함께 사용해야 한다.  @Bean메소드에 붙이는 어노테이션메소드에서 반환되는 객체를 스프링 빈에 등록한다. @Service - @Repository 사용할 때 개발자가 직접 만든 클래스를 스프링 빈으로 등록할 때  @Configuration - @Bean 사용할 때외부 라이브러리, 프레임워크에서 만든 클래스를 등록할 때알아볼 어노테이션@Component주어진 클래스를 '컴포넌트'로 간주한다. 이 클래스들은 스프링 서버가 뜰 때 자동으로 감지된다.@Qualifier스프링 빈에 이름을 지정함으로써 특정 클래스를 가져옴 스프링 빈을 가져오는 방법(가장 권장) 생성자를 이용해 주입받는 방식 : @Autowired 생략 가능setter와 @Autowired 사용 : 누군가 setter를 사용하면 오작동 할 수 있다.필드에 직접 @Autowired 사용 : 테스트를 어렵게 만드는 요인이다.   참고자료 : https://mihee0703.tistory.com/182 

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 4일차 - 데이터베이스를 사용해 만드는 API

 [이론 정리]생애 최초 database 조작하기디스크와 메모리 차이를 이해하고, Database의 필요성을 이해한다.SQL을 이용해 MySQL Database를 조작할 수 있다.스프링 서버를 이용해 Database에 접근하고 데이터를 저장, 조회, 업데이트, 삭제할 수 있다.API의 예외 상황을 알아보고 예외를 처리할 수 있다.  [과제]문제 1우리는 작은 과일 가게를 운영하고 있습니다. 과일 가게에 입고된 "과일 정보"를 저장하는 API를 만들어 봅시다. 스펙은 다음과 같습니다.HTTP method : POSTHTTP path : /api/v1/fruitHTTP 요청 Body { "name" : String, "warehousingDate" : LocalDate, "price" : long }HTTP 요청 Body 예시 { "name" : "사과", "warehousingDate" : "2024-02-01", "price" : 5000 }응답 : 성공시 200 💡한 걸음 더!자바에서 정수를 다루는 가장 대표적인 두 가지 방법은 int와 long입니다.이 두 가지 방법 중 위 API에서 long을 사용한 이유는 무엇일까요?  문제 2과일이 팔리게 되면, 우리 시스템에 팔린 과일 정보를 기록해야 합니다. 스펙은 다음과 같습니다.HTTP method : PUTHTTP path : /api/v1/fruitHTTP 요청 Body{ "id" : long }HTTP 요청 Body 예시 { "id" : 3 }응답 : 성공시 200  문제 3우리는 특정 과일을 기준으로 팔린 금액, 팔리지 않은 금액을 조회하고 싶습니다.예를 들어(1, 사과, 3000원, 판매O)(2, 사과, 4000원, 판매X)(3, 사과, 3000원, 판매O)와 같은 세 데이터가 있다면 우리의 API는 판매된 금액 : 6000원, 판매되지 않은 금액 : 4000원 이라고 응답해야 합니다.구체적인 스펙은 다음과 같습니다.HTTP method : GETHTTP path : /api/v1/fruit/statHTTP query- name : 과일 이름예시 GET /api/v1/fruit/stat?name=사과HTTP 응답 Body{ "salesAmount" : long, "notSalesAmount" : long }HTTP 응답 Body 예시 { "salesAmount" : 6000, "notSalesAmount" : 4000 }💡한 걸음 더!(문제 3번을 모두 푸셨다면) SQL의 sum, group by 키워드를 검색해 적용해보세요.   

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 3일차 - 기본적인 데이터베이스 사용법

Section 2. 생애 최초 Database 조작하기[목표]디스크와 메모리의 차이를 이해하고, Database의 필요성을 이해한다.MySQL Database를 SQL과 함께 조작할 수 있다.스프링 서버를 이용해 Database에 접근하고 데이터를 저장, 조회, 업데이트, 삭제할 수 있다.API의 예외 상황을 알아보고 예외를 처리할 수 있다.  과제[키워드]익명 클래스 / 람다 / 함수형 프로그래밍 / @FunctionalInterface / 스트림 API / 메소드 레퍼런스 [질문]자바의 람다식은 왜 등장했을까? 람다식이 등장하게 된 이유는 불필요한 코드를 줄이고, 가독성을 높이기 위함이다. 그렇기 때문에 함수형 인터페이스의 인스턴스를 생성하여 함수를 변수처럼 선언하는 람다식에서는 메소드의 이름이 불필요하다고 여겨져서 이를 사용하지 않는다. 대신 컴파일러가 문맥을 살펴 타입을 추론하게 된다. 또한 람다식으로 선언된 함수는 1급 객체이기 때문에 Stream API의 매개변수로 전달이 가능해진다. 람다식과 익명 클래스는 어떤 관계가 있을까? -> 람다식의 문법은 어떻게 될까? 람다식(Lambda Expression) 이란 함수를 하나의 식(expression)으로 표현한 것이다. 함수를 람다식으로 표현하면 메소드의 이름이 필요 없기 때문에, 람다식은 익명 함수(Anonymous Function)의 한 종류라고 볼 수 있다.익명함수(Anonymous Function)란 함수의 이름이 없는 함수로, 익명함수들은 모두 일급 객체이다. 일급 객체인 함수는 변수처럼 사용 가능하며 매개 변수로 전달이 가능하다는 등의 특징을 가지고 있다.//람다 방식 (매개변수, ... ) -> { 실행문 ... } //예시 () -> "Hello World!"; 출처 : https://bny9164.tistory.com/79참고 : https://dwaejinho.tistory.com/entry/Java-Lambda-Stream-%EB%8F%84%EC%9E%85-%EB%B0%B0%EA%B2%BD%EA%B3%BC-%EC%9B%90%EB%A6%AC-%ED%8C%8C%ED%95%B4%EC%B9%98%EA%B8%B0#1.1%20%EB%9E%8C%EB%8B%A4%20%EB%8F%84%EC%9E%85%20%EB%B0%B0%EA%B2%BD-1

백엔드워밍업클럽스터디백엔드자바스프링부트

wisehero

[워밍업 클럽 BE-0기 백엔드] 과제 5일차 - 코드 리팩토링 과제

오늘은 주사위를 던져서 숫자별로 나온 횟수를 기록하고 결과를 출력하는 절차지향적으로 작성된 코드를 리팩토링 해야합니다. 절차지향적으로 짠 코드가 모두 나쁜 것은 아니지만, 이번 스터디에서 우리는 객체지향 패러다임에 근거해 등장한 자바라는 언어와 그 언어가 가진 패러다임을 극대화한 스프링이라는 프레임워크를 공부하고 있으므로 객체지향적으로 깔끔하게 코드를 정리할 수 있는 역량을 길러야 합니다.  주어진 코드는 아래와 같습니다.public class Assignment { public static void main(String[] args) { // 입력을 받고 받은 입력을 저장하는 역할 역할 System.out.println("숫자를 입력하세요 : "); Scanner scanner = new Scanner(System.in); int a = scanner.nextInt(); // 주사위 숫자를 담는 역할 int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0; // 나온 숫자를 세는 역할 for (int i = 0; i < a; i++) { double b = Math.random() * 6; if (b >= 0 && b < 1) { r1++; } else if (b >= 1 && b < 2) { r2++; } else if (b >= 2 && b < 3) { r3++; } else if (b >= 3 && b < 4) { r4++; } else if (b >= 4 && b < 5) { r5++; } else if (b >= 5 && b < 6) { r6++; } } // 결과를 출력하는 역할 System.out.printf("1은 %d번 나왔습니다.\n", r1); System.out.printf("1은 %d번 나왔습니다.\n", r2); System.out.printf("1은 %d번 나왔습니다.\n", r3); System.out.printf("1은 %d번 나왔습니다.\n", r4); System.out.printf("1은 %d번 나왔습니다.\n", r5); System.out.printf("1은 %d번 나왔습니다.\n", r6); } }객체지향적으로 코드를 리팩토링하기 위해서는 여러 명령문들이 어떠한 역할을 하고있는지 구분하는 것이 중요한 것 같습니다. 역할을 구분해야 역할과 책임에 따른 클래스, 메소드 단위로 구분하기가 쉬워지기 때문입니다. 저는 우선 두 개의 클래스를 사용하려고 합니다. 단순히 주사위를 굴리고 결과를 저장하고, 결과를 출력하는 책임을 갖고 있는 메서드를 가진 클래스그리고 그 클래스를 실행하는 클래스 본디 자바의 main은 프로그램 실행의 진입점으로서 반드시 어딘가에 만들어져 있어야 합니다. 그리고 우리는 스프링 부트를 켜서 기본으로 생성되어있는 클래스를 보시면@SpringBootApplication public class LibraryAppApplication { public static void main(String[] args) { SpringApplication.run(LibraryAppApplication.class, args); } }이렇게 단순히 스프링 애플리케이션을 실행하는 main메서드와 명렁문만이 있습니다. 그래서, 저는 아래처럼 만들었습니다.public class DiceApplication { public static void main(String[] args) { DiceRoller diceRoller = new DiceRoller(); diceRoller.rollDice(); diceRoller.printResult(); } }이 클래스에선 단순히 하나의 일만 합니다. DiceRoller 즉, 주사위를 굴리고 그에 따른 결과를 출력하는 책임을 갖고 있는 클래스를 생성하고, 일을 시키기만 합니다! 저는 예전에 유튜브에서 TDA, Tell, Don't Ask(요청하지말고, 시켜라) 라는 개념을 본 적이 있었는데 그 원칙에 최대한 맞춰보기 위해 위와 같이 작성했습니다. 그리고 DiceRoller라는 클래스는 아래와 같이 작성했습니다.public class DiceRoller { private int[] results = new int[6]; public void rollDice() { System.out.print("숫자를 입력하세요 : "); Scanner scanner = new Scanner(System.in); int rolls = scanner.nextInt(); generateRandomRolls(rolls); } private void generateRandomRolls(int rolls) { for (int i = 0; i < rolls; i++) { int result = (int) (Math.random() * 6); // 0 to 5 results[result]++; } } public void printResults() { for (int i = 0; i < results.length; i++) { System.out.printf("%d은 %d번 나왔습니다.\n", i + 1, results[i]); } } }이 클래스는 초기 주사위 숫자 크기와 결과를 담고있는 배열을 선언하고 있구요. 다음 3개의 메서드를 갖고 있습니다.숫자를 입력받고 입력받은 숫자만큼 주사위를 굴리도록 '시키는' 메서드넘겨받은 숫자만큼 주사위를 굴리고 기록하는 메서드그리고 그 결과를 출력하는 메서드.물론 여기서 핵심 로직은 주사위를 굴리고 결과를 기록하는 것입니다. 더 나누려면 나눌 수 있습니다. 입출력 부분을 함께 수행하는 클래스로 말이죠. 하지만 여기서는 사이즈가 그렇게 크지 않으므로 입출력 및, 주사위 굴리고 결과를 기록하는 메서드를 한 클래스안에 두었습니다. 그리고 Math.random()은 그 결과를 double로 반환하는 까닭에 기존의 코드는 if (b >= 0 && b < 1) { r1++; } else if (b >= 1 && b < 2) { r2++; } else if (b >= 2 && b < 3) { r3++; } else if (b >= 3 && b < 4) { r4++; } else if (b >= 4 && b < 5) { r5++; } else if (b >= 5 && b < 6) { r6++; }이렇게 지저분하게 조건 분기를 해줘야 했죠. 하지만 주사위 굴리기의 결과는 늘 정수이기에 형변환 코드를 넣어줌으로써 저러한 조건 분기를 지울 수 있게 되었습니다. 그리고 입력은 보통 한 줄에서 받는 것이 보기 좋으므로 입력을 받는 부분의 System.out.println()을 System.out.print()로 바꾸어 주었습니다. 그러면 한 걸음 더! 에 있는 문제를 해결해봅시다. 지금 저는 주사위의 숫자가 1부터 6까지 있다고만 가정했습니다. 하지만, 어느날 주사위라는 것 자체가 규격이 바뀌었다고 가정한다면 제가 작성한 코드는 오작동하는 코드입니다. 왜냐면 private int[] results = new int[6]; int result = (int) (Math.random() * 6)이렇게 배열 크기를 주사위가 1부터 6까지 있다는 가정하에 직접 넣어주었기 때문입니다. 그래서 저는 필드에서 선언한 즉시 초기화를 하기보다는, 생성자로 초기화하는 것을 선택했습니다. 그러면 코드는 아래와 같이 바뀔 수 있습니다.public class DiceApplication { public static void main(String[] args) { DiceRoller diceRoller = DiceRoller.makeDice(); diceRoller.rollDice(); diceRoller.printResults(); } } class DiceRoller { private int[] results; private int sides; public DiceRoller(int sides) { this.sides = sides; this.results = new int[sides]; } public static DiceRoller makeDice() { Scanner scanner = new Scanner(System.in); System.out.print("주사위 면의 수를 입력하세요 : "); int sides = scanner.nextInt(); return new DiceRoller(sides); } public void rollDice() { System.out.print("굴릴 횟수를 입력하세요 : "); Scanner scanner = new Scanner(System.in); int rolls = scanner.nextInt(); generateRandomRolls(rolls); } private void generateRandomRolls(int rolls) { for (int i = 0; i < rolls; i++) { int result = (int)(Math.random() * sides); results[result]++; } } public void printResults() { for (int i = 0; i < sides; i++) { System.out.printf("%d은 %d번 나왔습니다.\n", i + 1, results[i]); } } }저는 스태틱 메서드를 사용해서 DiceRoller 객체를 생성하도록 하고 그렇게 생성된 주사위를 굴리고, 결과를 출력하게 끔 했습니다. 실행 결과는 아래와 같습니다. 어떤가요? 많이 클린해졌나요? 누군가는 '작성해야 하는 코드 양이 더 많아졌는데?' 라고 생각하실 순 있겠지만 내부 동작과 어떤 흐름으로 프로그램이 실행되는 지에 대한 '명확성' 부분에서 저는 좀 더 나아졌다고 생각합니다. 저의 리팩토링이 어떠했는지에 대해서 냉철한 평가를 내려주셔도 좋고 조금 더 개선할 부분이 있다면 알려주세요! 감사합니다!

백엔드백엔드최태현자바스프링

인프런 웜업 0기 - 과제 4

package com.group.libraryapp.controller.api.v1; import com.group.libraryapp.dto.fruit.request.FruitSellRequest; import com.group.libraryapp.dto.fruit.request.FruitCreateRequest; import com.group.libraryapp.dto.fruit.response.FruitResponse; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.web.bind.annotation.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; @RestController public class FruitController { private final JdbcTemplate jdbcTemplate; public FruitController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @PostMapping("api/v1/fruit") // POST /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()); } @PutMapping("api/v1/fruit") // PUT /fruit public void sellFruit(@RequestBody FruitSellRequest request) { String checkSql = "SELECT * FROM fruit WHERE id = ?"; // 해당 id가 존재하지않을 시 예외처리 boolean isNotExist = jdbcTemplate.query(checkSql, (rs, rowNum) -> 0, request.getId()).isEmpty(); if (isNotExist) { throw new IllegalArgumentException(); } String sql = "UPDATE fruit SET sold = 1 WHERE id = ?"; jdbcTemplate.update(sql, request.getId()); } @GetMapping("api/v1/fruit/stat") // GET /fruit public FruitResponse getFruit(@RequestParam String name) { String checkSql = "SELECT * FROM fruit WHERE name = ?"; boolean isNotExist = jdbcTemplate.query(checkSql, (rs, rowNum) -> 0, name).isEmpty(); if (isNotExist) { throw new IllegalArgumentException(); } // 1) sold 여부에 따른 각 price의 최종합계를 구해온 뒤, 리스트에 추가. // 2) 최종 list를 순회하면서 sold 여부에 따른 최종합계 재계산후 반환. String sql = "SELECT sold, SUM(price) AS total_price FROM fruit WHERE name = ? GROUP BY sold"; List<FruitResponse> responses = jdbcTemplate.query(sql, (rs, rowNum) -> { FruitResponse response = new FruitResponse(0, 0); if (rs.getBoolean("sold")) response.setSalesAmount(rs.getLong("total_price")); else response.setNotSalesAmount(rs.getLong("total_price")); return response; }, name); FruitResponse finalResponse = new FruitResponse(0, 0); for (FruitResponse response : responses) { finalResponse.setSalesAmount(finalResponse.getSalesAmount() + response.getSalesAmount()); finalResponse.setNotSalesAmount(finalResponse.getNotSalesAmount() + response.getNotSalesAmount()); } return finalResponse; } } Fruit 테이블 생성  Post를 이용하여 Fruit 테이블에 'apple' 레코드 생성레코드 생성확인apple의 'sold' 필드를 true로 설정.레코드 변경여부 확인2개의 apple들을 더 추가하고, sold 필드는 설정하지않았음.sold 여부에 따른 최종가격 받아오기 확인

백엔드인프런웜업클럽0기자바백엔드

[인프런 워밍업 클럽 스터디] 2일차 - 첫 HTTP API 개발

 [Section 1 정리]스프링 프로젝트를 시작하는 방법과 실행하는 방법네트워크, IP, 도메인, 포트, HTTP 요청과 응답 구조, 클라이언트-서버 구조, API와 같은 기반 지식Spring Boot를 이용해 GET API와 POST API를 만드는 방법 [과제]문제 1두 수를 입력하면, 다음과 같은 결과가 나오는 GET API를 만들어보자!path : /api/v1/calc쿼리 파라미터 : num1, num2 { "add" : 덧셈결과, "minus" : 뺄셈결과, "multiply" : 곱셈결과 } 예시GET /api/v1/calc?num1=10&num2=5{ "add" : 15, "minus" : 5, "multiply" : 50 } 문제 2날짜를 입력하면, 무슨 요일인지 알려주는 GET API를 만들어보자!path와 쿼리 파라미터는 임의로 만들어도 상관없다. 예시GET /api/v1/day-of-the-week?date=2023-01-01{ "dayOfTheWeek" : "MON" } 문제 3여러 수를 받아 총 합을 반환하는 POST API를 만들어보자!API에서 받는 Body는 다음과 같은 형태이다.(HINT : 요청을 받는 DTO에서 List를 갖고 있으면 JSON의 배열을 받을 수 있습니다.){ "numbers" : [1, 2, 3, 4, 5] }반환 결과15⚠주의반환결과는 JSON이 아닙니다.함수에서 String 혹은 Integer를 반환하면, API결과가 JSON으로 나가지 않고, 단순한 값으로 나가게 됩니다.POST MAN과 같은 API 테스트 툴을 이용해 한 번 확인해보세요.

백엔드워밍업클럽스터디백엔드자바스프링부트

[인프런 워밍업 클럽 스터디] 1일차 - 서버 개발을 위한 환경설정

 Section 1. 생애 최초 API 만들기[목표]스프링 프로젝트를 설정해 시작하고 실행할 수 있다.서버란 무엇인지, 네트워크와 HTTP, API는 무엇인지, JSON은 무엇인지 등 서버 개발에 필요한 다양한 개념을 이해한다.스프링 부트를 이용해 간단한 GET API, POST API를 만들 수 있다. [이론 총정리](웹을 통한)컴퓨터 간의 통신은 HTTP라는 표준화된 방식이 있다.HTTP 요청은 HTTP Method (GET, POST)와 Path (/portion)가 핵심이다.요청에서 데이터를 전달하기 위한 2가지 방법은 쿼리와 바디이다.HTTP 응답은 상태코드가 핵심이다.클라이언트와 서버는 HTTP를 주고 받으며 기능을 동작하는데 이때 정해진 규칙을 API라고 한다. [사용 어노테이션]@RestController : 주어진 Class를 Controller로 등록한다. API의 진입 지점.@GetMapping("/add") : 아래의 함수를 HTTP Method가 GET이고 HTTP Path가 /add인 API로 지정한다.@RequestParam : 주어지는 쿼리를 함수 파라미터에 넣는다. [질문]어노테이션을 사용하는 이유 (효과) 는 무엇일까? Annotations in JavaAnnotations are used to provide supplemental information about a program.Annotations start with ‘@’.Annotations do not change the action of a compiled program.Annotations help to associate metadata (information) to the program elements i.e. instance variables, constructors, methods, classes, etc.Annotations are not pure comments as they can change the way a program is treated by the compiler.Annotations basically are used to provide additional information, so could be an alternative to XML and Java marker interfaces. 나만의 어노테이션은 어떻게 만들 수 있을까?How to Create Your Own Annotations in Java?Annotations are a form of metadata that provide information about the program but are not a part of the program itself. An Annotation does not affect the operation of the code they Annotate. Now let us go through different types of java annotations present that are listed as follows:Predefined annotations.: @Deprecated, @Override, @SuppressWarnings, @SafeVarargs, @FunctionalInterface.Meta-annotations: @Retention, @Documented, @Target, @Inherited, @Repeatable.Custom annotations: These are defined by the user. (We will be learning to create custom annotations in this module).Geek, now you must be wondering how can we create our own java annotations, for that refer to simple steps sequentially as follows:To create your own Java Annotation you must use @interface Annotation_name, this will create a new Java Annotation for you.The @interface will describe the new annotation type declaration.After giving a name to your Annotation, you will need to create a block of statements inside which you may declare some variables. 출처 1. https://www.geeksforgeeks.org/annotations-in-java/출처 2. https://www.geeksforgeeks.org/how-to-create-your-own-annotations-in-java/ 

백엔드워밍업클럽스터디백엔드자바스프링부트

망그리

[인프런 워밍업 클럽] 1일차 과제

진도표 1일차와 연결됩니다우리는 최초로 API를 만들어 보았습니다. GET API를 만들기 위해 사용했던 어노테이션에 익숙하지 않다면 자바 어노테이션에 대해서 몇 가지 블로그 글을 찾아보세요! 다음 질문을 생각하며 공부해보면 좋습니다! 😊[질문]어노테이션을 사용하는 이유 (효과) 는 무엇일까?나만의 어노테이션은 어떻게 만들 수 있을까?> 어노테이션을 사용하는 이유(효과) 는 무엇일까?어노테이션이란, @로 시작하는 코드이고어떤 용도로 사용할지, 어떤 역할을 부여할지 결정한다.  어노테이션의 장점은간결하다로직을 방해하지 않는다.정보를 제공한다. 어노테이션은 자식 클래스에 여러개의 메소드가 정의되어 있을 때 사용한다.그리고 컴파일러에게 문법 체크를 하도록 알려주는 기능이 있어서 컴파일 하기 전에 컴파일러가 이러한 사항을 체크해주며,프로그램 작성을 위해 매번 많은 설정을 해야하며, 수 많은 설정 파일들을 관리해야했지만 이 문제점을 해결하기 위해 고안된 문법이 어노테이션이라고 한다. 그래서 사용하는 이유는 쉽게 파악할 수 있게 되는 점과 오류 감소라고 생각한다.   > 나만의 어노테이션은 어떻게 만들 수 있을까? 어노테이션 유형 package com.xxx.xxx; public @interface TODO{ String value(); }  package com.group.libraryapp.controller.calculator; import com.group.libraryapp.controller.dto.calculator.request.CalculatorAddRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class CalculatorController { @GetMapping("/add") // GET /add public int addTwoNumbers(CalculatorAddRequest request) { return request.getNumber1() * request.getNumber2(); } }  수강하면서 배운 계산기 어노테이션 +가 아니라 *나 /로도 실행해보았다. 

백엔드워밍업스터디백엔드자바JAVA

휴식중인 가재

[전액무료,실시간온라인] 지역ICT 이노베이션스퀘어 확산사업_블록체인 고급 프로젝트과정교육

    안녕하세요. 한국취업센터입니다.   지역ICT 이노베이션스퀘어 확산사업_블록체인 고급 프로젝트과정 안내드립니다.   수강혜택으로 수료증발급, 블록체인 자격증 응시 기회까지 제공해드리고 전액무료, 누구나 과정을 이수할 수 있으니 신청해보세요.   학생, 취업준비생, 재직자, 이직자 예정자분들 병행 추천드립니다!                     블록체인 고급 프로젝트과정 참여자 모집 공고를 아래와 같이 안내 드리오니, 참여 희망자는 해당 홈페이지로 참가 신청서를 제출하시길 바랍니다. 블록체인 고급 프로젝트과정 > 블록체인 | AI배울랑교_동남권ICT이노베이션스퀘어 (baeulang.kr) 조기 신청자가 많기에, 빠른 지원 바랍니다.   ※ 경상권 거주자분들은 즉시 신청 가능하며, 타 지역거주자는 신청 전에 오픈카톡으로 문의를 주시기 바랍니다. (경상권 거주자 즉시 참여가능) - 블록체인 훈련과정 문의 [ https://open.kakao.com/o/sctcWywe ]    [모집 개요] * 사업명: 블록체인 고급 프로젝트 과정 * 대상인원: 30명 * 모집대상: 블록체인 분야에 관심있는 누구나 / 블록체인 관련 스타트업을 준비하는 사람 * 모집기간: 2022년 08월 17일 ~ 2022년 09월 27일 * 교육기간: 2022년 09월 28일 ~ 2022년 11월 19일 * 교육장소: 경남테크노파크 정보산업진흥본부(봉암동) (실시간 온라인 수강 가능) * 교육내용: 암호기술, 스마트 컨트랙트 및 보안 취약점 사례 분석 등 자세한 내용 첨부파일 참조 * 교육비: 전액 무료 * 수강혜택: 교육비 전액 무료 , 수료증 발급, 블록체인 민간 자격증 응시 기회 제공       [교육 문의 사항] - 블록체인 훈련과정 문의 [ https://open.kakao.com/o/sctcWywe ] - E-MAIL : by.choi@k-abc.com/hi.kang@k-abc.com - 전화번호 : 02 - 6101 - 9956 / 8855       자세한 내용은 블록체인 고급 프로젝트과정 > 블록체인 | AI배울랑교_동남권ICT이노베이션스퀘어 (baeulang.kr) 에서 확인하시기 바랍니다. 문의사항이 있으신 경우 연락주시길 바랍니다. 감사합니다.  

백엔드프론트엔드자바자바스크립트스프링리엑트파이톤클론코딩코딩