21.06.25{코딩일기} 동빈나 유튜버 JSP게시판 만들기 (12) | 전자정부프레임워크 eclipse 게시판 만들기{day7}
게시판 코드작성완료 후기 생생하게 공유드립니다. 많이 놀러와주세여:)
https://www.youtube.com/watch?v=P5s5JwvZjBA&t=27s&pp=sAQA
# view.jsp code
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.PrintWriter"%>
<%@ page import="list.Board"%>
<%@ page import="list.ListDAO"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width" , initial-scale="1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<title>BluevulpeBoard</title>
</head>
<body style="background-color: lightblue;">
<%
String userID = null;
if (session.getAttribute("userID") != null) {
userID = (String) session.getAttribute("userID");
}
int listID = 0;
if (request.getParameter("listID") != null) {
listID = Integer.parseInt(request.getParameter("listID"));
}
if (listID == 0) {
PrintWriter script = response.getWriter();
script.println("<script>");
script.println("alert('유효하지 않은 글입니다.')");
script.println("location.href = 'list.jsp'");
script.println("</script>");
}
Board bbs = new ListDAO().getBbs(listID);
%>
<nav class="navbar navbar-default">
<!-- navbar-색상(inverse = 검은색, default = 색x) -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<!-- class="navbar-toggle collapsed"=>네비게이션의 화면 출력유무
data-toggle="collapse" : 모바일 상태에서 클릭하면서 메뉴가 나오게 설정 -->
<span class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
<!-- 아이콘 이미지 -->
</button>
<a class="navbar-brand" href="main.jsp">BluevulpeBoard</a>
<!-- Bootstrap navbar 기본 메뉴바 -->
</div>
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<!-- navbar-nav => 네비게이션 바의 메뉴 -->
<li><a href="main.jsp">메인</a></li>
<li class="active"><a href="list.jsp">게시판</a></li>
<!-- 메뉴, 게시판의 main.jsp와 bbs.jsp의 파일로 각각 이동 -->
</ul>
<%
if (userID == null) {
%>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">회원관리<span class="caret"></span></a>
<!-- caret = creates a caret arrow icon (▼) -->
<ul class="dropdown-menu">
<li><a href="login.jsp">로그인</a></li>
<li><a href="join.jsp">회원가입</a></li>
</ul></li>
</ul>
<%
} else {
%>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">회원관리<span class="caret"></span></a>
<!-- caret = creates a caret arrow icon (▼) -->
<ul class="dropdown-menu">
<li><a href="logout.jsp">로그아웃</a></li>
</ul></li>
</ul>
<%
}
%>
</div>
</nav>
<div class="container">
<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.getListTitle() %></td>
</tr>
<tr>
<td>작성자</td>
<td colspan="2"><%= bbs.getUserID() %></td>
</tr>
<tr>
<td>작성일자</td>
<td colspan="2"><%= bbs.getListDate().substring(0, 11) +
bbs.getListDate().substring(11, 13) + "시" +
bbs.getListDate().substring(14, 16) + "분" %></td>
</tr>
<tr>
<td>내용</td>
<td colspan="2" style="min-height: 200px; text-align: left;">
<%= bbs.getListContent() %></td>
</tr>
</tbody>
</table>
<a href="list.jsp" class="btn btn-primary">목록</a>
<%
if(userID != null && userID.equals(bbs.getUserID())) {
%>
<a href="update.jsp?listID=<%= listID %>"
class="btn btn-primary">수정</a>
<a href="deleteAction.jsp?listID=<%= listID %>"
class="btn btn-primary">삭제</a>
<%
}
%>
<a href="write.jsp" class="btn btn-primary pull-right">글쓰기</a>
</div>
</div>
</body>
</html>
view.jsp code를 만들고 list.jsp에서 게시글 제목 a태그의 링크을 list.jsp? -> view.jsp?로 아래처럼 수정해주었다.
<tr>
<td><%= list.get(i).getListID() %></td>
//href 경로를 list.jsp에서 vidw.jsp로 수정완료(동빈나 영상엔 언급안되어있음.)
<td><a href="view.jsp?listID=<%= list.get(i).getListID() %>">
<%= list.get(i).getListTitle() %></a></td>
<td><%= list.get(i).getUserID() %></td>
<td><%= list.get(i).getListDate().substring(0, 11) +
list.get(i).getListDate().substring(11, 13) +
"시" + list.get(i).getListDate().substring(14, 16) +
"분" %></td>
</tr>
# ListDAO class 내부 객체 문제
위와같이 수정했음에도 불구하고 500에러가 났다. 문제는 ListDAO class내부에서 만든
함수, 즉 객체가 근본 첫번째 문제였다.
그럼 무엇이 문제였나?
public Board getList1 (int listID) {
String SQL = "SELECT * FROM LIST WHERE listID = ?";
try {
PreparedStatement pstmt = conn.prepareStatement(SQL);
pstmt.setInt(1, listID);
rs =pstmt.executeQuery();
if (rs.next()) {
Board text = new Board();
text.setListID(rs.getInt(1));
text.setListTitle(rs.getString(2));
text.setUserID(rs.getString(3));
text.setListDate(rs.getString(4));
text.setListContent(rs.getString(5));
text.setListAvailable(rs.getInt(6));
return text;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
일단 Public 옆의 Board는 list패키지의 하위 클래스인 Board를 의미한다.
Board내부에 새로운 메소드 함수명을 getList1으로 설정한건 문제가 없다.
그런데, 메소드에 text라는 새로운 객체를 만들고
그안에 db에서 특정 id값으로 가져온 값들을 text객체로 담아서 view.jsp에 리턴해 보여주려고 하면 어떻게 해야하나?
글제목을 예로들어보자.
올바른 예라면, text.getListTitle()로 글제목을 가져와야 하는데,
나는 list.getListTitle()로 글제목을 호출하려하니 당연히 안가져와졌던 것이다.
public Board getBbs (int listID) {
String SQL = "SELECT * FROM LIST WHERE listID = ?";
try {
PreparedStatement pstmt = conn.prepareStatement(SQL);
pstmt.setInt(1, listID);
rs =pstmt.executeQuery();
if (rs.next()) {
Board bbs = new Board();
bbs.setListID(rs.getInt(1));
bbs.setListTitle(rs.getString(2));
bbs.setUserID(rs.getString(3));
bbs.setListDate(rs.getString(4));
bbs.setListContent(rs.getString(5));
bbs.setListAvailable(rs.getInt(6));
return bbs;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
그래서 동빈나영상을 보아하니
getBbs메소드 함수를 만들고, bbs객체를 만들어 특정id의 데이터값을 받아오게끔 만들은걸 그대로 따라했다. 코드는 위와 같다. 위 코드를 ListDAO.java 파일의 ListDAO 클래스에 추가하면 된다.
그리고 추가로 아래처럼 view.jsp 파일에 container div태그안에 코드를 수정입력해주면 된다.
<div class="container">
<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.getListTitle() %></td>
</tr>
<tr>
<td>작성자</td>
<td colspan="2"><%= bbs.getUserID() %></td>
</tr>
<tr>
<td>작성일자</td>
<td colspan="2"><%= bbs.getListDate().substring(0, 11) +
bbs.getListDate().substring(11, 13) + "시" +
bbs.getListDate().substring(14, 16) + "분" %></td>
</tr>
<tr>
<td>내용</td>
<td colspan="2" style="min-height: 200px; text-align: left;">
<%= bbs.getListContent() %></td>
</tr>
</tbody>
</table>
<a href="list.jsp" class="btn btn-primary">목록</a>
<%
if(userID != null && userID.equals(bbs.getUserID())) {
%>
<a href="update.jsp?listID=<%= listID %>" class="btn btn-primary">수정</a>
<a href="deleteAction.jsp?listID=<%= listID %>" class="btn btn-primary">삭제</a>
<%
}
%>
<a href="write.jsp" class="btn btn-primary pull-right">글쓰기</a>
</div>
</div>
글제목, 작성자, 작성일자,내용 td태그아래 해당내용을 가져오는 javaquery에 bbs가 보이는가?
<td colspan="2"><%= bbs.getListTitle() %></td>
<td colspan="2"><%= bbs.getUserID() %></td>
<td colspan="2"><%= bbs.getListDate().substring(0, 11) + bbs.getListDate().substring(11, 13) + "시" + bbs.getListDate().substring(14, 16) + "분" %></td>
<td colspan="2" style="min-height: 200px; text-align: left;"><%= bbs.getListContent() %></td>
이렇게 수정하고나면 아래와 같이 화면이 정상적으로 잘 출력됨을 알 수 있다.
# 악성 크로스 스크립트 문제
글쓰기 창 제목에 <scrpt>alert('Hi bluevulpe!')</script>를
입력하게 되면 스크립트로 인식이 되어 경고창이 아래와 같이 뜨는걸 확인할 수 있다.
위 문제를 해결하기위해 아래와 같이 코드를 추가해준다.
사실 이전에 우리가 filter를 추가해주었기 때문에 나는 당연히 스트링으로 처리가 될꺼라
기대했는데.. filter는 뒷단 톰캣서버 즉 뒷단에서 처리되고
DOM이 실행할때 DOM엔진이 처리하는 앞단쪽은 html코드로 꺽쇠를 읽기 때문에 발생한 문제였다.
# <> 꺽쇠 또는 공백을 String으로 정상출력하기
글제목과 내용 td태그안에 아래와 같은 replaceAll태그를 추가해 공백 및 꺽쇠를 String으로 처리한다.
<tbody>
<tr>
<td style="width: 20%;">글 제목</td>
<td colspan="2"><%= bbs.getListTitle().replaceAll(" ", " ")
.replaceAll("<", "$lt;").replaceAll(">", "$gt;")
.replaceAll("\n", "<br>") %></td>
</tr>
<tr>
<td>작성자</td>
<td colspan="2"><%= bbs.getUserID() %></td>
</tr>
<tr>
<td>작성일자</td>
<td colspan="2"><%= bbs.getListDate().substring(0, 11) +
bbs.getListDate().substring(11, 13) + "시" +
bbs.getListDate().substring(14, 16) + "분" %></td>
</tr>
<tr>
<td>내용</td>
<td colspan="2" style="min-height: 200px; text-align: left;">
<%= bbs.getListContent().replaceAll(" ", " "
).replaceAll("<", "$lt;"
).replaceAll(">", "$gt;"
).replaceAll("\n", "<br>") %></td>
</tr>
</tbody>
.replaceAll(" ", " ").replaceAll("<", "$lt;").replaceAll(">", "$gt;").replaceAll("\n", "<br>")
음 근데.. 위와같은 코드를 list.jsp에도 추가해주었더니 500에러가 떴다.
그래서 아래 링크를 따라 들어가 해보았는데도 안되었다..
XSS 필터(크로스 사이트 스크립트),Encoding 필터
-XSS 필터 웹 페이지를 만들보면 사용자의 악의적인 공격을 많이 받게되는데 이런 것들중 가장 대표적인것이 XSS 공격이다 크로스 사이트 스크립트 라는것인데 서버로 보내는 입력값에 자바스크
epthffh.tistory.com
그래서 일단 스킵하기로했다가
다시 발견해보니 apache tomcat에web.xml 파일에
패키지명을 아래처럼 이상하게 적어가지구 안되었던 건가 했는데
이것도 핵심원인은 아니었다.
핵심원인은 apache web.xml파일이 아닌, WebContent>WEB-INF>lib경로안에
web.xml파일을 추가하고 아래와 같이 코드를 넣어줘야 되었다.
#Web.xml 파일 추가
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>egov.sample</display-name>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter>
<filter-name>HTMLTagFilter</filter-name>
<filter-class>egovframework.rte.ptl.mvc.filter.HTMLTagFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HTMLTagFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:egovframework/spring/context-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/common/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/common/error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/common/error.jsp</location>
</error-page>
</web-app>
기존에 apache 폴더내 web.xml에 추가했던 필터들을 그대로 위 xml파일에 붙여넣기 해주면 된다.
# Web.xml 파일 복사하는 방법
web.xml파일을 어디서 어떻게 복사 붙여넣기하나?
방법은 새롭게 프로젝트를 아래처럼 생성한 다음 표시한 폴더 아래 xml파일을 복사해서
기존 test프로젝트에 WebContent>WEB-INF>lib 경로안에 붙여넣기 해주었다.
결과는 성공적이었다. 새로 추가한 게시글들은 아래 16,17번인데
스크립트가 아예 다른 정규식으로 변환되서 출력되었다.
# Column type값 에러
그런데 "글쓰기에 실패했습니다."라고 알림창이 뜨길래
writeGo.jsp에서 입력받은 값이 어떻게 출력되는지 확인하기 위해서
아래와같이 Mr.delber Woo님의 도움으로 코드를 추가했다.
script.println("alert('"+list.getListTitle().toString()+"');");
그러자 똑같이 alert창이 뜨면서 글쓰기에 실패해다고 뜨고
또 title값을 보아하니 아래 처럼 제목이 String값으로 잘 변환되어 출력되었다.
결국 글쓰기에 실패한것은 처음 설정해놓았던 listTitle 타입값이 너무 적어
db에 입력이 안되도록 막힌게 원인이었다.
# listTitle type 수정쿼리
하지만 기존에 filter가 안된 15번째 게시글은 여전히 alert창을 띄우고 있어서
이건 데이터베이스에서 삭제해주기 위해 언넝 삭제기능을 구현하러 다음포스팅으로
넘어가보자 :)
Copyright ⓒ 2021 by bluevulpe All Contents cannot be copied without permission.