[Spring] core1

호호빵·2022년 6월 17일
0

Spring

목록 보기
5/24

🪬 API 설계

src
main
ㄴ resources 
		ㄴ static
		ㄴ templates
        ㄴ application.properties
ㄴ java 
	ㄴ com.sparta.springcore
                ㄴ controller
                        ㄴ ProductController
                        ㄴ SearchRequestController
                ㄴ dto
                		ㄴ ItemDto
                        ㄴ ProductMyPriceRequestDto
                        ㄴ ProductRequestDto
                ㄴ model
                        ㄴ Product                 
                        ㄴ Timestamped
                ㄴ repository
                		ㄴ ProductRepository (i)
                ㄴ sevice
                        ㄴ ProductService
                ㄴ util
                		ㄴ NaverShopSearch
                ㄴ SpringcoreApplication

CRUD

타임라인 API

기능MethodURLReturn
관심 상품 검색,목록 보여주기GET/api/search?query=검색어List<'ItemDto'>
관심 상품 조회GET/api/products/List<'Product'>
관심 상품 등록POST/api/products/Product
관심 상품 가격 등록PUT/api/products/{id}Long

요구기능

- 상품명에 따른 검색, 그 결과를 목록으로 보여주기
- 관심 상품 등록 & 조회
- 관심 상품에 대한 최저가 등록하기

기타

json 라이브러리 : json <-> java 변환

# build.gradle 파일의 dependencies에 추가
implementation group: 'org.json', name: 'json', version: '20160810'

Servlet

  • 스프링 없이 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램
    Servlet

@Controller


@Controller
class ExamController {
	@GetMapping("/home")
	public String home() {
		return "/home.html";
	}
}

# String객체로 html 보내주면 view가 해당 html 찾아서 클라이언트에게 보내줌

# Json 형태를 보내고 싶으면 @ResponseBody 추가
@Controller
class ExamController {
	@Autowired
	private ProductRepository productRepository

	@GetMapping("/product/list")
	public @ResponseBody List<Product> getProducts() {
		return productRepository.findAll();
	}
}

@RestController

# Json 형태만 보낼 때 @Controller + RequestBody
@RestController
class ExamController {
	@Autowired
	private ProductRepository productRepository

	@GetMapping("/product/list")
	public List<Product> getProducts() {
		return productRepository.findAll();
	}
}


🪬 객체지향 프로그래밍

Controller : 클라이언트의 요청 받고 응답해줌
		   : 요청에 대한 처리는 Service에게
Service : 비즈니스 로직을 처리 (서버에서 사용자의 요구사항 처리)
		: DB정보가 필요할 때에는 Repositroy에게
Repository : DB관리 , DB CRUD 작업처리

역할 별 분리


Refactorying

  • 기능 상의 변경 없이 내부 구조를 개선하는 것
  • 다른 개발자가 작성한 코드를 보기 쉽고 빠르게 파악할 수 있어 협업을 잘 할 수 있는 환경을 만듦.

객체 생성의 중복 문제

  • 생성될 때 딱 한번 만들어서 계속 사용하면 됨!
  • ProductService, ProductRepository 모두
# ProductServie
// ProductService에서 필요할 때마다 
// new ProductRepository로 객체 생성해서 사용 (중복)
public class ProductService {

    public List<Product> getProducts() throws SQLException {
        ProductRepository productRepository = new ProductRepository();
				// ...
    }

    public Product createProduct(ProductRequestDto requestDto) throws SQLException {
        ProductRepository productRepository = new ProductRepository();
        // ...
    }

    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) throws SQLException {
        ProductRepository productRepository = new ProductRepository();
				// ...
    }
}	


# 멤버 변수로 ProductRepository 만들어 중복 줄임
public class ProductService {
	// 멤버 변수 선언
	private final ProductRepository productRepository;
    
    // 생성자
    public ProductService() {
    	// 멤버 변수 생성(this  지시자 생략 가능)
    	this.oductRepository = new ProductRepository();
    }
    
    public List<Product> getProducts() throws SQLException {
        // 멤버 변수 사용 (this 지시자 생략 가능!)
        return this.productRepository.getProducts();
    }
		// ...
}
    
}

