23.04.27

이준영·2023년 4월 27일
0
post-custom-banner

답변글 게시판 만들기

  1. 글에 대한 답글(Reply 형 게시판)
    • 모글 답글(리스트에서 작업)

=> 알고리즘 이해

기존의 테이블 수정해서 여러 개 컬럼 구현
seq = 글순서(글번호)

(ex.. 컬럼 이름 꼭 이렇게 안 써도 됨)
grp - 글그룹(글->답글->답글 ... = 모글)
grps - 글그룹 내의 순서
grpl - 글그룹 내의 깊이(글->답글이 얼마나 있는지에 대한 깊이)

이 3가지 컬럼으로 답글 만듦

  1. 모글

    grp : seq 와 동일

    grps : 무조건 0

    grpl : 무조건 0

  2. 답글

    grp : 모글 / 부모글의 grp 따라감

    grps : 부모글(뷰)과 같은 grp 그룹 내부에서
    1. 부모글의 grps보다 큰 grps는 무조건 + 1
    2. 자신은 부모글의 grps + 1

    grpl : 부모글의 grpl + 1


1. seq = grp 값 똑같이 집어넣기 작업

last_insert_id()를 이용 (자동증가된(auto적용된 seq) 값 가져오는 항목)

(저장용)
insert into rep_board values (0, 1, 0, 0, '제목', '이름', 'test@test.com', '1234', '내용', '0', '000.000.000.000', now());

에러날 수 있어 완전 깨끗한 테이블 상태에서 실행해줘야 함


증가된 값 볼 수 있음


그 후 list1.jsp에서 sql 바꿔주기!

오름 내림차순 적용해준 것

=String sql = "select seq, subject, writer, date_format(wdate, '%Y-%m-%d') wdate, 
        hit from rep_board order by grp desc, grps asc";		

2. write1_ok.jsp 작업

sql문 변경(rep_board 컬럼들)

//grp grps grpl 추가한 것 (각각 last_insert_id()+1, 0, 0 추가한 것임)
String sql = "insert into rep_board values (0, last_insert_id()+1, 0, 0, ?, ?, ?, 
?, ?, 0, ?, now())";


seq = 모글 grp인 것 확인할 수 있음


3. 답글 작업(view)

3_1 . 답글쓰기 버튼 생성( reply1.jsp로 이동할 것)

<input type="button" value="답글쓰기" class="btn_write btn_txt01" style="cursor: pointer;" 
onclick="location.href='board_reply1.jsp?seq =<%=seq %>'" /> // seq 해줘야함!

4.답글 작업2(reply1.jsp)

4_1. request로 seq 추가 후 hidden으로 보내줄 input 하나 생성

<%
	request.setCharacterEncoding("utf-8");

	String seq = request.getParameter("seq");
%>

...

		<input type="hidden" name="seq" value="<%=seq %>" />

4_2. reply1_ok.jsp 작업

부모글의 대한 정보 얻기 위하여 resultset 추가

sql에 부모글에 대한 정보와, 같은 그룹의 grps보다 큰 grps +1 시키는 구문, grp grps grpl 추가 구문 추가

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="javax.naming.Context"  %>
<%@ page import="javax.naming.InitialContext"  %>
<%@ page import="javax.naming.NamingException"  %>

<%@ page import="javax.sql.DataSource" %>

<%@ page import="java.sql.Connection"  %>
<%@ page import="java.sql.PreparedStatement"  %>
<%@ page import="java.sql.ResultSet"  %>
<%@ page import="java.sql.SQLException"  %>

