티스토리 뷰





반응형

회원목록을 보는 기능을 구현할 것이다. 근데 이때 저장된 회원수가 많을 것 이기에 페이징 처리를 해서 데이터를 짤라서 보도록 할 예정이다. 포스팅에 하기에 앞서 페이징 처리는 공식에 의한 것이라 그렇게까지 자세히 하진 않을것이다. 필요하다고 생각되는 부분만 포스팅 할 예정이니 이점 참고해서 봐두면 좋을것 같다.


1. 보안처리

회원목록을 보고 나아가 관리까지도 가능할 페이지라서 접근자가 회원이 아니거나, 회원이지만 관리자가 아닌경우 접속을 막는것 회원에 대한 정보는 세션에 넣어놨기 때문에 거기에 꺼내서 사용하고, 에러 페이지로 이동시켰다가 메인화면으로 다시 이동시키는 로직 

1
2
3
4
5
6
7
8
9
//회원리스트를 보는 기능이기 때문에 회원이 아니거나 id가 admin이 아닐경우 접근을 제한한다.
        Member logginMember = (Member)request.getSession().getAttribute("loginMember");
        if(logginMember == null || !logginMember.getMemberId().equals("admin")) 
        {
            request.setAttribute("msg""잘못된 경로로 접속하셨습니다");
            request.setAttribute("loc""/");
            request.getRequestDispatcher("/views/common/msg.jsp").forward(request, response);
            return;
        }
cs


2. 페이징 처리

cPage = 현재 사용자가 보고 있는 페이지

numPerPage = 한 페이지당 나타낼 자료의 갯수

totalMember = 현재 디비에 등록된 총 회원 수

totalPage = (총 회원수/한 페이지당 나타낼 회원 수)의 총 갯수, ex) 10명/2개씩 -> 총 5페이지

pageBar = html 코드를 넣어줄 변수 (아래서 자세히)

pageBarSize = 아래 사진과 같은건데 1~5까지 보일것이냐 1~10까지 보일꺼냐 정하는 것.  

pageNo=공식을 사용해 1,6,11만 나오게끔 유도하는 것(설명때 자세히)

pageEnd=공식을 사용해 페이지바가 특정 값이 넘어가는지 체크(설명때 자세히)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//페이징처리 하자
        int cPage; //현재 페이지를 의미
        try {
            cPage = Integer.parseInt(request.getParameter("cPage"));
        }catch (NumberFormatException e) {
            cPage = 1;
        }
        int numPerPage;    //페이지당 자료수
        try {
            numPerPage = Integer.parseInt(request.getParameter("numPerPage"));
        }catch (NumberFormatException e) {
            numPerPage = 10;
        }
        
        //페이지수 만큼 데이터를 불러옴
        List<Member> list = new AdminService().selectMemberList(cPage,numPerPage);
        
        //페이지 구성해보기
        //전체자료수를 확인
        int totalMember = new AdminService().selectMemberCount();
        //전체페이수
        int totalPage = (int)Math.ceil((double)totalMember/numPerPage);
        //페이지바 html코드 누적변수
        String pageBar="";
        //페이지바 길이
        int pageBarSize =5;
        int pageNo=((cPage-1)/pageBarSize)*pageBarSize+1;
        int pageEnd = pageNo+pageBarSize-1;
cs


일단 1~14번째 줄까지는 그냥 초기화를 시켜주는 코드이며 16번째 줄은 현재 페이지와 가져올 데이터 갯수를 넣고 멤버를 찾는 매소드를 호출한 것이다. 현재 페이지가 1이고 가져올 데이터가 5개면 1~5가 가져오겠죠? 근데 현재 페이지가 2이고 가져올 데이터가 5개면 6~10을 가져와야겠죠? 그것을 구현한 것입니다. 그 가져온 멤버를 list에 담은것이고 그 밑에 totalPage는 pageBar에서 사용하기위해 가져온것이다. 


totalPage에 자세한 설명은 위에 된거같아 생략하고 Math.ceil가 쓰인 이유는 무조건 올림 처리인데 전체 데이터가 10개고 3개씩 가져오면 데이터가 1개 남는다. 이것까지 가져오려면 올림을 해줘야지 가져오기 때문에 double로 소수점까지 나오게 캐스팅했다가 올림처리가 되면 다시 int형으로 바꿔나오게 한 것이다. 