DI(의존성 주입)

  • 서비스가 늘어나면서 계속 리포지토리를 만들면 그 개수가 증가하게 됨

  • 하나의 객체에서 다른 객체가 필요할 때, 객체를 직접 생성하지 않고, 이미 생성되어 있는 객체를 가져오는 작업(Dependency Injection)

  • IoC(Inversion of Control) : 제어의 역전
    사용자가 자신이 필요한 객체를 생성해서 사용하는 것이 일반적인데, 그 반대라 제어의 역전이라고도 함

    	Repository1 객체 생성 (ID,PW 입력)
    	Service1 객체 생성 (이미 생성된 Repository1 DI)
    	Controller 5개 생성 (이미 생성된 Service1 DI)


강한 결합

  • 만약 ProductRepository 클래스 생성과정에서 DB의 ID,PW 정보를 받아야 한다면
    -> ProductRepository 생성자 변경
    -> ProductRepository를 생성하는 ProductService 클래스 코드도 변경
  • 만약 ProductService에서도 DB의 ID,PW 정보를 받아야 한다면
    -> ProductController 클래스 코드도 변경
  • 강한 결합으로 연결되어 있어 하나의 클래스 생성자 변화가 다른 클래스에 영향을 줌
public class ProductRepository {
    private String dbId;
    private String dbPassword;

		// 생성자
    public ProductRepository(String dbId, String dbPassword) {
        this.dbId = dbId;
        this.dbPassword = dbPassword;
    }
}


public class ProductService {
    // 멤버 변수 선언
    private final ProductRepository productRepository;

    // 생성자: ProductService() 가 생성될 때 호출됨
    public ProductService(String dbId,String dbPassword) {
        // 멤버 변수 생성
        this.productRepository = new ProductRepository(dbId, dbPassword);
    }
}


public class ProductController {
    // 멤버 변수 선언
    private final ProductService productService;

    // 생성자: ProductController() 가 생성될 때 호출됨
    public ProductController() {
        // 멤버 변수 생성
        String dbId = "sa";
        String dbPassword = "";
        productService = new ProductService(dbId, dbPassword);
    }
}

강한 결합과 중복 해결하기 (DI)

  • ProductRepository 미리 생성하기
  • ProductService에서 미리 생성된 ProductRepository 객체 사용
  • ProductController에서도 미리 생성된 ProductService 사용
    	controller(service)
    		  	   service(repository)
       	   			       respository -> DB
                            (미리 생성)
# productRepository 미리 생성

    String dbId = "sa";
    String dbPassword = "";

ProductRepository productRepository = new ProductRepository(dbId, dbPassword);


# productRepository 사용
public class ProductService {
    
    private final ProductRepository productRepository;
												// 사용			  
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }
}
												// 사용
ProductService productService = new ProductService(productRepository);


# productService 사용
public class ProductController {
    
    private final ProductService productService;
   											    // 사용
    public ProductController(ProductService productService) {
        this.productService = productService;
    }
}
												// 사용
ProductController productController = new ProductController(productService);


// 이 때 추가적으로 ProductRepository에 DB의 URL이 필요해짐
public class ProductRepository {
    private String dbId;
    private String dbPassword;
	private String dbUrl;      // 추가!!

		// 생성자
    public ProductRepository(String dbId, String dbPassword, String dbUrl) {
        this.dbId = dbId;
        this.dbPassword = dbPassword;
		this.dbUrl = dbUrl;
    }
}

-> 생성자에 어떠한 변화가 생겨도 service, controller 모두 고칠 필요 없음
-> ProductRepository가 만들어지는 곳에서만 변경되면 됨

String dbId = "sa";
String dbPassword = "";
String dbUrl = "jdbc:h2:mem:springcoredb";   // 추가

// 변경
ProductRepository productRepository = new ProductRepository(dbId, dbPassword, dbUrl);

스프링 IoC 컨테이너