<%
	request.setCharacterEncoding("utf-8");

	//부모글의 seq
	String seq = request.getParameter("seq");

	String subject = request.getParameter("subject");
	String writer = request.getParameter("writer");
	
	String mail = "";
	if(!request.getParameter("mail1").equals("") && !request.getParameter("mail2").equals("")) { 
		mail = request.getParameter("mail1") + "@" + request.getParameter("mail2");
	}
	String password = request.getParameter("password");
	String content = request.getParameter("content");
	
	String wip = request.getRemoteAddr();
	
	/*
	System.out.println(subject);
	System.out.println(writer);
	System.out.println(mail);
	System.out.println(password);
	System.out.println(content);
	System.out.println(wip);
	*/
	
	Connection conn = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	
	//  0이면 정상 / 1이면 비정상
	int flag = 1;
	
	try { 
		Context initCtx = new InitialContext();
		Context envCtx = (Context)initCtx.lookup("java:comp/env");
		
		DataSource dataSource = (DataSource)envCtx.lookup("jdbc/mariadb3");
		
		conn = dataSource.getConnection();
		
		// seq 통하여 부모글에 대한 정보
		String sql = "select grp, grps, grpl from rep_board where seq = ?";
		
		pstmt = conn.prepareStatement(sql);
		
		pstmt.setString(1, seq);
		
		rs = pstmt.executeQuery();
		
		int grp = 0;
		int grps = 0;
		int grpl = 0;
		
		if(rs.next()) {
			grp = rs.getInt("grp");
			grps = rs.getInt("grps");
			grpl = rs.getInt("grpl");
		}
		
		//같은 그룹의 grps보다 큰 grps +1 시키는 구문
		sql = "update rep_board set grps=grps+1, where grp=? and grps>?";
		
		pstmt = conn.prepareStatement(sql);
		
		pstmt.setInt(1, grp);
		pstmt.setInt(2, grps);
		
		pstmt.executeUpdate();
		
		//grp, grps, grpl 추가
		sql = "insert into rep_board values (0, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, now())";
		pstmt = conn.prepareStatement(sql);
		

		pstmt.setInt(1, grp);
		pstmt.setInt(2, grps + 1);
		pstmt.setInt(3, grpl + 1);
		
		pstmt.setString(4, subject);
		pstmt.setString(5, writer);
		pstmt.setString(6, mail);
		pstmt.setString(7, password);
		pstmt.setString(8, content);
		pstmt.setString(9, wip);
		
		int result = pstmt.executeUpdate();
		
		if(result == 1) {
			flag = 0;
		}
		else {
			System.out.println("실패");			
		}
		
		} catch(NamingException e) {
			System.out.println("[에러] : " + e.getMessage());		
		} catch(SQLException e) {
			System.out.println("[에러] : " + e.getMessage());
		} finally {
			if(pstmt != null) try { pstmt.close(); } catch(SQLException e) {} 
			if(conn != null) try { conn.close(); } catch(SQLException e) {} 			
}
	//jsp코드로 자바스크립트로 만들기 위함
	out.println("<script type='text/javascript'>");
	if(flag == 0) {
		out.println("alert('답글쓰기에 성공')");
		out.println("location.href='board_list1.jsp'");
	}
	else {
		out.println("alert('답글쓰기에 실패')");		
		out.println("history.back()");		
	}
	out.println("</script>");	
%>


브라우저와 똑같은 구조인 것을 확인


5. 들여쓰기 해주기 (list1.jsp 작업)

grpl 이용하여 들여쓰기
1. sql에 grpl 추가
2. rs.next 부분에 반복문으로 공백줘서 부모글과 답글 나누기 + 답글 아이콘 달아주기

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="javax.naming.Context"  %>
<%@ page import="javax.naming.InitialContext"  %>
<%@ page import="javax.naming.NamingException"  %>

<%@ page import="javax.sql.DataSource" %>

<%@ page import="java.sql.Connection"  %>
<%@ page import="java.sql.PreparedStatement"  %>
<%@ page import="java.sql.ResultSet" %>
<%@ page import="java.sql.SQLException" %>


