반응형
SMALL

게시글 목록 클릭 시 상세페이지 연결하기

게시글 목록을 클릭하면 해당 게시글로 이동하는 기능을 구현해보자.

[ 만들 기능 ]
1. 목록에 있는 게시글 클릭 시 postNo를 넘겨줌
2. 해당 postNo에 해당하는 상세페이지로 이동
3. 해당 상세페이지에 글쓴이의 정보가 위젯에 뜨게 하기

1. 메인페이지에서 게시글 클릭 시 해당 postNo 보내주기

상세보기 페이지로 파라미터 postno를 함께 넘겨준다.

<c:forEach var="postList" items="${postList}">
    <!-- Featured blog post -->
    <div class="card mb-4">
        <div class="card-body">
            <a href="#!"><img class="card-img-top" src="../resources/img/thumbnail/${postList.POST_THUMBNAIL}" alt="..."/></a>
            <div class="small text-muted">${postList.POST_UPLOADTIME}</div>
            <h2 class="card-title">${postList.POST_TITLE} ----- ${postList.MEM_NO}</h2>
            <p class="card-text">${postList.POST_CONTENT}</p>
            <!-- 상세보기 페이지로 파라미터 postno를 함께 넘겨준다. -->
            <a class="btn btn-primary" href="postViewAction.me?postno=${postList.POST_NO}">Read more →</a>
        </div>
    </div>
</c:forEach>

2. 상세페이지에 게시글 내용 출력

부트스트랩 이용(출처 : https://startbootstrap.com/template/blog-post)

부트스트랩으로 가져온 페이지에 게시글 목록 띄운 것과 동일한 방법으로 상세페이지를 띄운다.

1) JSP

<header class="mb-4">
	<!-- Post title-->
	<h1 class="fw-bolder mb-1">${postObj.POST_TITLE}</h1>
	<!-- Post meta content-->
	<div class="text-muted fst-italic mb-2">${postObj.POST_UPLOADTIME} by ${postObj.MEM_NO}</div>
	<!-- Post categories-->
	<a class="badge bg-secondary text-decoration-none link-light" href="#!">Web Design</a>
	<a class="badge bg-secondary text-decoration-none link-light" href="#!">Freebies</a>
</header>
<!-- Preview image figure-->
<figure class="mb-4"><img class="img-fluid rounded" src="../resources/img/thumbnail/${postObj.POST_THUMBNAIL}" alt="..." /></figure>
<!-- Post content-->
<section class="mb-5">
	<p class="fs-5 mb-4">${postObj.POST_CONTENT}</p>
	<p class="fs-5 mb-4">The universe is large and old, and the ingredients for life as we know it are everywhere, so there's no reason to think that Earth would be unique in that regard. Whether of not the life became intelligent is a different question, and we'll see if we find that.</p>
	<p class="fs-5 mb-4">If you get asteroids about a kilometer in size, those are large enough and carry enough energy into our system to disrupt transportation, communication, the food chains, and that can be a really bad day on Earth.</p>
	<h2 class="fw-bolder mb-4 mt-5">I have odd cosmic thoughts every day</h2>
	<p class="fs-5 mb-4">For me, the most fascinating interface is Twitter. I have odd cosmic thoughts every day and I realized I could hold them to myself or share them with people who might be interested.</p>
	<p class="fs-5 mb-4">Venus has a runaway greenhouse effect. I kind of want to know what happened there because we're twirling knobs here on Earth without knowing the consequences of it. Mars once had running water. It's bone dry today. Something bad happened there as well.</p>
</section>
</article>

게시글 리스트와 구분해주려고 postObj라는 이름으로 쓰기로 함.

▼ blogPost.jsp 전체

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="vo.MemberBean"%>
<%@ page import="java.util.*"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 빨간줄 그어지는데 jstl 설치 안해서 그럼. lib에 넣어준다. jsp 확장태그로 c로 쓴다.-->


<!DOCTYPE html>
<html lang="en">
    <head>
    <!-- 부트스트랩 출처 : https://startbootstrap.com/template/blog-home -->
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <meta name="description" content="" />
        <meta name="author" content="" />
        <title>${postObj.POST_TITLE}</title>
        <!-- Favicon-->
       <!-- <link rel="icon" type="image/x-icon" href="assets/favicon.ico" /> -->
        <!-- Core theme CSS (includes Bootstrap)-->
         <link href="../resources/css/mainPage.css" rel="stylesheet" />
    </head>
    <body>
        <!-- Responsive navbar-->
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
            <div class="container">
                <a class="navbar-brand" href="#!">N Blog</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                        <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">About</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">Contact</a></li>
                        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Blog</a></li>
                    </ul>
                </div>
            </div>
        </nav>
        <!-- Page content-->
        <div class="container mt-5">
            <div class="row">
                <div class="col-lg-8">
                    <!-- Post content-->
                    <article>
                        <!-- Post header-->
                        <header class="mb-4">
                            <!-- Post title-->
                            <h1 class="fw-bolder mb-1">${postObj.POST_TITLE}</h1>
                            <!-- Post meta content-->
                            <div class="text-muted fst-italic mb-2">${postObj.POST_UPLOADTIME} by ${postObj.MEM_NO}</div>
                            <!-- Post categories-->
                            <a class="badge bg-secondary text-decoration-none link-light" href="#!">Web Design</a>
                            <a class="badge bg-secondary text-decoration-none link-light" href="#!">Freebies</a>
                        </header>
                        <!-- Preview image figure-->
                        <figure class="mb-4"><img class="img-fluid rounded" src="../resources/img/thumbnail/${postObj.POST_THUMBNAIL}" alt="..." /></figure>
                        <!-- Post content-->
                        <section class="mb-5">
                            <p class="fs-5 mb-4">${postObj.POST_CONTENT}</p>
                            <p class="fs-5 mb-4">The universe is large and old, and the ingredients for life as we know it are everywhere, so there's no reason to think that Earth would be unique in that regard. Whether of not the life became intelligent is a different question, and we'll see if we find that.</p>
                            <p class="fs-5 mb-4">If you get asteroids about a kilometer in size, those are large enough and carry enough energy into our system to disrupt transportation, communication, the food chains, and that can be a really bad day on Earth.</p>
                            <h2 class="fw-bolder mb-4 mt-5">I have odd cosmic thoughts every day</h2>
                            <p class="fs-5 mb-4">For me, the most fascinating interface is Twitter. I have odd cosmic thoughts every day and I realized I could hold them to myself or share them with people who might be interested.</p>
                            <p class="fs-5 mb-4">Venus has a runaway greenhouse effect. I kind of want to know what happened there because we're twirling knobs here on Earth without knowing the consequences of it. Mars once had running water. It's bone dry today. Something bad happened there as well.</p>
                        </section>
                    </article>
                    <!-- Comments section-->
                    <section class="mb-5">
                        <div class="card bg-light">
                            <div class="card-body">
                                <!-- Comment form-->
                                <form class="mb-4"><textarea class="form-control" rows="3" placeholder="Join the discussion and leave a comment!"></textarea></form>
                                <!-- Comment with nested comments-->
                                <div class="d-flex mb-4">
                                    <!-- Parent comment-->
                                    <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                    <div class="ms-3">
                                        <div class="fw-bold">Commenter Name</div>
                                        If you're going to lead a space frontier, it has to be government; it'll never be private enterprise. Because the space frontier is dangerous, and it's expensive, and it has unquantified risks.
                                        <!-- Child comment 1-->
                                        <div class="d-flex mt-4">
                                            <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                            <div class="ms-3">
                                                <div class="fw-bold">Commenter Name</div>
                                                And under those conditions, you cannot establish a capital-market evaluation of that enterprise. You can't get investors.
                                            </div>
                                        </div>
                                        <!-- Child comment 2-->
                                        <div class="d-flex mt-4">
                                            <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                            <div class="ms-3">
                                                <div class="fw-bold">Commenter Name</div>
                                                When you put money directly to a problem, it makes a good headline.
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <!-- Single comment-->
                                <div class="d-flex">
                                    <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                    <div class="ms-3">
                                        <div class="fw-bold">Commenter Name</div>
                                        When I look at the universe and all the ways the universe wants to kill us, I find it hard to reconcile that with statements of beneficence.
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
                <!-- Side widgets-->
                <div class="col-lg-4">
                    <!-- Search widget-->
                    <div class="card mb-4">
                        <div class="card-header">Search</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input class="form-control" type="text" placeholder="Enter search term..." aria-label="Enter search term..." aria-describedby="button-search" />
                                <button class="btn btn-primary" id="button-search" type="button">Go!</button>
                            </div>
                        </div>
                    </div>
                    <!-- Categories widget-->
                    <div class="card mb-4">
                        <div class="card-header">Categories</div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">Web Design</a></li>
                                        <li><a href="#!">HTML</a></li>
                                        <li><a href="#!">Freebies</a></li>
                                    </ul>
                                </div>
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">JavaScript</a></li>
                                        <li><a href="#!">CSS</a></li>
                                        <li><a href="#!">Tutorials</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- Side widget-->
                    <div class="card mb-4">
                        <div class="card-header">Side Widget</div>
                        <div class="card-body">You can put anything you want inside of these side widgets. They are easy to use, and feature the Bootstrap 5 card component!</div>
                    </div>
                </div>
            </div>
        </div>
        <!-- Footer-->
        <footer class="py-5 bg-dark">
            <div class="container"><p class="m-0 text-center text-white">Copyright &copy; Your Website 2022</p></div>
        </footer>
        <!-- Bootstrap core JS-->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
        <!-- Core theme JS-->
     <!--   <script src="js/scripts.js"></script>-->
    </body>
</html>

 

2) Controller

//-------------------- 게시글 상세보기 postViewAction 페이지 생성 ---------------------------				
else if (command.equals("/member/postViewAction.me")) {
    action = new PostViewAction();
    // PostViewAction, 게시글 상세보기 페이지 표시.
    try {
        forward = action.execute(req, resp);
        System.out.println( "게시글 상세보기 표시"))
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

3) Action

그냥 게시글이기 때문에 session은 필요없다. 관리자가 못볼 글들은 아니기 때문에... 파라미터 값을 받아서 서비스로 넘겨준다.

package action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import svc.PostViewService;
import vo.ActionForward;
import vo.PostBean;

/* 인터페이스를 함께 추가했다. 게시글 상세보기 표시를 위한 클래스이다.*/
public class PostViewAction implements Action {

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
		ActionForward forward = null; //어디로 갈지?
			forward = new ActionForward();

			int ClickPostNo = Integer.parseInt(req.getParameter("postno"));
			//URL 주소 뒤에 붙은 쿼리스트링은 getParameter로 가져온다.
			System.out.println("클릭한 포스트 번호: "+ClickPostNo);
	
