개발자 미니민의 개발스터디

[JSP] 글 리스트 Servlet 서블릿/DAO

by mini_min

JSP

[JSP] 글 리스트 Servlet 서블릿/DAO

✔️ 글 리스트 출력하기 (DB)

: 먼저 숙지할 것!! 글 리스트만 출력하면 <전체 데이터 갯수 구하는 DAO / 리스트 출력 DAO> 이렇게 2가지만 있어도 되지만, 검색 기능이 가능한 게시판을 만들기 때문에 DAO 가 2개 더 필요하다.

  • 전체 데이터 갯수 구하는 DAO
  • 전체 데이터 리스트 출력 DAO
  • 검색된 데이터 갯수 구하는 DAO (NEW)
  • 검색된 데이터 리스트 출력 DAO (NEW)
💡 중요!!
데이터 리스트를 출력할 때, 페이징 처리하여 출력할거다.
인수로 건너뛸 수 offset 과 데이터를 가져올 수 size  2가지를 갖는다.

 

📓 전체 데이터 갯수 구하는 DAO

public int dataCount() {
    //전체 데이터 갯수

    int result = 0;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    String sql;

    try {

        sql = " SELECT COUNT(*) FROM bbs ";

        pstmt = conn.prepareStatement(sql);

        rs = pstmt.executeQuery();
        if(rs.next()) {
            result = rs.getInt(1);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(rs!=null) {
            try {
                rs.close();
            } catch (Exception e2) {
            }
        }

        if(pstmt!=null) {
            try {
                pstmt.close();
            } catch (Exception e2) {
            }
        }
    }

    return result;
}

 

📓 전체 데이터 리스트 출력 DAO

public List<BoardDTO> listBoard(int offset, int size) {
    List<BoardDTO> list = new ArrayList<>();
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    StringBuilder sb = new StringBuilder();

    try {

        sb.append("  SELECT num, name, subject, hitCount, ");
        sb.append("  	TO_CHAR(reg_date, 'YYYY-MM-DD') reg_date ");
        sb.append("	 FROM bbs ");
        sb.append("	 ORDER BY num DESC ");
        sb.append("	 OFFSET ? ROWS FETCH FIRST ? ROWS ONLY ");

        pstmt = conn.prepareStatement(sb.toString());

        pstmt.setInt(1, offset);
        pstmt.setInt(2, size);

        rs = pstmt.executeQuery();

        while(rs.next()) {
            BoardDTO dto = new BoardDTO();

            dto.setNum(rs.getLong("num"));
            dto.setName(rs.getString("name"));
            dto.setSubject(rs.getString("subject"));
            dto.setHitCount(rs.getInt("hitCount"));
            dto.setReg_date(rs.getString("reg_date"));

            list.add(dto);

        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(rs!=null) {
            try {
                rs.close();
            } catch (Exception e2) {
            }
        }

        if(pstmt!=null) {
            try {
                pstmt.close();
            } catch (Exception e2) {
            }
        }
    }


    return list;

}

 

📓 검색된 데이터 갯수 구하는 DAO

: 검색한 데이터를 구하기 위해서는, select 박스의 조건과 검색어가 일치하는 부분을 가져와야한다.

- 1차로 볼 것 : select 박스의 조건 일치 여부

- 2차로 볼 것 : select 박스에 입력한 검색어와 조건 영역에 일치하는 것이 있는지 여부

 

👩‍💻 검색 케이스

• 제목, 내용에 일치하는게 있는지(조건: all) 확인하기 (2군데는 예외적인 케이스)

: WHERE INSTR(subject, ?) >= 1 OR INSTR(content, ?) >= 1

 

• 날짜에 일치하는게 있는지(조건: reg_date) 확인하기

이때, 날짜는 어떻게 입력될지 모르니까, 날짜로 입력되는 keyword 에 . / - 는 공백처리한다.(replaceAll)

: WHERE TO_CHAR(reg_date, 'YYYYMMDD')= ? 

 

• 2군데 검색 / 날짜 검색 말고 다른 검색들은 들어오는 조건과 검색어가 일치하는지 else 구문으로 파악한다.

: WHERE INSTR(condition, ?) >= 1

 

👩‍💻 2군데 검색(제목+내용) 부분은 pstmt.set keyword 값이 2개가 필요하며, if 문으로 처리하고 나머지 부분은 pstmt.set 1개만 입력한다. 

 

public int dataCount(String condition, String keyword) {
    //검색할 때 데이터 갯수

    int result = 0;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    String sql;

    try {

        sql = " SELECT COUNT(*) cnt FROM bbs ";
        if(condition.equals("all")) {		//제목, 내용에 일치하는게 있는지 확인
            sql += " WHERE INSTR(subject, ?) >= 1 OR INSTR(content, ?) >= 1 ";
        }else if(condition.equals("reg_date")) {	//날짜는 형식 다 제거하기
            keyword = keyword.replaceAll("(\\-|\\/|\\.)", "");
            sql += " WHERE TO_CHAR(reg_date, 'YYYYMMDD')= ? ";
        }else { 	//name, subject, content
            sql += " WHERE INSTR(" + condition + ", ?) >= 1 ";
        }

        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, keyword);

        if(condition.equals("all")) {
            pstmt.setString(2, keyword);
        }

        rs = pstmt.executeQuery();
        if(rs.next()) {
            result = rs.getInt("cnt");
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(rs!=null) {
            try {
                rs.close();
            } catch (Exception e2) {
            }
        }

        if(pstmt!=null) {
            try {
                pstmt.close();
            } catch (Exception e2) {
            }
        }
    }

    return result;
}

 

📓 검색된 데이터 리스트 출력

: 전체 리스트 출력 메소드와 윗부분은 동일하지만, <키워드, 조건>이 WHERE 절에 추가로 작성되어야한다.

 

마찬가지로 all 인 경우, reg_date 날짜 검색인 경우를 if 문으로 처리한다. 

public List<BoardDTO> listBoard(int offset, int size, String condition, String keyword) {
    List<BoardDTO> list = new ArrayList<>();
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    StringBuilder sb = new StringBuilder();

    try {

        sb.append("  SELECT num, name, subject, hitCount, ");
        sb.append("  	TO_CHAR(reg_date, 'YYYY-MM-DD') reg_date ");
        sb.append("	 FROM bbs ");
        if(condition.equals("all")) {
            sb.append(" WHERE INSTR(subject, ?) >= 1 OR INSTR(content, ?) >= 1");
        }else if(condition.equals("reg_date")) {
            keyword = keyword.replaceAll("(\\-|\\/|\\.)", "");
            sb.append(" WHERE TO_CHAR(reg_date, 'YYYYMMDD') = ? ");
        }else {
            sb.append(" WHERE INSTR(" + condition + ", ? ) >= 1 ");
        }

        sb.append("	 ORDER BY num DESC ");
        sb.append("	 OFFSET ? ROWS FETCH FIRST ? ROWS ONLY ");

        pstmt = conn.prepareStatement(sb.toString());

        if(condition.equals("all")) {
            pstmt.setString(1, keyword);
            pstmt.setString(2, keyword);
            pstmt.setInt(3, offset);
            pstmt.setInt(4, size);

        }else {
            pstmt.setString(1, keyword);
            pstmt.setInt(2, offset);
            pstmt.setInt(3, size);
        }

        rs = pstmt.executeQuery();

        while(rs.next()) {
            BoardDTO dto = new BoardDTO();

            dto.setNum(rs.getLong("num"));
            dto.setName(rs.getString("name"));
            dto.setSubject(rs.getString("subject"));
            dto.setHitCount(rs.getInt("hitCount"));
            dto.setReg_date(rs.getString("reg_date"));

            list.add(dto);

        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(rs!=null) {
            try {
                rs.close();
            } catch (Exception e2) {
            }
        }

        if(pstmt!=null) {
            try {
                pstmt.close();
            } catch (Exception e2) {
            }
        }
    }


    return list;

}

 

 

✔️ 글 리스트 출력하기 (서블릿)

: 서블릿 부분은 더 복잡하다....

왜냐하면, 페이징 처리까지 들어가기 때문이다.

 

• dao 객체 / 페이징 처리해주는 메소드가 있는 MyUtil (이전에 미리 작성) 객체를 만들어준다.

+ 추가로 ContextPath 경로 값도 cp 변수에 저장한다.

cp 변수는 페이징 처리할 때 필요하다. 검색했을 때 페이지에 따라 출력되는 데이터를 봐야하기 때문이다.

 

📓 필요한 것!!!!

1) 파라미터 구하기 (페이지 번호, 검색 조건, 검색어)

- 페이지 번호 파라미터 값 (전체 페이지 초과하는 것 막기)

- 검색 조건, 검색어(키워드) 파라미터 값

 

2) 디코딩

- GET 방식일 때, 검색어(키워드) 디코딩

 

3) 페이징 처리 - 데이터, 페이지 수 구하기