<%
	Connection conn = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	
	
	int totalRecord = 0;
	
	StringBuilder sbHtml = new StringBuilder();
	
	try {
		Context initCtx = new InitialContext();
		Context envCtx = (Context)initCtx.lookup("java:comp/env");
		
		DataSource dataSource = (DataSource)envCtx.lookup("jdbc/mariadb3");
		
		conn = dataSource.getConnection();
		
		//뒤에 정렬 확인
		String sql = "select seq, grpl, subject, writer, date_format(wdate, '%Y-%m-%d') wdate, hit from rep_board order by grp desc, grps asc";		
		pstmt = conn.prepareStatement(sql);
		
		
		rs = pstmt.executeQuery();
		
		//맨 마지막으로 rs커서 이동
		rs.last();
		//그 행 값을 얻음
		totalRecord = rs.getRow();
		//다시 커서를 돌려놓음
		rs.beforeFirst();
		
		while(rs.next()) {
			String seq = rs.getString("seq");

			int grpl = rs.getInt("grpl");
			String strGrpl = "";
			//공백 grpl개수만큼 누적 (부모글과 답글 나누기 위함)
			for(int j = 1; j <=grpl; j++) {
				strGrpl += "&nbsp;";
			}
			
			String subject = rs.getString("subject");
			String writer = rs.getString("writer");
			String wdate = rs.getString("wdate");
			String hit = rs.getString("hit");
			
			wdate = wdate.substring(0, 10);
			
			
			//db에서 데이터를 받아서 쓸 때마다 리스트 목록에서 그대로 보여주는 코드
			sbHtml.append("<tr>");
			sbHtml.append("<td>&nbsp;</td>");
			sbHtml.append("<td>" + seq + "</td>");
			//board 쪽 해석 : a기능의 board 부분을 클릭했을 때 seq의 seq 번호값을 가지고 가라 라는 뜻
			sbHtml.append("<td class='left'>");
			//답글에 이미지 넣어주기( 위치 확인!, 제목 앞에다 써주기 때문에 저 자리인 것임)
			if(grpl != 0 ) {
				sbHtml.append( strGrpl + "<img src='../../images/icon_re1.gif' />");
			}
			sbHtml.append("<a href='board_view1.jsp?seq=" + seq + "'>" + subject + "</a>&nbsp;<img src='../../images/icon_new.gif' alt='NEW'></td>");
			sbHtml.append("<td>" + writer + "</td>");
			sbHtml.append("<td>" + wdate + "</td>");
			sbHtml.append("<td>" + hit + "</td>");
			sbHtml.append("<td>&nbsp;</td>");
			sbHtml.append("</tr>");
		}
		
	} catch(NamingException e) {
		System.out.println("[에러] : " + e.getMessage());		
	} catch(SQLException e) {
		System.out.println("[에러] : " + e.getMessage());
	} finally {
		if(rs != null) try { rs.close(); } catch(SQLException e) {} 
		if(pstmt != null) try { pstmt.close(); } catch(SQLException e) {} 
		if(conn != null) try { conn.close(); } catch(SQLException e) {} 			
	}
	
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="../../css/board.css">
</head>

<body>
<!-- 상단 디자인 -->
<div class="con_title">
	<h3>게시판</h3>
	<p>HOME &gt; 게시판 &gt; <strong>게시판</strong></p>
</div>
<div class="con_txt">
	<div class="contents_sub">
		<div class="board_top">
			<div class="bold"><span class="txt_orange"><%=totalRecord %></span></div>
		</div>

		<!--게시판-->
		<div class="board">
			<table>
			<tr>
				<th width="3%">&nbsp;</th>
				<th width="5%">번호</th>
				<th>제목</th>
				<th width="10%">글쓴이</th>
				<th width="17%">등록일</th>
				<th width="5%">조회</th>
				<th width="3%">&nbsp;</th>
			</tr>
<!-- 내용 시작 -->
<%=sbHtml %>
<!-- 내용 끝 -->
			</table>
		</div>	

		<div class="btn_area">
			<div class="align_right">
				<input type="button" value="쓰기" class="btn_write btn_txt01" style="cursor: pointer;" onclick="location.href='board_write1.jsp'" />
			</div>
		</div>
		<!--//게시판-->
	</div>
</div>
<!--//하단 디자인 -->

</body>
</html>


	

6. 삭제시 주의!!!

(삭제 수정 방법은 기존과 동일)

주의!!

특정 모글 삭제하면 답글이 위로 올라가기 된다.
그래서 보통 모글 삭제하지 않고 작성자에 의해 삭제되었다 << 이런 식으로 삭제가 아닌 수정을 하고 못읽게 하는 것


  1. 글에 대한 댓글(Comment형 게시판)
    • 뷰에서 표현(뷰에 들어가서 댓글 다는 것이므로)



내장 객체(기본 객체)

out
request
(위 두 개가 가장 중요)

response
session
application
...

response : redirect - 자동 이동

<%
	//jsp 식
	// redirect = 자동 이동
	response.sendRedirect("https://www.daum.net");
    
    ->실행시 다음으로 이동
    
    
    //js 식 + 알림을 넣어줄 수 있다(ex=  alert)
	out.println("<script type='text/javascript>");
	out.println("location.href='http://www.daum.net';");
	out.println("<script>");
%>

jsp / js는 실행 방식이 다르다 (참고)

JSP 변환과 실행

  1. .jsp로 코드 작성

  2. 클라이언트로부터 요청 들어오면 jsp파일 자바 소스로 변환

  3. 실행시 소스의 자바파일 컴파일 되어(클래스 파일) 실행

  4. 실행 파일 서블릿 컨테이션에 의해 서블릿으로 동작

  5. 변환, 컴파일 == 최초요청, jso 변경시에만 사용

이클립스는 아파치톰캣 복사해서 metadata 안의 폴더에서 가져와서 실행

경로
C:\Java\jsp-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina
\localhost\JSPEx01\org\apache\jsp

아파치에서 실행

