๐Ÿ’ป ์ฝ”๋”ฉ ์ผ๊ธฐ : [Spring JDBC] '์นดํ…Œ๊ณ ๋ฆฌ ์„ ํƒ' ํŽธ

ybkยท2024๋…„ 4์›” 18์ผ

spring

๋ชฉ๋ก ๋ณด๊ธฐ
12/55
post-thumbnail

๐Ÿ”” 'Spring JDBC ์˜ˆ์ œ'์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž!


๐Ÿ’Ÿ Spring JDBC ์˜ˆ์ œ

  1. ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜ ์ฒ˜๋ฆฌ: SQL ์ฟผ๋ฆฌ์—์„œ ?๊ฐ€ ๋ช‡ ๊ฐœ์ธ์ง€ ์•Œ ์ˆ˜ ์—†์„ ๋•Œ, Spring JDBC๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

  2. ๋ชจ๋ธ๊ณผ ๋ทฐ ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ: 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๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    ๋งŒ์•ฝ selected ๋ณ€์ˆ˜์˜ ๊ฐ’์— ๋”ฐ๋ผ ์„ ํƒ ์†์„ฑ์ด ์ถ”๊ฐ€๋˜๋ฉฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ด์ „์— ์„ ํƒํ•œ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ํƒ๋˜์–ด ์ง‘๋‹ˆ๋‹ค.
    • select ํƒœ๊ทธ์˜ option์—์„œ selected ์†์„ฑ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ํƒ๋˜์–ด์•ผ ํ•˜๋Š” ์˜ต์…˜์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    • set ํƒœ๊ทธ๋Š” selected ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

๐ŸŸฆ SELECT * FROM Categories๋Š” ์ •์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์นดํ…Œ๊ณ ๋ฆฌ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์–ด Statement๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ทธ์— ๋ฐ˜ํ•ด SELECT * FROM Products WHERE CategoryID IN (?)๋Š” ๋™์ ์œผ๋กœ ์นดํ…Œ๊ณ ๋ฆฌ ID๋ฅผ ๋ฐ›์•„์™€์•ผ ํ•˜๋ฏ€๋กœ, ์ด ๊ฒฝ์šฐ์—๋Š” PreparedStatement๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SQL Injection์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

profile
๊ฐœ๋ฐœ์ž ์ค€๋น„์ƒ~

0๊ฐœ์˜ ๋Œ“๊ธ€