Coding History

국비 지원 IT(웹앱개발) 취업반 강의 46일차 (JSP)

BlackBirdIT 2024. 8. 8. 23:15

다음으로 글 작성을 회원만 할 수 있게끔 만들어주자.

기존의 글 작성 기능을 담당하던 코드들에 회원이 로그인 했을 때 접근할 수 있게끔 해야된다.

@WebServlet("/article/write")
public class ArticleWriteServlet extends HttpServlet {


    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        HttpSession session = request.getSession();

        if (session.getAttribute("loginedMemberId") == null) {
            response.getWriter().append(
                    String.format("<script>alert('로그인 하고 이용해'); location.replace('../member/login');</script>"));
            return;
        }
        request.getRequestDispatcher("/jsp/article/write.jsp").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);

    }

}

우선은 articleWrite의 코드부터 고쳤다. 로그인 하지 않으면 글 작성버튼을 누를 수 없게 알림창 띄우고 로그인 창으로 넘어가게끔.

잘 작동한다!

로그인상태일 때는 글 작성으로 넘어가는가도 확인해보면 잘 넘어간다.

@WebServlet("/article/dowrite")
public class ArticleDoWriteServlet extends HttpServlet {


    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        // DB 연결
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("클래스를 찾을 수 없습니다.");
            e.printStackTrace();
        }

        String url = "jdbc:mysql://127.0.0.1:3306/AM_JDBC_2024_07?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul";
        String user = "root";
        String password = "1234";

        Connection conn = null;

        try {
            conn = DriverManager.getConnection(url, user, password);

            HttpSession session = request.getSession();

            String title = request.getParameter("title");
            String body = request.getParameter("content");
            int loginedMemberId = (int) session.getAttribute("loginedMemberId");

            SecSql sql = SecSql.from("INSERT INTO article");
            sql.append("SET regDate = NOW(),");
            sql.append("updateDate = NOW(),");
            sql.append("title = ?,", title);
            sql.append("`body`= ?,", body);
            sql.append("memberId= ?,", loginedMemberId);

            int id = DBUtil.insert(conn, sql);

            response.getWriter().append(String.format(
                "<script>alert('%d번 글이 작성되었습니다.'); location.replace('detail?id=%d');</script>", id, id));

        } catch (SQLException e) {
            System.out.println("SQL 에러: " + e.getMessage());
            response.getWriter().append("<script>alert('글 작성에 실패했습니다.'); history.back();</script>");
        } finally {
            try {
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);

    }

}

다음으론 실제 글 작성시 글쓴이의 아이디가 실제 DB에 저장될 수 있도록 하드코딩을 지우고 session을 이용해서 넘겼다.

화면에 작성자가 나오게끔 만들어주지 않았으니 화면도 수정하자.

<div>
    작성자 :
    <%=articleRow.get("memberId")%>
</div>

detail JSP에 해당 div태그를 넣고 보면.

test2로 로그인 하고 글작성까지 해보면.. 작성자 표시까지 잘 뜬다. 근데 생각해보면 번호가 아니고 이름으로 떴으면 좋겠다.

이름을 가져오려면 데이터베이스의 테이블을 병합할 필요가 있다.
detail 서블릿에 이너조인을 해서 member 테이블의 이름을 뽑아와야된다.

            SecSql sql = SecSql.from("SELECT a.*, m.name");
            sql.append("FROM article AS a");
            sql.append("INNER JOIN `member` AS m");
            sql.append("ON a.memberId = m.id");
            sql.append("WHERE id = ?", id);

해당 서블릿의 쿼리를 일단 수정해주자.
이렇게 수정했는데 갑자기 디테일 페이지가 뜨지 않아서 좀 당황했다.
잘 보면 WHERE절에 alias를 빼먹었다.

            SecSql sql = SecSql.from("SELECT a.*, m.name");
            sql.append("FROM article AS a");
            sql.append("INNER JOIN `member` AS m");
            sql.append("ON a.memberId = m.id");
            sql.append("WHERE a.id = ?", id);

추가해주고,

JSP에 memberId를 name으로 고쳐주면

이름까지 잘 나와준다.

삭제시 권한 체크를 해보자.

doDelete 서블릿에

if (session.getAttribute("loginedMemberId") == null) {
            response.getWriter().append(
                    String.format("<script>alert('로그인 하고 이용해'); location.replace('../member/login');</script>"));
            return;
        }

로그인하지 않았을 때 삭제할 수 없게 기존 코드를 다시 붙혀넣고.

SecSql sql = SecSql.from("SELECT *");
            sql.append("FROM article");
            sql.append("WHERE id = ?", id);

            Map<String, Object> articleRow = DBUtil.selectRow(conn, sql);

            int loginedMemberId = (int) session.getAttribute("loginedMemberId");

            if (loginedMemberId != (int) articleRow.get("memberId")) {
                response.getWriter().append(
                        String.format("<script>alert('%d번 글에대한 권한 x'); location.replace('list');</script>", id));
                return;
            }

            sql = SecSql.from("DELETE");
            sql.append("FROM article");
            sql.append("WHERE id = ?", id);

기존에 delete만 있던 쿼리문에 select까지 추가해 게시물과 로그인 되어있는 ID가 동일한지 체크 할 수 있게 만든다.

2번 회원이 로그인 상태고.

1번회원으로 생성된 글을 지우도록 시도해보자.

권한이 없다고 잘 표시된다.

로그인 한 회원이 쓴 글을 삭제해보면 잘 된다.