2022년 4월 7일(목)
[스파르타코딩클럽] 웹개발의 봄, Spring 2주차 과정 - 2
public class NaverShopSearch {
public String search() {
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "발급받은 Client ID");
headers.add("X-Naver-Client-Secret", "발급받은 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=adidas", HttpMethod.GET, requestEntity, String.class);
HttpStatus httpStatus = responseEntity.getStatusCode();
int status = httpStatus.value();
String response = responseEntity.getBody();
System.out.println("Response status: " + status); // 200 : 정상작동
System.out.println(response); // 넘어온 데이터 확인
return response;
}
// main 함수는 실행 가능
public static void main(String[] args) {
NaverShopSearch naverShopSearch = new NaverShopSearch();
naverShopSearch.search(); // 위의 search 함수 실행 가능
}
}
// Timestamped.js
@Getter // get 함수를 자동 생성합니다.
@MappedSuperclass // 멤버 변수가 컬럼이 되도록 합니다.
@EntityListeners(AuditingEntityListener.class) // 변경되었을 때 자동으로 기록합니다.
public abstract class Timestamped {
@CreatedDate // 최초 생성 시점
private LocalDateTime createdAt;
@LastModifiedDate // 마지막 변경 시점
private LocalDateTime modifiedAt;
}
// Product.js
@Getter // get 함수를 일괄적으로 만들어줍니다.
@NoArgsConstructor // 기본 생성자를 만들어줍니다.
@Entity // DB 테이블 역할을 합니다.
public class Product extends Timestamped{
// ID가 자동으로 생성 및 증가합니다.
@GeneratedValue(strategy = GenerationType.AUTO)
@Id // 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;
// productRequestDto 를 통해 Product 생성
public Product(ProductRequestDto requestDto) {
this.title = requestDto.getTitle();
this.link = requestDto.getLink();
this.image = requestDto.getImage();
this.lprice = requestDto.getLprice();
this.myprice = 0;
}
//
public void updateByItemDto(ItemDto itemDto) {
this.lprice = itemDto.getLprice();
}
// myprice update시 사용
public void update(ProductMypriceRequestDto mypriceRequestDto){
this.myprice = mypriceRequestDto.getMyprice();
}
}
// ProductRepository.js : create, get, delete 시 이용
// 사용내장함수 .findAll() .save() .deleteById()
public interface ProductRepository extends JpaRepository<Product, Long> {
}
// ProductMypriceRequestDtp.js // myprice 데이터 들고 다니는 class
// product.update() 함수 인자로 사용됨
//
@Getter
public class ProductMypriceRequestDto {
private int myprice;
}
// ProducrRequestDto.js // Database에 저장할 데이터 들고 다니는 class
@Getter
public class ProductRequestDto {
private String title;
private String link;
private String image;
private int lprice;
}
@RequiredArgsConstructor // final로 선언된 멤버 변수를 자동으로 생성합니다.
@Service // 서비스임을 선언합니다.
public class ProductService {
private final ProductRepository productRepository;
// myprice 데이터 수정시 내장 함수로 사용
@Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
public Long update(Long id, ProductMypriceRequestDto requestDto) {
Product product = productRepository.findById(id).orElseThrow(
() -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
);
product.update(requestDto);
return id;
}
//
@Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
public Long updateBySearch(Long id, ItemDto itemDto) {
Product product = productRepository.findById(id).orElseThrow(
() -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
);
product.updateByItemDto(itemDto);
return id;
}
}
//ProductRestController.js
@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);
}
// myprice 데이터 수정
@PutMapping("/api/products/{id}")
public Long updateMyprice(@PathVariable Long id, @RequestBody ProductMypriceRequestDto mypriceRequestDto){
productService.update(id, mypriceRequestDto);
return id;
}
}
// SearchRestController.js
@RequiredArgsConstructor // final 로 선언된 클래스를 자동으로 생성합니다.
@RestController // JSON으로 응답함을 선언합니다.
public class SearchRequestController {
private final NaverShopSearch naverShopSearch;
// 네이버 쇼핑 API에서 데이터를 받아옴
@GetMapping("/api/search")
public List<ItemDto> getItems(@RequestParam String query) {
String resultString = naverShopSearch.search(query);
return naverShopSearch.fromJSONtoItems(resultString);
}
}
// com.sparta.week04.controller SearchRequestController.js
@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);
}
}
// com.sparta.week04.utils NaverShopSearch.js
@Component
public class NaverShopSearch {
// 네이버 쇼핑 API에서 정보 받아서 response로 내보내줌
//
public String search(String query) {
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "eoFux1Z5Y830gAqw7LQs");
headers.add("X-Naver-Client-Secret", "IzvVISSZUx");
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);
return response;
}
public List<ItemDto> fromJSONtoItems(String result) {
JSONObject rjson = new JSONObject(result);
JSONArray items = rjson.getJSONArray("items");
List<ItemDto> itemDtoList = new ArrayList<ItemDto>();
for (int i=0; i<items.length(); i++) {
JSONObject itemJson = items.getJSONObject(i);
ItemDto itemDto = new ItemDto(itemJson);
itemDtoList.add(itemDto);
}
return itemDtoList;
}
}
// com.sparta.week04.models ItemDto.js
// 네이버 쇼핑 API에서 받아온 JSON 데이터를 담는 Dto
@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");
}
}
특정 시간마다 반복하여 실행하게 만듦
적용하기
com.sparta.week04.utils Scheduler.js
@RequiredArgsConstructor // final 멤버 변수를 자동으로 생성합니다.
@Component // 스프링이 필요 시 자동으로 생성하는 클래스 목록에 추가합니다.
public class Scheduler {
private final ProductRepository productRepository;
private final ProductService productService;
private final NaverShopSearch naverShopSearch;
// 초, 분, 시, 일, 월, 주 순서 / 매일 새벽 1시에 실행
@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);
// 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);
}
}
}
// com.sparta.week04.service ProductService.js의 일부
@RequiredArgsConstructor // final로 선언된 멤버 변수를 자동으로 생성합니다.
@Service // 서비스임을 선언합니다.
public class ProductService {
private final ProductRepository productRepository;
@Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
public Long updateBySearch(Long id, ItemDto itemDto) {
Product product = productRepository.findById(id).orElseThrow(
() -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
);
product.updateByItemDto(itemDto);
return id;
}
}
// Week04Application.js
@EnableScheduling // 스프링 부트에서 스케줄러가 작동하게 합니다.
@EnableJpaAuditing // 시간 자동 변경이 가능하도록 합니다.
@SpringBootApplication // 스프링 부트임을 선언합니다.
public class Week04Application {
public static void main(String[] args) {
SpringApplication.run(Week04Application.class, args);
}
}