👉 톰캣은 다쓰고 나면 꼭 서버 종료를 잘하자

인터넷도 다 종료하고 톰캣을 다시 켜야한다.

프로그래밍에서 1 = 참 0 = 거짓

 

🎉 게시판 만들기

이 코드는 통으로 그냥 외워라.

 

프로그램 만드는 두가지 방식 : 모델 1방식, 모델 2방식

모델 1방식 → 코드 다 한 곳에

모델 2방식 → 코드를 여러 곳에 분산, 로직 분리 (유지보수에 유리)

 

게시판 만들기는 모델 1방식으로 코딩 후 모델 2방식으로 바꿔본다.

 


DB 는 DAO 와, DTO는 List.jsp와 연결되어 동작한다.

페이징 기능까지 추가하면 모델 1 방식으로 게시판 만들기는 끝이 난다.

하면서 오류가 많이 나서 오류코드를 찾느라 메모를 많이 못했다..

하루하루 그날 배운 것을 정리하곤 하지만 이번에는 한번에 정리하는 것이 더 효율적으로 기억할 수 있을 것 같아 한 곳에 정리해본다.

파일이 많아지고 기능이 분산되며 효율적인 정리의 중요성을 깨닫는다..

 

그동안 했던 것을 생각나는대로 나열해보면

  1. SQL 디벨로퍼에서 테이블 만들고 데이터 넣기, 커밋
  2. DB에서 정보를 가지고 오는 DAO, 각 파일과 DAO(DB) 연결을 도와줄 DTO 만들기
  3. 목록보기(List.jsp) 만들고 게시글 목록을 DB에서 가지고 와 보여주기
  4. 목록에서 내용, 제목으로 글찾기 기능 구현
  5. 로그인 폼 연결, DB에서 로그인 아이디가 일치하는지 확인, 불일치 시 알려주기
  6. 로그인 성공 시 글쓰기 가능, 로그인 실패 시 글쓰기 기능 이용 불가
  7. 글쓰기 화면 만들기, 저장해서 게시목록에 올리기까지
  8. 글쓰기 화면에서 다시쓰기, 목록으로 돌아가기 버튼 구현
  9. 로그인 정보가 일치하면 게시글 상세보기도 가능
  10. 게시글 상세보기 화면 만들기
  11. 게시글 상세보기에서 해당 글 작성자의 경우 글 수정 가능하게 하기
  12. 해당 글 작성자인지 알아보기 위해 기능 만들기
  13. 해당 글 작성자 글 수정, 삭제하기(삭제하기 아직 미완. 0627 완료)
  14. 페이징기능 (한 페이지에 10개, 아래 쪽에 번호 나열, 해당번호에 맞는 10개의 글 노출)

정도 된다.

 

정리하며 순서는 바뀔 수도 있다.

생각해보면 이렇게 했어도 ‘회원 삭제, 회원 정보 수정, 글 임시저장’ 등등 추가적으로 구현할 수 있는게 정말 많은 것 같다. 그래서 사실상 정말 이 코드는 기본 중의 기본인듯.

 

모델 1 방식임에도 만든 파일이 꽤 많다.

  1. BoardDAO.java
  2. BoardDTO.java
  3. List.jsp
  4. Edit.jsp
  5. EditProcess.jsp
  6. IsLoggedIn.jsp
  7. DeleteProcess.jsp
  8. View.jsp
  9. Write.jsp
  10. WriteProcess.jsp

나열된 순서는 만든 순서와 무관하다.

이젠 구현화면과 코드로 하나씩 살펴보겠다.


 

🌀 데이터 베이스 연결

 

SQL 디벨로퍼에서 테이블 만들고 데이터 넣기, 커밋

-- 회원정보를 가지고 있는 member테이블, 게시판 글 정보를 가지고 있는 board테이블 생성

create table member (
id varchar2(10) not null,
pass varchar2(10) not null,
name varchar2(30) not null,
regidate date default sysdate not null,
primary key(id)
);

create table board (
num number primary key,
title varchar2(200) not null,
content varchar2(2000) not null,
id varchar2(10) not null,
postdate date DEFAULT sysdate not null,
visitcount number(6)
);

alter table board
add constraint board_mem_fk foreign key (id)
REFERENCES member(id);

-- 시퀀스 객체
create sequence seq_board_num
increment by 1
start with 1
minvalue 1;

-- member에 회원정보 데이터 넣기
insert into member (id, pass, name) values ('musthave', '1234', '머스트해브');

