강의 목표
기본 코드 작성 숙달
- 3계층 숙달(Controller, Service, Repository)
- 개발의 핵심 - 분업 & 느슨한 결합(유연성 및 확장성 확보)
- 3계층(Controller, Service, Repository)을 손에 익을 때까지 연습
- Controller : 제일 바깥 쪽에서 요청을 받고, 응답을 되돌려주는 역할
- Service : 구체적인 작업 순서를 결정. (Controller ↔ Repository)
- Repository : DB와 연결되어 CRUD 실시
- 그리고 각 레이어 간에는 절대 Entity를 직접 사용하지 않고, DTO 사용
- API handling
- 실제 직접 코딩할 필요 없이 API를 이용하여 정해진 약속대로 요구하면 결과 수신 가능
- API 사용법 연습
네이버 쇼핑 API 사용하기
REST API - GET / POST / PUT / DELETE 를 통해 JSON 형식으로 자료를 받을 수 있음
- 네이버 쇼핑 API 설명문서
- 쇼핑 API를 신청한 뒤 ARC를 이용하여 값을 조회할 수 있음
- ARC를 통하여 원하는 프로그래밍 언어(이 경우 JAVA)로 API를 쓸 수 있는 코드로 변환 가능
**** 프로젝트 생성시 Preference에서 auto import와 complier 세팅 필수**
(add unambiguous import ~~) 와 (Enable annotation processing)
API 연동하기
- API를 가져오기 위한 ‘NaverShopSearch’ 클래스를 생성
public class NaverShopSearch {
public String search() {
// 이 곳에 ARC에서 변환한 코드를 붙여넣는다.
}
public static void main(String[] args) {
NaverShopSearch naverShopSearch = new NaverShopSearch();
naverShopSearch.search();
}
}
public class NaverShopSearch {
public String search() {
*RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "네이버 API 클라이언트 아이디");
headers.add("X-Naver-Client-Secret", "네이버 API 시크릿 코드");
String body = "";
HttpEntity requestEntity = new HttpEntity(body, headers);
ResponseEntity responseEntity = rest.exchange("<https://openapi.naver.com/v1/search/shop.json?query=아디다스>", HttpMethod.GET, requestEntity, String.class);
HttpStatus httpStatus = responseEntity.getStatusCode();
int status = httpStatus.value();
String response = responseEntity.getBody();
System.out.println("Response status: " + status);
System.out.println(response);*
return response; // 원하는 값을 가진(String) response를 리턴
}
public static void main(String[] args) {
NaverShopSearch naverShopSearch = new NaverShopSearch();
naverShopSearch.search();
}
}
- Project 설계하기
- 3계층 설계하기
- ProductRestController: 관심 상품 관련 컨트롤러
- SearchRequestController: 검색 관련 컨트롤러
- ProductService: 관심 상품 가격 변경
- Product: 관심 상품 테이블
- ProductRepository: 관심 상품 조회, 저장
- ProductRequestDto: 관심 상품 등록하기
- ProductMypriceRequestDto: 관심 가격 변경하기
- ItemDto: 검색 결과 주고받기
- <aside> 👉 여기서 DB에 저장되는 녀석은 Product 뿐이라는 점!
- Service
- Controller
프로젝트 필요 기능
- 키워드로 상품 검색 후 목록으로 보여주기
- 관심 상품 등록
- 관심 상품 조회
- 관심 상품에 원하는 가격 등록 후 가격보다 낮은 경우 화면에 띄워주기
세부 코드 작성
#1. Timestamped
Getter / MappedSuperclass / EntityListeners(AuditingEntityListener.class) 추가 할 것
**@Getter** // get 함수를 자동 생성
**@MappedSuperclass** // 멤버 변수가 컬럼이 되도록 함
**@EntityListeners**(AuditingEntityListener.class) // 변경되었을 때 자동으로 기록
public abstract class Timestamped { //abstract 클래스로 선언
@CreatedDate // 최초 생성 시점
private LocalDateTime createdAt;
@LastModifiedDate // 마지막 변경 시점
private LocalDateTime modifiedAt;
}
#2. Product 클래스
#3. Repository 인터페이스 생성 (JpaRepository extend 해주기)
#4. Controller 만들어주기
public class ProductRestController {
// Get방식 Mapping
@GetMapping("/api/products")
public List<Product> getProducts(){
return productRepository.findAll(); // productRepository에서 findAll하라고 명령
}
**// 근데 문제는 productRepository 선언을 안해줬으니까 멤버 변수를 선언해줘야함**
}
@RequiredArgsConstructor // 이거까지해줘야 에러 안남
public class ProductRestController {
final ProductRepository productRepository; // productRepository는 꼭 필요
// Get방식 Mapping
@GetMapping("/api/products")
public List<Product> getProducts(){
return productRepository.findAll();
}
}
#5. Dto생성하기
ProductMypriceRequestDto / ProductRequestDto 생성
#6 Product 클래스에 DTO 추가하기
public Product(ProductRequestDto requestDto){
this.title = requestDto.getTitle();
this.link = requestDto.getLink();
this.lprice = requestDto.getLprice();
this.image = requestDto.getImage();
this.myprice = 0; // 최초 값은 0
}
#7 Service 클래스 생성
@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
@Transactional // **이거 필수**
public Long update(Long id, ProductMypriceRequestDto requestDto){
Product product = productRepository.findById(id).orElseThrow(
()-> new IllegalArgumentException("아이디가 존재하지 않습니다")
);
product.update(requestDto); // **product 클래스에서 update하라고 토스**
return id;
}
}
public void update(ProductMypriceRequestDto requestDto){
this.myprice = requestDto.getMyprice();
}
// Product 클래스에서 update 메소드를 생성
//
#8. PostMapping
@PostMapping("/api/products")
public Product createProduct(@RequestBody ProductRequestDto requestDto){
Product product = new Product(requestDto);
return productRepository.save(product);
}
#9 검색어 바꾸기
public class NaverShopSearch {
public String search(String query) { // 검색어 query 스트링 넣기;
*RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "네이버 API 클라이언트 아이디");
headers.add("X-Naver-Client-Secret", "네이버 API 시크릿 코드");
String body = "";
HttpEntity requestEntity = new HttpEntity(body, headers);
ResponseEntity responseEntity = rest.exchange("<https://openapi.naver.com/v1/search/shop.json?query=>" +* query*, HttpMethod.GET, requestEntity, String.class);
HttpStatus httpStatus = responseEntity.getStatusCode();
int status = httpStatus.value();
String response = responseEntity.getBody();
System.out.println("Response status: " + status);
System.out.println(response);*
return response; // 원하는 값을 가진(String) response를 리턴
}
public static void main(String[] args) {
NaverShopSearch naverShopSearch = new NaverShopSearch();
naverShopSearch.search();
}
}
#10. 검색결과를 문자열에서 DTO로 바꾸기
public static void main(String[] args) {
NaverShopSearch naverShopSearch = new NaverShopSearch();
String result = naverShopSearch.search("z폴드3");
//JSON오브젝트가 모여서 JSON어레이가 됨
JSONObject rjson = new JSONObject(result); // 검색어로 찾은 값을 result로 받아와서 rjson으로 선언
JSONArray items = rjson.getJSONArray("items"); // rjson에서 items를 키값으로 가지는 리스트(items)를 가져온다
for(int i = 0; i < items.length(); i++){ // items 안에 들어있는 것들을 하나씩 빼올 것것
JSONObject itemJson = items.getJSONObject(i); //items에서 Json오브젝트를 꺼낸다 (i번째)
}
}
**// JSON 라이브러리를 이용해서 JSON으로 된 데이터를 꺼내온다**
for(int i = 0; i < items.length(); i++){ // items 안에 들어있는 것들을 하나씩 빼올 것것
JSONObject itemJson = items.getJSONObject(i); //items에서 Json오브젝트를 꺼낸다 (i번째)
String title = itemJson.getString("title");
String image = itemJson.getString("image");
int lprice = itemJson.getInt("lprice");
String link = itemJson.getString("link");
}
**//itemJson에서 필요한 데이터를 골라서 각각의 변수에 get해서 집어넣어준다
//itemJson에서 key값이 "title"인 애들을 title 변수에 넣고 뭐 이런식**
#11. itemDto 생성
@Getter
public class ItemDto {
private String title;
private String link;
private String image;
private int lprice;
public ItemDto(JSONObject itemJson) {
this.title = itemJson.getString("title");
this.link = itemJson.getString("link");
this.image = itemJson.getString("image");
this.lprice = itemJson.getInt("lprice");
}
}
public List<ItemDto> fromJSONtoItems(String result){
//JSON오브젝트가 모여서 JSON어레이가 됨
JSONObject rjson = new JSONObject(result); // 검색어로 찾은 값을 result로 받아와서 rjson으로 선언
JSONArray items = rjson.getJSONArray("items"); // rjson에서 items를 키값으로 가지는 리스트(items)를 가져온다
List<ItemDto> itemDtoList = new ArrayList<>(); // itemDto를 담아줄 리스트 선언
for(int i = 0; i < items.length(); i++){ // items 안에 들어있는 것들을 하나씩 빼올 것것
JSONObject itemJson = items.getJSONObject(i); //items에서 Json오브젝트를 꺼낸다 (i번째)
ItemDto itemDto = new ItemDto(itemJson);
itemDtoList.add(itemDto);
}
return itemDtoList;
}
#12 컴포넌트 등록하기
<aside> 👉 더 이상 검색을 main 메소드에서 진행하는게 아니라, Controller 에서 가져다 씀
스프링이 자동으로 필요한 클래스를 필요한 곳에 생성하려면, "아, 사용자가 요구하면 자동으로 생성할 클래스 목록이 이것이구나" 라고 확인할 수 있어야함
이를 위해 필요한 것이 Component 등록
</aside>
@Component // 컴포넌트 등록
public class NaverShopSearch {
public String search(String query) {
#13 SearchRequestDto 생성하기
NaverShopSearch를 컴포넌트 등록을 했으니 스프링이 자유롭게 가져다가 쓸 수 있음
@RequiredArgsConstructor // final 로 선언된 클래스를 자동으로 생성
@RestController // JSON으로 응답함을 선언
public class SearchRequestController {
private final NaverShopSearch naverShopSearch;
@GetMapping("/api/search")
// 최종 itemDto를 출력하는 메소드 선언 / @RequestParam를 넣어줘야 됨
public List<ItemDto> execSearch(@RequestParam String query){
// navershopsearch를 컴포넌트 등록했으니까 막 갖다쓰면 됨
// 파라미터 query를 가져와서 search한걸 result에 담기
String result = naverShopSearch.search(query);
// navershopsearch에 있는 fromJSONtoItems 메소드를통해 원하는걸 받아냄
return naverShopSearch.fromJSONtoItems(result);
}
}
#14 addProduct 생성하기
function addProduct(itemDto) {
/**
* modal 뜨게 하는 법: $('#container').addClass('active');
* data를 ajax로 전달할 때는 두 가지가 매우 중요
* 1. contentType: "application/json",
* 2. data: JSON.stringify(itemDto),
*/
// 1. POST /api/products 에 관심 상품 생성 요청
$.ajax({
type: "POST",
url: '/api/products',
contentType: "application/json",
data: JSON.stringify(itemDto),
success: function (response) {
// 2. 응답 함수에서 modal을 뜨게 하고, targetId 를 reponse.id 로 설정 (숙제로 myprice 설정하기 위함)
$('#container').addClass('active');
targetId = response.id;
}
})
}
#15 showProduct, addProductItem 만들기
function showProduct() {
/**
* 관심상품 목록: #product-container
* 검색결과 목록: #search-result-box
* 관심상품 HTML 만드는 함수: addProductItem
*/
// 1. GET /api/products 요청
$.ajax({
type: 'GET',
url: '/api/products',
success: function (response) {
// 2. 관심상품 목록, 검색결과 목록 비우기
$('#product-container').empty();
$('#search-result-box').empty();
// 3. for 문마다 관심 상품 HTML 만들어서 관심상품 목록에 붙이기!
for (let i = 0; i < response.length; i++) {
let product = response[i];
let tempHtml = addProductItem(product);
$('#product-container').append(tempHtml);
}
}
})
}
function addProductItem(product) {
// link, image, title, lprice, myprice 변수 활용하기
return `<div class="product-card" onclick="window.location.href='${product.link}'">
<div class="card-header">
<img src="${product.image}"
alt="">
</div>
<div class="card-body">
<div class="title">
${product.title}
</div>
<div class="lprice">
<span>${numberWithCommas(product.lprice)}</span>원
</div>
<div class="isgood ${product.lprice > product.myprice ? 'none' : ''}">
최저가
</div>
</div>
</div>`;
}
- 3항 조건문
${product.lprice > product.myprice ? 'none' : ''}
// 조건문? 참일 경우 출력: 거짓일 경우 출력
'JAVA' 카테고리의 다른 글
스프링 3주차 강의내용 정리 (0) | 2021.12.16 |
---|---|
스프링 2주차 강의내용 정리 (0) | 2021.12.12 |
스프링 1주차 강의내용 정리 (2) | 2021.12.01 |