			PostViewService postViewService = new PostViewService();
			//서비스 svc에서 getPostinfo를 만들어준다. 게시글 번호 보내주자.
			PostBean postObj = postViewService.getPostinfo(ClickPostNo);
			req.setAttribute("postObj", postObj);
			forward.setPath("./blogPost.jsp");

		return forward;
	}
}

4) Service

DB연결해서 커넥션 풀 열고 닫기

package svc;
import static db.JdbcUtil.close;
import static db.JdbcUtil.getConnection;
import java.sql.Connection;
import DAO.PostDAO;
import vo.PostBean;


/* 게시글 상세페이지를 띄울 시 DB와 JSP를 연결해주는 역할을 담당하는 클래스(Service) */
public class PostViewService {
	
	public PostBean getPostinfo(int postNo) {
		PostDAO postDAO = PostDAO.getInstance();
		// 객체에 저장된 고객 정보를 DB로 전달하는 클래스.
		// DAO : Data Access Object
		Connection con = getConnection();
		// DB와 jsp간의 연결을 해주는 것을 담당함.
		postDAO.setConnection(con);
		
		PostBean post = postDAO.selectPost(postNo); //selectPost는 postDAO에서 받아온다.

		close(con); //커넥션풀 닫음

		return post;
	}
}

5) DAO

postDAO에 게시글 목록을 뽑아주는 selectPostList가 이미 있다. 그 아래에 새롭게 selectPost를 생성해준다.

//=========================== 게시글 상세보기를 가져와 보여주는 SQL로직 ===============================
// PostViewService에서 게시글 상세보기정보를 볼때 DB와 JSP를 연결할 때 인자로 쓰임.
public PostBean selectPost(int postNo) {
    String sql = "select * from post_info where POST_NO=?""
    PostBean pb=null;

    try {
        pstmt=con.prepareStatement(sql);
        pstmt.setInt(1,postNo);
        rs=pstmt.executeQuery();

        if(rs.next()) {

            pb=new PostBean();

            //게시글 1개의 정보를 저장할 수 있는 PostBean 객체 생성.
            pb.setPOST_NO(rs.getInt( "POST_NO"))) //게시글번호
            pb.setMEM_NO(rs.getInt( "MEM_NO"))) //회원번호
            pb.setPOST_TITLE(rs.getString( "POST_TITLE"))) //게시글제목
            pb.setPOST_THUMBNAIL(rs.getString( "POST_THUMBNAIL"))) //게시글섬네일
            pb.setPOST_VIDEO(rs.getString( "POST_VIDEO"))) //게시글비디오
            pb.setPOST_CONTENT(rs.getString( "POST_CONTENT"))) //게시글 내용
            pb.setVisit_cnt(rs.getInt( "Visit_cnt"))) //게시글조회수
            pb.setPOST_UPLOADTIME(rs.getString( "POST_UPLOADTIME"))) //게시글업로드타임
        }
    }
    catch(Exception ex) {
        System.out.println( "getSelectPost 에러: " + ex))

    }
    finally {
        close(rs);
        close(pstmt);
    }
    return pb;
}

6) VO

vo에 있는 PostBean의 정보는 이전글 참고.

서버콘솔에서 포스트 번호 확인

3. 해당 상세페이지에 글쓴이의 정보가 위젯에 뜨게 하기

사실 연결은 게시글 목록 리스트 띄우는 것과 똑같이 부트스트랩 폼에 필요한 정보를 넣어주면 된다.

네비게이션을 따로 분리해서 띄워주는 방식을 사용할까 하다가, 결국 어떤 블로그 게시글을 클릭하면 그 글을 쓴 사람의 블로그로 이동된다는 사실을 깨닫고 이를 위젯으로 표시해주기로 했다.

글쓴이의 id값, 그리고 mem_pic으로 설정해준 멤버의 프로필 사진을 위젯에 띄워주자.

1) 위젯을 왼쪽으로 옮겨서 프로필 사진 나올 수 있게 하기

간단하게 div 위치를 수정해서 프로필이 나올 수 있게 한다. 메인페이지에 오른쪽에 위젯이 있다보니 차별점을 두고 싶었음.

게시글 출력되는 곳이 <div class="col-lg-8">로 되어있는데, 이를 <div class="col-lg-9">로 늘려주고 위젯 영역을 3으로 설정해주었다. 위젯이 그닥 클 필요는 없어보여서...

위젯에 사진 보이는 것은 기존 css를 이용해서 게시글 미리보기 이미지를 출력하는 class="card-img-top"를 사용했다.

▼blogPost.jsp 에 블로그 헤더 및 위젯 왼쪽으로 추가

    <!-- 블로그 헤더 및 블로그 배경화면 -->
        <header class="py-5 bg-light border-bottom mb-4" style="background-image: url('https://www.urbanbrush.net/web/wp-content/uploads/edd/2022/01/urbanbrush-20220105101328484351.jpg')">
            <div class="container">
                <div class="text-center my-5">
                    <h1 class="fw-bolder"> ${postObj.MEM_NO} 회원님의 블로그입니다.</h1>
                    <p class="lead mb-0">내가 쓴 글을 볼 수 있습니다.</p>
                </div>
            </div>
        </header>
        
        <!-- Page content-->
        <div class="container mt-5">
            <div class="row">
            
            <!-- 왼쪽 블로그 소개 위젯-->
                <div class="col-lg-3">
                <!-- Side widget-->
                    <div class="card mb-4">
                    	<img class="card-img-top" src="../resources/img/blog/${postObj.MEM_PIC}" alt="..." />
                        <div class="card-header">${postObj.MEM_ID}</div>
                        <div class="card-body">블로그 소개글 쓰는 곳.맛집을 좋아하는 ㅇㅇ의 블로그입니다!</div>
                    </div>
                    <!-- Categories widget-->
                    <div class="card mb-4">
                        <div class="card-header">카테고리?</div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="postEdit.jsp">내 블로그</a></li>
                                        <li><a href="#">오늘 ??명 방문 ></a></li>
                                        <li></li>
                                    </ul>
                                </div>
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="postEdit.jsp">새글작성</a></li>
                                        <li><a href="#">로그아웃</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- Search widget-->
                    <div class="card mb-4">
                        <div class="card-header">내 블로그에서 검색</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input class="form-control" type="text" placeholder="검색어를 입력하세요" aria-label="Enter search term..." aria-describedby="button-search" />
                                <button class="btn btn-primary" id="button-search" type="button">검색</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="col-lg-9">
                    <!-- Post content-->
                    <article>
                        <!-- Post header-->
                        <header class="mb-4">
                            <!-- Post title-->
                            <h1 class="fw-bolder mb-1">${postObj.POST_TITLE}</h1>
                            
                            
                           ...

2) 위젯과 블로그 배경에 멤버 정보 띄우기

기존에 게시글 상세보기 페이지의 SQL 문은 아래와 같다.

select * from post_info where POST_NO=?

그냥 게시글 번호가 맞는 포스트 정보를 전체 가져와서 사용했음.

post_info 테이블에서 FK로 mem_no를 연결해놓았기 때문에 멤버정보도 가지고 올 수 있음. join을 사용한다.

select p.*,m.mem_id,m.mem_pic from post_info p 
    left join memberinfo m on p.mem_no = m.mem_no where POST_NO=?

join으로 mem_no가 서로 같다는걸 표시해주고 그 중 post_no가 같은 게시글의 정보를 가져온다.

단, 게시글 정보 및 멤버id와 사진도 함께 가져옴. -> 일단 이것만 필요하니까.

VO에서 post_info 테이블 정보를 담아 가져오는데, 어차피 DAO에서 하나에 담아서 리턴쳐주기 때문에 VO에 변수를 하나 늘려주었다.

▼  PostBean.java에 내용 추가

   ...
    
	//블로그 게시글 네비에 표시하기 위해 추가
	private String MEM_ID;
	private String MEM_PIC;

	
	public String getMEM_ID() {
		return MEM_ID;
	}
	public void setMEM_id(String mEM_ID) {
		MEM_ID = mEM_ID;
	}
	public String getMEM_PIC() {
		return MEM_PIC;
	}
	public void setMEM_PIC(String mEM_PIC) {
		MEM_PIC = mEM_PIC;
	}
	
	...

▼  PostDAO.java에 회원정보 받아줌

...
pb.setPOST_UPLOADTIME(rs.getString("POST_UPLOADTIME")); //게시글업로드타임
				

// 가져올 회원 정보 추가
pb.setMEM_id(rs.getString("MEM_ID")); //게시글 쓴 회원 id
pb.setMEM_PIC(rs.getString("MEM_PIC")); //게시글 쓴 회원 사진

...

		}
		return pb;
	}

어차피 return은 PostBean에서 가져온 pb 변수이기 때문에 함께 담아서 보내주었다.

그럼 jsp 페이지에서 다른 변수들과 같은 방법으로 띄울 수 있음.

 blogPost.jsp에 내용 띄워줌

<h1 class="fw-bolder"> ${postObj.MEM_NO} 회원님의 블로그입니다.</h1>

...

<div class="card mb-4">
   <img class="card-img-top" src="../resources/img/blog/${postObj.MEM_PIC}" alt="..." />
   <div class="card-header">${postObj.MEM_ID}</div>
   <div class="card-body">블로그 소개글 쓰는 곳.맛집을 좋아하는 ㅇㅇ의 블로그입니다! 이미지는 일단 고정으로 박아뒀지롱...</div>
</div>

결과창

▼blogPost.jsp 전체

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="vo.MemberBean"%>
<%@ page import="java.util.*"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 빨간줄 그어지는데 jstl 설치 안해서 그럼. lib에 넣어준다. jsp 확장태그로 c로 쓴다.-->


<!DOCTYPE html>
<html lang="en">
    <head>
    <!-- 부트스트랩 출처 : https://startbootstrap.com/template/blog-home -->
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <meta name="description" content="" />
        <meta name="author" content="" />
        <title>${postObj.POST_TITLE}</title>
        <!-- Favicon-->
       <!-- <link rel="icon" type="image/x-icon" href="assets/favicon.ico" /> -->
        <!-- Core theme CSS (includes Bootstrap)-->
         <link href="../resources/css/mainPage.css" rel="stylesheet" />
    </head>
    <body>
        <!-- Responsive navbar-->
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
            <div class="container">
                <a class="navbar-brand" href="#!">N Blog</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                        <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">About</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">Contact</a></li>
                        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Blog</a></li>
                    </ul>
                </div>
            </div>
        </nav>
        
                <!-- 블로그 헤더 및 블로그 배경화면 -->
        <header class="py-5 bg-light border-bottom mb-4" style="background-image: url('https://www.urbanbrush.net/web/wp-content/uploads/edd/2022/01/urbanbrush-20220105101328484351.jpg')">
            <div class="container">
                <div class="text-center my-5">
                    <h1 class="fw-bolder"> ${postObj.MEM_NO} 회원님의 블로그입니다.</h1>
                    <p class="lead mb-0">내가 쓴 글을 볼 수 있습니다.</p>
                </div>
            </div>
        </header>
        
        <!-- Page content-->
        <div class="container mt-5">
            <div class="row">
            
            <!-- 왼쪽 블로그 소개 위젯-->
                <div class="col-lg-3">
                <!-- Side widget-->
                    <div class="card mb-4">
                    	<img class="card-img-top" src="../resources/img/blog/${postObj.MEM_PIC}" alt="..." />
                        <div class="card-header">${postObj.MEM_ID}</div>
                        <div class="card-body">블로그 소개글 쓰는 곳.맛집을 좋아하는 ㅇㅇ의 블로그입니다! 이미지는 일단 고정으로 박아뒀지롱...</div>
                    </div>
                    <!-- Categories widget-->
                    <div class="card mb-4">
                        <div class="card-header">카테고리?</div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="postEdit.jsp">내 블로그</a></li>
                                        <li><a href="#">오늘 ??명 방문 ></a></li>
                                        <li></li>
                                    </ul>
                                </div>
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="postEdit.jsp">새글작성</a></li>
                                        <li><a href="#">로그아웃</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- Search widget-->
                    <div class="card mb-4">
                        <div class="card-header">내 블로그에서 검색</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input class="form-control" type="text" placeholder="검색어를 입력하세요" aria-label="Enter search term..." aria-describedby="button-search" />
                                <button class="btn btn-primary" id="button-search" type="button">검색</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="col-lg-9">
                    <!-- Post content-->
                    <article>
                        <!-- Post header-->
                        <header class="mb-4">
                            <!-- Post title-->
                            <h1 class="fw-bolder mb-1">${postObj.POST_TITLE}</h1>
                            <!-- Post meta content-->
                            <div class="text-muted fst-italic mb-2">${postObj.POST_UPLOADTIME} by ${postObj.MEM_ID}</div>
                            <!-- Post categories-->
                            <a class="badge bg-secondary text-decoration-none link-light" href="#!">Web Design</a>
                            <a class="badge bg-secondary text-decoration-none link-light" href="#!">Freebies</a>
                        </header>
                        <!-- Preview image figure-->
                        <figure class="mb-4"><img class="img-fluid rounded" src="../resources/img/thumbnail/${postObj.POST_THUMBNAIL}" alt="..." /></figure>
                        <!-- Post content-->
                        <section class="mb-5">
                            <p class="fs-5 mb-4">${postObj.POST_CONTENT}</p>
                            <p class="fs-5 mb-4">The universe is large and old, and the ingredients for life as we know it are everywhere, so there's no reason to think that Earth would be unique in that regard. Whether of not the life became intelligent is a different question, and we'll see if we find that.</p>
                            <p class="fs-5 mb-4">If you get asteroids about a kilometer in size, those are large enough and carry enough energy into our system to disrupt transportation, communication, the food chains, and that can be a really bad day on Earth.</p>
                            <h2 class="fw-bolder mb-4 mt-5">I have odd cosmic thoughts every day</h2>
                            <p class="fs-5 mb-4">For me, the most fascinating interface is Twitter. I have odd cosmic thoughts every day and I realized I could hold them to myself or share them with people who might be interested.</p>
                            <p class="fs-5 mb-4">Venus has a runaway greenhouse effect. I kind of want to know what happened there because we're twirling knobs here on Earth without knowing the consequences of it. Mars once had running water. It's bone dry today. Something bad happened there as well.</p>
                        </section>
                    </article>
                    <!-- Comments section-->
                    <section class="mb-5">
                        <div class="card bg-light">
                            <div class="card-body">
                                <!-- Comment form-->
                                <form class="mb-4"><textarea class="form-control" rows="3" placeholder="Join the discussion and leave a comment!"></textarea></form>
                                <!-- Comment with nested comments-->
                                <div class="d-flex mb-4">
                                    <!-- Parent comment-->
                                    <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                    <div class="ms-3">
                                        <div class="fw-bold">Commenter Name</div>
                                        If you're going to lead a space frontier, it has to be government; it'll never be private enterprise. Because the space frontier is dangerous, and it's expensive, and it has unquantified risks.
                                        <!-- Child comment 1-->
                                        <div class="d-flex mt-4">
                                            <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                            <div class="ms-3">
                                                <div class="fw-bold">Commenter Name</div>
                                                And under those conditions, you cannot establish a capital-market evaluation of that enterprise. You can't get investors.
                                            </div>
                                        </div>
                                        <!-- Child comment 2-->
                                        <div class="d-flex mt-4">
                                            <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                            <div class="ms-3">
                                                <div class="fw-bold">Commenter Name</div>
                                                When you put money directly to a problem, it makes a good headline.
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <!-- Single comment-->
                                <div class="d-flex">
                                    <div class="flex-shrink-0"><img class="rounded-circle" src="https://dummyimage.com/50x50/ced4da/6c757d.jpg" alt="..." /></div>
                                    <div class="ms-3">
                                        <div class="fw-bold">Commenter Name</div>
                                        When I look at the universe and all the ways the universe wants to kill us, I find it hard to reconcile that with statements of beneficence.
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
                <!-- Side widgets-->
                <div class="col-lg-4">
                    <!-- Search widget-->
                    <div class="card mb-4">
                        <div class="card-header">Search</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input class="form-control" type="text" placeholder="Enter search term..." aria-label="Enter search term..." aria-describedby="button-search" />
                                <button class="btn btn-primary" id="button-search" type="button">Go!</button>
                            </div>
                        </div>
                    </div>
                    <!-- Categories widget-->
                    <div class="card mb-4">
                        <div class="card-header">Categories</div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">Web Design</a></li>
                                        <li><a href="#!">HTML</a></li>
                                        <li><a href="#!">Freebies</a></li>
                                    </ul>
                                </div>
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">JavaScript</a></li>
                                        <li><a href="#!">CSS</a></li>
                                        <li><a href="#!">Tutorials</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- Side widget-->
                    <div class="card mb-4">
                        <div class="card-header">Side Widget</div>
                        <div class="card-body">You can put anything you want inside of these side widgets. They are easy to use, and feature the Bootstrap 5 card component!</div>
                    </div>
                </div>
            </div>
        </div>
        <!-- Footer-->
        <footer class="py-5 bg-dark">
            <div class="container"><p class="m-0 text-center text-white">Copyright &copy; Your Website 2022</p></div>
        </footer>
        <!-- Bootstrap core JS-->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
        <!-- Core theme JS-->
     <!--   <script src="js/scripts.js"></script>-->
    </body>
</html>

 

 

 

 

▼ 진행중인 gitHub 링크를 남깁니다.

 

GitHub - k-haein/BlogPrj: 회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다.

회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다. Contribute to k-haein/BlogPrj development by creating an account on GitHub.

github.com

 

반응형
LIST
반응형
SMALL

게시글 목록 페이지 만들기

관리자가 아닌 일반로그인 후 게시글 목록을 띄우는 블로그 메인페이지로 이동하도록 구현해보겠다.

[ 만들 기능 ]
1. 로그인 후 블로그 메인페이지로 이동
2. 메인페이지에 postDB에 있는 게시글 목록 리스트 띄우기

1. 로그인 후 일반회원이면 메인페이지로 가도록 링크 연결.
2. Controller에서 호출 URL을 받아 Action과 연결함.
3. Action에서 getPostList로 가져온 postList 배열값을 Service로 보내줌.
4. Service에서 커넥션 풀에서 DB 연결하고, 게시글 목록 배열로 담아옴.
5. DAO 안에서 SQL에 맞게 검색 후 결과값 리턴해서 Service에게 줌. (+커넥션 끊음)
6. Action에서 Service에게 받은 결과값(게시글 목록 배열)을 mainPage.jsp로 던져줌.
8. jsp 페이지에서 게시글 목록 리스트를 반복문으로 출력해줌.


1. 회원정보 테이블(기존 테이블) 및 게시글 테이블 만들기

--회원정보 테이블 생성
create table memberinfo(
    mem_no number(5) Primary key,
    mem_id varchar2(20) not null,
    mem_pwd varchar2(20) not null,
    mem_name varchar2(10) not null,
    mem_bir_yy VARCHAR(25),
    mem_bir_mm VARCHAR(25),
    mem_bir_dd VARCHAR(25),
    mem_gender VARCHAR(25),
    mem_mail VARCHAR(25),
    mem_phone VARCHAR(25),
    mem_regdate  date default sysdate,
    mem_pic  varchar2(90)
);

--임시 멤버 및 관리자 넣어놓기
insert into memberinfo values(1,'heannim12','heannim12','김히앤','2022','4','10','','','','','');
insert into memberinfo values(2,'shopAdmin','shopAdmin','관리자','2022','4','10','','','','','');
--게시글 테이블 생성(회원목록의 mem_no 연결)
create table post_info (
    post_no  number(4) Primary key,
    mem_no  number(5) not null,
    post_title  varchar2(60) not null,
    post_thumbnail  varchar2(80) not null,
    post_video varchar2(50),
    post_content  varchar2(5000) not null,
    visit_cnt  number(5) default 0,
    post_uploadtime  date default sysdate,
    
    foreign key(mem_no) REFERENCES memberinfo(mem_no)
);

--게시글도 테스트용 데이터 넣어놓기
insert into post_info values(1,1,'게시글1제목','post1.jpg','','게시글1내용게시글1내용게시글1내용게시글1내용게시글1내용게시글1내용',0,'');
insert into post_info values(2,1,'게시글2제목','post2.jpg','','게시글2내용게시글2내용게시글2내용게시글2내용게시글2내용게시글2내용',1,'');

2. 부트스트랩 연결

우선 메인페이지에 게시글 전체를 띄워보자.

