기능 : 키워드로 상품 검색
Method : GET
URL : /api/search?query=검색어
반환 : List< ItemDto >
HTTP request, response를 위한 중복 코드를 생략할 수 있다.
Servlet은 요청과 응답을 수행하는 코드를 직접 만들어줘야하지만, Controller는 annotation을 이용해 간편하게 처리할 수 있다.
api이름마다 파일을 만들 필요가 없다
ItemSearchController.java
package com.sparta.springcore.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.springcore.dto.ItemDto;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.List;
@Controller
public class ItemSearchController {
// Controller 가 자동으로 해주는 일
// 1. API Request 의 파라미터 값에서 검색어 추출 -> query 변수
// 5. API Response 보내기
// 5.1) response 의 header 설정
// 5.2) response 의 body 설정
@GetMapping("/api/search")
@ResponseBody
public List<ItemDto> getItems(@RequestParam String query) throws IOException {
// 2. 네이버 쇼핑 API 호출에 필요한 Header, Body 정리
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "zdqMoIkFaK8uKvC2oNY2");
headers.add("X-Naver-Client-Secret", "LiZfsgtuD5");
String body = "";
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
// 3. 네이버 쇼핑 API 호출 결과 -> naverApiResponseJson (JSON 형태)
ResponseEntity<String> responseEntity = rest.exchange("https://openapi.naver.com/v1/search/shop.json?query=" + query, HttpMethod.GET, requestEntity, String.class);
String naverApiResponseJson = responseEntity.getBody();
// 4. naverApiResponseJson (JSON 형태) -> itemDtoList (자바 객체 형태)
// - naverApiResponseJson 에서 우리가 사용할 데이터만 추출 -> List<ItemDto> 객체로 변환
ObjectMapper objectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode itemsNode = objectMapper.readTree(naverApiResponseJson).get("items");
List<ItemDto> itemDtoList = objectMapper
.readerFor(new TypeReference<List<ItemDto>>() {})
.readValue(itemsNode);
return itemDtoList;
}
}
Model - View - Controller 디자인 패턴 (어플리케이션 설계 개발 방법론)
동적 웹페이지의 controller
서버와 클라이언트 간의 Request, Response는 HTTP 메시지 규약을 따른다.
@Controller
@RequestMapping("/hello/response")
public class HelloResponseController {
// [Response header]
// Location: http://localhost:8080/hello.html
@GetMapping("/html/redirect")
public String htmlFile() {
return "redirect:/hello.html";
}
@RequestMapping 안에 @GetMapping이 있다.
모든 페이지는 RequestMapping에 적어진 /hello/response를 주소창에 달게 되고, 그 뒤에 /html/redirect같이 다른걸 더 붙여서 페이지를 이동하게된다.
Model의 이해 : 내가 요청한 데이터를 화면에 띄워 줄 수 있는 빈 공간이라고 생각하면 됨
@RestController = @Controller + @ResponseBody
controller의 역할을 하면서, 응답값으로 JSON을 받아올것을 알려줌
Service와 Repository를 따로 만들지 않아도, Controller에서 모든 응답을 처리 할 수 있다.
하지만 굳이 나눠서 사용해야 하는 이유는 무엇일까?
노랑 : Controller / 빨강 : Service / 파랑 : Repository
AllInOneController.java
package com.sparta.springcore.controller;
import com.sparta.springcore.dto.ProductMypriceRequestDto;
import com.sparta.springcore.dto.ProductRequestDto;
import com.sparta.springcore.entity.Product;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor // final로 선언된 멤버 변수를 자동으로 생성합니다.
@RestController // JSON으로 데이터를 주고받음을 선언합니다.
public class AllInOneController {
// 신규 상품 등록
@PostMapping("/api/products")
public Product createProduct(@RequestBody ProductRequestDto requestDto) throws SQLException {
// 요청받은 DTO 로 DB에 저장할 객체 만들기
Product product = new Product(requestDto);
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성
PreparedStatement ps = connection.prepareStatement("select max(id) as id from product");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
// product id 설정 = product 테이블의 마지막 id + 1
product.setId(rs.getLong("id") + 1);
} else {
throw new SQLException("product 테이블의 마지막 id 값을 찾아오지 못했습니다.");
}
ps = connection.prepareStatement("insert into product(id, title, image, link, lprice, myprice) values(?, ?, ?, ?, ?, ?)");
ps.setLong(1, product.getId());
ps.setString(2, product.getTitle());
ps.setString(3, product.getImage());
ps.setString(4, product.getLink());
ps.setInt(5, product.getLprice());
ps.setInt(6, product.getMyprice());
// DB Query 실행
ps.executeUpdate();
// DB 연결 해제
ps.close();
connection.close();
// 응답 보내기
return product;
}
// 설정 가격 변경
@PutMapping("/api/products/{id}")
public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) throws SQLException {
Product product = new Product();
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성
PreparedStatement ps = connection.prepareStatement("select * from product where id = ?");
ps.setLong(1, id);
// DB Query 실행
ResultSet rs = ps.executeQuery();
if (rs.next()) {
product.setId(rs.getLong("id"));
product.setImage(rs.getString("image"));
product.setLink(rs.getString("link"));
product.setLprice(rs.getInt("lprice"));
product.setMyprice(rs.getInt("myprice"));
product.setTitle(rs.getString("title"));
} else {
throw new NullPointerException("해당 아이디가 존재하지 않습니다.");
}
// DB Query 작성
ps = connection.prepareStatement("update product set myprice = ? where id = ?");
ps.setInt(1, requestDto.getMyprice());
ps.setLong(2, product.getId());
// DB Query 실행
ps.executeUpdate();
// DB 연결 해제
rs.close();
ps.close();
connection.close();
// 응답 보내기 (업데이트된 상품 id)
return product.getId();
}
// 등록된 전체 상품 목록 조회
@GetMapping("/api/products")
public List<Product> getProducts() throws SQLException {
List<Product> products = new ArrayList<>();
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성 및 실행
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("select * from product");
// DB Query 결과를 상품 객체 리스트로 변환
while (rs.next()) {
Product product = new Product();
product.setId(rs.getLong("id"));
product.setImage(rs.getString("image"));
product.setLink(rs.getString("link"));
product.setLprice(rs.getInt("lprice"));
product.setMyprice(rs.getInt("myprice"));
product.setTitle(rs.getString("title"));
products.add(product);
}
// DB 연결 해제
rs.close();
connection.close();
// 응답 보내기
return products;
}
}