第4週
[学習目標]
1.Controller-ServiceRepositoryについて
2.JavaによるAPIの実装方法
3.スプリングスケジューラを使用して、サーバが必要な時間にタスクを実行できるようにする
分業+緩やかな結合分業:それぞれの責任を果たし、機能は正常 ばらばら結合:ばらばら結合、柔軟性と拡張性 3層(コントローラ、サービス、およびレポート)は、分業および分散結合の典型的な例 である.スプリングを回転させる脊椎作用 各階層間では決してEntityを直接使用するのではなく、DTO を作成して使用します.
一番外側からリクエストを受信し、応答するロールを返します.
そこから具体的な操作手順を決める
DBと直接コミュニケーションして資料を作成、表示、変更、削除する
分散結合の典型的な例 私たちが使用するNAVER検索APIの内部ロジックが何であるかにかかわらず、約束の要求に従えば、私たちは規定の結果を得ることができます. JSONは、JAVAにデータを要求し、その結果を処理する方法を知る必要があります.
Naver Shopping API説明ドキュメント
キーワードを使用して商品を検索し、結果をリストに表示
GET/api/search?Query=クエリー
return
POST/api/products
興味のある商品を調べる
GET/api/products
興味のある商品に興味のある価格を登録し、その価格を下回った場合に表示
PUT/api/products/{id}
Controller ProductRestControl:興味のあるコントローラ SearchRequestControl:関連コントローラの検索
Service ProductService:興味のある商品価格の変更
Repository
ここでデータベースに格納されているのはProductだけです! Product:興味のある商品表 ProductRepository:興味のある商品を表示・記憶 ProductRequestDto:興味のある商品を登録 ProductMypriceRequestDto:興味価格の変更 ItemDto:検索結果の交換
Product.java
商品表の場合、updateには
変更日を作成するclass
NAVER APIを使用して値をロードするクラス
構成部品の登録
簡単に言えばspring権限を与える!必要なときは自分で見て使いましょう.いわゆる
スプリングが構成部品を自動的にインポートおよび使用できるようにします.
RepositoryまたはServiceはコンポーネントが登録されているため、スプリングは自由に使用できます
スプリングには、任意にインポートおよび書き込みできるクラスのリストが表示されます.
リスト内のそれらは構成部品として登録されています.
コントローラ、サービス、エンティティなどがコンポーネントとして登録されています
NaverShopSearchは手動で登録する必要があります.
itemDto形式はJSON、
JSONが正しいとエラーになります.
だからJSONじゃなくString形式
JavaでJSONを扱うためにはJSOnObjectとJSOnArrayクラスが必要です.インポート
1)Maven中央検索
2)検索json
3)JSON In Javaクリック
4)数値の最上位バージョンをクリック
5)Gradleタブをクリック
6)コンテンツをコピーして構築する.gradle>依存項目に貼り付け
7)依存項目の横にあるrunボタンをクリック
=>import完了!
スケジューラを通じて毎日午前1時に新しい価格を提出します.
ProductRestController.java
NAVER API値を入力するAPI
1.Controller-ServiceRepositoryについて
2.JavaによるAPIの実装方法
3.スプリングスケジューラを使用して、サーバが必要な時間にタスクを実行できるようにする
開始前
開発の中核
分業+緩やかな結合
Spring 3層
Controller
一番外側からリクエストを受信し、応答するロールを返します.
Service
そこから具体的な操作手順を決める
Repository
DBと直接コミュニケーションして資料を作成、表示、変更、削除する
API Handling
NAVERショッピングAPI
Naver Shopping API説明ドキュメント
{
"title": "<b>아디다스</b> 알파바운스 BB슬라이드 BA8775",
"link": "https://search.shopping.naver.com/gate.nhn?id=24457175865",
"image": "https://shopping-phinf.pstatic.net/main_2445717/24457175865.20201014195220.jpg",
"lprice": "27990",
"hprice": "",
"mallName": "네이버",
"productId": "24457175865",
"productType": "1",
"brand": "아디다스",
"maker": "아디다스",
"category1": "패션잡화",
"category2": "남성신발",
"category3": "슬리퍼",
"category4": ""
},
JAVA利用NAVERショッピングAPI利用
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "**********");
headers.add("X-Naver-Client-Secret", "**********");
String body = "";
HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers);
ResponseEntity<String> 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);
IntelliJの設定
src > main > java > com.sparta.week04 > utils
API設計
キーワードを使用して商品を検索し、結果をリストに表示
GET/api/search?Query=クエリー
return
List<ItemDto>
興味のある商品を登録するPOST/api/products
興味のある商品を調べる
GET/api/products
興味のある商品に興味のある価格を登録し、その価格を下回った場合に表示
PUT/api/products/{id}
設計3階層
Controller
Service
Repository
ここでデータベースに格納されているのはProductだけです!
org.json
JavaヘルプjsonのライブラリModels
com > sparta > week04 > models
1)各モデル、レポート、タイムスタンプProduct.java
商品表の場合、updateには
update
があり、ユーザーが指定した最低価格を関数とスケジューラの価格に変更します.package com.sparta.week04.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter // get 함수를 일괄적으로 만들어줍니다.
@NoArgsConstructor // 기본 생성자를 만들어줍니다.
@Entity // DB 테이블 역할을 합니다.
public class Product extends Timestamped {
// ID가 자동으로 생성 및 증가합니다.
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Long id;
// 반드시 값을 가지도록 합니다.
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String image;
@Column(nullable = false)
private String link;
@Column(nullable = false)
private int lprice;
@Column(nullable = false)
private int myprice;
public Product(ProductRequestDto requestDto) {
this.title = requestDto.getTitle();
this.link = requestDto.getLink();
this.lprice = requestDto.getLprice();
this.image = requestDto.getImage();
this.myprice = 0;
}
public void update(ProductMypriceRequestDto requestDto) {
this.myprice = requestDto.getMyprice();
}
public void updateByItemDto(ItemDto itemDto) {
this.lprice = itemDto.getLprice();
}
}
Timestamped変更日を作成するclass
package com.sparta.week04.models;
@Getter
// get 함수를 자동 생성합니다.
@MappedSuperclass
// 멤버 변수가 컬럼이 되도록 합니다.
@EntityListeners(AuditingEntityListener.class)
// 변경되었을 때 자동으로 기록합니다.
public abstract class Timestamped {
@CreatedDate // 최초 생성 시점
private LocalDateTime createdAt;
@LastModifiedDate // 마지막 변경 시점
private LocalDateTime modifiedAt;
}
ProductRepository.javapackage com.sparta.week04.models;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Dtoの作成
updateByItemDto
ProductRequestDto.javapackage com.sparta.week04.models;
import lombok.Getter;
@Getter
public class ProductRequestDto {
private String title;
private String link;
private String image;
private int lprice;
}
ItemDto.javapackage com.sparta.week04.models;
import lombok.Getter;
import org.json.JSONObject;
@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");
}
}
ProductMypriceDto.javapackage com.sparta.week04.models;
import lombok.Getter;
@Getter
public class ProductMypriceRequestDto {
private int myprice;
}
Service
com > sparta > week04 > models
ProductService.javapackage com.sparta.week04.service;
...
import javax.transaction.Transactional;
@RequiredArgsConstructor // final로 선언된 멤버 변수를 자동으로 생성합니다.
@Service // 서비스임을 선언합니다.
public class ProductService {
private final ProductRepository productRepository;
@Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
public Long update(Long id, ProductMypriceRequestDto requestDto) {
Product product = productRepository.findById(id).orElseThrow(
() -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
);
product.update(requestDto);
return id;
}
@Transactional // DB 가 업데이트 되어야한다.
public Long updateBySearch(Long id, ItemDto itemDto) {
Product product = productRepository.findById(id).orElseThrow(
() -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
);
product.updateByItemDto(itemDto);
return id;
}
}
Utils
com > sparta > week04 > service
NaverShopSearch.javaNAVER APIを使用して値をロードするクラス
構成部品の登録
簡単に言えばspring権限を与える!必要なときは自分で見て使いましょう.いわゆる
スプリングが構成部品を自動的にインポートおよび使用できるようにします.
RepositoryまたはServiceはコンポーネントが登録されているため、スプリングは自由に使用できます
スプリングには、任意にインポートおよび書き込みできるクラスのリストが表示されます.
リスト内のそれらは構成部品として登録されています.
コントローラ、サービス、エンティティなどがコンポーネントとして登録されています
NaverShopSearchは手動で登録する必要があります.
itemDto形式はJSON、
com > sparta > week04 > utils
カッコに文字列を記入するJSONが正しいとエラーになります.
だからJSONじゃなくString形式
org.jsonパッケージのインストール
JavaでJSONを扱うためにはJSOnObjectとJSOnArrayクラスが必要です.インポート
1)Maven中央検索
2)検索json
3)JSON In Javaクリック
4)数値の最上位バージョンをクリック
5)Gradleタブをクリック
6)コンテンツをコピーして構築する.gradle>依存項目に貼り付け
7)依存項目の横にあるrunボタンをクリック
=>import完了!
package com.sparta.week04.utils;
...
@Component
public class NaverShopSearch {
public String search(String query) {
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "p234pvd2_wQpIjp6KlKi");
headers.add("X-Naver-Client-Secret", "bsVXyLy17e");
String body = "";
HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers);
ResponseEntity<String> 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;
}
public List<ItemDto> fromJSONtoItems(String result) {
JSONObject rjson = new JSONObject(result);
JSONArray items = rjson.getJSONArray("items");
List<ItemDto> itemDtoList = new ArrayList<>();
// JSONArray 에서는 length 로 꺼냄
for (int i = 0; i < items.length(); i++) {
JSONObject itemJson = (JSONObject) items.get(i);
// JSONObject itemJson = items.getJSONObject(i);
ItemDto itemDto = new ItemDto(itemJson);
itemDtoList.add(itemDto);
}
return itemDtoList;
}
}
Scheduler.javaスケジューラを通じて毎日午前1時に新しい価格を提出します.
package com.sparta.week04.utils;
...
@RequiredArgsConstructor // final 멤버 변수를 자동으로 생성합니다.
@Component // 스프링이 필요 시 자동으로 생성하는 클래스 목록에 추가합니다.
public class Scheduler {
private final ProductRepository productRepository;
private final ProductService productService;
private final NaverShopSearch naverShopSearch;
// 초, 분, 시, 일, 월, 주 순서
// cron : 시간이 맞을때 작동울 해라
// 0~23시까지 가능 1시 0분 1초부터 1시 59분 59초까지 매초 실행 * * 1 * * *
// 1시 0분 0초일 때 실행
@Scheduled(cron = "0 0 1 * * *")
public void updatePrice() throws InterruptedException { // 만약에 오류가 발생하면, 방해하는 요소가 발생했다고 오류를 보여줘라
System.out.println("가격 업데이트 실행");
// 저장된 모든 관심상품을 조회합니다.
List<Product> productList = productRepository.findAll();
for (int i=0; i<productList.size(); i++) {
// 1초에 한 상품 씩 조회합니다 (Naver 제한: 요청이 너무 자주 오면 네이버에서 막아버림)
TimeUnit.SECONDS.sleep(1); // 타임 단위 기준으로 초마다 한번씩 잠깐 쉬어라. = 1초에 한번 씩 for 문이 돌게 된다.
// i 번째 관심 상품을 꺼냅니다.
Product p = productList.get(i);
// i 번째 관심 상품의 제목으로 검색을 실행합니다.
String title = p.getTitle();
String resultString = naverShopSearch.search(title);
// i 번째 관심 상품의 검색 결과 목록 중에서 첫 번째 결과를 꺼냅니다.
List<ItemDto> itemDtoList = naverShopSearch.fromJSONtoItems(resultString);
ItemDto itemDto = itemDtoList.get(0);
// i 번째 관심 상품 정보를 업데이트합니다.
Long id = p.getId();
productService.updateBySearch(id, itemDto);
}
}
}
Controller
ProductRestController.java
package com.sparta.week04.controller;
...
@RequiredArgsConstructor // final 로 선언된 멤버 변수를 자동으로 생성합니다.
@RestController // JSON 으로 데이터를 주고받음을 선언합니다.
public class ProductRestController {
private final ProductRepository productRepository;
private final ProductService productService;
// 등록된 전체 상품 목록 조회
@GetMapping("/api/products")
public List<Product> getProducts() {
return productRepository.findAll();
}
@PostMapping("/api/products")
public Product createProduct(@RequestBody ProductRequestDto requestDto) {
Product product = new Product(requestDto);
return productRepository.save(product);
}
// 최저가 변경 API
@PutMapping("/api/product/{id}")
public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) {
return productService.update(id, requestDto);
}
}
SearchRequestController.javaNAVER API値を入力するAPI
package com.sparta.week04.controller;
...
@RequiredArgsConstructor // final 로 선언된 클래스를 자동으로 생성합니다.
@RestController // JSON 으로 응답함을 선언합니다.
public class SearchRequestController {
private final NaverShopSearch naverShopSearch;
@GetMapping("/api/search")
public List<ItemDto> getItems(@RequestParam String query) {
String resultString = naverShopSearch.search(query);
return naverShopSearch.fromJSONtoItems(resultString);
}
}
Reference
この問題について(第4週), 我々は、より多くの情報をここで見つけました https://velog.io/@soso0/spring-04テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol