JSP

[JSP] Authentification - 회원제 게시판

shb 2022. 4. 10. 21:07

회원제 게시판
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