경로
C:\Java\apache-tomcat-9.0.74\work\Catalina\localhost\ROOT\org\apache\jsp

진짜 중요!

1. 웹 브라우저에서 웹 서버로 요청을 전송.
2. 웹 서버는 동적 컨턴츠를 위해서 웹 컨테이너에게 요청을 다시 전달.
(tomcat에서는 서블릿 컨테이너에서 jsp파일에 관한 작업은 Jasper를 이용해서 처리하지 않을까 생각함.)
3. 웹 컨테이너에서 요청받은 jsp파일을 Servlet으로 변환. (.java 파일로 변환)
4. .java파일을 컴파일 해서 .class 생성.
5. 결과를 웹 컨테이너로 전달.
6. 그 결과를 웹 컨테이너는 웹 서버로 반환하고, 웹 서버는 웹 브라우저에게 응답.
7. .class 파일은 jsp파일이 처음 컴파일 이후로 변경되지 않는 이상은 기존의 .class 파일을 이용해서 서비스.

2.2 처리결과 전송시 - 바로 넘어가는 것이 아닌, 안에 버퍼라는 공간이 있고 out.println은 그 버퍼를 통해 출력됨




out : buffer

버퍼 크기와 남은 크기 확인 가능

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" buffer="1kb" %> -> buffer="1kb" -> 1kb크기로 확인한 것

<%
	out.println("버퍼 크기 : " + out.getBufferSize() + "<br>");
	out.println("버퍼 남은 크기 : " + out.getRemaining() + "<br>");
%>

flush

버퍼가 다 찼을 때, 버퍼에 쌓인 데이터를 실제로 출력되어야 할 곳에 전송하고
버퍼를 비우는 것

#autoFlush속성
true : 버퍼가 다 차면 버퍼를 플러시하고 계속해서 작업 진행
false : 버퍼가 다 차면 익셉션을 발생시키고 작업 x
디폴트값 : true

남은 크기 알아보기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" buffer="1kb" autoFlush="true" %>
    
