1. BbsDAO ํด๋์ค์ getBbs() ๋ฉ์๋ ๋ง๋ค๊ธฐ
`getBbs(int bbsID)` ๋ฉ์๋๋ ํน์ bbsID๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์๊ธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํํ์ฌ ๋ฐํํ๋ค.
์ฆ ํ๋์ ๊ธ ๋ด์ฉ์ ๋ถ๋ฌ์ค๋ ๋ฉ์๋์ด๋ค.
์ฒ์์ ์ ์ ์ฝ๋(ํ๋ฆผ)
public Bbs getBbs(int bbsID) {
String SQL = "SELECT * FROM BBS WHERE bbsID = ?";
try (PreparedStatement psmt = conn.prepareStatement(SQL);
ResultSet rs = psmt.executeQuery()) {
psmt.setInt(1, bbsID);
if (rs.next()) {
Bbs bbs = new Bbs();
bbs.setBbsID(rs.getInt(1));
bbs.setBbsTitle(rs.getString(2));
bbs.setUserID(rs.getString(3));
bbs.setBbsDate(rs.getString(4));
bbs.setBbsContent(rs.getString(5));
bbs.setBbsAvailable(rs.getInt(6));
return bbs;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
์ ์ฝ๋๋ก ์ผ๋ค๊ฐ ์ค๋ฅ ๋์ ์ฝ๋ ์์ ํ๋ค.
finally ์ ์ฐ๊ณ ์์ํด์ ๋ฅผ ์ฝ๊ฒ ํ๋ ค๊ณ ํ๋ค๊ฐ ๋์ฐธ์ฌ
psmt.executeQuery()๋ ResultSet์ ๋ฐํํ๋ ๋ฉ์๋๋ผ์ psmt = conn.prepareStatement(SQL)์ด๋ ๊ฐ์ try๋ธ๋ญ์ ํฌํจ์ํฌ ์ ์๋ค.
์์ ๋ ์ฝ๋
public Bbs getBbs(int bbsID) {
String SQL = "SELECT * FROM BBS WHERE bbsID = ?";
PreparedStatement psmt = null;
ResultSet rs = null;
try {
psmt = conn.prepareStatement(SQL);
psmt.setInt(1, bbsID);
rs = psmt.executeQuery();
if (rs.next()) {
Bbs bbs = new Bbs();
bbs.setBbsID(rs.getInt(1));
bbs.setBbsTitle(rs.getString(2));
bbs.setUserID(rs.getString(3));
bbs.setBbsDate(rs.getString(4));
bbs.setBbsContent(rs.getString(5));
bbs.setBbsAvailable(rs.getInt(6));
return bbs;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// ๋ช
์์ ์ผ๋ก ๋ฆฌ์์ค๋ฅผ ๋ซ๊ธฐ
try {
if (rs != null) {
rs.close();
}
if (psmt != null) {
psmt.close();
}
if (conn != null && !conn.isClosed()) {
conn.close(); // ์ฐ๊ฒฐ ๋ซ๊ธฐ
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
2. view.jsp ํ์ด์ง ๋ง๋ค๊ธฐ
์ค์ ๋ก ๊ฒ์๊ธ ๋ด์ฉ์ ๋ณด์ฌ์ฃผ๋ ํ์ด์ง์ด๋ค.
๊ธ ์ ๋ชฉ์ ํด๋ฆญํ๋ฉด ์ปจํ
์ธ ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ญํ ์ ํ๋ค.
๋ ์ด์์์ด ์ ์ฌํ `write.jsp` ๋ณต์ฌํด์ ์์ฑํด์ฃผ์๋ค.
์ด๋ ๊ฒ ์์ฑ์๊ฐ ๋ณธ์ธ์ด๋ฉด ์์ , ์ญ์ ๋ฒํผ์ด ํ๋จ์ ๋จ๋๋ก ๋ง๋ค์ด ์ฃผ๊ณ ํ
์คํธ!
<div class="container mt-5">
<div class="row card shadow-sm">
<table class="table table-striped" style="text-align: center; border: 1px solid #dddddd">
<thead>
<tr>
<th colspan="3" style="background-color: #eeeeee; text-align: center;">๊ฒ์ํ ๊ธ๋ณด๊ธฐ </th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 20%;">๊ธ์ ๋ชฉ</td>
<td colspan="2"><%= bbs.getBbsTitle() %></td>
</tr>
<tr>
<td>์์ฑ์</td>
<td colspan="2"><%= bbs.getUserID() %></td>
</tr>
<tr>
<td>์์ฑ์ผ์</td>
<td colspan="2"><%= bbs.getBbsDate().substring(0, 11) + bbs.getBbsDate().substring(11, 13) + "์" + bbs.getBbsDate().substring(14, 16) + "๋ถ" %></td>
</tr>
<tr>
<td>๋ด ์ฉ</td>
<td colspan="2" style="min-height: 200px; text-align: left;"><%= bbs.getBbsContent() %></td>
</tr>
</tbody>
</table>
<a href="bbs.jsp" class="btn btn-primary" style="width: auto;">๋ชฉ๋ก</a>
<%
if(userID != null && userID.equals(bbs.getUserID())) {
%>
<a href="update.jsp?bbsID=<%= bbsID %>" class="btn btn-primary">์์ </a>
<a href="deleteAction.jsp?bbsID=<%= bbsID %>" class="btn btn-primary">์ญ์ </a>
<%
}
%>
</div>
</div>
์ด์ฉ์ง ์ ๋๋๋ ์ค๋ฅ๋ฌ๋ค
public Bbs getBbs(int bbsID) ๋ฉ์๋์ ์ด์ ์๋ ๊ฒ ๊ฐ์ ํ์ธํด๋ณด์๋ค.
์๊น ์ ์ ์์ ํด์ ๋ฅผ ๊ฐ๋จํ๊ฒ ์ค์ด๋ค๊ฐ ์๋ชป๋ ๋ถ๋ถ์ด ์์๋ค.
try (PreparedStatement psmt = conn.prepareStatement(SQL); ResultSet rs = psmt.executeQuery())
์ด ๋ถ๋ถ์ด ์๋ชป๋์๋ค.
try๋ฌธ ์์๋ค๊ฐ psmt.executeQuery()๊น์ง ์จ ์ค ๋ฒ๋ ค์ ์ค๋ฅ๊ฐ ๋ ๊ฒ.
psmt๋ PreparedStatement๋ก SQL์ ์ค๋นํ๋ ๋ฐ ์ฌ์ฉ๋๊ณ , psmt.executeQuery()๋ ResultSet์ ๋ฐํํ๋ ๋ฉ์๋์ด๊ธฐ ๋๋ฌธ์ ๋ ๊ฐ๋ฅผ ๊ฐ์ try ๊ตฌ๋ฌธ์ ํฌํจ์ํฌ ์ ์๋ค. try๋ฌธ์ ๋ ๋ฒ ์จ์ psmt๊ฐ ๋ฐํํ ResultSet์ try ๋ธ๋ก ๋ด์์ ์ฒ๋ฆฌํ๋๋ก ํ๋๊ฐ finally๋ฅผ ์จ์ ์์ํด์ ๋ฅผ ๋ฐ๋ก ํด ์ฃผ์ด์ผ ํ๋ค. ๋๋ finally๋ฅผ ์ฐ๋ ๋ฐฉ๋ฒ์ผ๋ก ์์ ํ๋ค.
๋ค์ ์คํํด๋ณด๋ ์ด๋ฒ์๋ ๊บฝ์ ๊ฐ...;
๊บฝ์ ์์ ํ๋๋ฐ ์ด์ฒด์ ๋๊ตญ์ด๋ค.
- ์ผ๋จ ๋ด์ฉ ๋ถ๋ถ min-height ์๋จนํ
- ๋ชฉ๋ก๋ฒํผ์ด width 100% ๋จนํ๊ณ ์์ , ์ญ์ ๋ฒํผ ์๋ณด์...;;
์ผ๋จ card ๋ shadow-sm ํด๋์ค ๋นผ ์ฃผ๊ณ ์ญ์ ์ ์์ ๋ฒํผ์ style="width: auto;" ์ค์ ํฌ๊ธฐ๋ฅผ ์ค์๋ค.
๋ฒํผ ์ฌ์ด์ ` ` ๋ฃ์ด ์ฃผ์ด์ ์คํ์ด์ค๋ฐ ํ ์นธ์ฉ ๋ ๊ฐ๊ฒฉ์ ๋ง๋ค์ด์ฃผ์๋ค.
์ด์ ๋ด์ฉ ์นธ min-height๋ง ๋๋ฆฌ๋ฉด ๋๋ค!
min-height๊ฐ ์๋จนํ์ ๊ทธ๋ฅ ๋ช
์์ ์ผ๋ก height ๋ก ํ๋ค.
์ด์ฐจํผ ๊ธ ๋ด์ฉ์ ๋ฐ๋ผ ๋์ด๊ฐ ๋์ด๋๊ธฐ ๋๋ฌธ์ ์๊ด ์์ ๊ฒ ๊ฐ๋ค.
๋ชฉ๋ก ๋ฒํผ๋ ๋๋ฌ์ฃผ๊ณ
์ ์๋ํ๋ค.
์ด์ ํน์๋ฌธ์ ์ฒ๋ฆฌ๋ฅผ ํด ์ฃผ์ด์ผ ํ๋ค.
๋ง์ฝ ์ฒ๋ฆฌํ์ง ์๊ณ ์ด๋๋ก ํน์๋ฌธ์๋ฅผ ์
๋ ฅํด์ ๊ธ์ ์จ ๋ณด๋ฉด ์
๋ ฅํ ์์๊ณผ ๋ค๋ฅด๊ฒ ๋์จ๋ค.
ํ์ง๋ง ์์ฆ์๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ข์์ ธ์ ์์์ ์ฒ๋ฆฌ๊ฐ ๋๋ค.
ํ์ง๋ง ํน์๋ฌธ์ ์ฒ๋ฆฌ๋ ๋ณด์๊ณผ ์ฝํ ์ธ ์ ํ์ฑ ์ธก๋ฉด์์ ์ฌ์ ํ ์ค์ํ๋ค. ๋ฌผ๋ก ๋ธ๋ผ์ฐ์ ๊ฐ ์ผ๋ถ ํน์๋ฌธ์๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํด ์ฃผ๊ธด ํ์ง๋ง, ๋ณด์ ๋ฌธ์ (ํนํ XSS)์ ์์์น ๋ชปํ ์ถ๋ ฅ์ ๋ฐฉ์งํ๊ธฐ ์ํด์ ์๋์ผ๋ก ํน์๋ฌธ์๋ฅผ ์ฒ๋ฆฌํ๋ ์ต๊ด์ ๊ฐ์ง๋ ๊ฒ์ด ์ข๋ค.
์๋์ฒ๋ผ ๊ธ์ ์ฐ๊ณ ๋ด์ฉ์ ํ์ธ ํด ๋ณด๋ฉด
์์ฑํ ๊ธ๊ณผ ๋ค๋ฅด๊ฒ ์ถ๋ ฅ๋๋ค. ์ผ๋จ ์ํฐ๋ฅผ ์ณค๋๋ฐ ์ธ์์ด ์ ๋๊ณ ์ด์ด์ ธ์ ์ถ๋ ฅ๋๋ค. ใ
ใ
;
ํน์๋ฌธ์ ์ฒ๋ฆฌํ๋ ๋ฒ์ replaceAll() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ค.
ํ์ฌ <๋ง ์ฒ๋ฆฌํ์ง๋ง, HTML ์์ ์ฑ์ ๋ณด์ฅํ๋ ค๋ฉด ๋ค๋ฅธ ํน์๋ฌธ์(>, &, ", ')๋ ๋ณํํด์ผ ํ๋ค.
<%= bbs.getBbsContent().replaceAll(" "," ").replaceAll("<", "<") %>
์๋๋ StringEscapeUtils ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ๋ฉด HTML ์ด์ค์ผ์ดํ์ ๋ ๊ฐ๋จํ ์ฒ๋ฆฌํ ์ ์๋ค. ๋ ์ง๊ธ JSP๋ง์ผ๋ก ๋ง๋ค๊ณ ์์ด์ replaceAll()๋ฉ์๋๋ก ํน์๋ฌธ์ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๊ณ ์๋ค. ๋ง์ฝ Maven ํ๋ก์ ํธ๋ฅผ ํ๋ฉด pom.xml ํ์ผ์ ์์กด์ฑ ์ฃผ์
์ ํด์ค์ ์๋์ฒ๋ผ ๋ชจ๋ ํน์๋ฌธ์ ์ฒ๋ฆฌ๋ฅผ ํด ์ค ์ ์๋ค.
<%= StringEscapeUtils.escapeHtml4(bbs.getBbsContent()) %>
๋๋ ์ด๋ ๊ฒ ํ๋์ฉ ์ฒ๋ฆฌํด์ฃผ์๋ค.
์๋ก๊ณ ์นจํด์ ํ์ด์ง ํ์ธ
๋๋จธ์ง๋ ์ ์ฒ๋ฆฌ๋ ๊ฒ ๊ฐ์๋ฐ ๊ณต๋ฐฑ์ด ;; ๋ก ๋ฐ๋์ด์ ๋ณด๊ธฐ๊ฐ ์ ์ข๋ค;
๊ทธ๋ฅ replaceAll(" ", " ")๋ ๋นผ ๋ฒ๋ ธ๋ค.
JSP์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก <c:out> ๊ฐ์ ํ๊ทธ๊ฐ HTML ํน์๋ฌธ์๋ฅผ ์ด์ค์ผ์ดํ ์ฒ๋ฆฌํ๋ค๊ณ ํ๋ค.
๋๋ ์ง๊ธ <%=๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ HTML์ด ๊ทธ๋๋ก ๋ ๋๋ง๋๋ค.
escapeXml๋ฅผ ํด์ ํด ์ฃผ์ด์ผ ๊ณต๋ฐฑ์ด ๋ก ์นํ๋์ง ์๊ณ ์ ์์ ์ผ๋ก ์ถ๋ ฅ์ด ์ ๋๋ค๊ณ ํ๋ค.
์ด๊ฑธ ํด์ ํด ์ฃผ๋ ค๋ฉด JSTL + escapeXml="false" ํด์ JSTL <c:out> ํ๊ทธ์์ escapeXml ์์ฑ์ ๋นํ์ฑํํด ์ฃผ์ด์ผ ํ๋ค.
์,,, ๊ท์ฐฎ์์ ํจ์คํ๋ค....์๋ซ๋ฉด
JSP์์ JSTL์ ์ฌ์ฉํ๋ ค๋ฉด JSTL ๋ผ์ด๋ธ๋ฌ๋ฆฌ(JAR ํ์ผ)์ ํ๋ก์ ํธ์ ์ถ๊ฐํด์ผ ํ๋ค๋๋ฐ?
๋๋ Maven ํ๋ก์ ํธ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ JAR ํ์ผ์ ์๋์ผ๋ก ๋ค์ด๋ก๋ํ๊ณ , WEB-INF/lib ํด๋์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
๋นจ๋ฆฌ ๋นจ๋ฆฌ ์งํํ๊ธฐ ์ํด ํด์ ํ๋ ๋ฒ ์ ๋๋ง ์ตํ๊ณ ๊ตณ์ด jar ํ์ผ ๋ค์ด๋ฐ์ง๋ ์์ ๊ฒ์ด๋ค^^;;;
์ฌ๊ธฐ๊น์ง ํ์ผ๋ฉด ์ด์ ํฌ๋ก์ค ์ฌ์ดํธ ์คํฌ๋ฆฝํ
(Cross-Site Scripting, XSS) ๊ณต๊ฒฉ์ ํด ๋ณด์
ํฌ๋ก์ค ์ฌ์ดํธ ์คํฌ๋ฆฝํ
์ ์น ์ ํ๋ฆฌ์ผ์ด์
์์ ์ฌ์ฉ์ ์
๋ ฅ์ ์ ๋๋ก ๊ฒ์ฆํ์ง ์๊ณ ๊ทธ๋๋ก ์ถ๋ ฅํ ๋ ๋ฐ์ํ๋ ๋ณด์ ์ทจ์ฝ์ ์ด๋ผ๊ณ ํ๋ค. ์๋ฅผ ๋ค๋ฉด ๊ฒ์๊ธ ์ ๋ชฉ์ ์
์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฃ์ด์ ๋๋ฅด๋ฉด ์ด๋ฅผ ์คํํ๋๋ก ์ ๋ํ๋ ๊ฒ์ด๋ค.
์ ๋ชฉ์ Hello World!๋ฅผ ๋์ฐ๋ ์คํฌ๋ฆฝํธ๋ฌธ์ ์์ฑํด ๋ณด์๋ค.
๊ทธ๋๋ก ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋์ด์ Hello World! ๋ผ๋ ์ฐฝ์ด ๋จ๋ ๊ฑธ ๊ธฐ๋ํ๋๋ฐ
๋ธ๋ผ์ฐ์ ์์ ์๋์ผ๋ก ๋ง์์ฃผ๋์ง ์์ ์ ๋ชฉ์ด ์ ์ ํ๊ณ ๊ณต๋ฐฑ์ผ๋ก ์ถ๋ ฅ๋๋ค.
view.jsp ์ ์ฒด ์ฝ๋
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.PrintWriter"%>
<%@ page import="bbs.Bbs"%>
<%@ page import="bbs.BbsDAO"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.css">
<title>JSP ๊ฒ์ํ ์น ์ฌ์ดํธ</title>
</head>
<body>
<%
String userID = null;
if (session.getAttribute("userID") != null) {
userID = (String) session.getAttribute("userID");
}
int bbsID = 0;
if(request.getParameter("bbsID") != null) {
bbsID = Integer.parseInt(request.getParameter("bbsID"));
}
if (bbsID == 0) {
PrintWriter script = response.getWriter();
script.println("<script>");
script.println("alert('์ ํจํ์ง ์์ ๊ธ์
๋๋ค.')");
script.println("location.href = 'bbs.jsp'");
script.println("</script>");
}
Bbs bbs = new BbsDAO().getBbs(bbsID);
%>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">JSP ์น์ฌ์ดํธ</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" aria-current="page"
href="main.jsp">Home</a></li>
<li class="nav-item"><a class="nav-link active" href="bbs.jsp">๊ฒ์ํ</a></li>
</ul>
<%
if (userID == null) { // ๋ก๊ทธ์ธ ํ์ง ์์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค ํ๋ฉด
%>
<ul class="navbar-nav ms-auto">
<li class="nav-item dropdown"><a
class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-expanded="false"> ์ ์ํ๊ธฐ<span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="login.jsp">๋ก๊ทธ์ธ</a></li>
<li><a class="dropdown-item" href="join.jsp">ํ์๊ฐ์
</a></li>
</ul></li>
</ul>
<%
} else { // ๋ก๊ทธ์ธ ํ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค ํ๋ฉด
%>
<ul class="navbar-nav ms-auto">
<li class="nav-item dropdown"><a
class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-expanded="false"> ํ์๊ด๋ฆฌ<span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="logoutAction.jsp">๋ก๊ทธ์์</a></li>
</ul></li>
</ul>
<%
}
%>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="row">
<table class="table table-striped"
style="text-align: center; border: 1px solid #dddddd">
<thead>
<tr>
<th colspan="3"
style="background-color: #eeeeee; text-align: center;">๊ฒ์ํ
๊ธ๋ณด๊ธฐ</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 20%;">๊ธ์ ๋ชฉ</td>
<td colspan="2"><%= bbs.getBbsTitle() %></td>
</tr>
<tr>
<td>์์ฑ์</td>
<td colspan="2"><%= bbs.getUserID() %></td>
</tr>
<tr>
<td>์์ฑ์ผ์</td>
<td colspan="2"><%= bbs.getBbsDate().substring(0, 11) + bbs.getBbsDate().substring(11, 13) + "์" + bbs.getBbsDate().substring(14, 16) + "๋ถ" %></td>
</tr>
<tr>
<td>๋ด ์ฉ</td>
<td colspan="2" style="height: 200px; text-align: left;"><%=bbs.getBbsContent()
.replaceAll("<", "<") // ์์ ๊ดํธ <
.replaceAll(">", ">") // ํฐ ๊ดํธ >
.replaceAll("&", "&") // ์ฐํผ์๋ &
.replaceAll("\"", """) // ํฐ๋ฐ์ดํ "
.replaceAll("'", "'") // ์์๋ฐ์ดํ '
.replaceAll("\n", "<br>")); // ์ค๋ฐ๊ฟ ์ฒ๋ฆฌ %></td>
</tr>
</tbody>
</table>
<a href="bbs.jsp" class="btn btn-primary" style="width: auto;">๋ชฉ๋ก</a>
<%
if (userID != null && userID.equals(bbs.getUserID())) {
%>
<a href="update.jsp?bbsID=<%=bbsID%>" class="btn btn-primary"
style="width: auto;">์์ </a> <a
href="deleteAction.jsp?bbsID=<%=bbsID%>" class="btn btn-primary"
style="width: auto;">์ญ์ </a>
<%
}
%>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
์ค๋์ ์ฌ๊ธฐ๊น์ง;