[ITWILL : JSP]홈페이지만들기3 : 로그인/로그아웃 기능 구현

ITWILL학원 : 34강 JSP기초 BY 정규태강사

1. loginForm.jsp 생성

  • header include하기 : jsp:include page="../inc/top.jsp"
  • footer include하기 : jsp:include page="../inc/bottom.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
<body>
<div id="wrap">
<!-- 헤더들어가는 곳 -->
<jsp:include page="../inc/top.jsp"></jsp:include>
<!-- 헤더들어가는 곳 -->

<!-- 본문들어가는 곳 -->
<!-- 본문메인이미지 -->
<div id="sub_img_member"></div>
<!-- 본문메인이미지 -->
<!-- 왼쪽메뉴 -->
<nav id="sub_menu">
<ul>
<li><a href="#">Join us</a></li>
<li><a href="#">Privacy policy</a></li>
</ul>
</nav>
<!-- 왼쪽메뉴 -->
<!-- 본문내용 -->
<article>
<h1>로그인</h1>
<form action="loginPro.jsp" id="join" method="post">
<fieldset>
<legend>로그인정보</legend>
<label>아이디</label> <input type="text" name="id"><br>
<label>비밀번호</label> <input type="password" name="pw"><br>
</fieldset>
<div class="clear"></div>
<div id="buttons">
<input type="submit" value="Submit" class="submit">
<input type="reset" value="Cancel" class="cancel">
</div>
</form>
</article>
<!-- 본문내용 -->
<!-- 본문들어가는 곳 -->

<div class="clear"></div>
<!-- 푸터들어가는 곳 -->
<jsp:include page="../inc/bottom.jsp"></jsp:include>
<!-- 푸터들어가는 곳 -->
</div>
</body>

2. loginPro.jsp생성

  • int데이터타입으로 변수받아서 데이터처리.
  • 아이디와 비밀번호가 DB와 일치시 main.jsp페이지로 이동.
  • 아이디와 비밀번호가 DB와 불일치시 뒤로가기.
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
<% //1. 한글처리 및 변수가져오기
request.setCharacterEncoding("UTF-8");
String id = request.getParameter("id");
String pw = request.getParameter("pw");

//2. MemberDAO객체생성 -> idcheck(id, pw) 메서드생성
MemberDAO mdao = new MemberDAO();
int result = mdao.idCheck(id, pw);

//3.데이터처리
if(result == 1){
//아이값을 세션객체에 저장
session.setAttribute("id", id); //두번째파라미터에서 업캐스팅발생 object->String
System.out.println("아디일치비번일치->로그인성공");
response.sendRedirect("../main/main.jsp");
}else if(result == 0){
System.out.println("아디일치,비번불일치->로그인실패");
%>
<script type="text/javascript">
alert("비밀번호가 일치하지 않습니다");
history.back();
</script>
<%
}else{
System.out.println("아디불일치,비번불일치->로그인실패");
%>
<script type="text/javascript">
alert("존재하지않는 아이디입니다");
history.back();
</script>
<%
}
%>

