์๋น์ค๊ธฐ๋ฅ |
---|
1. ํค์๋๋ก ์ํ๊ฒ์ โ ๊ฒฐ๊ณผ ๋ชฉ๋ก์ผ๋ก ๋ณด์ฌ์ฃผ๊ธฐ |
2. ๊ด์ฌ์ํ ๋ฑ๋กํ๊ธฐ |
3. ๊ด์ฌ์ํ ์กฐํํ๊ธฐ |
4. ๊ด์ฌ์ํ ์ต์ ๊ฐ๋ฑ๋กํ๊ธฐ |
๊ธฐ๋ฅ | Method | URL | Request | Response |
---|---|---|---|---|
๋ฉ์ธํ์ด์ง | GET | /api/shop | - | index.html |
Query๋ก ์ํ๊ฒ์, ์ํ๊ฒ์๊ฒฐ๊ณผ ๋ชฉ๋ก๋ฐํ | GET | /api/search?query=๊ฒ์์ด | - | [ { ย ย "title" : String, ย ย "image" : String, ย ย "link" : String, ย ย "lprice" : int }, โขโขโข ] |
๊ด์ฌ์ํ ๋ฑ๋ก | POST | /api/products | { ย ย "title" : String, ย ย "image" : String, ย ย "link" : String, ย ย "lprice" : int } | { ย ย "id" : Long, ย ย "title" : String, ย ย "image" : String, ย ย "link" : String, ย ย "lprice" : int, ย ย "myprice" : int } |
๊ด์ฌ์ํ ์กฐํ | GET | /api/products | - | [ { ย ย "id" : Long, ย ย "title" : String, ย ย "image" : String, ย ย "link" : String, ย ย "lprice" : int, ย ย "myprice" : int }, โขโขโข ] |
๊ด์ฌ์ํ ์ต์ ๊ฐ ๋ฑ๋ก | PUT | /api/products/{id} | { ย ย "myprice" : int } | id |
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class NaverApiController {
private final NaverApiService naverApiService;
// ์ํ๊ฒ์๊ฒฐ๊ณผ ๋ชฉ๋ก๋ฐํ
@GetMapping("/search")
public List<ItemDto> searchItems(@RequestParam String query) {
return naverApiService.searchItems(query);
}
}
@Service
@Slf4j
public class NaverApiService {
public List<ItemDto> searchItems(String query) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
// HttpHeader -> Client Id/Pw ์ค์ด ๋ณด๋
httpHeaders.add("X-Naver-Client-Id", "_VwwboxD7N9gzc6pnvuC");
httpHeaders.add("X-Naver-Client-Secret", "e3kEsesnyl");
String body = "";
// HttpEntity -> header + body
HttpEntity<String> requestEntity = new HttpEntity<String>(body, httpHeaders);
// HttpResponse -> query + GET๋ฉ์๋ + Request(header+body)
ResponseEntity<String> responseEntity = restTemplate.exchange(
"https://openapi.naver.com/v1/search/shop.json?display=15&query="
+ query, HttpMethod.GET, requestEntity, String.class);
// display=15 : ๊ฒ์๊ฒฐ๊ณผ ์ด 15๊ฐ show
// HttpEntity ํด๋์ค : Http ์์ฒญ, ์๋ต์ ํด๋นํ๋ HttpHeader์ HttpBody๋ฅผ ๊ฐ์ง
// HttpEntity ํด๋์ค๋ฅผ ์์๋ฐ์ ๊ตฌํํ ํด๋์ค -> requestEntity, responseEntity
// HttpStatus
HttpStatusCode httpStatus = responseEntity.getStatusCode();
int status = httpStatus.value();
log.info("NAVER API Status Code : " + status);
// Response Body -> method
// responseEntity์ ๋ฐ๋์ ์๋ ๊ฐ์ -> String ํ์
response์ ๋ด์์ด
String response = responseEntity.getBody();
return fromJSONtoItems(response);
}
// String(๊ฒ์๊ฒฐ๊ณผ) -> Dto์ ๋ด๊ธฐ์ํด ๋ณํํ๋ ๋ฉ์๋
public List<ItemDto> fromJSONtoItems(String response) {
// JSONObject -> build.gradle์ ์ข
์์ฑ์ถ๊ฐ
JSONObject jsonObject = new JSONObject(response); // String ๊ฒ์๊ฒฐ๊ณผ -> JSONObject
JSONArray items = jsonObject.getJSONArray("items"); // JSONObject -> JSONArray
// Dto List ๊ฐ์ฒด์์ฑ
List<ItemDto> itemDtoList = new ArrayList<>();
// JSONArray -> for๋ฌธ ๋๋ฉด์ item ํ๋์ฉ ๊บผ๋ด -> ItemDto์ ๋ณํ
for (int i = 0; i < items.length(); i++) {
JSONObject itemJson = items.getJSONObject(i);
ItemDto itemDto = ItemDto.of(itemJson);
itemDtoList.add(itemDto);
}
return itemDtoList;
}
}
@Getter
@NoArgsConstructor
public class ItemDto {
private String title;
private String link;
private String image;
private int lprice;
// ์์ฑ์
@Builder
private ItemDto(String title, String link, String image, int lprice) {
this.title = title;
this.link = link;
this.image = image;
this.lprice = lprice;
}
// ์ ์ ํฉํ ๋ฆฌ๋ฉ์๋
public static ItemDto of(JSONObject itemJson) {
return ItemDto.builder()
.title(itemJson.getString("title"))
.link(itemJson.getString("link"))
.image(itemJson.getString("image"))
.lprice(itemJson.getInt("lprice"))
.build();
}
}
@Entity
@Getter @Setter
@NoArgsConstructor // ํ๋ผ๋ฏธํฐ ์๋ ๊ธฐ๋ณธ์์ฑ์
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
// 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;
// ์์ฑ์
@Builder
private Product(String title, String image, String link, int lprice) {
this.title = title;
this.image = image;
this.link = link;
this.lprice = lprice;
this.myprice = 0;
}
// ์ ์ ํฉํ ๋ฆฌ๋ฉ์๋
public static Product of(ProductRequestDto productRequestDto) {
return Product.builder()
.title(productRequestDto.getTitle())
.image(productRequestDto.getImage())
.link(productRequestDto.getLink())
.lprice(productRequestDto.getLprice())
.build();
}
}
@Getter
@NoArgsConstructor // ํ๋ผ๋ฏธํฐ์๋ ๊ธฐ๋ณธ์์ฑ์
public class ProductResponseDto {
private Long id;
private String title;
private String link;
private String image;
private int lprice;
private int myprice;
// ์์ฑ์
@Builder
private ProductResponseDto(Long id, String title, String link, String image, int lprice, int myprice) {
this.id = id;
this.title = title;
this.link = link;
this.image = image;
this.lprice = lprice;
this.myprice = myprice;
}
// ์ ์ ํฉํ ๋ฆฌ๋ฉ์๋
public static ProductResponseDto of(Product product) {
return ProductResponseDto.builder()
.id(product.getId())
.title(product.getTitle())
.link(product.getLink())
.image(product.getImage())
.lprice(product.getLprice())
.myprice(product.getMyprice())
.build();
}
}
@Getter
@NoArgsConstructor // ํ๋ผ๋ฏธํฐ์๋ ๊ธฐ๋ณธ์์ฑ์
@AllArgsConstructor // ๋ชจ๋ ํ๋๋ฅผ ํ๋ผ๋ฏธํฐ๋ก๋ฐ๋ ์์ฑ์
public class ProductRequestDto {
private String title;
private String image;
private String link;
private int lprice;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ProductMypriceRequestDto {
private int myprice;
}
// JSON ํํ์ ๋ฐ์ดํฐ๋ฐํ
@RestController
@RequestMapping("/api")
public class AllInOneController {
// ๊ด์ฌ์ํ ๋ฑ๋ก
@PostMapping("/products")
public ProductResponseDto createProduct(@RequestBody ProductRequestDto productRequestDto) throws SQLException {
// RequestDto -> DB์ ์ ์ฅํ Entity๊ฐ์ฒด ์์ฑ + ์ด๊ธฐํ
Product product = Product.of(productRequestDto);
// DB ์ฐ๊ฒฐ
Connection connection = DriverManager.getConnection("jdbc:h2:mem:db", "mallang", "");
// DB Query ์์ฑ
PreparedStatement preparedStatement = connection.prepareStatement("select max(id) as id from product");
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
// product id ์ค์ = product ํ
์ด๋ธ ๋ง์ง๋ง Id + 1
product.setId(resultSet.getLong("id") + 1);
} else {
throw new SQLException("product ํ
์ด๋ธ์ ๋ง์ง๋ง Id ๊ฐ์ ์ฐพ์์ค์ง ๋ชปํ์ต๋๋ค.");
}
preparedStatement = connection.prepareStatement("insert into product(id, title, image, link, lprice, myprice) values (?, ?, ?, ?, ?, ?)");
preparedStatement.setLong(1, product.getId());
preparedStatement.setString(2, product.getTitle());
preparedStatement.setString(3, product.getImage());
preparedStatement.setString(4, product.getLink());
preparedStatement.setInt(5, product.getLprice());
preparedStatement.setInt(6, product.getMyprice());
// DB Query ์คํ
preparedStatement.executeUpdate();
// DB ์ฐ๊ฒฐํด์
preparedStatement.close();
connection.close();
// Response ์ ์ก
return ProductResponseDto.of(product);
}
}
{
// ๊ด์ฌ์ํ ์กฐํ
@GetMapping("/products")
public List<ProductResponseDto> getProducts() throws SQLException {
// ๋ฐํํ์
(ResponseDtoList) ๊ฐ์ฒด์์ฑ
List<ProductResponseDto> productResponseDtoList = new ArrayList<>();
// DB ์ฐ๊ฒฐ
Connection connection = DriverManager.getConnection("jdbc:h2:mem:db", "mallang", "");
// DB Query ์์ฑ ๋ฐ ์คํ
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from product");
// DB Query ๊ฒฐ๊ณผ -> productResponseDtoList ๋ณํ
while (resultSet.next()) {
Product product = new Product();
product.setId(resultSet.getLong("id"));
product.setTitle(resultSet.getString("title"));
product.setImage(resultSet.getString("image"));
product.setLink(resultSet.getString("link"));
product.setLprice(resultSet.getInt("lprice"));
product.setMyprice(resultSet.getInt("myprice"));
productResponseDtoList.add(ProductResponseDto.of(product));
}
// DB ์ฐ๊ฒฐํด์
resultSet.close();
connection.close();
// Response ์ ์ก
return productResponseDtoList;
}
}
{
// ๊ด์ฌ์ํ ์ต์ ๊ฐ ๋ฑ๋ก
@PutMapping("/products/{id}")
public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto productMypriceRequestDto) throws SQLException {
// Entity ๊ฐ์ฒด์์ฑ
Product product = new Product();
// DB ์ฐ๊ฒฐ
Connection connection = DriverManager.getConnection("jdbc:h2:mem:db", "mallang", "");
// DB Query ์์ฑ
PreparedStatement preparedStatement = connection.prepareStatement("select * from product where id = ?");
preparedStatement.setLong(1, id);
// DB Query ์คํ
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
product.setId(resultSet.getLong("id"));
product.setTitle(resultSet.getString("title"));
product.setImage(resultSet.getString("image"));
product.setLink(resultSet.getString("link"));
product.setLprice(resultSet.getInt("lprice"));
product.setMyprice(resultSet.getInt("myprice"));
} else {
throw new NullPointerException("ํด๋น Id๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.");
}
// DB Query ์์ฑ
preparedStatement = connection.prepareStatement("update product set myprice = ? where id = ?");
preparedStatement.setInt(1, productMypriceRequestDto.getMyprice());
preparedStatement.setLong(2, product.getId());
// DB Query ์คํ
preparedStatement.executeUpdate();
// DB ์ฐ๊ฒฐํด์
resultSet.close();
preparedStatement.close();
connection.close();
// Response ์ ์ก
return product.getId();
}
}
1๊ฐ์ ํด๋์ค โ ๋๋ฌด ๋ง์ ์์ ์ฝ๋๊ฐ ์กด์ฌํจ
์ฝ๋ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ ์์ฒญ โ ๋์ ์ด๋ ต๊ณ ๋ฒ๊ฑฐ๋ก์
์ด๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์
์ปดํจํฐ๊ฐ ํด์ผํ๋ ์ผ โ ์์ฐจ์ ์ผ๋ก ์ญ ๋์ดํด๋์ ์ฝ๋ฉ๋ฐฉ์
(ex. AllInOneController ํด๋์ค API ์ฒ๋ฆฌ๋ด์ฉ)
์ํํธ์จ์ด ๊ท๋ชจ๊ฐ ์ปค์ง๋ฉด์ ๋ฑ์ฅ
ํ๋์ ์ฌ๋ฌผ(๊ฐ์ฒด) โ ํ๋์ ์๋ฏธ๋ฅผ ๋ถ์ฌํ๋ ๋ฐฉ์์ผ๋ก ํ๋ก๊ทธ๋๋ฐ
๐ ์ฒ์์ ์ ์ฐจ์ ํ๋ก๊ทธ๋๋ฐ, ๋์ค์ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ผ๋ก ๋ฆฌํฉํ ๋ง
๋ฆฌํฉํ ๋ง (Refactoring)
: ๊ธฐ๋ฅ ์ ๋ณ๊ฒฝ โ, ํ๋ก๊ทธ๋๋ฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ํ๋ ๊ฒ