
์น ํฌ๋กค๋ง : ์น ํฌ๋กค๋ง์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ , ์ด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
Jsoup ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์น ํ์ด์ง์์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํฉ๋๋ค.ProductController.java
@RestController
@RequestMapping("/api/product")
@RequiredArgsConstructor
public class ProductController {
private final ProductService service;
@GetMapping("/list")
public List<Product> product() throws IOException {
return service.getProduct();
}
}
ProductService.java
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductService {
private final ProductMapper mapper;
private static String product_url = "๋งํฌ";
public List<Product> getProduct() throws IOException {
List<Product> productList = new ArrayList<>();
Document document = Jsoup.connect(product_url).get();
Elements contents = document.select("section div.cards-wrap article.card-top");
for (Element content : contents) {
Product product = Product.builder()
.image(content.select("div img").attr("abs:src")) //์ด๋ฏธ์ง
.title(content.select("h2").text()) // ์ ๋ชฉ
.url(content.select("a").attr("abs:href")) // ๋งํฌ
.build();
productList.add(product);
// ๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธ
if (mapper.countByImage(product.getImage()) == 0) {
mapper.insertProduct(product);
}
}
return productList;
}
}
ํฌ๋กค๋ง์ ์ํํ๊ณ ํฌ๋กค๋ง๋ ๋ฐ์ดํฐ๋ฅผ DB์ ์ ์ฅํ๋ ๋ก์ง์ ์์ฑํฉ๋๋ค.
ํฌ๋กค๋ง์ ํตํ ๋ฐ์ดํฐ ์์ง
Jsoup.connect(PRODUCT_URL).get() : Jsoup์ ์ฌ์ฉํ์ฌ ํด๋น URL์์ HTML ๋ฌธ์๋ฅผ ๋ก๋ํ๊ณ ์ด๋ฅผ Document ๊ฐ์ฒด๋ก ๋ฐํํฉ๋๋ค.document.select : HTML ๋ฌธ์์์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋ ์์๋ค์ ์ ํํฉ๋๋ค. CSS ์ ํ์์ ๋ง๋ ์์๋ค์ ๊ฐ์ ธ์ต๋๋ค.Product ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.๋ฐ์ดํฐ๊ฐ DB์ ์์ผ๋ฉด(count๊ฐ 0) DB์ ์ ์ฅํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด DB์ ์ ์ฅํฉ๋๋ค.
ProductMapper.java
@Mapper
public interface ProductMapper {
@Insert("INSERT INTO product (image, title) VALUES (#{image}, #{title})")
int insertProduct(Product product);
@Select("SELECT COUNT(*) FROM product WHERE image=#{image}")
int countByImage(String image);
}
insertProduct : ์ํ์ DB์ ์ ์ฅํฉ๋๋ค.countByImage : ํด๋น ์ํ์ด ํ์ฌ DB์ ์๋์ง ์กฐํํฉ๋๋ค.Product.jsx(React)
export function ProductList() {
const [productList, setProductList] = useState([]);
useEffect(() => {
axios.get(`/api/product/list`).then((res) => setProductList(res.data));
}, []);
return (
<div>
<Table>
<Thead>
<Tr>
<Th>์ด๋ฏธ์ง</Th>
<Th>์ ๋ชฉ</Th>
</Tr>
</Thead>
<Tbody>
{productList.map((product) => (
<Tr key={product.title}>
<Td onClick={() => (window.location.href = product.url)}>
<Image src={product.image} />
</Td>
<Td>{product.title}</Td>
</Tr>
))}
</Tbody>
</Table>
</div>
);
}
export default ProductList;

product ํ ์ด๋ธ ์์ฑ
CREATE TABLE product (
id INT AUTO_INCREMENT PRIMARY KEY,
image VARCHAR(500) NOT NULL,
title VARCHAR(500) NOT NULL
);