3. memberDAO.java에 idCheck()메서드 생성

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
public int idCheck(String id, String pw){
int result = -1;

try {
//1.DB여결
con = getCon();
//2.SQL & PSTMT
sql = "select pw from fun_member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
//3.실행 -> rs -> 데이터처리
rs = pstmt.executeQuery();
if(rs.next()){
if(pw.equals(rs.getString("pw"))){
result = 1;
}else{
result = 0;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally { //4.자원해제
closeDB();
}
return result;
}//idCheck메서드 닫음

4. top.jsp 추가

  • 로그인한 경우 id님 환영합니다와 함께 로그인 버튼을 로그아웃으로 변경
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
<% //화면상단에 위치하는 메뉴바 처리페이지
String id = (String)session.getAttribute("id"); //다운캐스팅 Object -> String
%>
<header>
<div id="login">
<%if(id == null){
%>
<div id="login"><a href="../member/loginForm.jsp">로그인</a> | <a href="../member/joinForm.jsp">회원가입</a></div>
<%
}else if(id != null){
%>
<div id="login"><%=id %>님 환영합니다 | <a href="../member/logout.jsp">로그아웃</a></div>
<%
}
%>
</div>
<div class="clear"></div>
<!-- 로고들어가는 곳 -->
<div id="logo"><img src="../images/logo.gif" width="265" height="62" alt="Fun Web"></div>
<!-- 로고들어가는 곳 -->
<nav id="top_menu">
<ul>
<li><a href="../index.jsp">홈</a></li>
<li><a href="../company/welcome.html">회사소개</a></li>
<li><a href="#">솔루션</a></li>
<li><a href="../center/notice.jsp">고객센터</a></li>
<li><a href="#">무엇이든 물어보세요</a></li>
</ul>
</nav>
</header>

5. logout.jsp 생성

1
2
3
4
5
6
7
8
<%
session.invalidate();
System.out.println("로그아웃성공");
%>
<script type="text/javascript">
alert("정상적으로 로그아웃 되었습니다");
location.href="../main/main.jsp";
</script>

[ITWILL : JSP]홈페이지만들기1 : 프로젝트 시작 설정 및 자바빈생성과 DB연결

ITWILL학원 : 33강 JSP기초 BY 정규태강사

html로 만들어진 홈페이지를 jsp로 변경해보자.

1. main.jsp 생성

  • path설정

    • / 와 ./는 현재폴더
    • ../는 상위폴더
  • 페이지 인클루드 2가지방법

    1
    2
    3
    4
    5
    6
    7
    8
    <!-- JSP 지시어 : 공통으로 사용되는 변수를 파일에 지정해서 추가 -->
    <%@ include ~ %>

    <!-- 액션태그 : 공통으로 사용되는 메뉴들을(페이지) 특정 공간에 추가 -->
    <jsp:include page="">

    <!-- 예시 -->
    <jsp:include page="../inc/top.jsp"></jsp:include>
  • 코드블록 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<div id="wrap">

<!-- 헤더파일들어가는 곳 (page Include)-->
<jsp:include page="../inc/top.jsp"></jsp:include>
<!-- 헤더파일들어가는 곳 (page Include)-->

<!-- 메인이미지 들어가는곳 -->
<!-- 메인이미지 들어가는곳 -->

<!-- 메인 콘텐츠 들어가는 곳 -->
<!-- 메인 콘텐츠 들어가는 곳 -->

<!-- 푸터 들어가는 곳 -->
<jsp:include page="../inc/bottom.jsp"></jsp:include>
<!-- 푸터 들어가는 곳 -->

</div>
</body>

2. index.jsp생성

1
2
3
4
<%//프로젝트의 시작페이지 구현

response.sendRedirect("./main/main.jsp");
%>

3. top.jsp 생성

화면상단에 위치하는 메뉴바 처리페이지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- html코드가 필요없다  (html body태그안에 넣어도 되고 html태그 없어도 됨)-->

<% //화면상단에 위치하는 메뉴바 처리페이지

%>
<header>
<div id="login"><a href="../member/loginForm.jsp">login</a> | <a href="../member/joinFrom.jsp">join</a></div>
<div class="clear"></div>
<!-- 로고들어가는 곳 -->
<div id="logo"><img src="../images/logo.gif" width="265" height="62"></div>
<!-- 로고들어가는 곳 -->
<nav id="top_menu">
<ul>
<li><a href="../index.jsp">HOME</a></li>
<li><a href="../company/welcome.html">COMPANY</a></li>
<li><a href="#">SOLUTIONS</a></li>
<li><a href="../center/notice.html">CUSTOMER CENTER</a></li>
<li><a href="#">CONTACT US</a></li>
</ul>
</nav>
</header>

4. bottom.jsp 생성

화면하단에 위치하는 footer 처리페이지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- html코드가 필요없다  (html body태그안에 넣어도 되고 html태그 없어도 됨)-->

<% //화면하단에 위치하는 footer 처리페이지

%>
<footer>
<hr>
<div id="copy">All contents Copyright 2011 FunWeb 2011 FunWeb
Inc. all rights reserved<br>
Contact mail:funweb@funwebbiz.com Tel +82 64 123 4315
Fax +82 64 123 4321</div>
<div id="social">
<img src="../images/Instagram.gif" width="33" height="33" alt="Instagram">
<img src="../images/twitter.gif" width="34" height="34" alt="Twitter">
</div>
</footer>

5. joinForm.jsp 생성

원하는 회원가입 폼양식 생성하면 된다.
코드블록은 생략하도록 한다.

6. joinPro.jsp 생성

자바빈을 작성하려면 테이블이 생성되어있어야한다.
joinPro.jsp의 남은 코드는 순서대로 아래에 추가해서 작성할 예정이다.

1
2
3
4
5
<%
// 한글처리
request.setCharacterEncoding("UTF-8");
// 전달되는 데이터 입력(저장) => 자바빈 이용
%>

7. MySQL에서 테이블생성

  • 자바빈을 작성하려면 테이블이 생성되어있어야한다.

  • 회원테이블 정보 : 제약조건

    • 아이디(id) : pk
    • 비밀번호(pw) : nn
    • 이름(name) : nn
    • 이메일(email) : nn, uq
    • 생년월일(birth) : nn
    • 성별(gender) : nn
    • 주소(addr)
    • 휴대폰번호(mobile)
    • re_date : 가입일자
    • 전화번호 : 보통 실무에서 varchar를 이용하는 것이 편하다
    • 생년월일 : int나 varchar를 쓰는데, 실무에선 varchar로 받아서 바로 이용하는 것이 편하다

8. MemberBean.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

package com.itwillbs.member;

import java.sql.Date;

//1번규약 :public 클래스
public class MemberBean {
//자바빈은 항상 패키지를 포함해야한다.
//데이터를 저장하는 객체(한번에 회원정보를 저장가능한 객체) => DB에 데이터전달

//2번 규약: private멤버변수
private String id;
private String pw;
private String name;
private String email;
private int birth;
private String gender;
private String addr;
private String mobile;
private Date re_date;

//4번규약 : 디폴트생성자

//3번규약 : getter, setter
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}

(중략)

//5번 선택: toString
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "MemberBean [id=" + id + ", pw=" + pw + ", name=" + name + ", email=" + email + ", birth=" + birth
+ ", gender=" + gender + ", addr=" + addr + ", mobile=" + mobile + ", re_date=" + re_date + "]";
}
}

9. MemberDAO.java 생성

DB연결과 자원해제 메서드를 생성한다

  • 자원해제는 사용한 객체 역순으로 진행하는 것이 안전하게 자원해제할 수 있다
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
import javax.sql.DataSource;

public class MemberDAO {

Connection con = null;
String sql = "";
PreparedStatement pstmt = null;
ResultSet rs = null;

//디비연결메서드
/*private void getCon() throws NamingException, SQLException {
//Context 객체 생성
//Context인터페이스이기때문에 직접객체생성할 수 없어서 InitialContext클래스를 사용해서 객채생성
//예외처리 : throws사용하는 방법
Context init = new InitialContext(); //업캐스팅
//디비연결정보를 불러오기 ->DataSource 타입으로 저장
// 고정문구"java:comp/env/다른문구context파일의 name값입력"
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/mysqlDB");
//ds 사용해서 연결
//멤버변수는 static이 아니기때문에 new BoardDAO();객체생성 후에 멤버변수들이 생성된다.
//그리고 getCon()메서드를 하면 멤버변수 con에 데이터(ds.getConnection();)가 담기게 된다.
//따라서 이때 return하지 않고 써도된다.
con = ds.getConnection();
System.out.println("디비연결성공 :"+con);
}
*/
private Connection getCon() throws Exception {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/funwebDB");

return con;
}

//자원해제메서드
public void close(){
try{
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

10. context.xml 생성

주요 체크사항
- name : 사용할 이름으로 작성
- url : 테이블이 있는 DB경로
- username과 password

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!-- 디비연결에 필요한 정보 저장 -->
<Context>
<Resource
name="jdbc/fubwebDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/funwebdb"
username="root"
password="1234"
/>
</Context>

[ITWILL : JSP]Javabean 14 : 게시판만들기(ServletContext사용하여 파일업로드와 다운로드)

ITWILL학원 : 32강 JSP기초 BY 정규태강사

UTF-8인코딩을 기본으로 ServletContext이용하여 가상경로에 파일을 저장하는 파일업로드와 다운로드기능 구현

1. webcontent 하위 새로운 폴더 2개 생성 : fileuputf, upload

앞으로 파일다운로드기능구현시 생성되는 jsp, html페이지를 이 폴더(fileuputf)안에 생성한다.
업로드되는 파일들은 upload라는 폴더안에 들어가게 된다.=> 가상경로라고 부른다.

2. fileUploadForm.jsp 생성

1
2
3
4
5
6
7
8
<fieldset>
<form action="fileUploadPro.jsp" method="post" enctype="multipart/form-data">
작성자 : <input type="text" name="name"><br>
제목 : <input type="text" name="subject"><br>
파일 : <input type="file" name="file"><br>
<input type="submit" value="파일업로드">
</form>
</fieldset>

3. fileUploadPro.jsp 생성

  1. 가상경로

  2. MultipartRequest객체생성 : request정보를 직접 가져올 수 없고 multi를 통해서 가져올 수 있다.

  3. Enumeration : 다음 요소가 있으면 반환해주는 인터페이스.

  4. 파일업로드 기능은 예외가 많이때문에 예외처리를 해야한다

  5. 사용자가 입력한 데이터를 fileCheck.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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!-- 파일 업로드 처리  -->
<%
//1. 파일 저장 위치 (가상경로) 만들기
// D:\workspace_jsp7\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\fileUpload/upload
//System.out.println("가상경로 : "+request.getRealPath("/upload"));
String uploadPath = request.getRealPath("/upload");

//2. 저장 크기 지정 (10MB)
int maxSize = 10 * 1024 * 1024;

//3. 정보를 저장하는 변수 만들기
String name ="";
String subject ="";
String filename = ""; //서버에 올라갈 파일명
String OFilename = ""; //오리지널 파일명

//6. 예외처리
try{
//4. MultipartRequest 객체생성
//4-1. cos 라이브러리 추가
//4-2. 객체 생성
//request정보를 직접가져올 수 없고 multi를 통해서 가져올 수 있다.
MultipartRequest multi = new MultipartRequest(request, uploadPath,
maxSize, "UTF-8", new DefaultFileRenamePolicy());

//5. 파일업로드완료
//5-1. 전달되는 이름, 제목 저장
name = multi.getParameter("name");
subject = multi.getParameter("subject");
//5-2. 전달된 파일의 이름 확인
Enumeration files = multi.getFileNames(); //업캐스팅
String file1 = (String) files.nextElement(); //위의 업캐스팅한 걸 다운캐스팅
//5-3. 서버에 저장되는 파일 이름
filename = multi.getFilesystemName(file1);
System.out.println("filename : "+filename);
//5-4. 원래 파일이름
OFilename = multi.getOriginalFileName(file1);
System.out.println("OFilename : "+OFilename);
//여기까지 업로드 기능 구현 완료! => 6. 파일업로드는 예외가 많이때문에 예외처리를 해야한다
}catch(Exception e){
e.printStackTrace();
}
%>

<!-- 데이터를 전달하기
enctype안적어도 될까? 업로드 유무로 판단!
업로드할꺼면 필요, 업로드하지않을거면 필요하지않다
아래처럼 input type을 text로 그냥 가져가면 중요한 정보들이 유출될 수있다.
보안을 위해 2가지 방법이 있다.
1안은 submit버튼사용 2안은 a태그사용한 방법이다. 편한 걸로하면되지만 보통 2안으로 많이한다
-->

<%-- <form action="fileCheck.jsp" method="post">
<input type="text" name="name" value="<%=name %>" readonly><br>
<input type="text" name="subject" value="<%=subject %>"><br>
<input type="text" name="filename" value="<%=filename %>"><br>
<input type="text" name="ofilename" value="<%=OFilename %>"><br>
<input type="submit" value="확인하기">
</form> --%>

<!-- 1안 : form태그는 보여주지않는 않고 fileCheck에서 출력할 것이므로 hidden으로 type을 지정 후 submit버튼 이용-->
<form action="fileCheck.jsp" method="post">
<input type="hidden" name="name" value="<%=name %>" readonly><br>
<input type="hidden" name="subject" value="<%=subject %>"><br>
<input type="hidden" name="filename" value="<%=filename %>"><br>
<input type="hidden" name="ofilename" value="<%=OFilename %>"><br>
<input type="submit" value="올린 파일 정보하기">
</form>

<!-- 2안 : hidden때문에 생성된 submit버튼 위의 빈칸이 신경쓰이면 a태그를 이용가능.
a태그를 이용하여 post방식 어떻게 데이터를 전달할수있을까? 이때 js를 사용한다 onclick="javascript:filecheck.submit" -->
<form action="fileCheck.jsp" method="post" name="filecheck">
<input type="hidden" name="name" value="<%=name%>"><br>
<input type="hidden" name="subject" value="<%=subject%>"><br>
<input type="hidden" name="filename" value="<%=filename%>"><br>
<input type="hidden" name="ofilename" value="<%=OFilename%>"><br>
</form>
<a href="#" onclick="javascript:filecheck.submit();">업로드 확인 및 다운로드 페이지로 이동</a>

4. fileCheck.jsp생성

  • 사용자가 입력한 정보를 체크하고 파일명을 눌렀을때 다운로드 가능하도록 file_down.jsp로 이동하는 기능 구현
  • 서버에 저장된 파일명의 a태그에서 get방식으로 파라미터로 정보를 전달한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<h2>업로드하지 않고 확인용으로 전달받은 데이터 화면에 출력</h2>
<%
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
String subject = request.getParameter("subject");
String filename = request.getParameter("filename");
String ofilename = request.getParameter("ofilename");
%>


<fieldset>
<legend>업로드 정보 확인용</legend>
작성자명 : <%=name %><br>
제목 : <%=subject %><br>
서버에 저장된 파일명 : <a href="file_down.jsp?file_name=<%=filename %>"> <%=filename %></a><br>
원본파일명 : <%=ofilename %><br>
</fieldset>

5. file_down.jsp 생성

  1. servletContext : 지금 쓰고있는 내 프로젝트 정보.

  2. MIME타입 : 클라이언트에게 전송되는 데이터(문서)를 다양하게 처리 가능하도록 하는 메커니즘
    웹에서 파일의 확장자는 큰 의미가 없음(스트림형태로 데이터가 전달) -> 스트림형태일때는 데이터 구분못함.
    따라서 각 데이터(문서)에서 올바른 형태의 데이터를 전달하도록 MIME 타입을 지정
    브라우저들이 응답정보(리소스)를 받았을때 어떤 형태로 처리해야하는지 판단하는 기준
    마임타입을 가져오는 방법은 getServletContext().getMimeType()으로 가능

  3. 브라우저에 따른 데이터 처리(대응)

    • 왜 인터넷익스플로러를 기준으로 나눌까?

      • 인터넷익스폴러는 다운로드시 한글파일이 깨짐 -> 따라서 파일을 인코딩해서 다운로드함
      • 이때 공백문자가 플러스(+)기호로 나옴 -> 이걸 %20으로 변경
    • 인터넷익스플로러인지 아닌지는 어떻게 구분할까?

      • 접속한 사용자정보(User-Agent)를 불러와서 indexOf사용하여 MSIE이나 Trident이 들어가 있으면 익스플로러이다.
        1
        2
        3
        String agent = request.getHeader("User-Agent");
        System.out.println("agent : "+ agent);
        boolean ieBrowser = agent.indexOf("MSIE") > -1 || agent.indexOf("Trident") > -1;
  4. 데이터다운로드 처리

    • 브라우저가 응답정보를 읽어서(해석) 처리시 “Content-Disposition” 설정값이 “attachment;” 모든 데이터 다운로드 처리한다.

    • 만약 설정안하게되면 어떻게 될까? 브라우저의 기본값에 의해 처리한다.

  5. 데이터 출력(다운로드)

    • flush() : 데이터가 담긴 배열이 꽉 차지 않았을때는 데이터를 출력하지않는다. 이때 flush가 배열의 빈 공간을 공백으로 채워서 데이터 출력되도록 만들어준다.
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
<%@page import="java.net.URLEncoder"%>
<%@page import="javax.activation.MimeType"%>
<%@page import="java.io.FileInputStream"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<% //1. 전달받은 데이터 저장
String filename = request.getParameter("file_name");
System.out.println(" 전달된 파일 명 : "+filename);

//2. 파일 다운로드할 위치(= 파일 업로드 위치) =>가상경로
//savepath는 저장되는 폴더명
String savepath = "upload";

//3. 내 프로젝트 정보(ServletContext)안에서 가상경로를 실제경로로 계산해줘야한다.
//3-1. 서버안에 있는 물리적 위치 확인
ServletContext context = getServletContext();
String DownloadPath = context.getRealPath(savepath);
System.out.println("DownloadPath : "+DownloadPath);
//3-2. 다운로드할 파일의 전체 경로
//역슬러시 두개는 이스케이프문자로서 역슬러시 1개만 표현됨
String FilePath = DownloadPath+"\\"+filename;
//여기까지다운로드기능완료

//4. 데이터 응답처리를 다운로드 형태로 구현
//4-1. 파일을 한번에 처리하기위한 배열
byte[] b = new byte[4069];

//4-2. 파일입출력을 처리하는 파일 입력 스트림 객체생성(즉, 파일을 읽어오는 통로만들기)
FileInputStream fis = new FileInputStream(FilePath);

//4-3. 다운로드할 파일의 마임타입 확인(mime)
//=> 클라이언트에게 전송되는 데이터(문서)를 다양하게 처리 가능하도록 하는 메커니즘
String MimeType = getServletContext().getMimeType(FilePath);
System.out.println("Mime type: "+MimeType);

if(MimeType == null){
//기본값 지정 - 이진파일을 처리하기위한 기본타입
//-> 잘 알려지지 않은 파일을 의미하기때문에
//-> 브라우저는 보통 자동실행을 안하고 대화상자를 이용하여 사용자에게 실행할지 질문함
MimeType = "application/octet-stream";
}

//4-4내 응답정보를 마임타입으로 지정
response.setContentType(MimeType);

//5. 브라우저에 따른 데이터 처리(대응)
//왜 인터넷익스플로러를 기준으로 나눌까?
//인터넷익스폴러는 다운로드시 한글파일이 깨짐 -> 따라서 파일을 인코딩해서 다운로드함
//이때 공백문자가 플러스(+)기호로 나옴 -> 이걸 %20(공백)으로 변경

//익스인지 아닌지는 어떻게 알까?
String agent = request.getHeader("User-Agent");
System.out.println("agent : "+ agent);
boolean ieBrowser =
agent.indexOf("MSIE") > -1 || agent.indexOf("Trident") > -1;

if(ieBrowser){ // IE 일때 : +를 %20(공백)으로 변경
filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
}else{ // IE 아닐때 : 데이터인코딩(한글깨짐방지)
filename = new String(filename.getBytes("UTF-8"), "iso-8859-1");
}

//6. 데이터다운로드 처리
//브라우저가 응답정보를 읽어서(해석) 처리시
//"Content-Disposition" 설정값이 "attachment;" 모든 데이터 다운로드 처리
response.setHeader("Content-Disposition", "attachment; filename="+filename);

//7. 데이터출력(다운로드)
ServletOutputStream out2 = response.getOutputStream();
//7-1. 데이터출력 통로 생성
int data = 0;
while((data = fis.read(b,0,b.length)) != -1){
//데이터출력시 파일이 있을동안 계속 진행
out2.write(b,0,data); //배열에다가 data를 담아서 출력
out2.flush();
}
//8. 자원해제

out2.close();
fis.close();

//9. java.lang.IllegalStateException:
//이 응답을 위해 getOutputStream()이 이미 호출되었습니다.
// => JSP->Servlet 변환시 out 객체가 자동생성, 추가로 OutputStream 객체 생성시
// 오류 메세지 출력( 다운로드 문제 X, 서버에 에러 메세지 로그 쌓임)

out.clear();
out = pageContext.pushBody();
%>

5-1. java.lang.IllegalStateException에러

java.lang.IllegalStateException: 이 응답을 위해 getOutputStream()이 이미 호출되었습니다.

jsp가 실행될때 java파일로 변환되어 실행되고 그 바뀌는 걸 servlet이라고 한다.
이 변환시에 out이라는 객체가 자동 생성된다.
만약 추가로 OutputStream 객체생성시 IllegalStateException에러가 발생한다.

다운로드기능에는 문제가 없으나 에러가 실행될때마다 서버에 에러 메세지 로그 쌓이기때문에 처리해야한다.

1
2
out.clear();
out = pageContext.pushBody();

[ITWILL : JSP]Javabean 11 : MultipartRequest클래스

ITWILL학원 : 31강 JSP기초 BY 정규태강사

  • MultipartRequest클래스 (p305)
    MultipartRequest 클래스의 생성자와 메소드들을 사용하여 파일 업로드 기능 구현

https://slidesplayer.org/slide/14223134/
https://slidesplayer.org/slide/14223134/
https://slidesplayer.org/slide/14223134/

1. 라이브러리 설치

  1. servlets페이지 방문.
  2. 왼쪽 카테고리 COS File Upload Library 클릭 하여 com.oreilly.servlet로 이동.
  3. 맨 하단에 Download 에서 Version 밑에 zip압축파일 다운로드.
  4. lib폴더 안의 cos.jar복사하여 프로젝트의 WebContent\WEB-INF\lib에 붙여넣기.

2. fwriteForm.jsp 작성

  1. cos.jar라이브러리설치 (위에 내용 참고)
  2. 폼태그속성 enctype=”multipart/form-data”, method=”post”
  3. D드라이브에 `upfile’ 폴더생성
    • D드라이브말고 원하는 경로 지정가능.
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
<%
String id = (String) session.getAttribute("id");
if( id == null){
%>
<script type="text/javascript">
alert("로그인 후 이용가능합니다");
location.href="../member/loginForm.jsp"
</script>
<%
}

//1. cos.jar라이브러리설치 (위에 내용 참고)
//2. 폼태그속성 enctype="multipart/form-data", method="post" get방식은 처리되지 않음.
//3. D드라이브에 `upfile' 폴더생성- D드라이브말고 원하는 경로 지정가능.
%>

<fieldset>
<legend>게시판 글쓰기(p305~)</legend>
<form action="fwritePro.jsp" method="post" enctype="multipart/form-data">
글쓴이 : <input type="text" name="name" required><br>
비밀번호 : <input type="password" name="pw" required><br>
제목 : <input type="text" name="subject" maxlength="15" required><br>
내용 : <br>
<textarea rows="10" cols="35" name="content" placeholder="여기에 작성해주세요" required></textarea><br>
파일 : <input type="file" name="file">
<input type="submit" value="글등록" class="btn">
<button type="reset" class="btn">초기화</button>
<input type="button" value="목록으로" class="btn" onclick="location.href='boardList.jsp'">
</form>
</fieldset>

3. fwritePro.jsp 작성

파일업로드구현

  1. 파일 업로드 => cos.jar (MultipartRequest 클래스)
  2. 파일이 저장되는 위치 (D:/upfile)
  3. 파일 업로드 최대 크기
    • 크기를 왜 지정해야할까? 그 전에 파일을 업로드하면 어디로 저장되는지 알아야한다
    • 서버의 upfile폴더안으로 들어간다.
    • 따라서 유한한 디스크이고 메모리라서 최대 크기 지정이 필수이다.
    • 보통 20~250MB이다.
    • 1MB = 1024바이트 * 1024바이트 계산 꼭 하기
  4. MultipartRequest생성 : import하기 (다운받았던 cos.jar라이브러리)
    • 아래 코드처럼 객채생성하면 에러메세지가 뜬다
      1
      MultipartRequest multi = new MultipartRequest();
    • The constructor MultipartRequest() is undefined 기본생성자가 없는 클래스이다
    • 따라서 아래처럼 괄호안에 오버로딩되는 생성자를 작성해야한다.
    • MultipartRequest(요청정보,파일 업로드할 폴더,파일 업로드 제한 크기,인코딩방식,파일 이름동일시 처리객체)
      1
      MultipartRequest multi = new MultipartRequest(request, savePath, maxSize, "UTF-8", new DefaultFileRenamePolicy());
    • new DefaultFileRenamePolicy 객체의 역할 : 우리가 동일한 파일을 다운로드받는 경우 파일명에 파일명(1), 파일명(2)등등 자동으로 구분할 수 있도록 rename해주는 역할을 한다. 즉 중복처리하는 객체.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%
//파일 업로드 => cos.jar (MultipartRequest 클래스)
//1. 파일이 저장되는 위치 (D:/upfile)
String savePath = "d:\\upfile";

//2. 파일 업로드 최대 크기 => 5MB
int maxSize = 5 * 1024 * 1024;

//3. MultipartRequest 객체생성
MultipartRequest multi = new MultipartRequest(request, savePath, maxSize,"UTF-8", new DefaultFileRenamePolicy());

//4. 파일 업로드 완료 확인
out.println("파일 업로드 완료!");
%>
  • 테스트하면 만들었던 upfile폴더안에 저장되어있다. 성!공!적!
  • 하지만 이 방법은 보안상 매우 위험하다
    • 누구나 주소를 입력하여 upfile폴더에 접근가능하기때문이다.
    • 이제 디비와 연결해보자.

4. 디비연결

위의 코드에서 아래 코드를 더 추가해야한다.

  • multi객체 안에 request가 있으므로 request.getParameter()가 아닌 multi.getParameter()로 가지고 와야한다.
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
//6. 파일의 정보 + 글 정보를 디비에 저장
//6-1. 글정보저장하는 객체생성
BoardBean bb = new BoardBean();
//6-2. 전달되는 정보 저장
// bb.setName(request.getParameter("name")); enctype과 함께 쓸 수없다
bb.setName(multi.getParameter("name"));
bb.setPw(multi.getParameter("pw"));
bb.setSubject(multi.getParameter("subject"));
bb.setContent(multi.getParameter("content"));

// bb.setFile(multi.getParameter("file")); //DB에 파일저장 불가->아래코드로 진행
bb.setFile(multi.getFilesystemName("file"));
System.out.println("upfile에 저장된 파일명 : "+multi.getFilesystemName("file"));
System.out.println("사용자가 올린 원본 파일명 : "+multi.getOriginalFileName("file"));

//6-3. 따로 저장한 정보 저장
bb.setIp(request.getRemoteAddr());

//7. boardDAO객체생성
BoardDAO bdao = new BoardDAO();

//8. 글쓰기 메서드 호출
bdao.insertBoard(bb);

//9. 목록페이지로 이동
response.sendRedirect("boardList.jsp");

DB에도 잘 들어가는 걸 확인할 수 있다.
동일한 페이지 두번 작성하면 upfile에 저장된 파일명은 자동적으로 뒤에 숫자가 붙어 고유한 파일명으로 업로드가능하다.

[ITWILL : JSP]Javabean 13 : 게시판만들기(파일다운로드)

ITWILL학원 : 31강 JSP기초 BY 정규태강사

이 부분은 어렵다. 반복해서 보자.

1. up.jsp에 onclick이벤트 연결

  • onclick에 function을 넣어도 되고 location.href넣어도 둘 다 동일한 결과 출력된다.
    • input type=”button” value=”파일삭제” onclick=”downfile()”
    • input type=”button” value=”파일삭제” onclick=”location.href=’./down.jsp’”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<fieldset>
<form method="post" name="myform">
<input type="text" name="filename" value="<%=fileName%>">
<input type="button" value="파일삭제" onclick="delfile()">
<input type="button" value="파일다운로드" onclick="downfile()">
</form>
</fieldset>

<script type="text/javascript">
function delfile(){
document.myform.action="./delup.jsp"; //myform이름의 폼태그의 action값을 설정
document.myform.submit();
}

function downfile(){
document.myform.action="./down.jsp"; //myform이름의 폼태그의 action값을 설정
document.myform.submit();
}
</script>

2. down.jsp생성

  1. 인코딩

    • 모든 UTF-8을 EUC-KR(euc-kr)로 변경해준다. 대소문자 둘 다 가능.
    • string은 그냥 담아도 되고 객체에 담아도 된다. 즉 1번과 2번이 동일 WHY? String의 특징!
    • 1번 : String filename=request.getParameter(“filename”)
    • 2번 : String filename= new String(request.getParameter(“filename”));
  2. java.io 아래에 있는 입출력 객체를 import한다

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
<%@page import="java.io.FileNotFoundException"%>
<%@page import="java.io.FileInputStream"%>
<%@page import="java.io.File"%>
<%@page import="java.io.OutputStream"%>
<%@page import="java.io.InputStream"%>
<%@ page language="java" contentType="text/html; charset=euc-kr"
pageEncoding="euc-kr"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>Insert title here</title>
</head>
<body>
<h2>다운로드페이지</h2>
<%
//1. 인코딩
//string은 그냥 담아도 (=String filename=request.getParameter("filename"))되고 객체에 담아도된다
//String filename= new String(request.getParameter("filename"));
//파라미터 데이터를 가져와서 8859_1 인코딩방식으로 바꾼 뒤 EUC-KR로 한번 더 바꾸는 것
String filename = new String((request.getParameter("filename")).getBytes("8859_1"),"euc-kr");

//2. 파일저장경로(절대경로)
String filePath = "D:/upfile";

//3. 입출력시 필요한 객체 생성
InputStream in = null;
OutputStream os = null;
File file = null;
File viewFile = null;

//3-1. 추가 레퍼런스생성
boolean skip = false; //플래그만들기
String client = "";

// 4. 예외처리
try{
//5. 변수생성 : 인코딩시 변경되는 string 따로 저장하려고 3개 변수 만듬
String fname1 = "";
String fname2 = "";
String fname = "";

fname = filename;
fname1 = new String(fname.getBytes("8859_1"), "euc-kr");
//9. try catch구문으로 묶기
try{
//6. 전달된 파일 경로,이름 사용해서 파일 객체 생성
file = new File(filePath, fname);
viewFile = new File(filePath,fname1);

//확인차 페이지에 출력
out.print("file : "+file+"<br>");
out.print("viewfile : "+viewFile);

//8. 파일을 읽어오기 위해서 입력 통로를 생성
// 객체를 만든 순간 = 해당 폴더로 이동해서 파일을 선택한 상황임.
// InputStream in = null;
in = new FileInputStream(file); //업캐스팅
}catch(FileNotFoundException e){
skip = true;
}

//10. String변수만들어주기
fname2 = new String(fname1.getBytes("euc-kr"), "8859_1");

//11. 응답객체초기화 for 다운로드 팝업창 생성된 것처럼 보이게끔하여 다운로드 진행중임을 표시
response.reset();

2-1. down.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
	//12. 다운로드처리
//12-1. 클라이언트가 다운로드 요청시 사용자 웹브라우저 정보필요
//why? 브라우저별로 설정해줘야하는 것들이 다르기 때문
client = request.getHeader("User-Agent");
//System.out.println("client :" + client);
//12-2. 사용자브라우저에 따른 처리
//12-2-1. mine 타입이용하여 값세팅하기
response.setContentType("application/x-msdownload");
response.setHeader("Content-Description", "JS Generated Data");
//12-2-2. 브라우저마자 실행 제어
if(!skip){ //false항상실행
if(client.indexOf("MSIE 5.5") != -1){
response.setHeader("Content-Type", "doesn/matter; charset=euc-kr");
response.setHeader("Content-Disposition", "filename"+ new String(fname.getBytes("euc-kr"),"8859_1"));
}else{
response.setHeader("Content-Type", "application/octet-stream; charset=euc-kr");
response.setHeader("Content-Disposition", "attachment; filename="+new String(fname.getBytes("euc-kr"),"8859_1"));
}
//12-2-3. 문자열만들기
response.setHeader("Content-Transfer-Encoding", "binary;");
response.setHeader("Content-Length", ""+file.length());
response.setHeader("Pragma", "no-cache;");
response.setHeader("Expires", "-1;");

//12-3. 데이터출력할 수 있는 통로 생성
os = response.getOutputStream();

//12-3-1. 바이트스트림
byte[] b = new byte[4096];
int leng = 0;

//12-3-2. 파일을 읽어서 leng에 저장이 될 것이고 데이터가 있을 경우에만 진행
//leng은 데이터가 없으면 -1값을가진다
while((leng = in.read(b))> 0){
//데이터출력(다운로드)
os.write(b,0,leng);
}
}else{
out.print("파일다운로드 실패");
return;
}

}catch(Exception e){
System.out.println("다운로드도중 에러발생");
e.printStackTrace();
}finally{
if(in != null) in.close();
if(os != null) os.close();
}

%>

[ITWILL : JSP]Javabean 12 : 게시판만들기(파일업로드), UTF-8과 EUC-KR차이

ITWILL학원 : 31강 JSP기초 BY 정규태강사

1. 새로운 프로젝트 fileUpload 생성

  1. 새로운 다이나믹 앱 프로젝트 생성 : 프로젝트명 fileUpload
  2. 라이브러리 추가 : cos.jar를 복사하여 D:\fileUpload\WebContent\WEB-INF\lib에 복붙하기
  3. WebContent하위에 fileUP폴더 생성 후 그 안에 up.html페이지 생성(아래 단계)

2. up.html 작성

  • up.htmlmeta charset="UTF-8" 에서 meta charset="euc-kr"로 변경
    • UTF-8과 euc-kr 둘 다 한글을 처리하는 메타태그임.
    • UTF-8 : 한글 조합형의 유니코드 인코딩방식
    • EUC-KR : 한글 완성형의 유니코드 인코딩방식. 한글 2BYTE로 사용.
    • 참고링크 : UTF-8과 EUC-KR의 차이점
1
2
3
4
5
6
7
8
<fieldset>
<legend>파일업로드</legend>
<form action="up.jsp" method="post" enctype="multipart/form-data">
이름 : <input type="text" name="name"><br>
파일 : <input type="file" name="upfile"><br>
<input type="submit" value="파일업로드">
</form>
</fieldset>

3. up.jsp 작성

  • 에러해결 : java build path > library > add library > server runtime > 톰캣 추가
  • UTF-8euc-kr로 싹 다 바꾸기
  • onclick에 function을 넣어도 되고 location.href넣어도 둘 다 동일한 결과 출력된다.
    • input type=”button” value=”파일삭제” onclick=”delfile()”
    • input type=”button” value=”파일삭제” onclick=”location.href=’./delup.jsp’”
  • 참고링크1 : Enumeration
  • 참고링크2 : Enumeration
  • 참고링크3 : Enumeration
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
<%
//1. 전달되는 데이터 인코딩
request.setCharacterEncoding("euc-kr");

//2. 업로드 폴더 지정(절대경로 = 파일을 직접적으로 접근하는 방식)
String savePath = "d:\\upfile";

//3. 업로드 파일 크기 => 10MB
int maxSize = 10 * 1024 * 1024;

//4. 파일 이름 저장하는 변수 생성
String fileName="";
String originalFileName="";


//5. 예외처리 포함한 파일업로드
try{
MultipartRequest multi = new MultipartRequest(request, savePath, maxSize, "euc-kr", new DefaultFileRenamePolicy());
//여기까지 파일업로드완료

//6. 파일업로드 결과를 화면에 출력
//6-1. 폼의 이름 반환
Enumeration formNames = multi.getFileNames(); //업캐스팅

//6-2. 전달된 파일의 정보를 저장
String formname = (String) formNames.nextElement(); //위의 업캐스팅한 걸 다운캐스팅

//7. 서버에 저장된 파일의 이름저장
fileName = multi.getFilesystemName(formname);

//8. 원래 파일의 이름 저장
originalFileName = multi.getOriginalFileName(formname);

//9.파일업로드 성공시 해당 정보 출력
if(fileName == null){
out.println("파일업로드 실패!");
}else{
out.print("업로드한 사람 : "+multi.getParameter("name")
+"<br>업로드 파일이름(서버저장) : "+fileName+"<br>업로드 파일이름(원본): "+originalFileName
+"<br>file태그정보 : "+formname);
}

}catch(Exception e){
out.println("파일업로드 중 예외상황발생");
e.printStackTrace();
}
%>
<fieldset>
<form method="post" name="myform">
<input type="text" name="filename" value="<%=fileName%>">
//onclick에 function을 넣어도 되고 location.href넣어도 동일한 결과 출력
<input type="button" value="파일삭제" onclick="delfile()">
<input type="button" value="파일삭제" onclick="location.href='./delup.jsp'">
<input type="button" value="파일다운로드">
</form>
</fieldset>

4. delup.jsp 생성

한글파일빼고는 삭제가 잘 진행된다.
인코딩방식의 문제이므로 나중에 처리하기로한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%
//1. 전달된 파일 이름 저장
String filename = request.getParameter("filename");

//2. 파일 객체 생성 -> 삭제
//File f = new File("해당파일의 위치+파일명");
//객체를 만든 순간 = 해당 폴더로 이동해서 파일을 선택한 상황임.
File f = new File("D:\\upfile/"+filename);

//3. 파일삭제
f.delete();
out.println("파일삭제완료");

//3-1. 한글파일빼고는 삭제가 잘 진행된다.
out.println(filename);
%>

[ITWILL : JSP]Javabean 9 : 게시판만들기(글삭제하기)

ITWILL학원 : 30강 JSP기초 BY 정규태강사

1. 글삭제하기기능구현 순서

  1. deleteForm.jsp 작성
  2. deletePro.jsp 작성
  3. BoardDAO.java에서 bdao.deleteBoard(bno, pw)메서드 생성
  4. 기존의 boardList.jsp에 id가 있을 경우 추가
  5. 기존의 content.jsp 로그인상태에 따라 다르게 보이는 버튼 추가

2. deleteForm.jsp 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%
//1. 한글처리
request.setCharacterEncoding("UTF-8");

//2. 파라미터저장
int bno = Integer.parseInt(request.getParameter("bno"));
String pageNum = request.getParameter("pageNum");

%>
<fieldset>
<legend>게시글 삭제</legend>
<form action="deletePro.jsp?pageNum=<%=pageNum%>" method="post">
<input type="hidden" name="bno" value="<%=bno%>">
비밀번호 : <input type="password" name="pw"><br>
<input type="submit" value="글삭제하기" class="btn">
<input type="button" value="뒤로가기" class="btn" onclick="history.back()">
</form>
</fieldset>

3. deletePro.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
<%
//1. 한글처리
request.setCharacterEncoding("UTF-8");
//2. 파라미터저장(액션태그사용 & pageNum은 파라미터로)
int bno = Integer.parseInt(request.getParameter("bno"));
String pageNum = request.getParameter("pageNum");
String pw = request.getParameter("pw");
//3. DAO생성
BoardDAO bdao = new BoardDAO();
//4. 정보수정메서드 updateBoard(bb)
// -> 결과를 정수형 데이터로 리턴 (1=>정상처리, 0=>비번오류, -1=>해당글없음)
int result = bdao.deleteBoard(bno, pw);
if(result == 1){
%>
<script type="text/javascript">
alert("정상적으로 글 삭제되었습니다");
location.href="boardList.jsp";
</script>
<%
}else if(result == 0){
%>
<script type="text/javascript">
alert("비밀번호 오류");
history.back();
</script>
<%
}else{
%>
<script type="text/javascript">
alert("존재하지않는 게시글입니다");
history.back();
</script>
<%
}
%>

3. BoardDAO.java에서 bdao.deleteBoard(bno, pw)메서드 생성

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
public int deleteBoard(int bno, String pw){
int result = -1;

try {
getCon();
sql="select pw from itwill_board where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, bno);
rs = pstmt.executeQuery();
if(rs.next()){
if(pw.equals(rs.getString("pw"))){
sql="delete from itwill_board where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, bno);
pstmt.executeUpdate();
System.out.println("글삭제 성공");
result = 1;
}else{
result = 0;
System.out.println("글삭제 중 비번오류");
}
}else{
result = -1;
System.out.println("글삭제 중 select오류");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
closeDB();
}
return result;
}//deleteBoard()닫음

4. 기존의 main.jsp에 게시판바로가기 버튼 추가

글삭제의 경우 아무나 할 수 없어야한다.
따라서 로그인한 사람만이 글을 쓰고 글을 삭제할 수 있도록 구현해보자.
이전에 구현했던 main.jsp에 게시판글바로볼 수 있는 버튼을 추가하고 location.href='../board/boardList.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
<%//1.한글처리, 파라미터 
request.setCharacterEncoding("UTF-8");
String id = (String) session.getAttribute("id");//object를 string으로 다운캐스팅
String name = request.getParameter("name");
//1-1. id없이는 진입불가, id없는 경우 로그인페이지로 이동
if(id == null){
response.sendRedirect("loginForm.jsp");
}
%>
<h2><%=id %>님 환영합니다.</h2>
<%=name %><br>

<input type="button" value="ITWILL게시판가기" class="btn" onclick="location.href='../board/boardList.jsp'">
<input type="button" value="회원정보조회" class="btn" onclick="location.href='memberinfo.jsp'">
<input type="button" value="회원정보수정" class="btn" onclick="location.href='updateForm.jsp'">
<input type="button" value="로그아웃" class="btn" onclick="location.href='logout.jsp'">
<input type="button" value="회원탈퇴" class="btn" onclick="location.href='deleteForm.jsp'">

<!-- 관리자일때만 메뉴확인가능 -->
<% if(id != null){
if(id.equals("admin")){ %>
<input type="button" value="회원전체목록(관리자용)" class="btn" onclick="location.href='memberList.jsp'">
<%
}
}
%>

5. 기존의 boardList.jsp에 id가 있을 경우 추가

  • id가 없을 경우 : 로그인버튼만 표시
  • id가 있을 경우 : 로그아웃, 글쓰기버튼 표시
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
<fieldset>
<legend>땡땡게시판</legend>
<div id="contents">
게시판 총 글의 수 : <%=cnt%>
<%
if(id == null){
%>
<input class="btn" type="button" value="로그인" onclick="location.href='../member/main.jsp'">
<%
}else if( id != null){
%>
<input class="btn" type="button" value="로그아웃" onclick="location.href='../member/logout.jsp'">
<input class="btn" type="button" value="글쓰기" onclick="location.href='writeForm.jsp'">
<%
}
%>
<br>
<table>
<tr>
<th>글번호</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
<th>IP</th>
</tr>
<%//반복문
//ArrayList는 가변배열이므로 length가 없고 size가 존재한다.
//size()메서드는 배열의 요소의 갯수를 리턴
for(int i=0;i<boardList.size(); i++){
//ArrayList 한칸의 정보 ->BoardBean 객체 하나로 이동
BoardBean bb = (BoardBean) boardList.get(i);
%>
<tr>
<td><%=bb.getBno()%></td>
<td><a href="content.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>"><%=bb.getSubject()%></a></td>
<td><%=bb.getName()%></td>
<td><%=bb.getReadcount()%></td>
<td><%=bb.getDate()%></td>
<td><%=bb.getIp()%></td>
</tr>
<%
}
%>
</table>
</div>
</fieldset>

6. 기존의 content.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
<fieldset>
<legend>글 내용 보기</legend>
<table border="solid,1px">
<tr>
<th>글번호</th>
<td><%=bno%></td>
<th>조회수</th>
<td><%=bb.getReadcount()%></td>
</tr>
<tr>
<th>작성자</th>
<td><%=bb.getName()%></td>
<th>작성일</th>
<td><%=bb.getDate()%></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><%=bb.getSubject()%></td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"><%=bb.getFile()%></td>
</tr>
<tr>
<th>내용</th>
<td colspan="3" height="300px"><%=bb.getContent()%></td>
</tr>
<tr>
<td colspan="4" style="text-align:center">

<% //현재페이지에 로그인 정보가 없거나 글쓴이 이름과 아이디가 다를 경우 수정,삭제버튼을 숨긴다
//1.세션값 가져오기
String id = (String) session.getAttribute("id");//objectstring으로 다운캐스팅
//2. 아이디가 존재하면서 이름과 아이디가 같은 경우
if( id != null && id.equals(bb.getName())){
%>
<input type="button" value="글수정" class="btn" onclick="location.href='updateForm.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>'">
<input type="button" value="글삭제" class="btn" onclick="location.href='deleteForm.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>'">
<input type="button" value="답글쓰기" class="btn" onclick="location.href='reWriteForm.jsp?bno=<%=bb.getBno()%>&re_ref=<%=bb.getRe_ref() %>&re_lev=<%=bb.getRe_lev()%>&re_seq=<%=bb.getRe_seq()%>'">
<%
}
%>
<input type="button" value="목록으로" class="btn"
onclick="location.href='boardList.jsp?pageNum=<%=pageNum%>'">
<!-- location.href='boardList.jsp만 하면 5페이지보고있다가 다시 1페이지로 돌아가버린다
이때 historyback하면 조회수가 올라가지않는다.
따라서 pageNum을 가져와서 사용하면된다
-->
</td>
</tr>
</table>
</fieldset>

[ITWILL : JSP]Javabean 10 : 게시판만들기(답글쓰기)

ITWILL학원 : 30강 JSP기초 BY 정규태강사

1. 답글처리구현 순서

  • 일반글 = 답글이 아닌 글.
  • num : 일반글+답글 둘 다 작성할때마다 계속 증가된 값으로 사용(순차적)
  • re_ref : 답글의 그룹번호(일반글번호와 동일), 답글을 다는 원글의 그룹번호를 사용
  • re_lev (level) : 답글의 레벨값 (깊이), 원글을 기준으로한다 ex)한번내려가면1 두번내려가면 2
  • re_seq (sequence) : 답글의 순서, 원글에 답글이 몇개인지하는 순서대로 카운트.

글목록 예시

  • 일반글은 ref만 num값과 동일하게 초기화
  • 답글은 lev, seq는 0으로 초기화

만약 여기서 3번글의 답글 1개를 추가한다면?
6 / 답급3-1 / 3 / 1 / 1

만약 여기서 3번글의 답글 1개를 추가한다면?
6 / 답글3-1 / 3 / 1 / 1

만약 여기서 3번글의 답글 1개를 또 추가한다면?
7 / 답글3-2 / 3 / 1 / 2

만약 여기서 3번답글인 3-1에 답글 1개를 추가한다면?
8 / 답글3-1-1 / 3 / 2 / 3

만약 여기서 4번밑에 답글을 단다면?
9 / 답글4-1 / 4 / 1 / 1

만약 여기서 일반글 작성한다면?
10 / 일반글 / 10 / 0 / 0

만약 여기서 답글4-1에 답글을 단다면?
11 / 답글4-1-1 / 4 / 2 / 2

2. reWriteForm.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
<%
//한글처리
request.setCharacterEncoding("UTF-8");

//전달한 데이터 저장 (bno,re_ref, re_lev, &re_seq)
int bno = Integer.parseInt(request.getParameter("bno"));
int re_ref = Integer.parseInt(request.getParameter("re_ref"));
int re_lev = Integer.parseInt(request.getParameter("re_lev"));
int re_seq = Integer.parseInt(request.getParameter("re_seq"));

//어떻게 가져갈 것인가? 폼태그안에 담아갈까? 주소창에 GET방식으로 가져갈까?
//bean의 멤버변수에 있는 변수는 폼태그안에 담아가면된다. =>hidden 인풋태그
%>
<fieldset>
<legend>게시판 답글쓰기</legend>
<form action="reWritePro.jsp" method="post" name="fr">
<input type="hidden" name="bno" value="<%=bno%>">
<input type="hidden" name="re_ref" value="<%=re_ref%>">
<input type="hidden" name="re_lev" value="<%=re_lev%>">
<input type="hidden" name="re_seq" value="<%=re_seq%>">
글쓴이 : <input type="text" name="name" required><br>
비밀번호 : <input type="password" name="pw" required><br>
제목 : <input type="text" name="subject" maxlength="15" value="[답글] " required><br>
내용 : <br>
<textarea rows="10" cols="35" name="content" placeholder="여기에 답글을 작성해주세요" required></textarea><br>
<input type="submit" value="답글등록" class="btn">
<button type="reset" class="btn">초기화</button>
<input type="button" value="목록으로" class="btn" onclick="location.href='boardList.jsp'">
</form>
</fieldset>

3. reWritePro.jsp 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%
// 한글 처리
request.setCharacterEncoding("UTF-8");
// 액션태그 사용 파라미터값 저장
// useBean,setProperty
%>
<jsp:useBean id="bb" class="com.itwillbs.board.BoardBean"/>
<jsp:setProperty property="*" name="bb"/>
<%
System.out.println(bb);
// ip 정보 저장
bb.setIp(request.getRemoteAddr());

// BoardDAO 객체 생성 - reInsertBoard(객체)
BoardDAO bdao = new BoardDAO();
bdao.reInsertBoard(bb);

// 페이지 이동(글 목록)
response.sendRedirect("boardList.jsp");
%>

4. BoardDAO.java에서 reInsertBoard(BoardBean bb)메서드 만들기

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
public void reInsertBoard(BoardBean bb){
//1.지역변수생성
int num = 0;
//2. 디비연결
try {
getCon();
//sql(게시판의 글번호 중 최댓값 계산) & pstmt
//2-1. 답글번호 계산
sql = "select max(bno) from itwill_board";
pstmt = con.prepareStatement(sql);
// 실행
rs = pstmt.executeQuery();
// 데이터 처리
if(rs.next()){
num = rs.getInt(1)+1;
}
System.out.println(" 답글 번호 : "+num);

//2-2. 답글 순서 재배치
//re_ref(같은 그룹기준)으로 re_seq값이 기존의 값보다 큰 값이 있을경우 seq값을 1증가시킴
sql = "update itwill_board set re_seq=re_seq+1 "
+ "where re_ref=? and re_seq>?";
pstmt = con.prepareStatement(sql);

pstmt.setInt(1, bb.getRe_ref());
pstmt.setInt(2, bb.getRe_seq());

pstmt.executeUpdate();

//2-3. 답글 추가 동작
sql="insert into itwill_board "
+ "values(?,?,?,?,?"
+ ",?,?,?,?,now()"
+ ",?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);//bno는 가지고있는게 아니라 계산해서 만든것이므로 num사용
pstmt.setString(2, bb.getName());
pstmt.setString(3, bb.getPw());
pstmt.setString(4, bb.getSubject());
pstmt.setString(5, bb.getContent());
pstmt.setInt(6, bb.getReadcount());
pstmt.setInt(7, bb.getRe_ref()); //기존 원글의 그룹번호와 동일
pstmt.setInt(8, bb.getRe_lev()+1); // 기존의 값 + 1
pstmt.setInt(9, bb.getRe_seq()+1); // 기존의 값 + 1
pstmt.setString(10, bb.getFile());
pstmt.setString(11, bb.getIp());

//3. 실행
pstmt.executeUpdate();
System.out.println("답글쓰기 성공");
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDB();
}
} //reInsertBoard닫음

5. BoardList.jsp에서 답글 들여쓰기 추가 구현

이미지와 조건문을 통해 구현

  • img src=”level.gif” width=”<%=wid%>” height=”15”
  • img src=”re.gif”
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
<fieldset>
<legend>땡땡게시판</legend>
<div id="contents">
게시판 총 글의 수 : <%=cnt%> 개
<%
if(id == null){
%>
<input class="btn" type="button" value="로그인" onclick="location.href='../member/main.jsp'">
<%
}else if( id != null){
%>
<input class="btn" type="button" value="로그아웃" onclick="location.href='../member/logout.jsp'">
<input class="btn" type="button" value="글쓰기" onclick="location.href='writeForm.jsp'">
<%
}
%>
<br>
<table>
<tr>
<th>글번호</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
<th>IP</th>
</tr>
<%//반복문
//ArrayList는 가변배열이므로 length가 없고 size가 존재한다.
//size()메서드는 배열의 요소의 갯수를 리턴
for(int i=0;i<boardList.size(); i++){
//ArrayList 한칸의 정보 ->BoardBean 객체 하나로 이동
BoardBean bb = (BoardBean) boardList.get(i);
%>
<tr>
<td><%=bb.getBno()%></td>
<td>
<%
//답글일때만 이미지넣기
//변수 wid를 이용하여 들여쓰기 처리
int wid = 0;
if(bb.getRe_lev() > 0){
wid= 10 * bb.getRe_lev(); //레벨값의 10을 곱한 값만큼 이미지 가로길이를 길게해줌
%>
<img src="level.gif" width="<%=wid%>" height="15">
<img src="re.gif">
<% } %>
<a href="content.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>"><%=bb.getSubject()%></a></td>
<td><%=bb.getName()%></td>
<td><%=bb.getReadcount()%></td>
<td><%=bb.getDate()%></td>
<td><%=bb.getIp()%></td>
</tr>
<%
}
%>
</table>
</div>
</fieldset>

[ITWILL : JSP]Javabean 8 : 게시판만들기(글내용보기, 글수정하기)

ITWILL학원 : 29강 JSP기초 BY 정규태강사

1. 순서

  1. content.jsp 생성
    • html 테이블작성
  2. boardDAO.java에 updateReadCount(int bno)메서드 생성
  3. boardDAO.java에 getBoard(int bno)메서드 생성
  4. 글수정할 수 있는 updateForm.jsp 생성
  5. 글수정할 수 있는 updatePro.jsp 생성
  6. boardDAO.java에 updateBoard(bb)메서드 생성

2. content.jsp 생성

글목록에서 제목을 눌렀을때 컨텐츠를 볼 수 있게 만드는 페이지이다.

  • 목록으로 되돌아가는 버튼 만들때 주의점
    • location.href=boardList.jsp만 하면 5페이지보고있다가 다시 1페이지로 돌아가버린다
    • 이때 historyback하면 조회수가 올라가지않는다.
    • 따라서 pageNum을 가져와서 사용하면된다
    • location.href=boardList.jsp?pageNum=<%=pageNum%>으로 해줘야한다.
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
<%
//1. html테이블작성

//글번호(pk제약조건의 컬럼필수)에 해당하는 글의 정보를 가져오기
//2. 전달된 데이터 저장(bno, pageNum)

int bno = Integer.parseInt(request.getParameter("bno"));
String pageNum = request.getParameter("pageNum");

//3. DAO객체생성
BoardDAO bdao = new BoardDAO();

//4. 글의 조회수정보를 1증가 : DB에서처리 -> DAO객체에 updateReadCount(bno)메서드 생성
bdao.updateReadCount(bno);

//5. 화면(테이블)에 출력 (getBoard(bno))
// DAO객체에 글정보를 가져오는 메서드 생성
BoardBean bb = bdao.getBoard(bno);
//System.out.println(bdao.getBoard(bno));
%>

<fieldset>
<legend>글 내용 보기</legend>
<table border="solid,1px">
<tr>
<th>글번호</th>
<td><%=bno%></td>
<th>조회수</th>
<td><%=bb.getReadcount()%></td>
</tr>
<tr>
<th>작성자</th>
<td><%=bb.getName() %></td>
<th>작성일</th>
<td><%=bb.getDate() %></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><%=bb.getSubject() %></td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"><%=bb.getFile() %></td>
</tr>
<tr>
<th>내용</th>
<td colspan="3" height="300px"><%=bb.getContent() %></td>
</tr>
<tr>
<td colspan="4" style="text-align:center">
<input type="button" value="글수정" class="btn" onclick="location.href='updateForm.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>'">
<input type="button" value="글삭제" class="btn">
<input type="button" value="답글쓰기" class="btn">
<input type="button" value="목록으로" class="btn"
onclick="location.href='boardList.jsp?pageNum=<%=pageNum%>'">
<!-- location.href='boardList.jsp만 하면 5페이지보고있다가 다시 1페이지로 돌아가버린다
이때 historyback하면 조회수가 올라가지않는다.
따라서 pageNum을 가져와서 사용하면된다
-->
</td>
</tr>
</table>
</fieldset>

3. boardDAO.java에 updateReadCount(int bno)메서드 생성

조회수 올리는 메서드를 생성하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void updateReadCount(int bno){
try {
//1. 디비연결
getCon();
//2. sql작성 & pstmt생성
//select를 안하는 이유? 기존의 데이터를 굳이 가져올 필요가 없기 때문
sql = "update itwill_board set readcount=readcount+1 where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, bno);
//3. 실행
pstmt.executeUpdate();
System.out.println("조회수 1증가 완료");
} catch (Exception e) {
System.out.println("조회수 1증가 실패");
e.printStackTrace();
} finally {
//4. 자원해제
closeDB();
}
}

4. boardDAO.java에 getBoard(int bno)메서드 생성

글 내용을 다 가져와서 오는 메서드를 만들어보자
이는 글제목을 클릭시 화면에 내용을 보여줄때 사용된다.

  • 내코드
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
public BoardBean getBoard(int bno){
BoardBean bb = new BoardBean();
try {
//1. 디비연결
getCon();
//2. sql작성, pstmt
//sql = "select * from itwill_board";
sql = "select * from itwill_board where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, bno);
//3. 실행 -> rs저장
rs = pstmt.executeQuery();
//4. 데이터처리
if(rs.next()){
//4-1.BoardBean 객체생성해서 그 안에 rs데이터 저장
bb.setBno(rs.getInt("bno"));
bb.setContent(rs.getString("content"));
bb.setDate(rs.getDate("date"));
bb.setFile(rs.getString("file"));
bb.setIp(rs.getString("ip"));

bb.setName(rs.getString("name"));
bb.setPw(rs.getString("pw"));
bb.setRe_lev(rs.getInt("re_lev"));
bb.setRe_ref(rs.getInt("re_ref"));
bb.setRe_seq(rs.getInt("re_seq"));

bb.setReadcount(rs.getInt("readcount"));
bb.setSubject(rs.getString("subject"));
//여기까지가 한 행의 데이터를 저장한 것임

}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDB();
}
return bb;
}//getBoard닫음
  • 강사님코드
    • BoardBean객체를 언제 생성하는 지가 내 코드와 달랐다. BoardBean객체를 미리 생성할 필요가 없었다.
    • try catch로 예외가 발생하거나, rs에 데이터가 없는 경우에는 객체를 생성할 필요가 없기 때문이다.
    • 글정보 저장완료 후 리턴값 bb정보를 습관적으로 확인하자.
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
//글 정보를 가져오는 메서드구현
public BoardBean getBoard(int bno){
//rs에 데이터가 없으면 객체생성할 필요가 없음. 따라서 객채생성안하고 null함.
BoardBean bb = null;
try {
//1. 디비연결
getCon();
//2. sql작성, pstmt
//sql = "select * from itwill_board";
sql = "select * from itwill_board where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, bno);
//3. 실행 -> rs저장
rs = pstmt.executeQuery();
//4. 데이터처리
if(rs.next()){
//4-1.BoardBean 객체생성해서 그 안에 rs데이터 저장
// 글내용에서 보이지 않는 컴럼들도 만들어야할까?
// 만들기를 추천함 why? 매개변수인 bno자체가 pk를 가졌다.
// 지금뿐만아니라 다음 기능이 필요할때 불러와서 사용할 수 있다.
// 재사용성
bb = new BoardBean();
bb.setBno(rs.getInt("bno"));

(중략)

bb.setSubject(rs.getString("subject"));
//여기까지가 한 행의 데이터를 저장한 것임
}
//글정보 저장완료 후 정보확인
System.out.println("해당 글 저장 완료");
System.out.println(bb);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDB();
}
return bb;
}//getBoard닫음

5. updateForm.jsp생성

글을 수정할수있는 페이지를 만들어보자.

  • 아래 태그 두개는 동일할까?

    • <input type="button" value="목록으로" class="btn" onclick="location.href='boardList.jsp?bno=<%=bno%>'">
    • <input type="button" value="목록으로" class="btn" onclick="location.href='boardList.jsp?bno=<%=bb.getBno()%>'">
  • YES! 동일하다!

  • 인풋 히튼타입 : 화면에는 보이지않지만 데이터 저장 및 전달이 가능해서 데이터 이동용으로 주로 사용

  • BoardBean안에 포함되지 않는 pageNum 변수등은 어떻게 전달할까?

    • 액션페이지 주소줄에 get방식으로 전달
    • 만약 (BoardBean에 포함되지않은) 전달될 데이터가 개인정보등 중요한 데이터라면 get방식으로 전달해선 절대 안된다(=>정보유출문제발생)
      • 그럼 중요한 정보들은 전달할수없는걸까? CAN! 1. 클로저이용 또는 2.BoardBean구조자체를 변경
    • 결론: 가능하면 BoardBean형태의 데이터만 저장해서 처리할 수 있도록 해야한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<%//1. 파라미터저장
int bno = Integer.parseInt(request.getParameter("bno"));
String pageNum = request.getParameter("pageNum");

BoardDAO bdao = new BoardDAO();
BoardBean bb = bdao.getBoard(bno);
%>

<fieldset>
<legend>게시판 글쓰기</legend>
<form action="updatePro.jsp?pageNum=<%=pageNum %>" method="post" name="fr">
<!-- 인풋 히튼타입 : 화면에는 보이지않지만 데이터 저장 및 전달이 가능해서 데이터 이동용으로 주로 사용 -->
<input type="hidden" name="bno" value="<%=bb.getBno() %>">
글쓴이 : <input type="text" name="name" required value="<%=bb.getName() %>"><br>
비밀번호 : <input type="password" name="pw" required ><br>
제목 : <input type="text" name="subject" required value="<%=bb.getSubject() %>"><br>
내용 : <br>
<textarea rows="10" cols="35" name="content" placeholder="여기에 작성해주세요" required>
<%=bb.getContent() %></textarea><br>
<input type="submit" value="수정하기" class="btn">
<button type="reset" class="btn">초기화</button>
<input type="button" value="목록으로" class="btn" onclick="location.href='boardList.jsp'">
</form>
</fieldset>

6. updatePro.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
<%//1. 한글처리
request.setCharacterEncoding("UTF-8");
//2. 파라미터저장(액션태그사용 & pageNum은 파라미터로)
String pageNum = request.getParameter("pageNum");
%>
<jsp:useBean id="bb" class="com.itwillbs.board.BoardBean"></jsp:useBean>
<jsp:setProperty property="*" name="bb"/>
<% //3. DAO생성
BoardDAO bdao = new BoardDAO();
//4. 정보수정메서드 updateBoard(bb)
// -> 결과를 정수형 데이터로 리턴 (1=>정상처리, 0=>비번오류, -1=>해당글없음)
int result = bdao.updateBoard(bb);
if( result == 1){
%>
<script type="text/javascript">
alert("글 수정 완료!");
location.href="boardList.jsp?pageNum=<%=pageNum%>";
</script>
<%
}else if(result == 0){
%>
<script type="text/javascript">
alert("비번이 일치하지않습니다");
history.back();
</script>
<%
}else{
%>
<script type="text/javascript">
alert("존재하지 않는 글입니다");
history.back();
</script>
<%
}
%>

7. boardDAO.java에 updateBoard(bb)메서드 생성

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
public int updateBoard(BoardBean bb){
int result = 0;

try {
//DB연결
getCon();
System.out.println("디비연결완료");
//sql & pstmt
sql = "select pw from itiwill_board where bno=?";
pstmt = con.prepareStatement(sql);
System.out.println("pstmt 객체생성완료");
pstmt.setInt(1, bb.getBno());

rs = pstmt.executeQuery();
System.out.println("pstmt 실행");
if(rs.next()){
//비번비교 후 일치하면 update 쿼리실행
if(bb.getPw().equals(rs.getString("pw"))){
sql="update itwill_board set name=?, subject=?, content=? where bno=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, bb.getName());
pstmt.setString(2, bb.getSubject());
pstmt.setString(3, bb.getContent());
pstmt.setInt(4, bb.getBno());
pstmt.executeUpdate();
System.out.println("글수정완료 - 비번일치");
//리컨값 변경
result =1;
}else{//비번불일치
System.out.println("글수정실패 - 비번불일치");
result = 0;
}
}else{
System.out.println("글수정실패 - 해당글없음");
result = -1;
}

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
closeDB();
}
return result;
}//updateBoard닫음

[ITWILL : JSP]Javabean 7 : 게시판만들기(글 총갯수, 글목록, 페이징처리)

ITWILL학원 : 28강 JSP기초 BY 정규태강사

1. 순서

  1. 디비에서 전체 글목록을 읽어서 가져오기
    • 글을 읽어오는 작업은 많은 리소스를 필요로한다.
  2. BoardList.jsp 생성
  3. BoardDAO.java에 getBoardCount() 메서드 생성
    • 디비에 글이 있는지 확인 후 있으면 글 모두 가져오기, 없으면 가져오지않기
  4. BoardDAO.java에 getBoardList() 메서드 생성
  5. 최신 글이 위로 오게 정렬 (쿼리이용)
    • 데이터역순정렬의 방법은 두가지
      • 쿼리단계에서 가져올때부터 역순: 더욱 효율적
      • 쿼리로 가져와서 화면에 뿌릴때 역순
  6. 페이징처리하기
  7. 페이지블럭 만들기

2. BoardList.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
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<%
//1. 디비에서 전체 글목록을 읽어서 가져오기
//2. BoardDAO 객체생성
BoardDAO bdao = new BoardDAO();
//3. 디비에 글이 있는지 확인 후 있으면 글 모두 가져오기,없으면 가져오지않기 : getBoardCount()
int cnt = bdao.getBoardCount();

//7. 페이징처리 (이미 유명한 알고리즘 공식, 사용법만 알면 됨)
//7-1. 한 페이지에서 보여줄 글의 개수 설정(5개, 변경가능)
int pageSize = 5;
//7-2. 지금 내가 몇페이지에 있는 확인
//페이지번호는 숫자인데 왜 String으로 하는지 ? => 연산을 할 것이 아니라서 String이 편함
String pageNum = request.getParameter("pageNum");
//7-3. 페이지번호정보가 없을 경우 내가 보는 페이지가 첫페이지가 되도록
if(pageNum == null){
pageNum ="1";
}
//7-4. 시작행번호계산
//10개씩 컬럼 나누고 2페이지에서 시작행이 11이되고 3페이지에서 시작행이 21이 되게끔 만들기
int currentPage = Integer.parseInt(pageNum); //String을 integer로 변환
int startRow = (currentPage-1)*pageSize + 1;
//currentPage가 2인경우, (2-1)x10+1 = 11
//currentPage가 3인경우, (3-1)x10+1 = 21

//7-5. 끈행번호계산
int endRow= currentPage * pageSize;
//currentPage가 2인경우, 2*10 = 20
//currentPage가 3인경우, 3*10 = 30


//4. 게시판 글의 수를 화면에 데이터 출력
//게시판 총 글의 수 : cnt개
//5. getBoardList() 메서드생성
System.out.println(bdao.getBoardList());

ArrayList boardList = null;

if(cnt != 0){
//일반적인 리스트호출방법, 아래는 페이징처리한 리스트호출방법
//boardList = bdao.getBoardList();
//7-6. 페이징 처리한 리스트 호출 => getBoardList()메서드만들기(메서드 오버로딩)
boardList = bdao.getBoardList(startRow, pageSize);
}

//6. 게시판 모든 내용을 화면에 출력

%>
<fieldset>
<legend>땡땡게시판</legend>
<div id="contents">
게시판 총 글의 수 : <%=cnt %> 개
<input id="writebtn" type="button" value="글쓰기" onclick="location.href='writeForm.jsp'">
<br>
<table>
<tr>
<th>글번호</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
<th>IP</th>
</tr>
<%//반복문
//ArrayList는 가변배열이므로 length가 없고 size가 존재한다.
//size()메서드는 배열의 요소의 갯수를 리턴
for(int i=0;i<boardList.size(); i++){
//ArrayList 한칸의 정보 ->BoardBean 객체 하나로 이동
BoardBean bb = (BoardBean) boardList.get(i);
%>
<tr>
<td><a href="content.jsp?bno=<%=bb.getBno()%>&pageNum=<%=pageNum%>"><%=bb.getSubject() %></a></td>
<td><%=bb.getSubject() %></td>
<td><%=bb.getName() %></td>
<td><%=bb.getReadcount() %></td>
<td><%=bb.getDate() %></td>
<td><%=bb.getIp() %></td>
</tr>
<%
}
%>
</table>
</div>
</fieldset>
<%
//8. 페이지 이동버튼
if(cnt != 0){ //cnt는 전체 글 갯수
//8-1. 페이지갯수처리
//전체페이지 50개이고 화면에 10개씩 출력 => 5페이지만 있으면됨
//전체페이지 57개이고 화면에 10개씩 출력 => 6페이지만 있으면됨
//삼항연산자로 처리
int pageCount = cnt/pageSize + (cnt%pageSize == 0? 0:1);

//8-2. 화면에 보여줄 페이지번호의 갯수(페이지블럭)
int pageBlock = 3; //페이지에 10개 페이지갯수 보여줌

//8-3. 페이지블럭의 시작페이지번호
//현재 11페이지면, (11-1)/10 * 10 + 1 = 11
int startPage = ((currentPage-1)/pageBlock) * pageBlock + 1;

//8-4. 페이지블럭의 끝페이지번호
int endPage = startPage + pageBlock - 1;
if(endPage > pageCount){
endPage = pageCount;
}

//8-5. 이전, 숫자, 다음처리
// 이전
%>
<div id="pageBlock">
<%
if(startPage > pageBlock){
%>
<a href="boardList.jsp?pageNum=<%=startPage-pageBlock%>"> 이전 </a>
<%
}

//숫자
for(int i=startPage; i<=endPage; i++){
%>
<a href ="boardList.jsp?pageNum=<%=i%>"> <%=i%> </a>
<%
}
//다음
if(endPage < pageCount){
%>
<a href ="boardList.jsp?pageNum=<%=startPage+pageBlock%>"> 다음 </a>
<%
}
%>
</div>
<%

}
%>

3. BoardDAO.java에 getBoardCount() 메서드생성

BoardDAO.java에 getBoardCount() 메서드 생성

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 int getBoardCount(){

int count = 0;

try {
//디비연결
getCon();
//sql작성, pstmt
sql = "select count(*) from itwill_board";
pstmt = con.prepareStatement(sql);
//실행 -> rs저장
rs = pstmt.executeQuery();
//데이터처리
if(rs.next()){
count = rs.getInt(1); // 데이터가 없으면 null이고 return 0값이 된다.
//count = rs.getInt("count(*)"); 위와 동일한 결과
System.out.println("게시판 글 갯수 확인 :"+ count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDB();
}
return count;
}//getBoardCount닫기

4. BoardDAO.java에 getBoardList() 메서드생성

BoardDAO.java에 getBoardList() 메서드 생성

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
//DB에서 게시글 전체 가져오는 메서드 구현
public ArrayList getBoardList(){
//가변길이 배열 생성
ArrayList boardList = new ArrayList();

try {
//1. 디비연결
getCon();
//2. sql작성, pstmt
//sql = "select * from itwill_board";
//정렬(최신글이 가장 위쪽으로 보이게) : re_ref(그룹번호) 내림차순
sql = "select * from itwill_board order by re_ref desc";
pstmt = con.prepareStatement(sql);
//3. 실행 -> rs저장
rs = pstmt.executeQuery();
//4. 데이터처리
//정보의 갯수가 몇개인지 모르기때문에 while 반복문을 사용
while(rs.next()){
//4-1.BoardBean 객체생성해서 그 안에 rs데이터 저장
BoardBean bb = new BoardBean();
bb.setBno(rs.getInt("bno"));
bb.setContent(rs.getString("content"));
bb.setDate(rs.getDate("date"));
bb.setFile(rs.getString("file"));
bb.setIp(rs.getString("ip"));

bb.setName(rs.getString("name"));
bb.setPw(rs.getString("pw"));
bb.setRe_lev(rs.getInt("re_lev"));
bb.setRe_ref(rs.getInt("re_ref"));
bb.setRe_seq(rs.getInt("re_seq"));

bb.setReadcount(rs.getInt("readcount"));
bb.setSubject(rs.getString("subject"));
//여기까지가 한 행의 데이터를 저장한 것임. while로 모든 행을 반복

//가변배열(ArrayList)에 위의 데이터 저장
//즉 배열 한칸에 회원 1명의 정보를 저장함.
boardList.add(bb); //업캐스팅
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDB();
}
return boardList;
}//getBoardcontent닫기

5. 페이징처리 : BoardDAO.java에 getBoardList(int startRow, int pageSize) 오버로딩 메서드 만들기

getBoardList(int startRow, int pageSize) 오버로딩 메서드만들고 sql구문 변경하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//DB에서 게시글 전체 가져오는데 페이징처리한 메서드 구현 (메서드 오버로딩)
public ArrayList getBoardList(int startRow, int pageSize){
//가변길이 배열 생성
ArrayList boardList = new ArrayList();

try {
//1. 디비연결
getCon();
//2. sql작성, pstmt
//게시판의 데이터 목록중에서 10개씩 정렬해서 가져오기
//re_ref(그룹번호) 내림차순 + re_seq(답글순서결정)오름차순으로 정렬
//데이터 짤라서 가져오기 limit 시작행-1, 페이지갯수 => 해당 위치부터 개수만큼 가져오기
sql = "select * from itwill_board order by re_ref desc, re_seq asc"
+"limit ?,?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, startRow-1);
pstmt.setInt(2, pageSize);
//3. 실행 -> rs저장
rs = pstmt.executeQuery();

while(rs.next())이후로 getBoardList()와 동일
}
}