pageBar는 html코드를 이따가 써줄것이고 pageBarSize는 밑에 숫자를 몇까지 나오게 할 것인지 내맘대로 지정한 것이며 no와 end는 공식을 적용한 것이다. 이건 no를 기준으로 위에 barsize만큼 나오게 하기 위함이다. no의 공식대로라면 1~5까지는 1이 나오고 그걸 기준으로 5개가 나오도록 한것이다. 6~10부터는 2가 된다. end는 그 숫자를 넘어가면 바뀌는 처리를 위한 것 (이따가 설명)


3. Dao 뜯어보기

자 이제 내가 왜 공식에 의한것이고 필요한 부분만 하겠다는지 나오는 대목이다. 집중해서 보도록 하자

(이 전의 service 부분은 크게 별다른 거 없이 호출만하는 부분이라 생략함)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public List<Member> selectMemberList(Connection conn, int cPage, int numPerPage){
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        ArrayList<Member> list = new ArrayList();
        String sql = prop.getProperty("selectMemberList");
        try {
            pstmt = conn.prepareStatement(sql);
            
            pstmt.setInt(1, (cPage-1)*numPerPage+1;
            pstmt.setInt(2, cPage*numPerPage);
            rs = pstmt.executeQuery();
            Member m = null;
            
            while(rs.next()) 
            {
                m = new Member();
                m.setMemberId(rs.getString("userid"));
                m.setMemberPwd(rs.getString("password"));
                m.setMemberName(rs.getString("username"));
                m.setGender(rs.getString("gender"));
                m.setAge(rs.getInt("age"));
                m.setAddress(rs.getString("address"));
                m.setPhone(rs.getString("phone"));
                m.setHobby(rs.getString("hobby"));
                m.setEmail(rs.getString("email"));
                m.setEnrollDate(rs.getDate("enrolldate"));
                
                list.add(m);
            }
            
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            close(rs);
            close(pstmt);
        }
        return list;
    }
public int selectMemberCount(Connection conn) {
        PreparedStatement pstmt = null;
        ResultSet rs=null;
        int result =0 ;
        String sql = prop.getProperty("selectMemberCount");
        try {
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            if(rs.next()) {
                result = rs.getInt("cnt");
                
            }
        }catch (Exception e) {
            // TODO: handle exception
        }finally {
            close(rs);
            close(pstmt);
        }
        return result;
    }
//위에서 사용된 sql문 2개다.
selectMemberList=
    SELECT * FROM (SELECT ROWNUM AS RNUM, V.* FROM
    ( SELECT * FROM MEMBER ORDER BY ENROLLDATE DESC) V ) V 
        WHERE RNUM BETWEEN ? AND ?
 
selectMemberCount = select count(*) as cnt from member
cs
cs


먼저 selectMemberList다. pstmt.setInt에 들어가는 값 보이는가? 역시 개어렵다 그냥 필요할 때 저렇게 쓰자.. 일단 확실한건 저렇게 넣어주면 아까 말했던 cPage는 현재 몇번째 페이지이고 거기서 몇개의 데이터를 뽑아올지 numPerPage로 알려주는데 저렇게 데이터의 1~5, 6~10 등등의 정보를 가져오는것이다. sql문을 보자 첫번째 sql문인데 엄청나게 복잡하다... 간단하게 설명을 하자면.. 정렬된 값을 가져오려면 sql 한 문장으론 절대 되지못한다. 로직 실행순서에 의해 정렬 후 가져올수가 없어서 한 단계를 거쳐야하는데 오라클에서 순번에 쓰이는 rownum또한 제대로 쓰려면 한 단계를 또 거쳐야한다. 그래서 별칭을 지어준 채로 한번 더 사용해 총 3단계에 걸쳐서 쿼리문을 작성을 한 것이다.


혹시 정렬할 기준이 바뀔일이 있으면 제일 안쪽에 있는 값을 바꿔야한다. 

ex)

 select * from (select rownum as rnum, v.* from 

(select * from member where username like '%김%'order by enrolldate desc;)v)v 