블로그 메인페이지, 상세페이지 부트스트랩 사용함(부트스트랩 출처 : https://startbootstrap.com/template/blog-home)

블로그 메인페이지 부트스트랩

네이버와 깔맞춤 해주기 위해서 상단 네비게이션 배경색을 바꿔주었다.

--bs-dark-rgb: 0, 199, 60; /*네이버 배경색 맞춤*/

3. 어떤 화면에서 띄울 것인가?

로그인 화면에서 로그인을 할 때, "shopAdmin"이라는 아이디를 가진 관리자라면 회원목록이 나오도록 했다.

▼ MemberListAction.java

더보기
package action;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import svc.MemberListService;
import vo.ActionForward;
import vo.MemberBean;

/* 인터페이스를 함께 추가했다. 로그인 후 분기 처리를 위한 클래스이다.*/
public class MemberListAction implements Action { //Action을 implements 해줌

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		
		//session을 써서 서버 생성함.
		HttpSession session = req.getSession();
		// 로그인할 때는 setSession해서 가져오고
		// 여기 리스트에서는 get으로 뿌린다
		String id = (String) session.getAttribute("id");
		ActionForward forward = null; //어디로 갈지?

		
		//=========================== 로그인 후 분기처리 ================================
		//1. 회원 아님(id 정보 없음) => 로그인 안됨
		if (id == null) {
			// 세션에 저장된 아이디가 없다면~
			forward = new ActionForward();
			forward.setRedirect(true);
			forward.setPath("./memberLogin.me");
			// 회원이 아니니까 로그인 페이지로 이동하라.

			
		//2. 관리자 아니고 회원임 => 일반로그인
		} else if (!id.equals("shopAdmin")) {
			// 상점 주인이 아니면
			resp.setContentType("text/html;charset=UTF-8");
			PrintWriter out = resp.getWriter();
			out.println("<script>");
			out.println("alert('관리자가 아닙니다');");
			out.println("location.href='./postListAction.me'"); //관리자가 아니면 메인페이지로 이동
			out.println("</script>");

		//3. 관리자임 => 회원목록 보여짐
		} else {
			// 관리자가 맞다면 모든 회원 목록 표시.
			forward = new ActionForward();
			MemberListService memberListService = new MemberListService();
			ArrayList<MemberBean> memberList = memberListService.getMemberList();
			req.setAttribute("memberList", memberList);
			forward.setPath("./member_list.jsp");
		}

		return forward;
	}
}

이제 일반로그인을 하면 블로그 메인페이지로 연결되게 해주자. [postList]라는 이름으로 엮어줄 것임.

