35일차(1)/jsp(21) : 게시판 목록 보기, 새 글 작성, 글 상세보기 기능 구현
- 글 목록 보기 (list.jsp)
- 새 글 작성하기 (insertform.jsp, insert.jsp)
- 글 상세보기 (detail.jsp)
- table.sql에 이런 내용을 추가해주고, 실제 DB에서도 테이블을 생성한다.
<index.jsp>에 게시판 링크추가
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//session scope에 id라는 키값으로 저장된 값이 있는지 읽어와 본다.(없으면 null)
String id=(String)session.getAttribute("id");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/index.jsp</title>
</head>
<body>
<div class="container">
<%if(id != null) {%>
<p>
<a href="${pageContext.request.contextPath }/users/private/info.jsp"><%=id %></a>님 로그인중....
<a href="${pageContext.request.contextPath }/users/logout.jsp">로그아웃</a>
</p>
<%}else{ %>
<a href="${pageContext.request.contextPath }/users/loginform.jsp">로그인</a>
<%} %>
<h1>인덱스 페이지입니다.</h1>
<ul>
<li><a href="${pageContext.request.contextPath }/users/signup_form.jsp">회원가입</a></li>
<li><a href="${pageContext.request.contextPath }/private/study.jsp">회원전용공간(공부)</a></li>
<li><a href="${pageContext.request.contextPath }/private/game.jsp">회원전용공간(게임)</a></li>
<li><a href="file/list.jsp">자료실</a></li>
<li><a href="cafe/list.jsp">글목록보기</a></li>
</ul>
</div>
</body>
</html>
/cafe/ <list.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/cafe/list.jsp</title>
</head>
<body>
<div class="container">
<a href="${pageContext.request.contextPath }/cafe/private/insertform.jsp">새글 작성</a>
<h3>카페 글 목록입니다.</h3>
<table>
<thead>
<tr>
<th>글번호</th>
<th>작성자</th>
<th>제목</th>
<th>조회수</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</body>
</html>
<a href="${pageContext.request.contextPath }/cafe/private/insertform.jsp">새글 작성</a>
- 새 글 작성은 회원만 할 수 있도록! private 폴더 안에 생성해준다.
- 제목을 누르면 글 자세히 보기로 이동하게 만들 예정
- loginfilter에 " /cafe/private/* " 도 추가하기.
- test.cafe.dto / test.cafe.dao 패키지 생성
<CafeDto>
package test.cafe.dto;
public class CafeDto {
private int num;
private String writer;
private String title; //글제목
private String content; //글내용
private int viewCount; //조회수
private String regdate;
//페이징 처리할때 필요한 필드
private int startNum;
private int endRowNum;
//생성자
public CafeDto() {}
public CafeDto(int num, String writer, String title, String content, int viewCount, String regdate, int startNum,
int endRowNum) {
super();
this.num = num;
this.writer = writer;
this.title = title;
this.content = content;
this.viewCount = viewCount;
this.regdate = regdate;
this.startNum = startNum;
this.endRowNum = endRowNum;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
public String getRegdate() {
return regdate;
}
public void setRegdate(String regdate) {
this.regdate = regdate;
}
public int getStartNum() {
return startNum;
}
public void setStartNum(int startNum) {
this.startNum = startNum;
}
public int getEndRowNum() {
return endRowNum;
}
public void setEndRowNum(int endRowNum) {
this.endRowNum = endRowNum;
}
}
<CafeDao> - getData, getList, insert 메소드
package test.cafe.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.cafe.dto.CafeDto;
import test.util.DbcpBean;
public class CafeDao {
private static CafeDao dao;
/*
* static 메소드는 생성자를 호출하지 않고 클래스명ㅇ로 바로 호출을 하기 때문에
* 메소드 호출전에 무언가 준비작업을 하고 싶다면 static 블럭 안에서 하면 된다.
* static 블럭은 해당 클래스를 최초로 사용할때 한번만 실행되기 때문에
* 초기화 작업을 하기에 적당한 블럭이다.
*/
static {
if(dao==null) {
dao=new CafeDao();
}
}
private CafeDao() {}
public static CafeDao getInstance() {
return dao;
}
//글 하나의 정보를 리턴해주는 메소드
public CafeDto getData(int num) {
//필요한 객체를 담을 지역변수를 미리 만들어둔다.
CafeDto dto=null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool에서 Connection 객체를 하나 얻어온다.
conn = new DbcpBean().getConn();
//실행할 sql문의 뼈대 구성하기
String sql = "SELECT writer, title, content, viewCount, regdate"
+ " FROM board_cafe"
+ " WHERE num=?";
//sql문의 ?에 바인딩할게 있으면 한다.
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, num);
//SELECT문을 수행하고 결과값을 받아온다.
rs = pstmt.executeQuery();
//반복문 돌면서 resultSet에서 필요한 값을 얻어낸다.
if (rs.next()) {
dto=new CafeDto();
dto.setNum(num);
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setContent(rs.getString("content"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setRegdate(rs.getString("regdate"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection Pool에 Connection 반납하기
} catch (Exception e2) {
}
}
return dto;
}
//글 목록 리턴하기
public List<CafeDto> getList() {
//회원 목록을 담을 객체 생성
List<CafeDto> list = new ArrayList<>();
//필요한 객체를 담을 지역변수를 미리 만들어둔다.
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool에서 Connection 객체를 하나 얻어온다.
conn = new DbcpBean().getConn();
//실행할 sql문의 뼈대 구성하기
String sql = "SELECT num, writer, title, viewCount, regdate"
+ " FROM board_cafe"
+ " ORDER BY num DESC";
//sql문의 ?에 바인딩할게 있으면 한다.
pstmt = conn.prepareStatement(sql);
//SELECT문을 수행하고 결과값을 받아온다.
rs = pstmt.executeQuery();
//반복문 돌면서 resultSet에서 필요한 값을 얻어낸다.
while (rs.next()) {
CafeDto dto=new CafeDto();
dto.setNum(rs.getInt("num"));
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setRegdate(rs.getString("regdate"));
//CafeDto 객체의 참조값을 List 에 누적 시키기
list.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection Pool에 Connection 반납하기
} catch (Exception e2) {
}
}
return list;
}
//새글을 저장하는 메소드
public boolean insert(CafeDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = "INSERT INTO board_cafe"
+ " (num, writer, title, content, viewCount, regdate)"
+ " VALUES(board_cafe_seq.NEXTVAL, ?, ?, ?, 0, SYSDATE)";
pstmt = conn.prepareStatement(sql);
//?에 바인딩
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getTitle());
pstmt.setString(3, dto.getContent());
//INSERT or UPDATE or DELETE문을 수행하고 수정,삭제,추가된 row의 개수 리턴
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e2) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
}
- static 블럭은 클래스가 최초로 사용될때 한번만 호출된다.
- 위에서는 static {} 상태로만 작성해도 된다.
- new를 한번만 만들어서 사용하기 위해서 작성!
- private 폴더 생성.
/cafe/private/<insertform.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/cafe/private/insertform.jsp</title>
</head>
<body>
<div class="container">
<h3>새글 작성 폼입니다.</h3>
<form action="insert.jsp" method="post">
<div>
<label for="title">제목</label>
<input type="text" name="title" id="title" />
</div>
<div>
<label for="content">내용</label>
<textarea name="content" id="content" rows="10" /></textarea>
</div>
<button type="submit">저장</button>
</form>
</div>
</body>
</html>
- input, textarea 요소에서 name 을 빠뜨리지 않도록 유의하기...
- 간단하게 만들어진 폼. 버튼을 누르면 제출된다.
- 글 목록보기 기능 구현
<CafeDao>에 메소드 추가 (insert, getList)
//글 목록 리턴하기
public List<CafeDto> getList() {
//회원 목록을 담을 객체 생성
List<CafeDto> list = new ArrayList<>();
//필요한 객체를 담을 지역변수를 미리 만들어둔다.
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool에서 Connection 객체를 하나 얻어온다.
conn = new DbcpBean().getConn();
//실행할 sql문의 뼈대 구성하기
String sql = "SELECT num, writer, title, viewCount, regdate"
+ " FROM board_cafe"
+ " ORDER BY num DESC";
//sql문의 ?에 바인딩할게 있으면 한다.
pstmt = conn.prepareStatement(sql);
//SELECT문을 수행하고 결과값을 받아온다.
rs = pstmt.executeQuery();
//반복문 돌면서 resultSet에서 필요한 값을 얻어낸다.
while (rs.next()) {
CafeDto dto=new CafeDto();
dto.setNum(rs.getInt("num"));
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setRegdate(rs.getString("regdate"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection Pool에 Connection 반납하기
} catch (Exception e2) {
}
}
return list;
}
//새글을 저장하는 메소드
public boolean insert(CafeDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = "INSERT INTO board_cafe"
+ " (num, writer, title, content, viewCount, regdate)"
+ " VALUES(board_cafe_seq.NEXTVAL, ?, ?, ?, 0, SYSDATE)";
pstmt = conn.prepareStatement(sql);
//?에 바인딩
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getTitle());
pstmt.setString(3, dto.getContent());
//INSERT or UPDATE or DELETE문을 수행하고 수정,삭제,추가된 row의 개수 리턴
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e2) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
- viewCount 조회수는 초기값을 0으로 넣어준다.
- 아니면 테이블 생성시에 디폴트값을 0으로 지정할 수도있다.
List<CafeDto> list = new ArrayList<>();
- CafeDto type을 담을 수 있는 제너릭 리스트
CafeDto dto=new CafeDto();
- 글의 개수만큼 new되어야 한다. 그래서 while문 안에 있다. 필요한 객체를 어디서 생성하느냐도 중요!
<insert.jsp>
<%@page import="test.cafe.dto.CafeDto"%>
<%@page import="test.cafe.dao.CafeDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//폼 전송되는 내용을 추출해서
String title=request.getParameter("title");
String content=request.getParameter("content");
//CafeDto 에 담고
CafeDto dto=new CafeDto();
dto.setTitle(title);
dto.setContent(content);
//글 작성자는 로그인된 아이디(세션영역에 저장된 id값)
String writer=(String)session.getAttribute("id");
dto.setWriter(writer);
//DB에 저장하기
boolean isSuccess=CafeDao.getInstance().insert(dto);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>insert.jsp</title>
</head>
<body>
<div class="container">
<% if(isSuccess){%>
<p>
새글을 저장했습니다.
<a href="${pageContext.request.contextPath }/cafe/list.jsp">확인</a>
</p>
<%}else{%>
<p>
게시물 작성 실패!
<a href="insertform.jsp"></a>
</p>
<%}%>
</div>
</body>
</html>
- 새 글을 저장하는 메소드. 작성자를 로그인된 id(session에 저장된 값)로 매칭시켜주는 것에 유의!
- textarea는 입력할때 개행기호(\r\n)도 입력을 받는다.
- 여러 줄을 입력받을 수 있는 입력도구는 대부분 개행기호를 인식한다.
- 글 내용 상세보기
- 제목 부분에 링크를 걸어서 자세히 보기(content) 기능을 추가한다!
cafe/<detail.jsp>
<%@page import="test.cafe.dao.CafeDao"%>
<%@page import="test.cafe.dto.CafeDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//자세히 보여줄 글의 번호를 읽어온다.
int num=Integer.parseInt(request.getParameter("num"));
//DB에서 해당 글의 정보를 읽어와서
CafeDto dto=CafeDao.getInstance().getData(num);
//응답한다.
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cafe/detail.jsp</title>
</head>
<body>
<div class="container">
<h3>글 상세 보기</h3>
<table>
<tr>
<th>글번호</th>
<td><%=dto.getNum() %></td>
</tr>
<tr>
<th>작성자</th>
<td><%=dto.getWriter() %></td>
</tr>
<tr>
<th>제목</th>
<td><%=dto.getTitle() %></td>
</tr>
<tr>
<th>조회수</th>
<td><%=dto.getViewCount() %></td>
</tr>
<tr>
<th>작성일</th>
<td><%=dto.getRegdate() %></td>
</tr>
<%--
textarea를 이용해서 문자열을 입력받으면 tab기호, 공백, 개행기호도 같이 입력받는다.
해당 기호를 재현하는 방법은 세가지가 있는데
1. textarea에 출력하기
2. <pre></pre> 요소안에 출력하기
3. 개행기호를 찾아서 <br>로 대체하기
--%>
<tr>
<th>내용</th>
<td colspan="2">
<div><%=dto.getContent() %></div>
</td>
</tr>
</table>
<%
//로그인된 아이디가 있으면 읽어온다(null 일수도 있다)
String id=(String)session.getAttribute("id");
%>
<%-- 만일 글 작성자가 로그인된 아이디와 같다면 수정, 삭제 링크를 제공한다. --%>
<%if(dto.getWriter().equals(id)) {%>
<a href="private/updateform.jsp?num=<%=dto.getNum()%>">수정</a>
<a href="javascript:" onclick="deleteConfirm()">삭제</a>
<script>
function deleteConfirm(){
const isDelete=confirm("이 글을 삭제 하겠습니까?");
if(isDelete){
location.href="private/delete.jsp?num=<%=dto.getNum()%>";
}
}
</script>
<%} %>
</div>
</body>
</html>
<a href="detail.jsp?num=<%=tmp.getNum() %>"><%=tmp.getTitle() %></a>
- 제목을 클릭했을때, 자세히 보여줄 글 번호를 넘겨주어야한다.(get방식 전송)
<td><%=dto.getContent() %></td>
- 다른 내용과 동일하게 이렇게 넣으면 입력창 안의 개행기호가 무시된다.
** 개행기호를 처리하는 방법이 3가지 있다.
1. textarea에 출력하기
2. <pre></pre> 요소안에 출력하기
3. 개행기호를 찾아서 <br>로 대체하기
<td><textarea rows="10"><%=dto.getContent() %></textarea></td>
- textarea는 value 속성이 따로 없다. 이렇게 끼워넣어서 작성하면 된다.
- 'readonly' 를 넣어주면 읽기 전용으로 작성할 수 있다.(커서가 들어가지 않는다)
<td><pre><%=dto.getContent() %></pre></td>
- pre 요소를 사용하면 이렇게 작성된다. 사이에 끼워넣기!
- textarea와 pre 요소를 비교해본 것!
'국비교육(22-23)' 카테고리의 다른 글
35일차(3)/jsp(23) : 게시판 조회수 기능, 페이징 처리 기능 구현 (0) | 2022.11.27 |
---|---|
35일차(2)/jsp(22) : 게시판 SmartEditor 적용 / 글 수정, 삭제 기능 구현 (0) | 2022.11.27 |
34일차(2)/jsp(20) : 회원 프로필 이미지 등록, 수정 기능 구현 (0) | 2022.11.25 |
34일차(1)/jsp(19) : fetch, ajax 함수 (0) | 2022.11.24 |
33일차(4)/javascript : Promise (0) | 2022.11.24 |