7.springBoot/1)개념_springBoot

springBoot_개념_Day_13

구이제이 2024. 4. 12. 18:46

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