스프링 IoC 컨테이너

  • Inversion of Control : 제어의 역전
  • DI를 사용하기 위해선 객체 생성이 우선되어야 하고 스프링 프레임워크가 필요한 객체를 생성하여 관리하는 역할 대신해줌
  • 컨테이너에 객체를 생성해 Bean으로 만들어 보관
    bean : 스프링이 생성해주는 객체
    스프링 IoC 컨테이너 : 빈을 모아두는 통
# BeanConfiguration 파일 만듦
# Bean으로 ProductRepository, ProductService 만듦

@Configuration
public class BeanConfiguration {
    @Bean
    public ProductRepository productRepository() {
        String dbId = "sa";
        String dbPassword = "";
        String dbUrl = "jdbc:h2:mem:springcoredb";
        return new ProductRepository(dbId, dbPassword, dbUrl);
    }

    @Bean
		@Autowired
    public ProductService productService(ProductRepository productRepository) {
        return new ProductService(productRepository);
    }
}

Annotation (@)

  • 모두 스프링 Bean으로 등록됨
  • @Controller, @RestController, @Service, @Repository
    public interface ProductRepository extends JpaRepository<Product, Long> {}
    										 				   Entity, id 타입
    
    # extends 라면 @ 없어도 자동으로 @Repository로 추가됨
    # 원래 class로 선언되야 하지만 JPA가 알아서 class로 만들고 객체로 만들어서 Bean으로 등록해 줌

숙제

  • BeanConfiguration 삭제 후 @Service, @Repository 사용
# productService
getProduct() -> findAll()
createProduct() -> save()
getProduct(Id) -> findByID(Id) .orElseThrow() 필요

updatePrice() 
-> 1.      save(product)
public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) throws SQLException {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new NullPointerException("해당 아이디가 존재하지 않습니다."));
        
        int myPrice = requestDto.getMyprice();
        product.setMyprice(myPrice);
        productRepository.save(product);
        return product;
    }
    
-> 2. @Transactional
 @Transactional
    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) throws SQLException {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new NullPointerException("해당 아이디가 존재하지 않습니다."));

        int myPrice = requestDto.getMyprice();
        product.updateMyPrice(myPrice); 함수 만들어 사용
        return product;
    }
-> updateMyPrice 함수 만들고 
-> create MethodfProduct에도 새로 메소드 생성

추가

findAll() 함수들을 알아보려면
JPARepository(ProductRepository) - Go to  (op+cmd+B)
- SimpleJpaRepository에서 찾아보면됨 

findById(), save() 등 다 구현되어 있음

정리

# ProductService
@Service
public class ProductService {
    private final ProductRepository productRepository;     // 멤버 변수 선언

    // 생성자: ProductService() 가 생성될 때 호출됨
    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;   // 멤버 변수 생성
    }

    public List<Product> getProducts() {
        return productRepository.findAll();  // 멤버 변수 사용
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언
    public Product createProduct(ProductRequestDto requestDto){
        Product product = new Product(requestDto);    // 요청받은 DTO 로 DB에 저장할 객체 만들기
        productRepository.save(product);
        return product;
    }

    @Transactional
    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new NullPointerException("해당 아이디가 존재하지 않습니다."));
        int myPrice = requestDto.getMyprice();
        product.updateMyPrice(myPrice);
        return product;
    }
}
# ProductController
@RestController // JSON으로 데이터를 주고받음
public class ProductController {
    private final ProductService productService;   // 멤버 변수 선언

    // 생성자: ProductController() 가 생성될 때 호출됨
    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;     // 멤버 변수 생성
    }

    // 등록된 전체 상품 목록 조회
    @GetMapping("/api/products")
    public List<Product> getProducts() {
        List<Product> products = productService.getProducts();
        // 응답 보내기
        return products;
    }

    // 신규 상품 등록
    @PostMapping("/api/products")
    public Product createProduct(@RequestBody ProductRequestDto requestDto) {
        Product product = productService.createProduct(requestDto);
        // 응답 보내기
        return product;
    }

    // 설정 가격 변경
    @PutMapping("/api/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) {
        Product product = productService.updateProduct(id, requestDto);
        return product.getId();
    }
}
profile
하루에 한 개념씩

0개의 댓글