1
2
3
4
5
6
7
8
ㅡㅡㅡ
●1
#
IOC(Inversion of control) - 제어의 역전
-기존
Car car = new Car();
-IOC
직접 생성하거나 제어하는 것이 아닙니다.
스프링프레임워크가 관리한다. 만들어져있는 것을 가져다가
필요한 곳에 주입해서 사용한다. 제어권이 개발자한테 있는 것 아니라,
프레임워크한테 있다라고해서 제어의 역전이라 합니다.
컨테이너한테 빈으로 등록 @Bean라고 입력
#DI
(Dpendency Injection)
외부에서 객체 간의 관계(의존성)를 결정해 주는데 즉, 객체를 직접 생성하는 것이 아니라 외부에서 생성 후 주입시켜 주는 방식이라 할 수 있다.
[출처]https://backendcode.tistory.com/249
#bean, autowired
@Component 란,
@Component는 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 Annotation 입니다.
* 위에서 설명한 스프링의 컴포넌트 스캔 (@ComponentScan) 기능에 의해 스캔될 때, 주어진 패키지 내에서 @Component 어노테이션이 적용된 클래스를 식별하고, 그러한 클래스의 빈을 생성하여 ApplicationContext에 등록합니다.
* (value = "") 옵션이 있고, 해당 옵션을 사용하지 않는다면 class의 이름을 camelCase로 변경한 것을 bean id로 사용합니다.
그렇다면 @Controller, @Service, @Repository 어노테이션은 무엇일까요?
@Controller, @Service, @Repository
@Controller, @Service, @Repository 어노테이션들은 @Component 어노테이션의 구체화된 형태입니다.
어노테이션을 세분화 함으로써 가독성 측면에서 해당 각각의 어노테이션을 가진 클래스의 역할을 알 수 있게 됩니다.
[출처] : https://wildeveloperetrain.tistory.com/26#google_vignette
@Bean 이란,
@Bean 어노테이션은 개발자가 직접 제어가 불가능한 외부 라이브러리 등을 Bean으로 만들려고 할 때 사용됩니다.
* (name = "") 옵션이 있고, 해당 옵션을 사용하지 않는다면 method 이름을 camelCase로 변경한 것이 bean id로 등록됩니다.
// 암호화에 필요한 PasswordEncoder Bean 등록
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// authenticationManager Bean 등록
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean과 같이 알아야 할 @Configuration
@Configuration 어노테이션은 해당 클래스에서 1개 이상의 Bean을 생성하고 있음을 명시합니다.
그러므로 @Bean 어노테이션을 사용하는 클래스는 반드시 @Configuration과 함께 사용되어야 합니다,
출처 : https://wildeveloperetrain.tistory.com/26
@Autowired, @Qualifier
@Autowired는 field(속성) , setter, method, constructor(생성자)에서 사용하며 Type에 따라 자동으로 bean을 주입합니다.
Type을 먼저 확인하여 못 찾는 경우에는 name에 따라서 bean을 주입합니다.
이때 해당 타입의 bean 객체가 존재하지 않거나, 2개 이상 존재할 경우 스프링은 예외가 발생합니다.
같은 타입의 bean이 두 개 이상 존재하는 경우, 어떤 bean을 주입해야 할지 알 수 없기 때문에 스프링 컨테이너를 초기화하는 과정에서 예외가 발생하는데요. 이 경우 @Qualifier 어노테이션을 @Autowired와 함께 사용하여 어떤 bean을 사용할지 명시할 수 있습니다.
* 추가적으로 @Autowired를 사용할 경우 순환 참조가 발생할 수 있기 때문에 @Autowired 보다 생성자 주입 방식이 더 권장되고 있습니다.
출처 : https://wildeveloperetrain.tistory.com/26
#스프링컨테이너
객체 간의 의존성을 낮추어(느슨한 결합)
결합도는 낮추고,
높은 캡슐화를 위해 스프링 컨테이너가 사용된다.
[출처] : https://ittrue.tistory.com/220 [IT is True:티스토리]
빈을 생성하고 관리하는 곳
생명주기- 만들어지고 , 쓰이고, 소멸하는 것
Autowired으로 빈을 주입받는다 그래서 DI
#인메모리, 마이그레이션, 리팩토링,
#
클래스를 빈으로 등록하고 싶다
@Conponent
#스프링 빈
#API, document 정리 ★★★
#AOP(Aspect Oriented programming)
관점지향프로그래밍
통으로 다짤수있지만, ㅡ프로그램은 수시로 바뀐다 ㅡ 그래서 유지보수가 필요하다
ㅡ 쪼개서 관리하는 것이 중요합니다. ㅡ
#
핵심관점
부가관점
횡단관심사
종단괌심사
로그기록
시큐리티 - 하나만 만들고 끌어다가 사용
중요한 부분들에 집중하는 것들이 AOP이다.
#
POJO (예전 자바로 돌아가자)
Plain old java object
#
●2
아이템 레포지토리안에는 CRUD같은 것들이 지원되고 있다라고 생각하면 됩니다.
JPA가 구현한 것이 하이버네이트(구현체)
3가지 처리를 한다합니다.
1.쿼리메소드 ㅡ 일반적으로 사용
2.@쿼리어노테이션 (스프링에서 제공하는 Data JPA@Query) ㅡ 조금더 복잡
3.querydsl ㅡ 조금더 세밀하게
#쿼리메소드
find는 정해져있습니다.
1.(find)Item(By)ItemName
2.item은 생략가능합니다.(엔티티명)
#JPA - 쿼리문
#스프링의특징
파일명을 길게 씁니다. 무엇인지 알아보기이 위함 입니다.
#
장점 : 익숙한 것을 쓴다는 장점이 있지만,(복잡한 쿼리를 사용하려고할떄 )
단점 : 다른 데이터베이스에서 독립적으로 쓸수없다는 단점(종속이 되어버립니다.)
●3
pom을 통해서 이것들은 처리가 되었습니다.
●4 테스트프로그램1
package com.cshop.repository;
import com.cshop.constant.ItemSellStatus;
import com.cshop.entity.Item;
import com.cshop.entity.QItem;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.thymeleaf.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
//#1. 통합테스트를 위한 어노테이션
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
class ItemRepositoryTest {
//영속성 컨텍스트란? JPA의 중요한 특징으로 엔티티를 관리합니다.
//(엔티티를 관리하는 가상공간)을 사용하기 위해
//데이터베이스를 효과적으로 사용할 수 있게 되는 것입니다. 엔티티를 편하게 사용하는 이유가 영속성 컨텍스트 때문입니다.
//영속성 컨텍스트를 사용하기 위해
@PersistenceContext // import jakarta.persistence.PersistenceContext;
EntityManager em; //프록시(가짜) 엔티티 매니저, 필요할 때 진짜 엔티티 매니저 호출
//스프링 부트는 기본적으로 빈을 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있음
//그래서 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 proxy(가짜) 엔티티 매니저를 사용
//엔티티 : 데이터베이스의 테이블과 직접 연결
// Entity Manager : Entity를 관리해 데이터베이스와 애플리케이션 사이에서 객체를 생성, 수정, 삭제하는 역할
//엔티티 팩토리 : 엔티티 매니저를 만드는 곳
//# 스프링 빈에 빈으로 등록되어 있는 것을 주입
@Autowired
ItemRepository itemRepository;
//빈을 하나만 생성한다.
//실제로는 엔티티매니저와 연결되어있는 프록시(가짜) 엔티티매니저를 사용한다.
//그래서 필요할떄, 데이터베이스트랜잭션, 엔티티매니저를 호출
// @Test //#4.
// //#5.
// @DisplayName("상품 저장(insert) 테스트")
// public void createItemTest(){
// Item item = new Item();
//
// item.setItemName("테스트 상품");
// item.setPrice(100000);
// item.setItemDetail("테스트 상품 상세 설명");
// item.setItemSellStatus((ItemSellStatus.SELL));
// item.setStockNumber(100);
// item.setRegTime(LocalDateTime.now());
// item.setUpdateTime(LocalDateTime.now());
//
// Item saveItem = itemRepository.save(item);
// System.out.println(saveItem.toString());
// }
//10개의 데이터를 만들기
// public void createItemList(){
// for(int i=1; i<=10; i++){
// Item item = new Item();
//
// item.setItemName("테스트 상품"+i);
// item.setPrice(150000);
// item.setItemDetail("테스트 상품 상세 설명" + i);
// item.setItemSellStatus(ItemSellStatus.SELL); //enum
// item.setStockNumber(100+i);
// item.setRegTime(LocalDateTime.now());
// item.setUpdateTime(LocalDateTime.now());
//
// Item saveItem = itemRepository.save(item); //#6. 저장
// System.out.println(saveItem.toString()); //
// }
// }
//
// @Test
// @DisplayName("상품명 조회 테스트")
// public void findByItemNameTest(){
// this.createItemList();
// List<Item> itemList = itemRepository.findItemByItemName("테스트 상품3");
//
// for(Item item : itemList){
// System.out.println(item.toString());
// }
// }
// @Test
// @DisplayName("@Query를 이용한 상품 조회 테스트")
// public void findByItemDetailTest(){
// this.createItemList();
// List<Item> itemList = itemRepository.findByItemDetail("상품 상세 설명");
//
// for(Item item : itemList){
// System.out.println(item.toString());
// }
// }
//
//
// @Test
// @DisplayName("상품 Querydsl 조회 테스트")
// public void queryDslTest(){
// this.createItemList();
//
// //팩토리를 이용해서 쿼리를 동적으로 생성
// JPAQueryFactory queryFactory = new JPAQueryFactory(em); // 동적으로 쿼리 생성
// QItem qItem = QItem.item; // querydsl을 통해 쿼리를 생성하기 위해
// // 모든 SQL이 그렇듯이, 설정이 오래걸립니다.
// JPAQuery<Item> query = queryFactory.selectFrom(qItem)
// .where(qItem.itemSellStatus.eq(ItemSellStatus.SELL))
// .where(qItem.itemDetail.like("%"+"테스트 상품 상세 설명" + "%"))
// .orderBy(qItem.price.desc());
//
// List<Item> itemList = query.fetch(); //쿼리 결과 리스트로 반환
//
// for(Item item : itemList){
// System.out.println(item.toString());
// }
// }
/*
-- Predicate : '이 조건이 맞다' 고 판단하는 근거를 함수로 제공
-- predicate를 파라미터로 전달하기 위해서는 QueryDslPredicateExecutor 인터페이스를
-- 상속받아야함
QueryDslPredicateExecutor 인터페이스 정의 메소드
long count(Predicate) : 조건에 맞는 데이터의 총 개수 반환
boolean exists(Predicate) : 조건에 맞는 데이터 존재 여부 반환
Iterable findAll(Predicate) : 조건에 맞는 모든 데이터 반환
page<T> findAll(Predicate, pageable) : 조건에 맞는 페이지 데이터 반환
Iterable findAll(Predicate, Sort) : 조건에 맞는 정렬된 데이터 반환
T findOne(Predicate) : 조건에 맞는 데이터 1개 반환
*/
public void createItemList2() {
for (int i = 1; i <= 5; i++) {
Item item = new Item();
item.setItemName("테스트 상품" + i);
item.setPrice(10000 + i);
item.setItemDetail("테스트 상품 상세 설명" + i);
item.setItemSellStatus(ItemSellStatus.SELL);
item.setStockNumber(100);
item.setRegTime(LocalDateTime.now());
item.setUpdateTime(LocalDateTime.now());
itemRepository.save(item);
}
for (int i = 6; i <= 10; i++) {
Item item = new Item();
item.setItemName("테스트 상품" + i);
item.setPrice(10000 + i);
item.setItemDetail("테스트 상품 상세 설명" + i);
item.setItemSellStatus(ItemSellStatus.SOLD_OUT);
item.setStockNumber(0);
item.setRegTime(LocalDateTime.now());
item.setUpdateTime(LocalDateTime.now());
itemRepository.save(item);
}
}
@Test
@DisplayName("상품 querydsl 조회테스트 2")
public void querydslTest2(){
this.createItemList2();
BooleanBuilder booleanBuilder = new BooleanBuilder();
QItem item = QItem.item;
String itemDetail = "테스트 상품 상세 설명";
int price = 10003;
String itemSellStat = "SELL";
booleanBuilder.and(item.itemDetail.like("%" + itemDetail + "%"));
booleanBuilder.and(item.price.gt(price));
System.out.println(ItemSellStatus.SELL);
// StringUtils : import org.thymeleaf.util.StringUtils;
if(StringUtils.equals(itemSellStat, ItemSellStatus.SELL)){
booleanBuilder.and(item.itemSellStatus.eq(ItemSellStatus.SELL));
}
}
}
●5
#공공데이터포털
//#버전을 찾아서
//sts3 : 스프링(3.0 책을 찾아서, 그 예제들을 쫓아가는 것이 좋습니다.)
//sts4 : 스프링부트
//#1. 다른 사람 소스코드 ㅡ 3.0대
//#2. 에러를 만드는 것(최대한 대로) - 원인찾고, 해결한다면 실력이 많이 상승합니다.
//하나의 책, 하나의 예제를 공부하는 것이 필요합니다.
//예제★★★, 다른사람이 짜논 코드를 본다.
//정리하십시오...(책,도큐먼트,예제)
//순서는 책으로,
●6
구조
Controller
DTO
ENtity
Repository
Service
서비스가 레포지토리 호출, 레포지토리가db연동 작업하는 것
●7
●8 free
'7.springBoot > 1)개념_springBoot' 카테고리의 다른 글
springBoot_개념_Day_15 (0) | 2024.04.26 |
---|---|
springBoot_개념_Day_14 (0) | 2024.04.15 |
springBoot_개념_Day_12 (0) | 2024.04.11 |
springBoot_개념_Day_11 (0) | 2024.04.09 |
springBoot_개념_Day_10 (0) | 2024.04.08 |