buffer="1kb" autoFlush="true"  -> 버퍼 제어 구문(버퍼 크기 조절, autoFlush는 false면 출력 x, true면 띄움
명시되어 있지 않아도 기본적으로 버퍼는  8kb의 autoFlush속성은 true로 설정되어있다

<%
for(int i = 1; i<100; i++) {
		out.println(i + "Hello Jsp<br>");
		
		if(i % 50 == 0 ) {
			out.println("버퍼 남은 크기 : " + out.getRemaining() + "<br>");
		}
	}
%>



out의 메서드

<%
	out.println(out.getRemaining() + "<br>");
	out.println("1<br>");
	out.println("2<br>");
	out.println("3<br>");
	
	//누적된 버퍼 지움(출력 표시 안됨)
	out.clearBuffer();
	out.println(out.getRemaining() + "<br>");

	out.println("4<br>");
	out.println("5<br>");
	out.println("6<br>");
	
	//출력을 하고 버퍼를 비움
	out.flush();
	out.println(out.getRemaining() + "<br>");
	
	out.println("7<br>");
	out.println("8<br>");
	
	// 스크립트 강제 종료
	out.close();
	
	out.println("9<br>");
	out.println("10<br>");
%> 



pageContext

pageContext.getOut

사용하는 메서드를 원하는 것으로 바꿀 수 있음

<%
	out.println("Hello JSP<br>");

	//out.println을 바꿈
	JspWriter writer = pageContext.getOut();
	writer.println("Hello JSP<br>");
%>

include

해당 페이지를 가져온다.


include.jsp


-- include 이전<br>
<%
	//지정된 페이지 
	//pageContext.include("./include1/include.jsp");

	//지정한 경로로 페이지 이동
	pageContext.forward("./include1/include.jsp");
%>
-- include 이후<br>


pageContext.forward

지정한 경로로 페이지 이동

-- include 이전<br>
<%
	//지정된 페이지 
	//pageContext.include("./include1/include.jsp");

	//지정한 경로로 페이지 이동
	pageContext.forward("./include1/include.jsp");
%>
-- include 이후<br>




표준 액션 태그 : include

jsp 책(362 그림 참조)

액션 태그를 이용해서 include 구현할 수도 있다.

<body>
-- include 이전<br>

<jsp:include page="./include1/include.jsp"></jsp:include>

-- include 이후<br>
</body>

실행 결과 위 include와 동일
include 사용 방법 (종류)
	1. a -> b = a+b => compile   ( <% include file = "b"> )
    = <%@ include
    			프로그램적인 포함
                소스/ 변수 선언시 주로 사용
                
                
    2. a -> b = a
    			b => 출력 결과가 결합 (jsp:include page="b")
                (지금은 2번째 케이스, 클래스가 두개 나옴)
    = <jsp: include 
    			디자인적인 포함

a를 실행 시키고, 중간에 b를 실행시켜서 결과를 가지고 a로 와서 실행시킨다.



jsp:param : 데이터 전달하기

<jsp:param 을 사용하여 값을 보내고 request로 읽어올 수 있다.

include2에서 include 데이터 가져와서 출력하기

include.jsp

<body>
-- include 이전<br>
<%
	int i = 2;
%>
<jsp:include page="./include1/include2.jsp">
	<!-- include2 넘어갈 때 이 데이터 가져간다. -->
	<jsp:param name="data1" value="value1" />  <-- value1 전달
	<jsp:param name="data2" value="<%=i %>" />  <-- i 데이터 전달
</jsp:include>

-- include 이후<br>
</body>

include2.jsp

<%
	//출력만 보냄
	out.println("include.jsp<br>");
	out.println("data1 : " + request.getParameter("data1") + "<br>");
	out.println("data1 : " + request.getParameter("data2") + "<br>");
%>



include 또 다른 방법 : <%@ include

<body>
<%@ include file="include1/include.jsp" %>
</body>


기본에서 안에 합쳐지는 효과( 하나에 파일이 둘로 합쳐지는 경우 )


따라서 아까와 다르게 데이터 전달 없이 출력이 된다.

include2.jsp
<body>
<%
	int i = 2;
%>
<%@ include file="include1/include3.jsp" %>
</body>

include3.jsp

에러가 생기나, include2에서 실행해보면 나온다.

에러를 없애려면 include3.jspf로 만들어준다.




jsp:foward

pageContext.forward와 동일



foward.jsp


이렇게도 사용 가능 (결과 동일)

-- forward 이전
<%
	RequestDispatcher dispatcher = request.getRequestDispatcher("./foward1/foward.jsp");
	dispatcher.forward(request, response);
%>
-- forward 이후



클래스 공통부분 추출하여 가져다놓고 활용 (TO / DAO)

클래스 만들어서 클래스 호출

JSP  - model (DAO / TO)

JSP ---> TO(=java beans) ---> DAO ---> DB  /   TO -> DAO 이 부분 model이라고 함

절차

1.패키지 무조건 만들고(default 개념 없음) 새로고침 하기!!(그래야 안으로 들어간다)


  1. MemberTO class 생성

  1. src->weeapp에 jsp file 만들고 MemberTO import + set / get으로 TO 데이터 가져오기
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="pack1.MemberTO" %>

<%
	MemberTO to = new MemberTO();
	to.setId("tester");
	to.setPassword("1234");
	
	out.println( to.getId() + "<br>");
	out.println( to.getPassword() + "<br>");
%>


액션 태그 활용하여 TO 데이터 사용

jsp:useBean : 액션 태그로 사용 (인스턴스 객체 사용)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="to" class="pack1.MemberTO">
<%
	to.setId("tester");
	to.setPassword("1234");

	out.println( to.getId() + "<br>");
	out.println( to.getPassword() + "<br>");
%>
</jsp:useBean>

jsp:setProperty로 set도 액션 태그 사용

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="to" class="pack1.MemberTO">
<jsp:setProperty name="to" property="id" value="tester" />
<jsp:setProperty name="to" property="password" value="1234" />
<%

out.println( to.getId() + "<br>");
out.println( to.getPassword() + "<br>");

%>
</jsp:useBean>

jsp:getProperty로 get도 액션 태그 사용


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="to" class="pack1.MemberTO" />
<jsp:setProperty name="to" property="id" value="tester" />
<jsp:setProperty name="to" property="password" value="1234" />
<jsp:getProperty name="to" property="id" />
<jsp:getProperty name="to" property="password" />

결과는 모두 동일

액션 태그들을 썼다고 해서 TO에 필드변수(Private ~~) 를 건드릴 수 없다.
getter / setter 사용하여 가져오는 것


실행하면 getter가 출력되는 것을 볼 수 있다.



메일 만들기


  1. 프로젝트 생성해서 lib에 api 2개 넣기 (activation.jar / mail.jar


  1. src/main/java에 mail 패키지 (com.exam.mail) 가져오기
  1. webapp -> jsp 생성 (mail.jsp) 후 import 시키고 App class 내용 가져오기

메일 실행해보기!

profile
끄적끄적
post-custom-banner

0개의 댓글