본문으로 바로가기

[JSP개발] 총방문자 수, 오늘 방문자 수 추가

category 코딩/JSP 2016. 12. 5. 09:00







1. 개요






MVC 패턴 적용 이후 이번에는 방문자 수를 보여주는 부분을 추가할 것이다. 방문자 수를 구하는 방법은 여러 가지가 있는데 여기에서는 세션과 DB를 사용할 것이다.



■ Java

  • VisitSessionListener.java : 방문자 수를 계산하는 클래스로 web.xml에 listener 등록을 해두었다.

  • VisitCountDAO.java : Visit 테이블의 DAO


JSP

  • Footer.jsp : 하단 영역 JSP를 추가 하였다. 여기에는 방문자 수가 표시된다.




2. 소스 코드



■ 테이블


먼저 테이블을 생성하고 아래의 쿼리를 실행시켜 몇 개의 데이터를 집어넣는다.


1
2
3
4
 
<테이블 생성 쿼리>
 
CREATE TABLE VISIT (V_DATE DATE NOT NULL);
cs


1
2
3
INSERT INTO VISIT (V_DATE) VALUES ( TO_DATE('10-06-2016','MM-DD-YYYY') );
INSERT INTO VISIT (V_DATE) VALUES ( TO_DATE('11-07-2016','MM-DD-YYYY') );
INSERT INTO VISIT (V_DATE) VALUES ( TO_DATE('11-08-2016','MM-DD-YYYY') );
cs



 VisitSessionListener.java 


  • 22 ~ 24 줄

세션이 새로 생성될 경우 방문자 수를 처리하는 메서드인 execute( )를 실행시킨다.


  • 33 ~ 37줄

방문자 수를 처리하는 부분이다. setTotalCount( )를 실행시켜 총방문자 수를 층가시킨다. 그리고 총방문자 수와 오늘 방문자 수를 가져온다. 


  • 39 ~ 43 줄

세션에 총문자 수와 오늘 방문자 수를 담는다.


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
package jsp.visit.action;
 
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
 
import jsp.visit.model.VisitCountDAO;
 
 
/**
 * 방문자 수를 계산하는 클래스<br>
 * web.xml에 listener 등록을 해두었다. 이렇게 할 경우 톰캣이 실행되면서
 * 리스너가 실행된다. 
 */
public class VisitSessionListener implements HttpSessionListener
{
 
    @Override
    public void sessionCreated(HttpSessionEvent sessionEve) {
        
        // 세션이 새로 생성되면 execute() 실행한다.
        if(sessionEve.getSession().isNew()){
            execute(sessionEve);
        }
    }
 
    private void execute(HttpSessionEvent sessionEve) 
    {
        VisitCountDAO dao = VisitCountDAO.getInstance();
        
        try {
            // 전체 방문자 수 증가
            dao.setTotalCount();
            // 총 방문자 수
            int totalCount = dao.getTotalCount();
            // 오늘 방문자 수
            int todayCount = dao.getTodayCount();
            
            HttpSession session = sessionEve.getSession();
            
            // 세션에 방문자 수를 담는다.
            session.setAttribute("totalCount", totalCount); 
            session.setAttribute("todayCount", todayCount);
            
        } catch (Exception e) {
            System.out.println("===== 방문자 카운터 오류 =====\n");
            e.printStackTrace();
        }
    }
 
    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {}
 
}
cs



■ web.xml


VisitSessionListener 클래스를 등록한다. <listener>에 패키지 경로를 모두 적어준다. 이렇게 listener로 등록을 해두면 톰캣이 실행될 때 listener가 실행된다.


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
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
         id="WebApp_ID" version="2.5">
 <display-name>JSP_create</display-name>
 
     <servlet>
        <description>Controller</description>
        <display-name>MemberController</display-name>
        <servlet-name>MemberController</servlet-name>
        <servlet-class>jsp.member.action.MemberController</servlet-class>
    </servlet>
 
     <servlet-mapping>
        <servlet-name>MemberController</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
 
     <listener>
        <listener-class>jsp.visit.action.VisitSessionListener</listener-class>
    </listener>
 
    <resource-ref>
         <description>connection</description>
         <res-ref-name>jdbc/orcl</res-ref-name>
         <res-type>javax.sql.DataSource</res-type>
         <res-auth>Container</res-auth>
    </resource-ref>
 