//2. 관리자 아니고 회원임 => 일반로그인
		} else if (!id.equals("shopAdmin")) {
			// 상점 주인이 아니면
			resp.setContentType("text/html;charset=UTF-8");
			PrintWriter out = resp.getWriter();
			out.println("<script>");
			out.println("alert('관리자가 아닙니다');");
			//관리자가 아니면 블로그 메인 페이지로 이동한다.
			out.println("location.href='./postListAction.me'");
			out.println("</script>");

4. Controller

먼저 컨트롤러에서 Action페이지로 연결해주자.

▼ MemberFrontController.java

//-------------------- 로그인이 된 후 메인페이지(게시글 목록) 보여주는 PostListAction 페이지 생성 ---------------------------
//메인 포스트 페이지에 정보만 띄워준다.
else if (command.equals("/member/postListAction.me")) {
    action = new PostListAction();
    // PostListAction, 로그인 후의 메인 포스트 페이지 표시.
    try {
        forward = action.execute(req, resp);
        System.out.println( "로그인 후 메인페이지 포스트 리스트 표시"))
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

5. Action

Action페이지에서 게시글 리스트를 PostBean에서 배열(ArrayList)로 받아 mainPage.jsp로 던져준다.

한번 더 로그인이 되어있는지 세션을 체크한다.

PostListAction.java

package action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import svc.PostListService;
import vo.ActionForward;
import vo.PostBean;

/* 인터페이스를 함께 추가했다. 메인페이지 처리를 위한 클래스이다.*/
public class PostListAction implements Action { //Action을 implements 해줌

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    
		//session을 써서 서버 생성함.
		HttpSession session = req.getSession();
		// 로그인할 때는 setSession해서 가져오고
		// 여기 리스트에서는 get으로 뿌린다
		String id = (String) session.getAttribute("id");
		ActionForward forward = null; //어디로 갈지?
        
		//1. 로그인 상태인지 확인
		if (id == null) {
			// 세션에 저장된 아이디가 없다면~
			forward = new ActionForward();
			forward.setRedirect(true);
			forward.setPath("./memberLogin.me");

		//2. 게시글 목록 보여짐	
		} else {
			// 모든 게시글 목록 표시.
			forward = new ActionForward();
			PostListService postListService = new PostListService();
			//배열로 게시글목록을 가져온다.
			ArrayList<PostBean> postList = postListService.getPostList(); 
			req.setAttribute("postList", postList);
			
			//mainPage로 게시글 목록을 던져준다.
			forward.setPath("./mainPage.jsp");
		}
		return forward;
	}
}

6. Service

service를 만들어주고 게시글 리스트를 가져오기 위해 DB와 JSP를 연결해준다.

커넥션 풀을 열어 커넥션 객체들을 풀에 저장해두었다가 클라이언트에서 요청하면 객체를 빌려주고 반납받아 풀에 저장한다. DB 접속용 DAO 객체도 참조로 얻어온다.

커넥션으로 DAO에서 selectPostList(=게시글 목록)를 받아오면 배열에 저장해서 리턴해준다.

리턴한 postList를 Action에서 받는 것.

PostListService.java

package svc;
import static db.JdbcUtil.close;
import static db.JdbcUtil.getConnection;
import java.sql.Connection;
import java.util.ArrayList;
import DAO.PostDAO;
import vo.PostBean;


/* 게시글를 띄울 시 DB와 JSP를 연결해주는 역할을 담당하는 클래스(Service) */
public class PostListService {
	
	public ArrayList<PostBean> getPostList() { //리스트이므로 배열로 가져온다.
		//커넥션 풀 : DB와 미리 연결해놓은 커넥션 객체들을 풀에 저장해뒀다가 클라에서 요청오면 객체 빌려주고 볼일 끝나면 다시 반납받아 풀에 저장하는 방식
		Connection con = getConnection();
		// DB와 연결을 얻어내고.
		PostDAO postDAO = PostDAO.getInstance();
		// DB접속용 DAO 객체 참조 얻어오기.(싱글톤 패턴 : 인스턴스가 1개만 생성됨)
		// import static db.JdbcUtil.*;
		postDAO.setConnection(con);
		// 얻어온 커넥션 저장. -> 연결해서 할일 함.
		ArrayList<PostBean> postList = postDAO.selectPostList(); //selectPostList는 PostDAO에서 받아온다.
		//커넥션으로 DB에서 게시글 목록 받아서 배열에 저장

		close(con);
		// 사용을 마친 커넥션 반환
		return postList;
		// 게시글 목록 리턴.
	}
}

7. DAO

DB접속용 DAO 객체를 만들어보자. 여기서 직접적으로 SQL 문을 돌려 원하는 데이터를 DB에서 가져온다.

DB에서 필요한 정보를 가져오되, 게시글 내용은 미리보기로 보여줄 것이므로 substring을 통해 잘라낸다.

PostDAO.java

package DAO;
import static db.JdbcUtil.close;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import javax.sql.DataSource;
import vo.PostBean;

public class PostDAO {

	//db패키지의 JdbcUtil을 통해 자바와 오라클이 연결이 가능해졌으니 이 두 프로그램을 연결했으면 이제 정보를 넘겨줘야한다.
	//DAO의 클래스에서 회원가입을 진행하면서 입력한 정보들을 오라클로 넘겨준다.
	
	public static PostDAO instance;
	Connection con;
	// jsp와 오라클 연결 유지.
	PreparedStatement pstmt;
	// 쿼리문 전달.
	ResultSet rs;
	// 쿼리문 결과 저장 객체.
	DataSource ds;
	// 어떤 DB에 연결할 지.

	private PostDAO() {

	}

	public static PostDAO getInstance() {
		if (instance == null) {
			instance = new PostDAO();
		} // 1개의 객체를 공동으로 사용.
		return instance;
	}

	public void setConnection(Connection con) {
		this.con = con;
	}

	//=========================== 로그인된 후 게시글 목록을 가져와 보여주는 SQL로직 ===============================
	// selectPostList : PostListService에서 DB와 JSP를 연결해서 게시글 목록을 배열로 가져와 저장할 때 인자로 쓰임.
	public ArrayList<PostBean> selectPostList() {
		// ArrayList: 객체 배열 비슷, 컬렉션 프로임워크
		// 여러 개의 게시글 정보를 저장한다.

		// 디비에 저장된 모든 게시글 목록을 확인하는 SQL문(DB 이름 확인하기***)
		String sql = "select * from post_info";

		ArrayList<PostBean> postList = new ArrayList<PostBean>();
		PostBean pb = null; //Bean(vo)은 그릇이다. 뭘 가져올지는 vo에 목록이 있다.

		try {
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery(); //executeQuery : resultSet 객체 반환
			//select는 executeQuery()를 사용한다.
			//쿼리문 처리결과 ResultSet의 객체인 rs에 저장.

			if (rs.next()) {//조회된 결과가 있다면 아래 문장 수행.
				do {//한 번 수행하고 또 수행할 게 있으면 수행.
					pb = new PostBean();
					//게시글 1개의 정보를 저장할 수 있는 PostBean 객체 생성.
					pb.setPOST_NO(rs.getInt("POST_NO")); //게시글번호
					pb.setMEM_NO(rs.getInt("MEM_NO")); //회원번호
					pb.setPOST_TITLE(rs.getString("POST_TITLE")); //게시글제목
					pb.setPOST_THUMBNAIL(rs.getString("POST_THUMBNAIL")); //게시글섬네일
					pb.setPOST_VIDEO(rs.getString("POST_VIDEO")); //게시글비디오
					
					//--- 게시글 내용 가져와서 15자만 미리보기로 보여줌 ---
					String preStr=rs.getString("POST_CONTENT"); 
					if(preStr.length()>30){ 
						preStr=preStr.substring(0,15)+"..."; //자르고 ... 붙이기
					};
					pb.setPOST_CONTENT(preStr); //게시글내용 미리보기
					//----------------------------------------
					
					pb.setVisit_cnt(rs.getInt("Visit_cnt")); //게시글조회수
					pb.setPOST_UPLOADTIME(rs.getString("POST_UPLOADTIME")); //게시글업로드타임
					//조회된 결과를 PostBean객체에 저장.
					postList.add(pb);
					//저장하면서 생성된 것을 이제 List에 담아냄.(ArrayList)
					//반복문이 실행될 때마다 게시글 1개씩 누적 시킴.
				} while (rs.next());
				//rs.next때문에 어레이 리스트 다음 값으로 넘어간다.(차례차례 읽어옴)
			}
		} catch (Exception ex) {
			System.out.println("selectPostList 에러 : " + ex);
		} finally {
			close(rs);
			close(pstmt);
		}
		return postList;
	}
}

8. VO

DAO에서 가져온 DB데이터를 담을 변수를 선언한다. int와 String 등 자료형을 신경쓸 것!

 PostBean.java

package vo;

public class PostBean {
	
	//사용할 변수들 선언
	private int POST_NO;
	private int MEM_NO;
	
	private String POST_TITLE;
	private String POST_THUMBNAIL;
	private String POST_VIDEO;
	private String POST_CONTENT;
	private int visit_cnt;
	private String POST_UPLOADTIME;
	
	//그 후 source > getter,setter
	
	public int getPOST_NO() {
		return POST_NO;
	}
	public void setPOST_NO(int pOST_NO) {
		POST_NO = pOST_NO;
	}
	public int getMEM_NO() {
		return MEM_NO;
	}
	public void setMEM_NO(int mEM_NO) {
		MEM_NO = mEM_NO;
	}
	public String getPOST_TITLE() {
		return POST_TITLE;
	}
	public void setPOST_TITLE(String pOST_TITLE) {
		POST_TITLE = pOST_TITLE;
	}
	public String getPOST_THUMBNAIL() {
		return POST_THUMBNAIL;
	}
	public void setPOST_THUMBNAIL(String pOST_THUMBNAIL) {
		POST_THUMBNAIL = pOST_THUMBNAIL;
	}
	public String getPOST_VIDEO() {
		return POST_VIDEO;
	}
	public void setPOST_VIDEO(String pOST_VIDEO) {
		POST_VIDEO = pOST_VIDEO;
	}
	public String getPOST_CONTENT() {
		return POST_CONTENT;
	}
	public void setPOST_CONTENT(String pOST_CONTENT) {
		POST_CONTENT = pOST_CONTENT;
	}
	public int getVisit_cnt() {
		return visit_cnt;
	}
	public void setVisit_cnt(int visit_cnt) {
		this.visit_cnt = visit_cnt;
	}
	public String getPOST_UPLOADTIME() {
		return POST_UPLOADTIME;
	}
	public void setPOST_UPLOADTIME(String pOST_UPLOADTIME) {
		POST_UPLOADTIME = pOST_UPLOADTIME;
	}
}

9. jsp에서 게시글 목록 출력하기

ArrayList를 jsp로 뿌려주었으니 출력해보자. 간단하게 jstl를 이용해서 c:forEach로 리스트를 출력해줄 것이다.

단, 섬네일은 이름만 받아서 "post1.jpg"과 같이 이름만 받아왔으므로, 이미지 src에 정확한 경로를 앞에 추가해주어야 한다. 이미지는 미리 그 경로에 DB와 동일한 이름으로 저장해두자.

이미지는 미리 경로에 넣어둠

...

		<!-- Page header with logo and tagline-->
        <header class="py-5 bg-light border-bottom mb-4">
            <div class="container">
                <div class="text-center my-5">
                    <h1 class="fw-bolder"> ${postList[0].MEM_NO}회원님의 블로그 홈에 오신걸 환영합니다!</h1>
                    <p class="lead mb-0">여기는 블로그 홈페이지입니다.배경사진 넣을꺼임.</p>
                </div>
            </div>
        </header>
        <!-- Page content-->
        <div class="container">
       
            <div class="row">
                <!-- Blog entries-->
                <div class="col-lg-8">
                        <c:forEach var="postList" items="${postList}">
                    <!-- Featured blog post -->
                    <div class="card mb-4">
                        <div class="card-body">
                           <a href="#!"><img class="card-img-top" src="../resources/img/thumbnail/${postList.POST_THUMBNAIL}" alt="..." /></a>
                          
                          <div class="small text-muted">${postList.POST_UPLOADTIME}</div>
                            <h2 class="card-title">${postList.POST_TITLE} -----  ${postList.MEM_NO}</h2>
                            <p class="card-text">${postList.POST_CONTENT}</p>
                            <a class="btn btn-primary" href="#!">Read more →</a>
                        </div>
                    </div>
                    </c:forEach>
...

mainPage.jsp 전체

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="vo.MemberBean"%>
<%@ page import="java.util.*"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 빨간줄 그어지는데 jstl 설치 안해서 그럼. lib에 넣어준다. jsp 확장태그로 c로 쓴다.-->


<!DOCTYPE html>
<html lang="ko">
    <head>
    <!-- 부트스트랩 출처 : https://startbootstrap.com/template/blog-home -->
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <meta name="description" content="" />
        <meta name="author" content="" />
        <title>Blog Home</title>
        <!-- Favicon-->
      <!--   <link rel="icon" type="image/x-icon" href="assets/favicon.ico" />  -->
        <!-- Core theme CSS (includes Bootstrap)-->
        <link href="../resources/css/mainPage.css" rel="stylesheet" />
    </head>
    <body>
        <!-- Responsive navbar-->
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
            <div class="container">
                <a class="navbar-brand" href="#!">N Blog</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                        <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">About</a></li>
                        <li class="nav-item"><a class="nav-link" href="#!">Contact</a></li>
                        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Blog</a></li>
                    </ul>
                </div>
            </div>
        </nav>
        <!-- Page header with logo and tagline-->
        <header class="py-5 bg-light border-bottom mb-4">
            <div class="container">
                <div class="text-center my-5">
                    <h1 class="fw-bolder"> ${postList[0].MEM_NO}회원님의 블로그 홈에 오신걸 환영합니다!</h1>
                    <p class="lead mb-0">여기는 블로그 홈페이지입니다.배경사진 넣을꺼임.</p>
                </div>
            </div>
        </header>
        <!-- Page content-->
        <div class="container">
       
            <div class="row">
                <!-- Blog entries-->
                <div class="col-lg-8">
                        <c:forEach var="postList" items="${postList}">
                    <!-- Featured blog post -->
                    <div class="card mb-4">
                        <div class="card-body">
                           <a href="#!"><img class="card-img-top" src="../resources/img/thumbnail/${postList.POST_THUMBNAIL}" alt="..." /></a>
                          
                          <div class="small text-muted">${postList.POST_UPLOADTIME}</div>
                            <h2 class="card-title">${postList.POST_TITLE} -----  ${postList.MEM_NO}</h2>
                            <p class="card-text">${postList.POST_CONTENT}</p>
                            <a class="btn btn-primary" href="#!">Read more →</a>
                        </div>
                    </div>
                    </c:forEach>
                    
                    <!-- Pagination-->
                    <nav aria-label="Pagination">
                        <hr class="my-0" />
                        <ul class="pagination justify-content-center my-4">
                            <li class="page-item disabled"><a class="page-link" href="#" tabindex="-1" aria-disabled="true">Newer</a></li>
                            <li class="page-item active" aria-current="page"><a class="page-link" href="#!">1</a></li>
                            <li class="page-item"><a class="page-link" href="#!">2</a></li>
                            <li class="page-item"><a class="page-link" href="#!">3</a></li>
                            <li class="page-item disabled"><a class="page-link" href="#!">...</a></li>
                            <li class="page-item"><a class="page-link" href="#!">15</a></li>
                            <li class="page-item"><a class="page-link" href="#!">Older</a></li>
                        </ul>
                    </nav>
                </div>
                <!-- Side widgets-->
                <div class="col-lg-4">
                    <!-- Search widget-->
                    <div class="card mb-4">
                        <div class="card-header">Search</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input class="form-control" type="text" placeholder="Enter search term..." aria-label="Enter search term..." aria-describedby="button-search" />
                                <button class="btn btn-primary" id="button-search" type="button">Go!</button>
                            </div>
                        </div>
                    </div>
                    <!-- Categories widget-->
                    <div class="card mb-4">
                        <div class="card-header">Categories</div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">Web Design</a></li>
                                        <li><a href="#!">HTML</a></li>
                                        <li><a href="#!">Freebies</a></li>
                                    </ul>
                                </div>
                                <div class="col-sm-6">
                                    <ul class="list-unstyled mb-0">
                                        <li><a href="#!">JavaScript</a></li>
                                        <li><a href="#!">CSS</a></li>
                                        <li><a href="#!">Tutorials</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- Side widget-->
                    <div class="card mb-4">
                        <div class="card-header">Side Widget</div>
                        <div class="card-body">You can put anything you want inside of these side widgets. They are easy to use, and feature the Bootstrap 5 card component!</div>
                    </div>
                </div>
            </div>
           
        </div>
        <!-- Footer-->
        <footer class="py-5 bg-dark">
            <div class="container"><p class="m-0 text-center text-white">Copyright &copy; Your Website 2022</p></div>
        </footer>
        <!-- Bootstrap core JS-->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
        <!-- Core theme JS-->
       <!-- <script src="js/scripts.js"></script> -->
    </body>
</html>

10. 마무리로 조절하기

이미지가 너무 커서 리스트 모양이 이쁘지 않으므로, css로 섬네일 이미지 크기를 고정해준다.

.card-img,
.card-img-top,
.card-img-bottom {
/* 섬네일 이미지 크기 고정 및 왼쪽으로 */
  width: 200px;
  height:200px;
  vertical-align:middle;
  float:left; 
}

 

결과

 

++추가) 게시글 목록에 이웃들 글만 보이게 하기(session값 DAO로 보냄)


전체 블로그 게시글 목록을 띄우는게 아니라 "로그인 한 나"를 제외한 나머지 글들이 보이게끔 변경해줘봤다.

약간 헤맸는데, 이미 로그인하면서 session에 현재 로그인한 id값은 저장되어 있고... 그럼 SQL 문에서 현재 session에 접속된 id값에 해당하는 멤버가 아닌 멤버의 게시글들을 전부 불러오면 되는거 아닌가?

select * from post_info p join memberinfo m on p.mem_no = m.mem_no 
where m.mem_id !='heannim12';

현재 로그인한 계정의 id는 [heannim12] 이다. JOIN 문을 써서 FK로 연결한 mem_no가 같다는 조건 하에 mem_id가 [heannim12]인 테이블만 전부 뽑아보았다.(즉, mem_no 가 1이 아니어야만 한다.)

mem_no가 1이 아닌 애들만 뽑혔다.

현재 나는 DAO에서 SQL문을 써서 진행하고 있는데...Action 페이지에서부터 어떻게 session값을 가져가야하나...생각하다가 파라미터로 들려주기로 했다.

이렇게 Service로 갈 때 들려보내고

ArrayList<PostBean> postList = postListService.getPostList(sessionId);

String sessionId로 받아서 그대로 다시 DAO에게 전달해줬다.

DAO 갈때도 들려보내줬다.

ArrayList<PostBean> postList = postDAO.selectPostList(sessionId);

DAO까지 잘 들고온 sessionId값을 SQL문의 물음표에 넣어준다!

SQL 문에 조건으로 넣어준다.