- 전체 데이터 수 (검색 or not)

- 전체 페이지 수 util 의 pageCount 이용

- offset 값 설정

 

4) 데이터 출력

- list DAO 실행 (검색 or not)

 

5) 페이징 처리 - query 값 설정

- 검색시 보여지는 url 를 query 값에 저장 (검색 or not)

 

6) 페이징 처리 - uri 설정

- 검색에 따른 url 를 설정하기 위해서 query 값 이용

query 가 url 가 되는 조건들을 설정하고 util 의 paging 메소드를 실행해서 페이징 처리한다.

이때, listUrl 이 query 가 url 가 되는 조건들이 설정되어서 생성된 url 이 되는 것이다.

 

이 주소는 검색해서 페이징이 넘어갈 때 뜨는 URL 이다. 이걸 봐야하기 때문에 위와 같은 작업을 하는 것임.

 

7) 포워딩할 JSP 에 지금까지 작성한 모든 속성 전달하기~~

+ 포워딩하기, JSP 에서 사용하기만 하면 끝...ㅠㅠ

 

 

📓 아래 코드 순서대로 풀이함

protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //글 리스트 

    BoardDAO dao = new BoardDAO();
    MyUtil_c util = new MyUtil_c();
    String cp = req.getContextPath();

    try {
        //페이지 번호
        String page = req.getParameter("page");
        int current_page = 1;
        //클라이언트가 전송한 페이지 번호가 있으면 그게 현재 페이지
        if(page != null) {
            current_page = Integer.parseInt(page);
        }

        //검색 (검색조건과 검색어 파라미터값 가져오기)
        //따로 검색한게 없으면 all / 검색어x
        String condition = req.getParameter("condition");
        String keyword = req.getParameter("keyword");
        if(condition == null) {
            condition = "all";
            keyword = "";
        }

        //GET 방식이면 디코딩
        if(req.getMethod().equalsIgnoreCase("GET")) {
            keyword = URLDecoder.decode(keyword, "utf-8");
        }

        //전체 데이터 개수
        int dataCount;
        if(keyword.length()==0) { //검색이 아닌경우 모두 출력
            dataCount = dao.dataCount();
        }else { //검색인 경우
            dataCount = dao.dataCount(condition, keyword);
        }

        //전체 페이지 수?
        int size = 10; //데이터 10개씩 출력
        int total_page = util.pageCount(dataCount, size);
        if(current_page>total_page) {
            current_page = total_page;
        }

        //게시글 가져오기 0 10 20 30 이거!
        int offset = (current_page - 1) * size;
        if(offset < 0) offset = 0;

        //검색어 1)무 2)유
        List<BoardDTO> list;
        if(keyword.length()==0) {
            list = dao.listBoard(offset, size);
        }else {
            list = dao.listBoard(offset, size, condition, keyword);
        }

        String query = "";
        if(keyword.length()!=0) {
            query = "condition =" +condition+ "&keyword="+URLEncoder.encode(keyword, "utf-8");

        }

        //페이징 처리
        String listUrl = cp + "/bbs/list.do";
        String articleUrl = cp + "/bbs/article.do?page="+current_page;
        if(query.length()!=0) {
            listUrl += "?" + query;
            articleUrl += "&" + query;
        }

        String paging = util.paging(current_page, total_page, listUrl);

        //포워딩할 JSP 에 전달할 속성(attribute)
        //포워딩할 곳 : list.jsp 입니다.
        req.setAttribute("list", list);
        req.setAttribute("page", current_page);
        req.setAttribute("dataCount", dataCount);
        req.setAttribute("size", size);
        req.setAttribute("total_page", total_page);
        req.setAttribute("articleUrl", articleUrl);
        req.setAttribute("paging", paging);
        req.setAttribute("condition", condition);
        req.setAttribute("keyword", keyword);


    } catch (Exception e) {
        e.printStackTrace();
    }


    // 포워딩에서의 /는 cp까지
    forward(req, resp, "/WEB-INF/views/bbs/list.jsp");

}

 

 

 

블로그의 정보

개발자 미니민의 개발로그

mini_min

활동하기