</web-app>
cs



 VisitCountDAO.java


  • 31 ~ 68

방문자 수를 증가시키는 부분이다. 테이블에 현재 날짜를 추가한다. 추가된 날짜의 수가 곧 방문자 수가 된다.


  • 74 ~ 109 줄

방문자 수를 구한다. COUNT(*)를 이용해 테이블에 저장된 레코드의 수를 읽어 온다. 읽어온 값이 총방문자 수이다.


  • 115 ~ 149 줄

오늘 방문자 수를 가져온다. 쿼리의 Where 절을 살펴보자.


WHERE TO_DATE(V_DATE, 'YYYY-MM-DD') = TO_DATE(sysdate, 'YYYY-MM-DD')


TO_DATE(V_DATE, 'YYYY-MM-DD') 부분은 V_DATE 칼럼에 입력된 날짜의 포맷을 YYYY-MM-DD로 변경한다. TO_DATE(sysdate, 'YYYY-MM-DD') 에서는 sysdate, 즉 현재 날짜의 포맷을 YYYY-MM-DD로 변경한다. 이후 현재 날짜와 V_DATE 칼럼에 날짜 값을 비교하여 같은 경우만 출력한다.


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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package jsp.visit.model;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import javax.naming.NamingException;
 
import jsp.util.DBConnection;
 
/**
 * Visit 테이블의 DAO<br>
 * 방문자 관련 처리를 한다.
 */
public class VisitCountDAO 
{
    private static VisitCountDAO instance;
    
    // 싱글톤 패턴
    private VisitCountDAO(){}
    public static VisitCountDAO getInstance(){
        if(instance==null)
            instance=new VisitCountDAO();
        return instance;
    }
    
    /**
     * 총방문자수를 증가시킨다.
     */
    public void setTotalCount() throws SQLException
    {
        Connection conn = null;
        PreparedStatement pstmt = null;
        
        try {
            
            // 쿼리생성
            // 총 방문자수를 증가시키기 위해 테이블에 현재 날짜 값을 추가시킨다.
            StringBuffer sql = new StringBuffer();
            sql.append("INSERT INTO VISIT (V_DATE) VALUES (sysdate)");
            
            // 커넥션을 가져온다.
            conn = DBConnection.getConnection();
                        
            // 자동 커밋을 false로 한다.
            conn.setAutoCommit(false);
            
            pstmt = conn.prepareStatement(sql.toString());
            // 쿼리 실행
            pstmt.executeUpdate();
            // 완료시 커밋
            conn.commit(); 
            
        } catch (ClassNotFoundException | NamingException | SQLException sqle) {
            // 오류시 롤백
            conn.rollback(); 
            throw new RuntimeException(sqle.getMessage());
        } finally {
            // Connection, PreparedStatement를 닫는다.
            try{
                if ( pstmt != null ){ pstmt.close(); pstmt=null; }
                if ( conn != null ){ conn.close(); conn=null;    }
            }catch(Exception e){
                throw new RuntimeException(e.getMessage());
            }
        }
    } // end setTotalCount()
    
    /**
     * 총 방문자수를 가져온다.
     * @return totalCount : 총 방문자 수
     */
    public int getTotalCount()
    {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int totalCount = 0;
        
        try {
            
            // 테이블의 테이터 수를 가져온다.
            // 데이터 수 = 총 방문자 수
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT COUNT(*) AS TotalCnt FROM VISIT");
            
            conn = DBConnection.getConnection();
            pstmt = conn.prepareStatement(sql.toString());
            rs = pstmt.executeQuery();
            
            // 방문자 수를 변수에 담는다.
            if (rs.next()) 
                totalCount = rs.getInt("TotalCnt");
            
            return totalCount;
            
        } catch (Exception sqle) {
            throw new RuntimeException(sqle.getMessage());
        } finally {
            // Connection, PreparedStatement를 닫는다.
            try{
                if ( pstmt != null ){ pstmt.close(); pstmt=null; }
                if ( conn != null ){ conn.close(); conn=null;    }
            }catch(Exception e){
                throw new RuntimeException(e.getMessage());
            }
        }
    } // end getTotalCount()
    