-- board에 글 데이터 넣기
insert into board (num, title, content, id, postdate, visitcount) 
   values (seq_board_num.nextval, '제목1입니다', '내용1입니다', 'musthave', sysdate, 0);

commit;


-- board에 글 데이터 넣기
insert into board
   values (seq_board_num.nextval, '지금은 봄입니다', '봄의왈츠', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 여름입니다', '여름향기', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 가을입니다', '가을동화', 'musthave', sysdate, 0);
insert into board
   values (seq_board_num.nextval, '지금은 겨울입니다', '겨울연가', 'musthave', sysdate, 0);      

commit;

회원정보를 가지고 있는 member 테이블과 게시판 글의 정보를 가지고 있는 board 테이블을 만들고 그 안에 데이터를 넣어두었다.

 

DAO, DTO 만들기

💡 DAO (Date Access Object) : 직접 DB에 접근하며 data를 삽입, 삭제, 조회 등 조작
💡 DTO (Data Transfer Object) : 로직을 가지지 않는 데이터 객체, 계층 간 데이터 교환
을 위한 Java Bean을 의미한다.

→ Java Bean 이란 특정한 정보를 가지고 있는 클래스를 표현하는 하나의 규칙. 데이터를 표현하기 위해 사용한다.

 

BoardDTO.java

package model1.board;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardDTO {
private String num;
private String title;
private String content;
private String id;
private java.sql.Date postDate;
private String visitcount;
private String name; // 로그인했을 떄 필요한 이름 member 테이블에도 접근할 수 있어야 한다
}

 

BoardDAO.java

package model1.board;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import common.JDBConnect;
import jakarta.servlet.ServletContext;

public class BoardDAO extends JDBConnect {

	public BoardDAO(ServletContext application) {
		super(application);
	}