String sql = "select * from post_info p join memberinfo m on p.mem_no = m.mem_no where m.mem_id != ?";

...

//세션 id값 가져와서 SQL 문에 넣어줌.
pstmt.setString(1, sessionId);

결과

++추가) sessionScope 이용해서 jsp 페이지에 세션값 보여주기

${sessionScope.id} 를 사용하면 세션에 저장된 id 값을 가져올 수 있다. 그럼 위처럼 메인에 현재 접속된 세션값 회원 이름을 출력할 수 있음!

<div class="text-center my-5">
  <h1 class="fw-bolder"> ${sessionScope.id} 회원님! 블로그 메인홈에 오신걸 환영합니다!</h1>
  <p class="lead mb-0">이곳에서는 나를 제외한 모든 블로거들의 글을 볼 수 있습니다.</p>
</div>

 

 


다음은 게시글 목록과 게시글 상세보기를 연결해보자.

 

▼ 진행중인 gitHub 링크를 남깁니다.

 

GitHub - k-haein/BlogPrj: 회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다.

회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다. Contribute to k-haein/BlogPrj development by creating an account on GitHub.

github.com

 

반응형
LIST
반응형
SMALL

프론트엔드 단에서 자바스크립트만 열심히 만지다보니 이벤트나 메소드는 익숙해지고 있으나 서버단, 그리고 SQL 쿼리는 점차 까먹기에 이르렀다.

학원 다니면서 만들어봤던 쇼핑몰 프로젝트도 열심히 했지만, 여러명이서 나눠서 했기 때문에 디테일한 부분은 잘 모르는게 사실이다. 다시 복기시키는 겸, 요즘 열심히 하는 네이버 블로그의 폼을 따서 나만의 블로그(이지만 실상은 게시판인)를 만들어보기로 했다.

디자인은 크게 자신이 없어서 네이버 소스보기로 틀을 긁어오고, 나머지는 BootStrap을 사용할 예정이다.

회원가입/로그인 기능도 구글링해서 기본 테이블 제작 후, 후에 세부적으로 커스터마이징 하기로 마음먹었다.

하나하나 한걸 나눠서 전부 포스팅하면 좋을거라 생각하지만.... 로그인/회원가입 예제는 구글링에 잘 나와있어 참고한 링크만 걸어놓는다.


1. 초기 세팅

이클립스를 설치하고 DB를 세팅한다.

 

[Eclipse] 이클립스 (Eclipse) 설치 및 프로젝트 생성

● 이클립스 (Eclipse) 란? - 다양한 플랫폼에서 쓸 수 있으며, 자바를 비롯한 다양한 언어를 지원하는 프로그래밍 통합 개발 환경을 목적으로 시작하였으나, 현재는 OSGi를 도입하여, 범용 응용 소

daram2-everyday.tistory.com

 

[Eclipse] 이클립스 (Eclipse) - 테마 및 폰트 사이즈 변경

안녕하세요 오늘은 이클립스 테마(배경색) 및 글자 크기를 변경하려고 합니다 개발하시는 분들 입장에서 하얀색 배경과 검정 글자를 장시간보다 보면 눈이 금방 피로해지는데 저는 그래서 이클

daram2-everyday.tistory.com

 

[Eclipse] 톰캣(Tomcat) 이클립스에서 실행하기 - 간단 예제 JSP

이클립스에서 톰캣(WAS) 서버를 만든 후 간단한 예제를 통해 홈페이지에 "안녕하세요" 를 출력해보겠습니다. 1. 톰캣 연동 이클립스에서 Window -> Preferences 클릭 Server -> Runtime Environments -> Add.. 클릭 A

daram2-everyday.tistory.com

 

[Eclipse] JSP/HTML 실행결과 외부 웹 브라우저로 띄우기

JSP/HTML 실행 결과가 이클립스 말고 외부 웹브라우저 (ex: 익스플로러, 크롬 등)로 띄우기입니다. 바로 시작해보죠 Go Go 위와 같이 JSP 또는 HTML 실행 시 이클립스 내부 브라우저로 실행 결과가 출력

daram2-everyday.tistory.com

 

[JAVA] JDK 1.8 설치 및 환경변수 설정

● JDK란? - 자바 개발 키트(Java Development Kit, JDK)는 JAVA SE, JAVA EE, 또는 모바일 지원 JAVA ME 플랫폼 중 하나를 구현한 것으로 솔라리스, 리눅스, 맥 OS X, 윈도우 자바 개발자를 대상으로 오라클에 의해

daram2-everyday.tistory.com

이미 시스템 > 고급 시스템 설정 > 시스템속성 고급탭 > 환경변수 > jdk1.8.0_281 가 JAVA_HOME으로 등록되어있음.

환경변수 설정

DB는 예전에 설치한 SQL Developer 사용했다.

 

[Oracle] 계정 생성 및 권한 부여 방법

Oracle 11g 기준으로 작성된 글입니다. oracle 11g 설치를 다 하신 후에 cmd와 sql developer에서 oracle에 접근해 계정 설정이 가능합니다. 1. cmd에서 계정 설정하기 1) cmd에서 접속하기 sqlplus 로 접속하시면 u

ajdahrdl.tistory.com

계정은 system이 가장 상위이다. 12345 비번으로 되어있었음. cmd에서 새로 계정 만들고 권한주고 할 수 있음. BlogDB 계정을 따로 만들어서 거기서 작업해주자. 비밀번호도 재설정해주었다.

DB계정 설정

2. 회원가입/로그인 기본 기능 만들기

dynamic Web project로 진행함.

처음에는 그대로 따라서 만들었다.

 

웹서버 2일차 - Apache Tomcat9으로 웹서버 구현하기 - 회원가입 페이지 만들기-①

오늘의 영타는 315타 웹서버(Web Server)가 있다. 웹서버는 http라는 통신 규약을 사용하고 있다. 인터넷...

blog.naver.com

 

 

 

웹서버 3일차 - 회원가입 페이지 만들기 -②

오늘의 영타는 341타. (드디어 340타 돌파~) 2019.03.13 어제 하던 회원 가입 페이지 만들기 계속해서 진행...

blog.naver.com

이클립스 자동 정렬 Shrift + Ctrt + F

이클립스 자동 import Ctrl+ Shift + O

 

웹서버 4일차 - 회원가입 홈페이지 - ③

사용 프로그램 : 이클립스(Eclipse) 회원가입 홈페이지 만들기 - 좀 더 해보기  는 공백을 만들어...

blog.naver.com

me로 끝나는 가상페이지로 이동시켜서 컨트롤러에서 그에 해당하는 Action페이지로 갈 수 있게 한다. 실제 페이지 주소를 숨긴다.

 

웹서버 5일차 - 홈페이지 만들기 진행 중 - 수정 완료 - ④

어제까지 했던 부분이 회원가입을 누른다면 회원가입 페이지로 넘어가고 정보를 입력할 수 있도록 하는 부...

blog.naver.com

여기까지 회원가입 버튼 누르면 DB에 데이터 들어가는거까지 완료했다.

여기서 뭐가 안되나 했더니, context.xml에서 Resource name = “jdbc/oracleDB”로 되어있었는데 내 오라클 이름은 myora 였다. 이거 언제 어디서 설정했는지 모르겠음…몰?루ㅋㅋ

→ 찾았다. JdbcUtil 안에 DB 이름이 설정되어있다. 내 DB이름 어디서 설정했더라...

▼ 지금까지 과정 요약

더보기

dynamic Web Project 만들고 WebContent 아래에 화면 만들어서 각자 연결한다.

각 페이지 연결은 href로 각각 연결해주는 것도 있지만 Controller 단에서 가상의 페이지(.me)를 만든 뒤 만약 링크가 거기로 접속한다면 이리로 가라! 라는 식으로 연결해줬다. 로그인 가상창, 회원가입 가상창, 회원가입버튼 누를 시 액션을 취하는 가상창까지 만듦. input을 누르면 가상창으로 간다.

(컨트롤러에서 doGet부분만 doProcess로 가게 해줬는데, doPost도 doProcess(req,resp);를 추가해줬다.)

그래서 doProcess에서 주소 가져오고.로그인.me로 가면 로그인 창으로 이동해주고~ 회원가입 버튼 누르면 me로 가서 이동해주고~(여기서 경로 문제때문에 한참걸림 ./는 현 위치니까 /로 시작하면 루트 경로라고 생각하고 설정해주기.) 그 후 회원가입을 도와주는 Action.me도 연결은 했는데 여기서 SQL로 보내주는 것. 리모콘 역할.

VO : 사용할 변수 선언 및 getter/setter로 받고 보내줄 변수 준비 / actionForward에서는 어디로 이동할지에 대한 다이렉트 변수 선언

db : 자바와 오라클을 연결해줌. 접속 하고 해제하고 등등 쿼리문 전달도 함

DAO : 정보 넘겨주는 애. 자바랑 오라클 사이에서 전달해줌. 자바 → 오라클

svc : DAO가 고객정보를 DB로 전달해줬으면 얘가 그거 보고 가입 완료했는지 불가했는지 보고 잘 됐으면 DB 커밋하고 안되면 쿼리 롤백하고 DB와의 연결을 끊는다.

action : 입력할 목록 정해주고 vo에서 설정된 변수들을 받아서 목록에 대한 파라미터 설정과 등록이 안되면 alert를 띄우고 등록 잘되면 로그인 페이지로 이동시켜줌

controller : 이 위에서 흩어져있는거 다 가져온 다음에 대가리가 시킴. 야 foward 있으면 주소로 이동해. 가입하고 forward = action.execute(req, resp); 여기서 받은 action을 뜯어서 SQL로 보내준다.

그럼 SQL로 슝 가는것^_^ 예에~~!!


그다음 로그인 기능 구현 시작

 

웹서버 6일차 - 회원가입 정보로 로그인 처리 -⑤

오늘의 영타는 평균 331타. 지금까지 한 것) 멤버로그인으로 이동하게 되면 로그인폼으로 와지고 로그인페...

blog.naver.com

 

 

웹서버 7일차 - 회원가입 홈페이지 -⑥

어제한 것) 회원가입 후 DB에 저장된 정보로 로그인하기. 이번에 해볼 것) 관리자 계정으로 로그인 시, ...

blog.naver.com

회원가입 하고 나니까 로그인은 비슷하게 술술 넘어가네.

 

Connection이란

DBMS 내부의 Pool 속에 미리 생성되어 있는 Connection을 가져다가 사용하고, 사용이 끝나면 Connection을 Pool에 반환한다. pool 속에 미리 생성되어 있는 connection을 가져다가 사용하고, 사용이 끝나면 conne

ok4u.tistory.com

