JSP파일 직접 접근 방지
웹으로 접속하는 사용자가 .do가 아닌 .jsp로 접근할 가능성도 있다. .jsp로 직접 접근을 하지 못하게 막기 위해서는 web.xml에 <security-constraint> 코드를 추가하면 된다.
[경로: src/main/webapp/WEB-INF/web.xml]
1
2
3
4
5
6
7
8
9
10
11
12
|
<security-constraint>
<web-resource-collection>
<web-resource-name>Prevent JSP</web-resource-name>
<description>Prevent JSP</description>
<url-pattern>*.jsp</url-pattern> <!-- 제약을 걸 자원 -->
<http-method>GET</http-method> <!-- 제약을 걸 HTTP 메서드 -->
<http-method>POST</http-method><!-- 제약을 걸 HTTP 메서드 -->
</web-resource-collection>
<auth-constraint>
<role-name></role-name>
</auth-constraint>
</security-constraint>
|
cs |
URL에 http://localhost:9090/MyMVC/index.jsp라고 쳐서 들어가면 HTTP Status 403 - Access to the requested resource has been denied 에러가 뜬다. 즉, 접근할 수 없도록 서버에서 차단한 것이다.
properties 파일
여러 JSP파일을 호출할 때 서브 컨트롤러를 매핑해주는 파일
[경로: src/main/webapp/WEB-INF/command.properties]
1
2
3
4
5
6
7
8
|
# comment
# key=value
/index.do=common.controller.IndexAction
#board
/board/input.do=board.controller.BoardWriteFormAction
/board/insert.do=board.controller.BoardInsertAction
/board/list.do=board.controller.BoardListAction
/board/view.do=board.controller.BoardViewAction
|
cs |
만약 웹에서 http://localhost:9090/MyMVC/board/input.do를 입력하면 BoardWriteFormAction 서브 컨트롤러가 작동한다.
게시판 글쓰기 페이지
- 서브 컨트롤러: BoardWriteFormAction
- JSP: src/main/webapp/board/input.jsp
[경로: src/main/java/board.controller/BoardWriteFormAction.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class BoardWriteFormAction extends AbstractAction {
@Override
public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
//뷰페이지 지정
this.setViewName("/board/input.jsp");
//이동방식 지정
this.setRedirect(false); //forward이동
}
}
|
cs |
[경로: src/main/webapp/board/input.jsp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- content -->
<div class="container">
<h1>MVC Board</h1>
<br><br>
<form name="bbsF" method="post" action="insert.do">
<table border="1">
<tr>
<th width="20%">글제목</th>
<td width="80%">
<input type="text" name="title" id="title" placeholder="Title" required>
</td>
</tr>
<tr>
<th>작성자</th>
<td>
<input type="text" name="name" id="name" placeholder="Name" required>
</td>
</tr>
<tr>
<th>글내용</th>
<td>
<textarea name="content" id="content" placeholder="Content" rows="7" cols="60"></textarea>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td>
<input type="password" name="passwd" id="passwd" placeholder="Password" required>
</td>
</tr>
<tr>
<th>첨부파일</th>
<td>
<input type="file" name="fileName" id="fileName">
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<button>글쓰기</button>
<button type="reset">다시쓰기</button>
</td>
</tr>
</table>
</form>
</div>
|
cs |
게시판 글쓰기 구현
- 서브 컨트롤러: BoardInsertAction
- JSP: message.jsp
[경로: src/main/java/board.controller/BoardInsertAction.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class BoardInsertAction extends AbstractAction {
@Override
public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
//1. 사용자가 입력한 값 받기
String title = req.getParameter("title");
String name = req.getParameter("name");
String content = req.getParameter("content");
String passwd = req.getParameter("passwd");
//첨부파일명, 파일크기 받기 => 나중에
String fileName = null;
long fileSize = 0;
//2. 유효성 체크
if(title==null || name==null || passwd==null || title.trim().isBlank()
|| name.trim().isBlank() || passwd.trim().isBlank()) {
this.setRedirect(true); //redirect이동
this.setViewName("input.do");//input.do로 redirect이동
return;
}
//3. 1번에서 받은 값 BoardVO객체에 담기
BoardVO vo = new BoardVO(0, name, passwd, title, content, null, 0, fileName, fileSize);
//4. BoardDAO 생성 후 insertBoard() 호출
BoardDAO dao = new BoardDAO();
int n = dao.insertBoard(vo);
//5. 그 결과 메시지, 이동경로 설정해서 req에 저장하기
String msg = (n>0)? "글 등록 완료":"글 등록 실패";
String loc = (n>0)? "list.do":"javascript:history.back()";
//request에 msg와 loc 저장 => message.jsp에서 꺼내야 함
req.setAttribute("msg", msg);
req.setAttribute("loc", loc);
//뷰페이지 지정
this.setViewName("/board/message.jsp");
//이동방식 지정
this.setRedirect(false); //forward이동
}
}
|
cs |
[경로: src/main/webapp/board/message.jsp]
1
2
3
4
5
6
7
8
9
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<script type="text/javascript">
alert('${msg}');
/* requestScope.msg ==> request에서 찾는다.
sessionScope.msg ==> 세션에서 찾는다.
생략 가능 */
location.href = '${loc}';
</script>
|
cs |
게시판 글쓰기 DB연동
1) SQL문
[경로: src/main/webapp/board/mvc_board.sql]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
DROP table mvc_board;
--단순형 게시판
CREATE table mvc_board(
num NUMBER(8) primary key, --글번호
name VARCHAR2(30) not null, --작성자
passwd VARCHAR2(20) not null, --글 비밀번호
title VARCHAR2(300) not null, --글제목
content VARCHAR2(2000), --글내용
wdate DATE default SYSDATE, --작성일
readnum NUMBER(8) default 0, --조회수
fileName VARCHAR2(500), --첨부파일명
fileSize NUMBER(8) --첨부파일 크기
);
DROP sequence mvc_board_seq;
CREATE sequence mvc_board_seq
START WITH 1
INCREMENT BY 1
NOCACHE;
|
cs |
2) BoardVO 객체
[경로: src/main/java/board.model/BoardVO.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
package board.model;
import java.sql.Date;
public class BoardVO {
//멤버변수(property)
private int num;
private String name;
private String passwd;
private String title;
private String content;
private java.sql.Date wdate;
private int readnum;//조회수
private String fileName;//첨부파일명
private long fileSize;//첨부파일 크기
//기본생성자
public BoardVO() {
}
//인자생성자
public BoardVO(int num, String name, String passwd, String title, String content, Date wdate, int readnum,
String fileName, long fileSize) {
super();
this.num = num;
this.name = name;
this.passwd = passwd;
this.title = title;
this.content = content;
this.wdate = wdate;
this.readnum = readnum;
this.fileName = fileName;
this.fileSize = fileSize;
}
//setter, getter
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public java.sql.Date getWdate() {
return wdate;
}
public void setWdate(java.sql.Date wdate) {
this.wdate = wdate;
}
public int getReadnum() {
return readnum;
}
public void setReadnum(int readnum) {
this.readnum = readnum;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public long getFileSize() {
return fileSize;
}
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
//toString()
@Override
public String toString() {
return "BoardVO [num=" + num + ", name=" + name + ", title=" + title + ", content=" + content + ", wdate="
+ wdate + ", readnum=" + readnum + ", fileName=" + fileName + ", fileSize=" + fileSize + "]";
}
}
|
cs |
3) BoardDAO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class BoardDAO {
private DataSource ds;
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
public BoardDAO() {
try {
Context ctx = new InitialContext();
ds = (DataSource)ctx.lookup("java:comp/env/jdbc/myoracle");
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
if(con!=null) con.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
|
cs |
게시판 글목록 페이지
- 서브 컨트롤러: BoardListAction
- JSP: src/main/webapp/board/list.jsp
# 페이징 처리
- 총 게시글 수: totalCount
- 한 페이지에 보여줄 글의 개수: oneRecordPage (= 5로 하자)
- 페이지 수: pageCount
총 게시글 수(totalCount) | 한 페이지에 보여줄 글의 개수 (oneRecordPage) |
페이지 수(pageCount) |
1, 2, 3, 4, 5 | 5 | 1 |
6, 7, 8, 9, 10 | 5 | 2 |
11, 12, 13, 14, 15 | 5 | 3 |
16, 17, 18, 19, 20 | 5 | 4 |
if(totalCount % oneRecordPage == 0){ //totalCount가 5, 10, 15, 20일 때
pageCount = totalCount/oneRecordPage;
}else{
pageCount = totalCount/oneRecordPage + 1;
}
==> 한 줄로 줄이면
pageCount = (totalCount - 1)/oneRecordPage + 1;
4. jsp에서 페이지 네비게이션 구현
링크 걸기 => 현재 보여줄 페이지 번호를 pageNum이라는 파라미터 값으로 전달한다.
[<a href="list.do?pageNum=2"> 2 </a>]
5. BoardListAction(서브 컨트롤러)에서 pageNum 파라미터 값 받기
pageNum을 이용해서 DB에서 데이터를 끊어 가져오기 위한 연산 수행
--rownum을 활용한 페이징 처리
SELECT * FROM(
SELECT rownum rn, a.* FROM
(SELECT * FROM mvc_board ORDER BY num DESC) a)
WHERE rn BETWEEN 1 AND 5;
현재 보여줄 페이지 번호 (pageNum) |
한 페이지에 보여줄 글의 개수 (oneRecordPage) |
start | end |
1 | 5 | 1 | 5 |
2 | 5 | 6 | 10 |
3 | 5 | 11 | 15 |
4 | 5 | 16 | 20 |
int end = pageNum * oneRecordPage;
int start = end - (oneRecordPage - 1);
[경로: src/main/java/board.controller/BoardListAction.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public class BoardListAction extends AbstractAction {
@Override
public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
//0. pageNum 파라미터값 받기
String pageNumStr = req.getParameter("pageNum");
if(pageNumStr==null) {
pageNumStr="1"; //default 페이지를 1페이지로 지정
}
int pageNum = Integer.parseInt(pageNumStr.trim());
if(pageNum<1) {
pageNum = 1;
}
//BoardDAO 생성 listBoard() 호출
BoardDAO dao = new BoardDAO();
//1. 총 게시글 수 가져오기
int totalCount = dao.getTotalCount();
//2. 한 페이지당 보여줄 목록 개수 정하기 => 5개씩 보여주기
int oneRecordPage = 5;
//3. 총 페이지수 구하기
int pageCount = (totalCount - 1)/oneRecordPage + 1;
System.out.println("pageCount: " + pageCount);
//4. jsp에서 페이지 네비게이션 출력 => 링크 ==> pageNum파라미터 전달
if(pageNum > pageCount) {
pageNum = pageCount; //마지막 페이지로 지정
} //url에 pageNum을 직접 치고 들어오는 경우를 방지
//5. pageNum을 이용해서 DB에서 끊어올 범위 정하기 int end = pageNum * oneRecordPage;
int start = end - (oneRecordPage - 1);
//6. 게시글 목록 가져오기
List<BoardVO> boardList = dao.listBoard(start, end);
//반환하는 List<BoardVO> 객체를 req에 저장
req.setAttribute("boardAll", boardList);
//페이지 관련된 각각의 숫자들을 req에 저장
req.setAttribute("totalCount", totalCount);
req.setAttribute("pageCount", pageCount);
req.setAttribute("pageNum", pageNum);
//뷰페이지 지정
this.setViewName("list.jsp");
//이동방식 지정
this.setRedirect(false); //forward방식
}
}
|
cs |
|
|
[경로: src/main/webapp/board/list.jsp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!-- ---------------------------------------------------- -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!-- 제어문은 core태그에 모여 있음. 숫자, 날짜 format은 ftm태그에 있음- -->
<!-- content -->
<div class="container">
<h1>MVC Board</h1>
<br>
[<a href="input.do">글쓰기</a>]
<br><br>
<table border="1">
<tr>
<th class="m1" width="10%">글번호</th>
<th class="m1" width="40%">글제목</th>
<th class="m1" width="20%">작성자</th>
<th class="m1" width="20%">작성일</th>
<th class="m1" width="10%">조회수</th>
</tr>
<!-- ----------------- empty: boardArr.size()==0 -->
<c:if test="${boardAll==null || empty boardAll}">
<tr>
<td colspan="5">
<b>데이터가 없습니다</b>
</td>
</tr>
</c:if>
<c:if test="${boardAll !=null && not empty boardAll}">
<%--for(BoardVO board:boardAll){...}와 동일함 --%>
<c:forEach var="board" items="${boardAll}">
<tr>
<td>${board.num}</td>
<td>
<a href="view.do?num=${board.num}">${board.title}</a>
</td>
<td>${board.name}</td>
<td>
<fmt:formatDate value="${board.wdate}" pattern="yyyy-MM-dd"/>
</td>
<td>${board.readnum}</td>
</tr>
</c:forEach>
</c:if>
<!-- ---------------------- -->
<tr>
<td colspan="3" style="text-align:center">
<!-- 페이지 네비게이션 -->
<c:forEach var="i" begin="1" end="${pageCount}" step="1">
[<a href="list.do?pageNum=${i}"
<c:if test="${pageNum==i}">class='active'</c:if>> ${i} </a>]
</c:forEach>
</td>
<td colspan="2" style="text-align:center">총 게시글 수
<span style="color:red; font-weight:bold">${totalCount}</span>개
</td>
</tr>
</table>
</div>
|
cs |
[경로: src/main/java/css/style.css] CSS에 추가 - class='active'인 요소를 빨간색으로 처리
1
2
3
4
|
.active{
color:red;
font-weight:bold;
}
|
cs |
게시글 상세보기 처리
to be continued...