	// 1. 검색 조건에 맞는 게시물의 개수를 반환합니다.
	public int selectCount(Map<String, Object> map) {

		int totalcount = 0;

		// 복잡한 쿼리문은 오류날 확률이 높으므로 디벨로퍼에서 미리 실행해보고 옮기는 것이 좋다.
		String query = " select count(*) from board ";

		// searchWord를 선택하면 이름, 내용으로 분류해서 count 해줘야 한다.
		if (map.get("searchWord") != null) {
			query += " where " + map.get("searchField") + "" + " like '%" + map.get("searchWord") + "%'";

			// where title like '%제목%';
		}

		try {

			psmt = con.prepareStatement(query);
			rs = psmt.executeQuery();

			if (rs.next()) {
				totalcount = rs.getInt(1);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return totalcount;
	}

	// 2. 검색 조건에 맞는 게시물 목록을 반환합니다.
	public List<BoardDTO> selectList(Map<String, Object> map) {

		List<BoardDTO> bbs = new ArrayList<>();

		String query = " select * from board ";

		if (map.get("searchWord") != null) {
			query += " where " + map.get("searchField") + " like '%" + map.get("searchWord") + "%'";
		}

		query += " order by num desc ";

		try {

			psmt = con.prepareStatement(query);
			rs = psmt.executeQuery();

			while (rs.next()) {
				// 이 정보들을 DTO에 넣어준다
				BoardDTO dto = new BoardDTO();
				// DB 컬럼명
				dto.setNum(rs.getString("num"));
				dto.setTitle(rs.getString("title"));
				dto.setContent(rs.getString("content"));
				dto.setPostDate(rs.getDate("postdate"));
				dto.setId(rs.getString("id"));
				dto.setVisitcount(rs.getString("visitcount"));

				// DTO는 가장 최근의 정보만 읽어온다.
				// 읽어와서 DTO에 담긴 정보를 다른 곳에 저장해야 목록을 볼 수 있다.
				// collection ArayList()에 저장
				bbs.add(dto);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		// 목록 데이터가 담긴 bbs를 리턴한다.
		return bbs;
	}

	// 3. 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).

	// 4. 게시글 데이터를 받아 DB에 추가합니다.
	// 실제 데이터를 insert할 수 있는 기능
	public int insertWrite(BoardDTO dto) {

		// insert 구문이 들어갔는지 확인
		int result = 0;

		String query = " insert into board " + " (num, title, content, id, visitcount) "
				+ " values (seq_board_num.nextval,?,?,?,0) ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getTitle());
			psmt.setString(2, dto.getContent());
			// 로그인한 ID 받아오기 -> session 영역의 정보를 받아온다
			psmt.setString(3, dto.getId());

			result = psmt.executeUpdate();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	// 5. 지정한 게시물을 찾아 내용을 반환합니다.
	public BoardDTO selectView(String num) {

		BoardDTO dto = new BoardDTO();

		String query = " select B.*, M.name " + " from member M inner join board B " + " on M.id = B.id"
				+ " where num = ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, num);
			rs = psmt.executeQuery();

			if (rs.next()) {

				dto.setNum(rs.getString(1));
				dto.setTitle(rs.getString(2));
				dto.setContent(rs.getString("content"));
				dto.setPostDate(rs.getDate("postdate"));
				dto.setId(rs.getString("id"));
				dto.setVisitcount(rs.getString(6));
				dto.setName(rs.getString("name"));

				// System.out.println("kkkkkk : " + dto.getId());

			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return dto;

	}

	// 6. 지정한 게시물의 조회수를 1 증가시킵니다.
	public void updateVisitCount(String num) {

		String query = " update board " + " set visitcount = visitcount + 1 " + " where num = ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, num);
			psmt.executeUpdate();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 7. 지정한 게시물을 수정합니다.
	public int updateEdit(BoardDTO dto) {

		int result = 0;

		String query = " update board " + " set title = ? , content = ? " + " where num = ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getTitle());
			psmt.setString(2, dto.getContent());
			psmt.setString(3, dto.getNum());

			result = psmt.executeUpdate();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	// 8. 지정한 게시물을 삭제합니다.
	public int deletePost(BoardDTO dto) {

		int result = 0;

		String query = " delete from board where num = ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getNum());
			
			result = psmt.executeUpdate();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

}

이곳에 게시판에 쓸 기능을 다 모아두었다.

 


🌀 게시판 목록

 

목록보기(List.jsp) 만들고 게시글 목록 보여주기

  1. 목록보기(List.jsp) 만들고 게시글 목록을 DB에서 가지고 와 보여주기
  2. 목록에서 내용, 제목으로 글찾기 기능 구현

 

List.jsp

<%@page import="model1.board.BoardDAO"%>
<%@page import="model1.board.BoardDTO"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
// DB에 연결
BoardDAO dao = new BoardDAO(application);

// form에서 액션 속성 생략 -> 자기 자신 페이지를 파라매터로 받는다. 
String searchField = request.getParameter("searchField");
String searchWord = request.getParameter("searchWord");

Map<String, Object> param = new HashMap<>();

// 검색조건으로 검색하려 할때
if (searchWord != null) {
	param.put("searchField", searchField);
	param.put("searchWord", searchWord);
}

// 전체 개수 구하기 selectCount()
// 검색 했을 때 개수 dao.selectCount(param)
// boardLists 에 DTO의 정보가 들어있다.
int totalCount = dao.selectCount(param);
List<BoardDTO> boardLists = dao.selectList(param);
dao.close();

%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:include page="../Common/Link.jsp" />
	<h2>목록 보기(List)</h2>

	<!-- 폼태그에 action 속성이 생략되면 자신의 현재 페이지를 요청한다. (List.jsp)-->
	<form method="get">
		<table border="1" width="90%">
			<tr>
				<td align="center">
				<select name="searchField">
						<option value="title">제목</option>
						<option value="content">내용</option>
				</select> 
				<input type="text" name="searchWord" /> 
				<input type="submit" value="검색하기" />
				</td>
			</tr>
		</table>
	</form>

	<table border="1" width="90%">
		<tr>
			<th width="10%">번호</th>
			<th width="50%">제목</th>
			<th width="15%">작성자</th>
			<th width="10%">조회수</th>
			<th width="15%">작성일</th>
		</tr>


		<!-- 게시물이 없을 떄 -->
		<% if (boardLists.isEmpty()) {%>

		<tr>
			<td colspan="5" align="center">등록된 게시물이 없습니다^^*</td>
		</tr>

		<% }else{

		int virtualNum = 0;
		for(BoardDTO dto : boardLists){ 
			virtualNum = totalCount--;
		%>

		<!-- 게시물이 있을 때 -->
		<tr align="center">
		<!-- DTO에서 쓴 이름과 같게 -->
			<%-- <td><%= dto.getNum() %></td> --%>
			<td><%= virtualNum %></td>
			<td>
			<a href="View.jsp?num=<%= dto.getNum() %>"> <%= dto.getTitle() %> </a>

			</td>
			
			
			<td><%= dto.getId() %></td>
			<td><%= dto.getVisitcount() %></td>
			<td><%= dto.getPostDate() %></td>
		</tr>

		<%
		 } // for문 
		} // if else문
		%>

	</table>

	<table border="1" width="90%">
		<tr>
			<td align="right">
				<button type="button" onclick="location.href='write.jsp'">글쓰기</button>
			</td>
		</tr>
	</table>
</body>
</html>

DB에서 게시글 데이터를 읽어온다.

form으로 제목,내용으로 게시글을 검색할 수 있는 검색바를 만들고

table에 게시글 목록이 보여지게 화면을 구성했다.

 

폼태그에 action 속성이 생략되었으므로 페이지 이동 없이 현재 페이지에서 검색된 결과를 보여준다.


 

🌀 로그인 인증과 글 게시

  1. 로그인 폼 연결, DB에서 로그인 아이디가 일치하는지 확인, 불일치 시 알려주기
  2. 로그인 성공 시 글쓰기 가능, 로그인 실패 시 글쓰기 기능 이용 불가
  3. 글쓰기 화면 만들기, 저장해서 게시목록에 올리기까지
  4. 글쓰기 화면에서 다시쓰기, 목록으로 돌아가기 버튼 구현

 

IsLoggedIn.jsp

<%@page import="utils.JSFunction"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!--  로그인 유무를 판단 -->
<%
if (session.getAttribute("UserId") == null){
	JSFunction.alertLocation("로그인 후 이용해주세요.", "../Session/LoginForm.jsp", out);
	return;
}
%>

 

JSFunction

package utils;

import jakarta.servlet.jsp.JspWriter;

public class JSFunction {
	// location.href = "페이지 경로" -> 특정페이지 지정
	// history.back(), history.forward() -> 뒤로가기, 앞으로 가기

	public static void alertLocation(String msg, String url, JspWriter out) {
		try {
			String script = ""
					+ "<script>"
					+ "alert('" + msg + "');" // alert('hello')
					+ "location.href = '" + url + "'"
					+ "</script>";
			
			out.print(script);
					
		}catch(Exception e) {
			
		}
	}

	public static void alertBack(String msg, JspWriter out) {
		try {
			String script = ""
					+ "<script>"
					+ "alert('" + msg + "');"
					+ "history.back();"
					+ "</script>";
					
			out.print(script);
			
		}catch(Exception e) {
			
		}

	}
}

 

게시판 설계도를 보면 어디로 이동을 하든 로그인 유무를 체크한다.

<%@ include file ="./IsLoggedIn.jsp"%>

때문에 위와 같이 함수를 만들어두고 로그인 유무 체크를 하는 사이트마다 페이지 속성 지정을 해준다.

 

 

로그인 성공 시 글 쓰고, 올리기 기능

 

유효성 검사)

더보기
<!-- 유효성 검사 -->
<script>
function validateForm(form){
	if (form.title.value == ""){
		alert("제목을 입력하세요");
		form.title.focus();
		return false;
	}
	
	if (form.content.value == ""){
		alert("내용을 입력하세요");
		form.content.focus();
		return false;
	}
}
</script>

 (이미지)

 

로그인 성공 후 글쓰고 작성완료하면 게시글 목록에 글이 올라가고, DB에도 잘 전달이 되었는지 확인해본다.

 

write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	<!-- 공통관심사항 -->
	<%@ include file ="./IsLoggedIn.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- 유효성 검사 -->
<script>
function validateForm(form){
	if (form.title.value == ""){
		alert("제목을 입력하세요");
		form.title.focus();
		return false;
	}
	
	if (form.content.value == ""){
		alert("내용을 입력하세요");
		form.content.focus();
		return false;
	}
}
</script>
</head>
<body>
	<jsp:include page="../Common/Link.jsp" />
	<h2>회원제 게시판 - 글쓰기(Write)</h2>


	<form name="writeFrm" method="post" action="WriteProcess.jsp"
		onsubmit="return validateForm(this);">
		<table bordar="1" width="90%">
			<tr>
				<td>제목</td>
				<td><input type="text" name="title" style="width: 90%;" /></td>
			</tr>

			<tr>
				<td>내용</td>
				<td><textarea name="content" style="width: 90%; height: 100px;"></textarea>
				</td>
			</tr>

			<tr>
				<td colspan="2" align="center">
					<button type="submit">작성 완료</button>
					<button type="reset">다시 입력</button>
					<button type="button" onclick="location.href='List.jsp';">
						목록 보기</button>
						</td>
			</tr>

		</table>
	</form>
</body>
</html>

 

WriteProcess.jsp

작성한 글을 DB와 연결해 DB에 전달해준다.

<%@page import="model1.board.BoardDTO"%>
<%@page import="model1.board.BoardDAO"%>
<%@ include file ="./IsLoggedIn.jsp"%>
<%@page import="utils.JSFunction"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
// 타이틀과 컨텐츠를 파라메터로 받는다.
String title = request.getParameter("title");
String content = request.getParameter("content");

// DTO의 데이터를 묶어서 DAO로 보낸다.
// 서버 -> DTO -> DAO -> DB
// 서버 <- DTO <- DAO

BoardDTO dto = new BoardDTO();

dto.setTitle(title);
dto.setContent(content);
dto.setId((String)session.getAttribute("UserId"));

// DAO에 데이터를 삽입하는 기능 추가
// DB에 연결
BoardDAO dao = new BoardDAO(application);
int result = dao.insertWrite(dto);
dao.close(); 

if(result > 0){
	// 성공했을 때 페이지 이동
	response.sendRedirect("List.jsp");
}else{
	// 실패 시 이전 페이지로 
	JSFunction.alertBack("글쓰기에 실패하였습니다.", out);
}

%>

 

 

글쓰기 폼을 만들고 작성완료, 다시입력, 목록보기 버튼을 만들었다.

 

글을 쓰고 나면 DB에도 잘 반영이 되는 것을 볼 수 있다.

 


 

🌀 게시글 상세보기, 수정 및 삭제

  1. 로그인 정보가 일치하면 게시글 상세보기도 가능
  2. 게시글 상세보기 화면 만들기
  3. 게시글 상세보기에서 해당 글 작성자의 경우 글 수정 가능하게 하기
  4. 해당 글 작성자인지 알아보기 위해 기능 만들기
  5. 해당 글 작성자 글 수정, 삭제하기(삭제하기 아직 미완. 0627 완료)

 

게시글 상세보기

 

View.jsp

어떤 글을 상세화면으로 보고, 수정하고 삭제할지 알기 위해 글의 번호(num)를 받는다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ include file="./IsLoggedIn.jsp"%>
<%@page import="model1.board.BoardDTO"%>
<%@page import="model1.board.BoardDAO"%>

<%
String num = request.getParameter("num");
BoardDAO dao = new BoardDAO(application);

// 글에 대한 상세보기 -> 조회수 증가 처리
dao.updateVisitCount(num);

// 상세정보 보기
BoardDTO dto = dao.selectView(num);
%>


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script>

function deletePost(){
	let confirmed = confirm("정말로 삭제하시겠습니까?");
	
	if(confirmed){
		let form = document.writeFrm; // 이름이 writeFrm인 폼 선택
		// 입력 폼에 값이 없지만 post 방식으로 넘긴다
		form.method = "post"; // 전송 방식
		form.action = "DeleteProcess.jsp"; // 전송 경로
		// 객체 = 기능 + 속성
		form.submit(); // 폼값전송
		
	}
}

</script>
</head>

<body>
<%@ include file ="./IsLoggedIn.jsp"%>
<h2>회원제 게시판 - 상세보기(View)</h2>
	<form name="writeFrm">
	<input type="hidden" name="num" value="<%=num %>">

		<table border="1" width="90%">
		
			<tr>
				<td>번호</td>
				<td><%=dto.getNum()%></td>
				<td>작성자</td>
				<td><%=dto.getName()%></td>
			</tr>
			
			<tr>
				<td>작성일</td>
				<td><%=dto.getPostDate()%></td>
				<td>조회수</td>
				<td><%=dto.getVisitcount()%></td>
			</tr>
			
			<tr>
			<td>제목</td>
			<td colspan="3"><%= dto.getTitle() %></td>
			</tr>
			
			<tr>
			<td>내용</td>
			<!-- 줄바꿈이 안되어 저장되기 때문에 강제 줄바꿈을 해줘야 한다 -->
			<td colspan="3" height="100px"><%= dto.getContent().replace("\r\n", "<br/>") %></td>
			</tr>
			
			<tr>
			<td colspan="4" align ="center">
			<!-- 글을 작성한 사람이 아니라면 수정하기, 삭제하기 버튼 안보이게 -->
			<%
			if (session.getAttribute("UserId") != null
			&& session.getAttribute("UserId").toString().equals(dto.getId())) {
				
			%>
			<button type = "button" onclick="location.href = 'Edit.jsp?num=<%= dto.getNum() %>'">수정하기</button>
			<button type = "button" onclick="deletePost()">삭제하기</button>
			
			<% } %>
			<button type = "button" onclick="location.href = 'List.jsp'">목록보기</button>
			</td>
			</tr>
		</table>
		
	</form>
</body>

</html>

 

게시글 상세화면으로 가기 위한 링크가 생긴다.

 

😞 질문 input type= “hidden” 인 이유

<input type="hidden" name="num" value="<%=num %>">

<input type="hidden" > 은 사용자에게는 보이지 않는 숨겨진 입력 필드를 정의한다. 

숨겨진 입력 필드는 렌더링이 끝난 웹페이지에서는 전혀 보이지 않으며 페이지 콘텐츠 내에서도 보게 만들 방법이 없다. 

폼 제출 시 사용자가 변경해서는 안되는 데이터를 전달할 때 유용하게 쓰인다. -> num 과 같은 PK 값, 업데이트 되야 하는 데이터 베이스 레코드 값, 고유한 보안 토큰 등을 서버로 보낼 때 주로 사용 

 

글 수정, 삭제하기

 

Edit.jsp

해당 글 작성자인지 확인하고 해당 글 작성자라면 글을 수정하고 삭제할 수 있게 해준다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ include file="./IsLoggedIn.jsp"%> 
<%
   String num = request.getParameter("num");
   
   BoardDAO dao = new BoardDAO(application);
   BoardDTO dto = dao.selectView(num);
   
   String sessionId = session.getAttribute("UserId").toString();
   
   System.out.println(sessionId);
   System.out.println(dto.getId());
   System.out.println(dto.getNum());
   
   if(!sessionId.equals(dto.getId())){
      JSFunction.alertBack("작성자 본인만 수정할 수 있습니다.", out);
      return;
   }
   
   dao.close();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>

   //validateForm()
   function validateForm(form) {
      if (form.title.value == "") {
           alert("제목을 입력하세요.");
           form.title.focus();
           return false;
       }
       if (form.content.value == "") {
           alert("내용을 입력하세요.");
           form.content.focus();
           return false;
       }
   }
</script>
</head>
<body>
<%@ include file ="./IsLoggedIn.jsp"%>
   <h2>회원제 게시판 - 수정하기(Edit)</h2>
   <form name="writeFrm" method="post" action="EditProcess.jsp" onsubmit="return validateForm(this);">
   <!-- 값을 추가적으로 지정해서 넘길 때 hidden form -->
   <!-- num, title, content 가 넘어간다. -->
   <input type="hidden" name="num" value="<%=dto.getNum() %>">
   
      <table border="1" width="90%">
         <tr>
            <td>제목</td>
            <td>
               <input type="text" name="title" value="<%= dto.getTitle() %>" />
            </td>
         </tr>
         <tr>
            <td>내용</td>
            <td>
               <textarea name="content" style="width: 90%; height: 100px;"><%=dto.getContent() %></textarea>
            </td>
         </tr>
         <tr>
            <td colspan="2" align="center">
                <button type="submit">작성완료</button>
                <button type="reset">다시입력</button>
                <button type="button" onclick="location.href='List.jsp'">목록보기</button>
            </td>
         </tr>
      </table>
   </form>
</body>
</html>

 

EditProcess.jsp

수정한 글을 DB에 올린다

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page import="utils.JSFunction"%>
<%@ include file="./IsLoggedIn.jsp"%>

<%
String num = request.getParameter("num");
String title = request.getParameter("title");
String content = request.getParameter("content");

BoardDTO dto = new BoardDTO();
dto.setNum(num);
dto.setTitle(title);
dto.setContent(content);

BoardDAO dao = new BoardDAO(application);
int result = dao.updateEdit(dto);
dao.close();

/* 글 올리기 성공했을 때는 상세보기 화면, 실패하면 수정하기 */
if (result > 0){
	/* View 페이지에서 어떤 글을 수정해야 하는지 알기 위해  */
	response.sendRedirect("View.jsp?num=" + dto.getNum());
}else{
	JSFunction.alertBack("수정하기에 실패했습니다", out);
}

%>

 

DeleteProcess.jsp

글을 삭제하고 DB에 연결해 해당 데이터를 삭제한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page import="utils.JSFunction" %>
<%@ include file="./IsLoggedIn.jsp"%> 

<%
String num = request.getParameter("num");

BoardDTO dto = new BoardDTO();
BoardDAO dao = new BoardDAO(application);
dto = dao.selectView(num);

String sessionId = session.getAttribute("UserId").toString();

// 글을 작성한 사람인지 아닌지. 글을 작성한 사람만 게시글을 삭제할 수 있다.
if (sessionId.equals(dto.getId())){
	// 본인 인증 성공, 삭제 처리
	dto.setNum(num);
	int result = dao.deletePost(dto);
	dao.close();
	
	if (result > 0) {
		// 삭제 성공
		JSFunction.alertLocation("삭제되었습니다", "List.jsp", out);
	}else{
		// 삭제 실패 -> 상세 페이지 화면
		JSFunction.alertBack("삭제에 실패했습니다.", out);
	}
	
}else{
	// 본인 인증 실패
	JSFunction.alertBack("본인만 삭제할 수 있습니다.", out);
	return;
}

%>

 


💫 페이징이 된 모습을 보기 위해 Borad를 복사해 PagingBorad 폴더를 만들었다.

 

🌀 페이징

 

페이징 기능 (0627)

더보기

예를 들면 최신순으로 게시글 10개 화면에 노출 후 그 이상으로 글이 있다면

페이지 하단에 [1], [2], [3], [4], [5] 이런식으로 블록을 눌러 나머지 글을 더 볼 수 있게 해준다.

첫번째 페이지 < [1], [2], [3], [4], [5], > 마지막 페이지
첫번째 페이지 < [6], [7], [8], [9], [10], > 마지막 페이지
첫번째 페이지 < [11], [12], [13] > 마지막 페이지로

이런 식으로 총 123개의 글이 있고, 10개 단위로 페이징 기능을 구현한다고 하면 블록 간에 이동 ( < , > )을 할수도 있게 만든다. 추가로 한번에 첫번째 페이지로 이동할 수도 있고 마지막 페이지로 이동할 수도 있다.

글도 10개 단위로 글을 노출할 수도 있고, 5개 단위로 노출할 수도 있다. 또, 사용자의 선택에 따라 10개, 5개 등 선택할 수도 있다.

 

페이징 기능을 위한 변수

  • 한 페이지에 출력할 게시물의 개수

변수 이름 ) POSTS_PER_PAGE = 10

  • 한 화면(블록)에 출력할 페이지 번호 개수

변수 이름 ) PAGES_PER_BLOCK = 5

 

페이징 구현 절차

 

1. 테이블에 저장된 전체 레코드의 개수

ex) 105개

 

2. 각 페이지 별 출력될 게시물의 범위 계산

범위의 시작값 구하는 두가지 방식 : 

1. 범위의 끝 값 - 9
2. (현재 페이지 번호 - 1) * 게시물의 개수 + 1
범위의 끝 값 : 현재 페이지 번호 * POST_PER_PAGE (한 페이지에 출력할 게시물의 개수)

 

3. 전체 페이지 수 구하기

게시물 수 105개

페이지 수 : Math.ceil(105 / POST_PER_PAGE) ⇒ 11

 

4. 이전 페이지 블록 가기

- 현재 1 페이지 일 때

pageTemp = ( (현재 페이지 - 1 ) / PAGES_PER_BLOCK) ) * PAGES_PER_BLOCK + 1

어떤 페이지를 받든 처음 시작되는 번호를 계산한다.

-현재 5 페이지 일 때

pageTemp = ( (5-1) / 5 ) * 5 + 1 ⇒ 1

// 몫을 구하는 것 (예를 들어 4/5 ⇒ 0)

-현재 10 페이지 일 때

pageTemp = ( (10-1) / 5 ) * 5 + 1 ⇒ 6

// 몫을 구하는 것 (예를 들어 9/5 ⇒ 1)

pageTemp - 1 하면 이전 블록의 끝 값이 된다.

 

5. 블록에 페이지 번호 5개 출력하기

pageTemp에 1씩 더하기 한다 ⇒ 1, 2, 3, 4, 5

 

6. 다음 페이지 블럭가기

마지막 pageTemp값에 1을 더하면 다음 블록의 시작값이 구해진다.

 

게시글 데이터 100개를 추가했다.

 

데이터베이스에서

-- 뷰 테이블을 활용한 TOP-N 구하기
-- rownum(의사컬럼) : 조회 시 레코드 순서대로 1번 부터 번호 부여
-- 오라클 시스템에서 제공해주는 컬럼, 테이블에는 없지만 제공 -> 의사컬럼
-- 아무 테이블이나 사용 가능
-- rownum은 order by절보다 먼저 실행된다, 조건절에 사용 시 반드시 1을 포함한 조건식을 만들어야 한다.

-- 인라인 뷰
-- 일회성 가상 테이블
-- 메모리의 부화를 주지 않음 -> 효율성이 높아진다

-- board에 rm 주기
select * from board; 

-- 별칭을 부여해서 고정된 값으로 사용할 수 있게 해준다.
select rownum rm, p.*
from (
select *
from board
order by postdate desc 
) p;


-- 인라인 컬럼으로 쓰면서 실제 테이블에 고정되게 만든다.
-- 최신순으로 1번부터 10번까지 조회하기
select *
from (
select rownum rm, p.*
from (
select *
from board
order by postdate desc
) p
)
where rm between 1 and 10; 


-- 검색 조건에 맞는 게시물 목록 반환
select *
from (
select rownum rm, p.*
from (
select *
from board
where title like '%2%' -- 예를 들어 제목에 2가 포함된 게시글을 검색 
order by postdate desc
) p
)
where rm between 1 and 10;

rownum을 붙이게 되면 1번부터 데이터의 순서가 고정된다.

 

😞 질문 → 번호 부여하는 것에 왜 시퀸스를 안쓰나? 비슷한 거 아닌가??

더보기

시퀸스도 똑같이 번호를 부여하지만 primary key 값을 생성하기 위해 사용된다.

또 시퀸스로 번호를 매길 경우, 중간에 데이터를 지우게 되면 해당 번호 게시글은 삭제됨에도 번호는 재정렬이 되지 않기 때문에 이때는 rownum을 쓰는 것이 적절하다.

 

시퀀스 객체가 사용하는 값은 계속 캐시에 저장되어 있어서 삭제를 해도 되돌리는 것이 불가능하다. (!)

 

그러고 보니 쿠키는 알겠는데 캐시는 뭐지!? 비슷한거같은데 (아님)

→ 캐시(Cache)는 컴퓨터 시스템에서 빠른 데이터 액세스를 가능하게 하는 저장 공간의 한 형태입니다. 이는 자주 사용되는 데이터나 값을 복사해 임시로 저장해 놓는 공간으로, 한 번 저장된 데이터에 대한 요청이 있을 경우 원래의 저장 위치보다 더 빠르게 데이터를 제공하게 됩니다. 이로 인해 시스템의 전체 성능이 향상되고, 데이터에 접근하는 시간이 줄어듭니다.

완전 다른거였다..

쿠키와 캐시의 가장 큰 차이점은 저장 위치와 데이터의 사용 목적입니다. 쿠키는 클라이언트에 저장되어 서버와의 통신에 사용되는 반면, 캐시는 브라우저 내부에 저장되고 페이지 로딩 속도를 향상시키는 데 사용됩니다.

쿠키와 캐시는 모두 웹 애플리케이션의 성능 및 사용자 경험 개선을 위해 사용되는 도구이지만, 쿠키는 사용자 상태 정보를 추적하고 유지하는 데 사용되고, 캐시는 리소스 로딩 속도를 향상시키는 데 사용됩니다.

출처) https://www.inflearn.com/questions/969727/쿠키와-캐시의-차이점이-뭔가요

 

BoardDAO.java 에 추가한 코드)

	// 3. 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).
	public List<BoardDTO> selectListPage(Map<String, Object> map) {
		
		List<BoardDTO> bbs = new ArrayList<>();
		
		String query = " select * "
				+ " from ( "
				+ " select rownum rm, p.* "
				+ " from ( "
				+ " select * "
				+ " from board ";
				
				if (map.get("searchWord") != null) {
					query += " where " + map.get("searchField") + " like '%" + map.get("searchWord") + "%'";
				}
				
				query += " order by num desc "
						+ " ) p "
						+ " ) "
						+ " where rm between ? and ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, map.get("start").toString());
			psmt.setString(2, map.get("end").toString());

		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}

 


0625)

오늘 시험에서 잘 몰랐던 부분

더보기

오라클 null 값 제외하고 값 읽어오기

 

SELECT A컬럼 FROM B테이블 WHERE NOT A컬럼 is NULL;

그냥 머리 속에 아예 not 구문이 삭제되어 있었다..;

 

+ Recent posts