▼ 커넥션풀 / 인스턴스 / 싱글톤 패턴

더보기

커넥션 풀 : DB와 미리 연결해놓은 커넥션 객체들(도구들)을 풀에 저장해뒀다가 클라에서 요청오면 커넥션 객체 빌려주고(접근 가능 도구를 빌려주고) DB에 접근해서 쿼리 막 날린 뒤 볼일 끝나면 다시 커넥션을 반납받아 풀에 저장하는 방식 / 너무 많으면 메모리 차지하니까 주의.

원래 클라가 서버로 게시글 저장 요청을 하면 서버에서 가공해서~그걸 DB에 저장하기 위해 DB랑 커넥션 맺고~DB에 게시글 저장하고~다시 DB랑 커넥션 끊고~ 다시 응답 가공해서~ 클라이언트에게 전달하는 로직인데…. → 이걸 DB랑 커넥션 맺고 끊고 안하게 하기 위해서 미리 연결해놓은 공용 와이파이(?)만 접속하면 내가 거기랑 일일히 연결했다가 끊을 필요가 없다. 그러므로 성능이 향상되는 것.(100명이 각각 데이터 연결할 필요 없이 공용 wifi 쓰면 원래 연결되어있는 wifi 커넥션들을 딱 사용할만큼만 쓸 수 있음)

인스턴스 : 집합의 개별요소. 객체지향이면 어떤 클래스에 속하는 각 객체를 인스턴스라고 함. 만약 list라는 클래스에서 myList라는 객체를 생성(메모리할당)하면 그 클래스의 인스턴스가 생성된다.

예를 들어 붕어빵틀(Class)에 반죽과 팥(변수variable)을 각각 넣어 구우면(인스턴스화) 각각의 붕어빵(Instance)가 탄생한다. 각각의 붕어빵은 객체이면서 각각의 개성이 있는 인스턴스이다.

클래스는 객체를 만들기 위한 설계도 또는 틀이고, 연관된 변수와 메소드를 묶는 집합이다.

객체는 클래스에서 선언한 모양 그대로 생성된 실체이다. 사용될 대상을 의미(=클래스의 인스턴스). 모든 인스턴스를 대표하는 포괄적인 의미

인스턴스는 만들어진 객체를 소프트웨어에 실체화하면 각각의 개성이 있으므로 각각 메모리가 할당되며 객체를 설명할 때 쓴다. 객체의 추상적인 개념이고 관계에 대한 말을 할 때 쓴다.(ex. 객체는 클래스의 인스턴스이다.) 추상적이고 여러 개성이 있으므로 원본(추상적 개념)의 생성된 복제본을 말한다.

https://gmlwjd9405.github.io/2018/09/17/class-object-instance.html

싱글톤 : 객체가 인스턴스화가 되면서 메모리를 할당할 때 그 영역을 1개만 고정해서 쓰는 것(static). 객체의 인스턴스가 오직 1개만 생성되는 패턴이다. 메모리 낭비를 안하고 데이터 공유가 쉽다. 주소가 1개로 고정되니까. 오직 한 개의 인스턴스 생성을 보증한다.

커넥션풀처럼 공통된 객체를 여러개 생성해서 사용할 때에 싱글톤 패턴을 쓴다. DB에 데이터가 공통적으로 있고, 사람들이 로그인을 동시다발적으로 하면 커넥션 풀에서 DB랑 연결된 와이파이를 빌려줘서 필요한 정보만 뺴서 쓰는거니까 싱글톤 패턴을 사용한다고 볼 수 있다.


▼ JSTL 설치 및 세팅

더보기

▼ 이클립스와 Git 연동

더보기
 

웹서버 8일차 - 회원가입 홈페이지 만들기 -⑦

어제한 것) 관리자로 로그인 시, 회원 목록 나타냄. 오늘할 것) 관리자 로그인 후, 회원 목록 중 회원 누르...

blog.naver.com


여기까지 구현된 기능 : 회원가입 / 로그인 / 관리자 로그인 시 회원목록 나오고 관리자는 회원 목록에서 회원 삭제가 가능함.

3. 네이버 CSS 긁어오기

일단 회원가입 페이지 소스보기해서 html 다 긁어오고 style 하나하나 설정해볼 예정

-> 나중에 알고보니 css도 긁어올 수 있더라.

요소 클릭해서 보면
이렇게 css 다 나옴

처음엔 일일히 따서 css 긁어왔는데^^...그래도 뭐 좋은 공부였다.

갑자기 CSS가 안먹더라.

결론적으로는 css 를 인식하지 못하는 mime 문제였던 것 같다. 왜냐면 IE에서 열었을 때 [MIME 형식이 일치하지 않아 CSS가 무시되었습니다.] 라고 떴거든. type=text/css로 되어있는데 왜 안되나 싶은데…

web.xml에서 .css 파일을 읽을 수 있도록 mime 설정 해주니 해결됨. 해결하는데 한참 걸렸다.

 

이클립스(Eclipse) 갑자기 CSS가 안먹을 때

네이버 블로그를 만들어보는 프로젝트 진행중이다. CSS랑 HTML만 긁어서 디자인 만들어놓고 회원가입 및 로그인, 게시판 기능을 구현해보고 있다. 근데 갑자기 어느날 화면이 깨지기 시작함... 심

heannim-world.tistory.com

getter setter 단축키 : Alt + Shift + S → R

4. 테이블 컬럼 맞추고 DB연결

 

java.sql.SQLException:인덱스에서 누락된 IN 또는 OUT 매개변수

이 메세지 나올때는 ps.setString() 하는 부분이 제대로 되어있는지 살펴본다. method 매개인자 개수와 ps.setString 할때 숫자가 틀렸을때 혹은 변수가 틀릴때 나는 에러이다

learn-some-computer-basics1.tistory.com

에러발생...

java.sql.SQLException: 인덱스에서 누락된 IN 또는 OUT 매개변수:: 4 에러메시지 계속 나서 뭔가 했더니 ? 갯수도 맞고 set도 제대로 했는데 왜 안되나 했더니…숫자도 맞춰야하는데 그냥 복붙해서 그랬음..ㅋ

숫자 차례대로 맞춰줘야함.

근데 왜 날짜가 안들어가지? 이상하다...했는데

날짜가 안들어감

name값이 없어서였음. id값으로 가는게 아니라 name값으로 가는거다.

회원가입 부분에 유효성 검사가 생각보다 할게 많았다. ajax부터 다시 주석달면서 DB연결해줌.



여기까지 구글링 보고 기본 세팅 및 회원가입/로그인/회원리스트 출력 및 삭제까지 완료했다.

기본기는 여기 링크에 걸린 것들로 충분히 세팅할 수 있었고, ajax 통신부터 세부적인 부분은 따로 포스팅해볼 예정이다.

5. 회원가입/로그인 소스 정리

1) MEMBERINFO 테이블

MEMBERINFO 테이블

회원 정보를 담은 MEMBERINFO 테이블이다.

회원가입 시 해당 테이블에 데이터를 insert하고, 로그인 시 이 테이블에서 select하여 가입 여부를 확인한다.

▼자세한 소스 보기

더보기

- MemberDAO 에서 설정한 sql 구문

1) 회원가입 SQL 로직

//=========================== 회원가입하는 SQL로직 ===============================
	// MemberJoinService에서 회원가입할 때 DB와 JSP를 연결할 때 인자로 쓰임.
	public int insertMember(MemberBean member) {
		//회원가입 시 DB에 member 정보를 넣는 SQL문(DB 이름 확인하기***)
		//String sql = "insert into memberinfo() values (?,?,?,?,?,?,?,?,?)";
		//memberinfo 테이블이 언제 또 추가될지 모르니 따로 넣자.
		
		String sql = 
				"INSERT INTO memberinfo("
						+ "MEM_NO,"
						+ "MEM_ID,"
						+ "MEM_PWD,"
						+ "MEM_NAME,"
						+ "MEM_BIR_YY,"
						+ "MEM_BIR_MM,"
						+ "MEM_BIR_DD,"
						+ "MEM_GENDER,"
						+ "MEM_MAIL,"
						+ "MEM_PHONE,"
						+ "MEM_REGDATE,"
						+ "MEM_PIC"
				+ ") "
				+ "VALUES( "
						+ "(SELECT NVL(MAX(mem_no), 0) + 1 FROM memberinfo)," //MEM_NO
						+ "?," //MEM_ID
						+ "?," //MEM_PWD
						+ "?," //MEM_NAME
						+ "?," //MEM_BIR_YY
						+ "?," //MEM_BIR_MM
						+ "?," //MEM_BIR_DD
						+ "?," //MEM_GENDER
						+ "?," //MEM_MAIL
						+ "?,"//MEM_PHONE
						+ "TRUNC(SYSDATE)," //MEM_REGDATE
						+ "'default.jpg'" //MEM_PIC
				+ ")";
		
		int insertCount=0;

		try {
			pstmt = con.prepareStatement(sql); 
			//prepareStatement : SQL문 실행하는 기능을 갖는 객체(변수는 ?로, setString으로 아래에 지정함.)
			pstmt.setString(1, member.getMEMBER_ID());
			pstmt.setString(2, member.getMEMBER_PW());
			pstmt.setString(3, member.getMEMBER_NAME());
			pstmt.setString(4, member.getMEMBER_BIR_YY());
			pstmt.setString(5, member.getMEMBER_BIR_MM());
			pstmt.setString(6, member.getMEMBER_BIR_DD());
			pstmt.setString(7, member.getMEMBER_GENDER());
			pstmt.setString(8, member.getMEMBER_MAIL());
			pstmt.setString(9, member.getMEMBER_PHONE());
			insertCount=pstmt.executeUpdate(); //executeUpdate : 데이터베이스 변경할 때
			//select는 executeQuery()를 사용한다.
			// insert, update, delete는 executeUpdate()를 사용한다.
			System.out.println("MemberDAO : 성공");
		
			//이 것을수행해서 정상적으로 된다면 insertCount가 1이 된다.

		} catch (Exception ex) {
			System.out.println("JoinMember 에러 : " + ex);

		} finally {
			close(pstmt); // import static db.JdbcUtil.*;
		}
		return insertCount;
	}

2) 로그인 SQL 로직(select)