    /**
     * 오늘 방문자 수를 가져온다.
     * @return todayCount : 오늘 방문자
     */
    public int getTodayCount()
    {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int todayCount = 0;
        
        try {
            
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT COUNT(*) AS TodayCnt FROM VISIT");
            sql.append(" WHERE TO_DATE(V_DATE, 'YYYY-MM-DD') = TO_DATE(sysdate, 'YYYY-MM-DD')");
            
            conn = DBConnection.getConnection();
            pstmt = conn.prepareStatement(sql.toString());
            rs = pstmt.executeQuery();
            
            // 방문자 수를 변수에 담는다.
            if (rs.next()) 
                todayCount = rs.getInt("TodayCnt");
            
            return todayCount;
            
        } catch (Exception sqle) {
            throw new RuntimeException(sqle.getMessage());
        } finally {
            // Connection, PreparedStatement를 닫는다.
            try{
                if ( pstmt != null ){ pstmt.close(); pstmt=null; }
                if ( conn != null ){ conn.close(); conn=null;    }
            }catch(Exception e){
                throw new RuntimeException(e.getMessage());
            }
        }
    }// end getTodayCount()
}
 
cs



 MemberLogoutAction.java 


  • 19

기존의 세션을 삭제하는 부분에서 세션에 담긴 sessionID 값만 삭제하도록 변경하였다. 세션을 삭제해 버리면 세션이 변경이 되어 로그아웃 시 방문자 수가 증가하게 된다. 그렇기에 sessionID 값만 삭제하도록 처리했다.


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
package jsp.member.action;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 *  로그아웃 작업을 처리하는 Action 클래스
 */
public class MemberLogoutAction implements Action
{
 
    @Override
    public ActionForward execute(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        
        ActionForward forward = new ActionForward();
        
        // 로그아웃시 세션에 담긴 아이디 값을 삭제한다.
        request.getSession().removeAttribute("sessionID");
        
        // 로그아웃 후 메인화면으로 돌아간다.
        forward.setRedirect(true);
        forward.setNextPath("MainForm.do");
        
        return forward;
    }
}
cs



 MemberDeleteAction.java 


  • 31

MemberLogoutAction과 마찬가지로 sessionID 값만 삭제하도록 변경하였다.


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
package jsp.member.action;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import jsp.member.model.MemberDAO;
 
/**
 * 회원삭제 작업을 처리하는 Action 클래스
 */
public class MemberDeleteAction implements Action
{
 
    @Override
    public ActionForward execute(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        
        ActionForward forward = new ActionForward();
        
        // 세션이 가지고있는 로그인한 ID 정보를 가져온다
        HttpSession session = request.getSession();
        String id = session.getAttribute("sessionID").toString();
        String password = request.getParameter("password");
        
        MemberDAO dao = MemberDAO.getInstance();
        int check = dao.deleteMember(id, password);
        
        if(check == 1){
            // 세션의 회원정보 삭제
            session.removeAttribute("sessionID");
            forward.setRedirect(true);
            forward.setNextPath("Result.do");
        }
        else{
            System.out.println("회원 삭제 실패");
            return null;
        }
        
        return forward;
    }
}
cs



 Footer.jsp


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<html>
<head>
    <title>하단 영역</title>
</head>
<body>
    <br>
    전체 : <%=session.getAttribute("totalCount"%>
    <br>
    오늘 : <%=session.getAttribute("todayCount"%>
    <br>
</body>
</html>
cs




3. 소스코드 다운로드 (war파일)



JSP_DEV.war






RSS구독 링크추가 트위터 이메일 구독