where rnum between ? and ?


두번째는 뭐 총 회원수가 몇명인지 도출하는 값으로 쉽다. 다만 별칭을 지정해서 그 이름으로 가져오는것만 주의하면 될것 같다.


4. 페이지 바 구성하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//페이지바를 구성
        if(pageNo==1) {
            pageBar +="<span>[이전]</span>";
        }else {
            pageBar += "<a href='"+request.getContextPath()+
                    "/admin/memberList?cPage="+(pageNo-1)+"&numPerPage="+numPerPage+"'>[이전]</a>";
        }
        //선택페이지 만들기
        while(!(pageNo>pageEnd || pageNo>totalPage))
        {
            if(cPage==pageNo) {
                pageBar += "<span class='cPage'>"+pageNo+"</span>";
            }else {
                pageBar += "<a href='"+request.getContextPath()+
                        "/admin/memberList?cPage="+(pageNo)+"&numPerPage="+numPerPage+"'>"+pageNo+"</a>";
            }
            pageNo++;
        }
        //[다음] 구현
        if(pageNo>totalPage) 
        {
            pageBar += "<span>[다음]</span>";
        }else {
            pageBar +="<a href='"+request.getContextPath()+
                    "/admin/memberList?cPage="+pageNo+"&numPerPage="+numPerPage+"'>[다음]</a>";
        }
        request.setAttribute("list", list);
        request.setAttribute("cPage", cPage);
        request.setAttribute("numPerPage", numPerPage);
        request.setAttribute("pageBar", pageBar);
        request.getRequestDispatcher("/views/admin/memberList.jsp").forward(request, response);
cs

일단 시작 페이지가 1이면 pageBar는 1~5가 나오게 된다. 그러면 이전이라는 기능은 사용하지 못하니까 span태그로 그냥 텍스트로 저장한다. 하지만 그렇지 않으면 이전으로 돌아갈게 있다는 소리니까 클릭이 가능하다록 a태그로 생성하고 href는, 이전을 눌렀으니 이전의 데이터를 가져오기위해 현재의 서블릿을 호출한다.pageNo가 6이면 6~10 구간이니 이전인 cPage(현재페이지)는 1~5중 -1 해서 5로 가게끔 하고 numPerPage는 사실 안보내도 되는데 내가 구성한 페이지에선 한 페이지에 나타낼 데이터 갯수를 바꿀수 있도록 구성해서 저렇게 같이 보내게 만들었다. 

이제 while문이다. 조건은 2개가 있는데 뒤에부터 하자면 이게 지금 no가 1일때 1~5가 나오는데 총 페이지가 4페이지까지만 있다면 5는 나오면 안되기 때문에 no가 totalPage보다 크면 탈출해 더이상 번호가 안찍히도록 하는 조건이다. 처음 조건식 !(no>end)는 1~5까지만 나오게 하고싶어서 end에 공식으로 5가 나온다. 근데 no가 6이 되면 6개가 보이는 꼴이니 그걸 막아주기위한 것이다. 따라서 no가 end를 넘지않는 선까지만 로직이 돌아가게끔 구현.
그래서 안에 if로는 현재 보는 창에만 span으로 텍스트만 출력하게끔 하고 그 이외엔 위와 마찬가지로 현재의 서블릿을 다시 호출해서 해당 번호의 자료를 가져오도록 하고 쿼리스트링으로 cPage의 값을 넘겨준다. 밑에 no를 증가시켜 1~5가 밑에 주르륵 나오게 만들기도 한다.

다음은 이전에서의 기능과 유사하니 생략.

이렇게 값을 memberList.jsp로 보내준다. 아그리고 pageNo는 처음의 공식에 의해 1~5 구간은 1로 6~10은 6으로 늘 초기화된다.


memberList.jsp의 일부 소스를 가져왔다. 위와같이 데이터를 넘겨받고 for-in문으로 데이터를 뿌려주고 밑에 pageBar에는 바로 위에서했던 [이전]1245[다음]이 있어서 div로 넣어주기만 했다.


결과창


반응형
댓글
반응형
최근에 달린 댓글
글 보관함
Total
Today
Yesterday
최근에 올라온 글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30