//=========================== 로그인하는 SQL로직 ===============================
	// MemberLoginService에서 로그인할 때 DB와 JSP를 연결할 때 인자로 쓰임.
	public String selectLoginId(MemberBean member) { 
		String loginId = null;
		// 로그인 시 사용자가 입력한 아이디와 패스워드로 디비에 저장된 아이디 확인하는 SQL문(DB 이름 확인하기***)
		String sql = "select MEM_ID from memberinfo " + "where MEM_ID=? and MEM_PWD=?";

		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, member.getMEMBER_ID());
			pstmt.setString(2, member.getMEMBER_PW());
			rs = pstmt.executeQuery();
			//select는 executeQuery()를 사용한다.
			// insert, update, delete는 executeUpdate()를 사용한다.
			//쿼리문 처리결과 ResultSet의 객체인 rs에 저장.
			
			if (rs.next()) { 
				//rs객체에서 첫 번째 값 가져오기
				//가져올 값이 있다면~
				loginId = rs.getString("MEM_ID");  //DB 컬럼 이름 쓰기
				//member_id를 가져와서 loginId로 저장하겠다.
			}

		} catch (Exception ex) {
			System.out.println("LoginMember 에러: " + ex);
		} finally {
			close(rs);
			close(pstmt);
		}

		return loginId;
	}

2) Controller에서 Action 페이지로 보냄

회원가입 페이지, 로그인페이지 이동 및 처리할 Action 페이지로 연결한다.

▼자세한 소스 보기

더보기

- 각 분기별로 페이지를 연결해줌.

		//=============== 여기서부터 화원가입/로그인 페이지 연결해줌.  ===============
		
		ActionForward forward = null; 
		// Action이 모든 작업을 끝내고서 이동하는 위치을 가상적으로 지정한 것이 ActionForward이다.
		//ActionForward를 null로 리턴하면 이미 response에 응답을 끝냈다는 의미가 된다. 다른 어떤 페이지로도 이동하지 않는다.
		Action action = null; // execute라는 실행 메소드 return.

		//-------------------- 로그인 버튼 누르면 로그인 페이지로 이동 ---------------------------
		if(command.equals("/member/memberLogin.me")) {
			//전달된 명령이 memberLogin.me라면
			forward = new ActionForward();
			//객체 생성
			forward.setRedirect(true);
			//이동 허락
			forward.setPath("./login.jsp");
			//거기의 주소는 loginForm.jsp로 해라.(이동할 주소 저장)
		}
		
		//-------------------- 회원가입 버튼 누르면 회원가입 페이지로 이동 ---------------------------
		else if(command.equals("/member/memberJoin.me")) { //이거네...
			//member 폴더 안 login.jsp에서 전달된 명령이 member 폴더 안 memberJoin.me라면(컨트롤러 기준은 ROOT)
			forward = new ActionForward();
			//객체 생성
			forward.setRedirect(false);
			//이동 허락 안함
			forward.setPath("./joinUs.jsp");
			//거기 주소는 joinForm.jsp으로 해라.(이동할 주소 저장)
		}
		
		//-------------------- 회원가입을 처리할 memberJoinAction 페이지 생성 ---------------------------
		else if (command.equals("/member/memberJoinAction.me")) {
			
			action = new MemberJoinAction();
			try {
				forward = action.execute(req, resp); //받은 action을 뜯어서 SQL로 보내준다.
				System.out.printf("MemberFrontController : 회원가입 - SQL DB로 보내는 로직 실행 \n",req, resp);
				
				
				//메인페이지로 이동하자.
				//forward.setRedirect(true);
				//forward.setPath("../index.jsp");

			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("MemberFrontController : 회원가입 - SQL DB로 보내는 로직 실패(위에 에러)");
			}
		} //회원가입을 하면 회원 가입이 되어야하는데 이를 DB에 저장도 할 수 있어야함. -> jdbcUtil에서 연결하고 DB로 보냄.
		

		//-------------------- 로그인을 처리할 memberLoginAction 페이지 생성 ---------------------------
		
		 else if(command.equals("/member/memberLoginAction.me")) {
	    	  action = new MemberLoginAction();
	    	  //MemberLoginAction : 로그인 처리 준비. DB접속 전 준비.
	    	  
	    	  try {
	    		  forward = action.execute(req, resp); //받은 action을 뜯어서 SQL로 보내준다.
					System.out.printf("MemberFrontController : 로그인 - SQL DB로 보내는 로직 실행 \n",req, resp);
	    	  }catch (Exception e) {
	    		  e.printStackTrace();
					System.out.println("MemberFrontController : 로그인 - SQL DB로 보내는 로직 실패(위에 에러)");
	    	  }
	      }

forward.setRedirect(true);
forward.setPath("./login.jsp");

를 통해 Path로 주소를 이동시킨다.

생성된 action 은 execute로 요청과 응답값을 받는데, execute() 메소드는 리턴값으로 스트링형을 반환하며, 반환되는 이 리턴값이 무엇이냐에 따라서 그 다음 로직이 어떻게 진행될지가 결정된다고 생각하면 된다.

3) Action 페이지에서 회원가입 처리

회원가입 시 클라이언트는 HTTP 프로토콜을 이용해서 서버로 데이터를 요청한다. 이 때 jsp 페이지에서 폼에 작성한 내용을 파라미터로 하여금 요청(request)에 끼워서 보낼 수 있다. 그래서 jsp 폼에 작성한 내용들이 서버로 전달되는 것.

이 전달된 값을 서버에서 읽기 위해 request.getParameter() 메소드를 사용한다.

반대로 서버에 있는 내용을 클라이언트인 jsp 페이지로 전달해줘야한다고 하면, 다른곳으로 정보를 넘겨주기 위해 request 객체의 attribute 속성을 사용한다. 서블릿 간에 주고받는 데이터들을 setAttribute 한 값을 getAttribute 등으로 꺼내 쓰는 것.

▼자세한 소스 보기

더보기
/* 인터페이스를 함께 추가했다. 회원가입 처리를 위한 클래스이다.*/
public class MemberJoinAction implements Action { //Action을 implements 해줌

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		MemberBean member = new MemberBean(); //vo에 선언한 변수들 import한거.
		//회원 정보를 저장하고 DB로 전달.
		//회원 정보를 가지고 있을 공간이 된다.
		
		
		boolean joinResult = false;
		
		//입력 목록 적어주기(vo에서 받아옴.)
		member.setMEMBER_ID(req.getParameter("MEMBER_ID"));
		member.setMEMBER_PW(req.getParameter("MEMBER_PW"));
		member.setMEMBER_NAME(req.getParameter("MEMBER_NAME"));
		member.setMEMBER_BIR_YY(req.getParameter("MEMBER_BIR_YY"));
		member.setMEMBER_BIR_MM(req.getParameter("MEMBER_BIR_MM"));
		member.setMEMBER_BIR_DD(req.getParameter("MEMBER_BIR_DD"));
		member.setMEMBER_GENDER(req.getParameter("MEMBER_GENDER"));
		member.setMEMBER_MAIL(req.getParameter("MEMBER_MAIL"));
		member.setMEMBER_PHONE(req.getParameter("MEMBER_PHONE"));
			

		MemberJoinService memberJoinService = new MemberJoinService();
		
		//서비스 svc에서 만들어준다. 아래에 회원가입 처리를 해주자.
		
		//=========================== 회원가입 처리 ================================
		joinResult = memberJoinService.joinMember(member);

		ActionForward forward = null;
		if (joinResult == false) { //회원가입 실패 시
			resp.setContentType("text/html;charset=UTF-8");
			PrintWriter out = resp.getWriter(); //위에 있음
			out.println("<script>");
			out.println("alert('회원등록실패')");
			out.println("history.back()");
			out.println("</script>");
		} else { //회원가입 성공 시
			forward = new ActionForward();
			forward.setRedirect(true);
			forward.setPath("./memberLogin.me");
		}
		
		return forward;
	}

}

4) Action 페이지에서 로그인 처리

로그인은 더 간단하게 id 비밀번호만 폼에서 받아서 SQL 검색대로 보내준다.

▼자세한 소스 보기

더보기
/* 인터페이스를 함께 추가했다. 로그인 처리를 위한 클래스이다.*/
public class MemberLoginAction implements Action { //Action을 implements 해줌
	

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		//session을 써서 서버 생성함.
		HttpSession session = req.getSession();
		//session - 페이지 로그인 유지 방법
		//**참고: cookie - 페이지 로그인 유지 방법, 클라이언트 생성. **
		
		
		// session상의 회원 등급은 존재하지 않음. ???
		// DB관리자의 회원 등급은 서로 다름. ???
		
		MemberBean member = new MemberBean();

		member.setMEMBER_ID(req.getParameter("MEMBER_ID"));
		member.setMEMBER_PW(req.getParameter("MEMBER_PW"));
		// vo의 MemberBean에서 아이디와 패스워드를 넘겨받아와라.

		
		
		MemberLoginService memberLoginService = new MemberLoginService();
		//서비스 svc에서 만들어준다. 아래에 로그인 처리를 해주자.
		

		//=========================== 로그인 처리 ================================
		boolean loginResult = memberLoginService.login(member);
		//사용자가 등록되어 있다면 true, 아니라면 false리턴.
		
		ActionForward forward = null; //어디로 갈지?

		if (loginResult) { //로그인 성공 시
			forward = new ActionForward();
			session.setAttribute("id", member.getMEMBER_ID());
			//session에 사용자의 ID 저장.
			forward.setRedirect(true);
			//Redirect유무
			forward.setPath("./memberListAction.me");
			//패스 지정
			
			// ++ 추가로 로그인 했다고 alert를 띄워줄꺼임.
//			resp.setContentType("text/html;charset=UTF-8");
//			PrintWriter out = resp.getWriter();
//			out.println("<script>");
//			out.println("alert('로그인성공');");
//			out.println("</script>");
			
		} else { //로그인 실패 시
			resp.setContentType("text/html;charset=UTF-8");
			PrintWriter out = resp.getWriter();
			out.println("<script>");
			out.println("alert('로그인실패');");
			out.println("location.href='./memberLogin.me';");
			//로그인 창으로 다시 이동하라.
			out.println("</script>");
			
		}//else는 로그인 실패 부분을 담당함.
		//자바 코드에서 문자열을 만들어내서 결과적으로 자바 스크립트로 생성하여 console.log에 표시함.

		return forward; //null이 아니라 forward로 가야지.
		//ActionForward를 null로 리턴하면 이미 response에 응답을 끝냈다는 의미가 된다. 다른 어떤 페이지로도 이동하지 않는다.
	}

}

 

회원가입 기능 구현
로그인 기능 구현

이 다음은 회원가입 기능 중 id 체크나 validation 관련된 기능을 구현해보겠습니다.

▼ 진행중인 gitHub 링크를 남깁니다.

 

GitHub - k-haein/BlogPrj: 회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다.

회원가입/로그인/게시글 등록 등의 블로그를 처음부터 만듭니다. Contribute to k-haein/BlogPrj development by creating an account on GitHub.

github.com

반응형
LIST
반응형
SMALL

+ Recent posts

반응형
LIST