
๋์ ๋งค๊ฐ๋ณ์ ์ฒ๋ฆฌ: SQL ์ฟผ๋ฆฌ์์ ?๊ฐ ๋ช ๊ฐ์ธ์ง ์ ์ ์์ ๋, Spring JDBC๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ์ผ๋ก ๋งค๊ฐ๋ณ์๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
๋ชจ๋ธ๊ณผ ๋ทฐ ๊ฐ ๋ฐ์ดํฐ ์ ๋ฌ: Controller์์ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ JSP ๋ทฐ๋ก ์ ๋ฌํ๋ ๊ณผ์ ์์ categoryList์ productList์ ์ฐ๊ด์ฑ์ ์ค๋ช
ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ธ์จ ์นดํ
๊ณ ๋ฆฌ ๋ชฉ๋ก์ ์ฌ์ฉ์๊ฐ ์ ํํ ์ ์๋ select ํ๊ทธ์ ๋ฃ์ด์ฃผ๊ณ , ์ ํ๋ ์นดํ
๊ณ ๋ฆฌ์ ํด๋นํ๋ ์ํ ๋ชฉ๋ก์ ์กฐํํ์ฌ ํ
์ด๋ธ์ ํ์ํฉ๋๋ค.
MyBean256Product.jsp
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyBean256Product {
private Integer id;
private String name;
private Integer supplierId;
private Integer categoryId;
private String unit;
private Double price;
}
Controller26.jsp
@GetMapping("sub3")
public String method3(@RequestParam(value="category", required = false)
String[] categorySelect, Model model) throws Exception {
Connection conn = dataSource.getConnection();
// ์นดํ
๊ณ ๋ฆฌ๊ฐ ์ ํ๋์์ ๋๋ง ๋ฐ์ํด์ผ ํจ
if (categorySelect != null && categorySelect.length > 0) {
/* ? ๋ฏธ์ง์ : ๋ฐฐ์ด์ ๊ธธ์ด์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค. ? = categorySelect */
String questionMarks = "";
for (int i = 0; i < categorySelect.length; i++) {
questionMarks += "?";
if(i != categorySelect.length-1){
questionMarks += ",";
}
}
String productSql = STR."""
SELECT *
FROM Products
WHERE CategoryID IN (\{questionMarks})
ORDER BY CategoryID, Price
""";
/* productList์ categorySelect์ ๋ง๋ ๊ฐ์ ๋ฃ์ด์ค */
var productList = new ArrayList<MyBean256Product>();
PreparedStatement pstmt = conn.prepareStatement(productSql);
// i+1๋ฒ์งธ ?์ categorySelect ๊ฐ์ ๋ฃ์ด์ค์ผ ํจ
for (int i = 0; i < categorySelect.length; i++) {
pstmt.setString((i + 1), categorySelect[i]);
}
ResultSet resultSet = pstmt.executeQuery();
try (pstmt; resultSet) {
while (resultSet.next()) {
MyBean256Product bean = new MyBean256Product();
bean.setId(resultSet.getInt(1));
bean.setName(resultSet.getString(2));
bean.setSupplierId(resultSet.getInt(3));
bean.setCategoryId(resultSet.getInt(4));
bean.setUnit(resultSet.getString(5));
bean.setPrice(resultSet.getDouble(6));
productList.add(bean);
}
model.addAttribute("products", productList);
model.addAttribute("prevCategorySelect", categorySelect);
}
}
// ์ ํํ ์ ์๊ฒ ์ ์(select)
// ์นดํ
๊ณ ๋ฆฌ์ ์์ด๋์ ์ด๋ฆ categoryList์ ๋ฃ๊ธฐ
String categorySql = "SELECT * FROM Categories";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(categorySql);
var categoryList = new ArrayList<MyBean263Category>();
try (rs; stmt; conn){
while (rs.next()) {
MyBean263Category category = new MyBean263Category();
category.setId(rs.getInt(1));
category.setName(rs.getString(2));
categoryList.add(category);
}
model.addAttribute("categoryList", categoryList);
}
return "main25/sub6ProductList";
}
sql ๊ตฌ๋ฌธ์ ?๊ฐ ์ผ๋ง๋ ๋ค์ด๊ฐ์ง ๋ชฐ๋ผ IN์ ์ ๋ค์ด๊ฐ ?๊ฐ ๋ค์ด๊ฐ๋ ๋งํผ categorySelect ๋ฐฐ์ด์ ์ ์ฅ๋ฉ๋๋ค.? ์๋ ์ ํ๋ category.id๊ฐ ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค.productList๋ ์ ํ๋ ์นดํ
๊ณ ๋ฆฌ์ ํด๋นํ๋ ์ํ ์ ๋ณด๋ฅผ ๋ด๋ ๋ฆฌ์คํธ์
๋๋ค. SQL ์ฟผ๋ฆฌ๋ฅผ ์ํํ๋ฉด์ ๊ฐ๊ฐ์ ์ํธ ์ ๋ณด๋ฅผ MyBean256Porduct ๊ฐ์ฒด์ ๋งคํํ์ฌ ์ ์ฅ๋ฉ๋๋ค. categoryList๋ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ ํํ ์ ์๋๋ก select ํ๊ทธ์ ๋ค์ด๊ฐ ์ต์
์ ๋ด์ต๋๋ค. ๊ฐ ์ต์
์ category.id์ category.name์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ํ, prevCategorySelect๋ฅผ ๋ชจ๋ธ์ ์ถ๊ฐํจ์ผ๋ก์จ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ํ๋๋๋ก ์ด์ ์ ์กฐํํ๋ ๊ธฐ๋ก์ด ๋จ๋๋ก ์ค์ ํฉ๋๋ค.sub6ProductList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<html>
<head>
<title>Title</title>
<style>
table, tr, th, td {
border: 1px solid black;
border-collapse: collapse;
}
table {
width: 100%;
}
</style>
</head>
<body>
<h3>์ํ ์กฐํ</h3>
<form>
์นดํ
๊ณ ๋ฆฌ ์ ํ
<div>
<select name="category" multiple>
<c:forEach items="${categoryList}" var="category">
<c:set var="selected" value="false"></c:set>
<c:forEach items="${prevCategorySelect}" var="prevSelect">
<c:if test="${category.id == prevSelect}">
<c:set var="selected" value="true"></c:set>
</c:if>
</c:forEach>
<option ${selected ? "selected" : ""} value="${category.id}">${category.name}</option>
</c:forEach>
</select>
</div>
<div>
<button>์กฐํ</button>
</div>
</form>
<c:if test="${empty products}" var="emptyProduct">
<p style="background-color: beige; padding: 20px 20px; width: 300px">์กฐํ๋ ์ํ์ด ์์ต๋๋ค.</p>
</c:if>
<c:if test="${not emptyProduct}">
<table>
<thead style="background-color: burlywood">
<tr>
<th>์์ด๋</th>
<th>์ํ๋ช
</th>
<th>๊ณต๊ธ์
์ฒด</th>
<th>์นดํ
๊ณ ๋ฆฌ</th>
<th>Unit</th>
<th>๊ฐ๊ฒฉ</th>
</tr>
</thead>
<tbody>
<c:forEach items="${products}" var="product">
<tr style="background-color: beige">
<td>${product.id}</td>
<td>${product.name}</td>
<td>${product.supplierId}</td>
<td>${product.categoryId}</td>
<td>${product.unit}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:if>
</body>
</html>
select ํ๊ทธ์์ ๋ค์ค ์ ํ์ด ๊ฐ๋ฅํ๋๋ก ํ์ฌ๊ณ ๊ฐ ์นดํ
๊ณ ๋ฆฌ๋ง๋ค ์ ํ ์ํ๋ฅผ ์ฒ์์ false๋ก ์ด๊ธฐํ ํ ํ ๊ทธ ์นดํ
๊ณ ๋ฆฌ๊ฐ ์ด์ ์ ์ ํ๋ ์นดํ
๊ณ ๋ฆฌ ๋ชฉ๋ก์์ ํ์ฌ ์นดํ
๊ณ ๋ฆฌ์ ์์ด๋์ ์ด์ ์นดํ
๊ณ ๋ฆฌ ๋ชฉ๋ก์ ํฌํจ๋์๋์ง ํ์ธํ๊ณ ๋ง๋ค๋ฉด selected ๋ณ์๋ฅผ true๋ก ์ค์ ํฉ๋๋ค.select ํ๊ทธ์ option์์ selected ์์ฑ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ํ๋์ด์ผ ํ๋ ์ต์
์ ์ง์ ํฉ๋๋ค.set ํ๊ทธ๋ selected ๋ณ์๋ฅผ ์ค์ ํฉ๋๋ค.๐ฆ SELECT * FROM Categories๋ ์ ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์คํํ์ฌ ์นดํ
๊ณ ๋ฆฌ ํ
์ด๋ธ์ ๋ชจ๋ ์ด์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ์
๋ ฅ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์ฑํ ํ์๊ฐ ์์ด Statement๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ทธ์ ๋ฐํด SELECT * FROM Products WHERE CategoryID IN (?)๋ ๋์ ์ผ๋ก ์นดํ
๊ณ ๋ฆฌ ID๋ฅผ ๋ฐ์์์ผ ํ๋ฏ๋ก, ์ด ๊ฒฝ์ฐ์๋ PreparedStatement๋ฅผ ์ฌ์ฉํ์ฌ SQL Injection์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
