회원제 게시판
session 기반의 인증 (authentication)
1. 권한, 인가 (authorization)
/list.do 글목록 누구나 접근 가능
/view.do 글조회 로그인만 하면 조회 가능
/write.do 글작성 ROLE_MEMBER 권한 있는 사람만 가능.
/update.do 글수정 ROLE_MEMBER, 작성자만 가능
/delete.do 글삭제 ROLE_MEMBER, 작성자만 가능
회원 , 게시글 의 relation
1:N 관계,
ERD
DDL
샘플데이터
ERD 작성
user 테이블과 1:N 관계의 게시판 테이블 생성
기존 쿼리문에서 테이블명, 컬럼명 수정하기

글목록
'누구나' 접근 가능한 글 목록 페이지 부터 작성하기
특정 user id 값의 User 정보 읽어오기 준비
D.java 에 필요한 쿼리 작성
UserDAO 의 함수 작성
WriteDTO 도 수정
기존 name 대신 UserDTO 로 수정.
package domain;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import lombok.Data;
import lombok.NoArgsConstructor;
//DTO : Data Transfer Object
//DAO 등과 연동하여 데이터를 실어 나르는 객체
//필요한 객체(entity) 만큼 작성
@Data
@NoArgsConstructor
public class WriteDTO {
private int uid; // uid
private String subject; // subject
private String content; // content
private UserDTO user; // user_id (FK)
private int viewCnt; // viewcnt
private LocalDateTime regDate; // regdate
// 웹개발시...
// 가능한, 다음 3가지는 이름을 일치시켜주는게 좋습니다.
// 클래스 필드명 = DB 필드명 = form의 name명
// LocalDateTime 을 String 으로 리턴하는 getter
public String getRegDateTime() {
if(this.regDate == null) return "";
return this.regDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
}
} // end DTO
WriteDAO 수정
buildList() 외.
package domain;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import common.D;
//DAO : Data Access Object
//특정 데이터 리소스(ex: DB) 에 접속하여 트랜잭션등을 전담하는 객체
//데이터 리소스별로 작성하거나,
//혹은 기능별로 작성가능 (ex: 게시판용 DAO, 회원관리용 DAO, ...)
public class WriteDAO {
Connection conn;
PreparedStatement pstmt;
Statement stmt;
ResultSet rs;
// DAO 객체가 생성될때 Connection 로 생성된다.
public WriteDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
// System.out.println("WriteDAO 생성, 데이터베이스 연결!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} // end 생성자
// DB 자원 반납 메소드
public void close() throws SQLException {
// 리소스 해제
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(pstmt != null) pstmt.close();
if(conn != null) conn.close();
} // end close()
// 새글 작성 <-- DTO
public int insert(WriteDTO dto) throws SQLException {
int cnt = 0;
String subject = dto.getSubject();
String content = dto.getContent();
UserDTO user = dto.getUser(); // 글 작성자 (로그인 한 사용자)
int uid; // auto-generated keys 값 (wr_uid 컬럼값)
// auto-generated 컬럼
String [] generatedCols = {"uid"};
// 트랜잭션 실행
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT, generatedCols);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setInt(3, user.getUid()); // FK
cnt = pstmt.executeUpdate();
if(cnt > 0){
// auto-generated 값 뽑아오기
rs = pstmt.getGeneratedKeys();
if(rs.next()){
uid = rs.getInt(1);
dto.setUid(uid); // DTO 에 autogenerated key 값 set
}
}
} finally {
close();
}
return cnt;
} // end insert()
// 글 목록을 읽어와서
// ResultSet --> List<DTO> 로 리턴
private List<WriteDTO> buildList(ResultSet rs) throws SQLException {
List<WriteDTO> list = new ArrayList<>();
while(rs.next()){
int uid = rs.getInt("write_uid");
String subject = rs.getString("write_subject");
String content = rs.getString("write_content");
if(content == null) content = "";
int viewcnt = rs.getInt("write_viewcnt");
LocalDateTime t = rs.getObject("write_regdate", LocalDateTime.class);
String regdate = t.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
// user_id 의 User 정보 가져오기
UserDTO user = UserDTO.builder()
.uid(rs.getInt("user_uid"))
.username(rs.getString("user_username"))
.password(rs.getString("user_password"))
.name(rs.getString("user_name"))
.authorities(rs.getString("user_authorities"))
.regdate(rs.getObject("user_regdate", LocalDateTime.class))
.build()
;
WriteDTO dto = new WriteDTO();
dto.setUid(uid);
dto.setUser(user); // 글 작성자 User 세팅
dto.setSubject(subject);
dto.setContent(content);
dto.setViewCnt(viewcnt);
dto.setRegDate(t);
list.add(dto);
}
return list;
}
// 전체 SELECT
public List<WriteDTO> select() throws SQLException {
List<WriteDTO> list = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT);
rs = pstmt.executeQuery();
list = buildList(rs);
} finally {
close();
}
return list;
} // end select()
// 특정 uid 글 하나 SELECT + 조회수 증가 : view.jsp
// viewcnt 로 +1 증가해야 하고, 글 하나 읽어와야 한다, 트랜잭션 처리
// -> List<DTO> 로 리턴
public List<WriteDTO> readByUid(int uid) throws SQLException{
int cnt = 0;
List<WriteDTO> list =null;
try {
// 트랜잭션 처리
conn.setAutoCommit(false);
// 1. 조회수 증가
pstmt = conn.prepareStatement(D.SQL_WRITE_INC_VIEWCNT);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
// ※ cnt 결과값에 따른 처리 필요
pstmt.close();
// 2. uid 의 글 읽어오기 쿼리
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
list = buildList(rs); // 글 하나 --> List<>
conn.commit();
} catch(SQLException e) {
conn.rollback(); // 예외 발생하면 rollback
throw e;
} finally {
close();
}
return list;
} // end readByUid()
// 특정 uid 의 글 하나 SELECT --> List<DTO> 로 리턴
public List<WriteDTO> selectByUid(int uid) throws SQLException {
List<WriteDTO> list = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
list = buildList(rs);
} finally {
close();
}
return list;
} // end selectByUid()
// 특정 uid 의 글 수정 <- DTO
public int update(WriteDTO dto) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_UPDATE);
pstmt.setString(1, dto.getSubject());
pstmt.setString(2, dto.getContent());
pstmt.setInt(3, dto.getUid());
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end update()
// 특정 uid 글 삭제하기
public int deleteByUid(int uid) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_DELETE_BY_UID);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
}
} // end DAO
WriteCommand 수정
글 작성시 현재 로그인 한 사람으로 INSERT 되게 하기.
package command.write;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import command.Command;
import common.C;
import domain.UserDTO;
import domain.WriteDAO;
import domain.WriteDTO;
public class WriteCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int cnt = 0;
// 입력한 값 받아오기
String subject = request.getParameter("subject");
String content = request.getParameter("content");
// ※ 파라미터 유효성 검증
// 현재 로그인 한 사용자 정보
UserDTO user = (UserDTO)request.getSession().getAttribute(C.PRINCIPAL);
WriteDTO dto = new WriteDTO();
dto.setUser(user);
dto.setSubject(subject);
dto.setContent(content);
WriteDAO dao = new WriteDAO();
try {
cnt = dao.insert(dto);
} catch (SQLException e) {
e.printStackTrace();
}
request.setAttribute("result", cnt);
request.setAttribute("dto", dto); // auto-generated key (uid)
}
}
list.jsp 수정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%-- JSTL 버젼으로 바뀌니, import 의 번잡함도 사라진다! JAVA 변수 선언도 사라진다! --%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script>
<title>목록</title>
</head>
<body>
<%-- 인증 헤더 --%>
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="container mt-3">
<h2>목록</h2>
<hr>
<table class="table table-hover">
<thead class="table-success">
<tr>
<th>UID</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
<c:forEach var="dto" items="${list }">
<tr>
<td>${dto.uid }</td>
<td><a href="view.do?uid=${dto.uid }">${dto.subject }</a></td>
<td>${dto.user.username }</td>
<td>${dto.viewCnt }</td>
<td>${dto.regDateTime }</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="row">
<c:if test="${not empty sessionScope.PRINCIPAL }">
<div class="col-12">
<a class="btn btn-outline-dark" href="write.do">작성</a>
</div>
</c:if>
</div>
</div>
</body>
</html>
'JSP' 카테고리의 다른 글
[JSP] FileUpload / Download (0) | 2022.04.11 |
---|---|
[JSP] Pagination (0) | 2022.04.11 |
[JSP] Authentication - 로그인/로그아웃 (0) | 2022.04.10 |
[JSP] Authentication - 회원가입 (0) | 2022.04.07 |
[JSP] JSTL(JSP Standard Tag Library) (0) | 2022.04.06 |