Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 이클립스
- restapi
- Eclipse
- 스파르타코딩클럽
- 티스토리챌린지
- 기업설명회
- 자바
- JavaScript
- 오류
- 코딩
- 오블완
- github
- SQLD
- firestore
- vscode
- myBatis
- 웹개발
- HTML
- bootstrap
- error
- AJAX
- icon
- chart.js
- 깃허브
- CSS
- spring
- java
- Firebase
- SQL
- jQuery
Archives
- Today
- Total
푸들푸들
1218 [Error] Listener 접속자 수 count 본문
Listener
@SpringBootApplication에 @ServletComponentScan 어노테이션 추가
@SpringBootApplication
@ServletComponentScan // @WebServlet, @Filter, @WebListener 사용가능
public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
}
}
@Mapper
public interface StatsMapper {
Integer selectStatsAmountByToday();
Integer selectStatsAmountByTotal();
String selectStatsCurdate();
int insertStats();
int updateStats();
}
<mapper namespace="com.example.app.mapper.StatsMapper">
<!-- 오늘 접속자 수 -->
<select id="selectStatsAmountByToday" resultType="Integer">
SELECT amount
FROM stats
WHERE last_update = CURDATE()
</select>
<!-- 누적 접속자 수 -->
<select id="selectStatsAmountByTotal" resultType="Integer">
SELECT SUM(amount) FROM stats
</select>
<!-- 오늘 날짜에 데이터(접속자)가 있는지 -->
<select id="selectStatsCurdate" resultType="String">
SELECT last_update lastUpdate
FROM stats
WHERE last_update = CURDATE()
</select>
<!-- 오늘 날짜의 amount 1로 insert -->
<insert id="insertStats">
INSERT INTO stats(amount) VALUES (1)
</insert>
<!-- 오늘 날짜의 amount +1 증가 update -->
<update id="updateStats">
UPDATE stats SET amount = amount+1
WHERE last_update = CURDATE()
</update>
</mapper>
@Service
@Transactional
public class StatsService {
@Autowired StatsMapper statsMapper;
public Integer getStatsAmountByToday() {
return statsMapper.selectStatsAmountByToday();
}
public Integer getStatsAmountByTotal() {
return statsMapper.selectStatsAmountByTotal();
}
public String getStatsCurdate() {
return statsMapper.selectStatsCurdate();
}
public int addStats() {
return statsMapper.insertStats();
}
public int modifyStats() {
return statsMapper.updateStats();
}
}
@WebListener
public class TomacatListener implements ServletContextListener {
public TomacatListener() { }
// 톰캣이 켜질 때
public void contextInitialized(ServletContextEvent sce) {
// jsp application 속성 변수 추가
// ServletContext -> context (jsp에서는 application)
ServletContext sc = sce.getServletContext();
sc.setAttribute("totalCount",0); // 톰캣이 켜질때 totalCount라는 변수 생성
}
public void contextDestroyed(ServletContextEvent sce) {
// 톰캣이 꺼질 때
}
}
컨텍스트 생명주기 리스너 : 톰켓 부팅시 현재접속자수에 사용될 컨텍스트(application)변수 totalCount 초기화
@Slf4j
@WebListener
public class SessionListener implements HttpSessionListener {
@Autowired StatsService statsService;
public SessionListener() {
}
// 현재 서버(tomcat context)에 새로운 세션이 생성될 때 콜백
public void sessionCreated(HttpSessionEvent se) {
// 현재 접속자 +1
ServletContext sc = se.getSession().getServletContext();
// application.totalCount 값을 +1 해서 덮어쓰기
sc.setAttribute("totalCount",(Integer)(sc.getAttribute("totalCount")) + 1);
// 오늘 접속자 +1 -> StatsService
// 1) 오늘 데이터 있는지 확인
String todayData = statsService.getStatsCurdate();
if(todayData == null) { // 오늘 데이터가 없으면
log.debug("insert 실행");
statsService.addStats();
} else {
log.debug("update 실행");
statsService.modifyStats();
}
}
// 현재 서버(tomcat context)에 새로운 세션이 폐기될 때 콜백
public void sessionDestroyed(HttpSessionEvent se) {
// 현재 접속자 -1
ServletContext sc = se.getSession().getServletContext();
// application.totalCount 값을 -1 해서 덮어쓰기
sc.setAttribute("totalCount",(Integer)(sc.getAttribute("totalCount")) - 1);
}
}
Session 생명주기 리스너 : 세션이 생성되고 사라질때 마다 콜백되는 메서드 구현
home.jsp
<body class="container">
<h1>HOME</h1>
<br>
<div>
<a href="/addMember">회원가입</a>
<a href="/login">로그인</a>
</div>
<div>
<div>현재 접속자 수 : ${totalCount}</div> <!-- 서버에 세션이 몇개 만들어져 있는지 -->
<div>오늘 접속자 수 : </div> <!-- DB -->
<div>누적 접속자 수 : </div> <!-- DB -->
</div>
</body>
--> 오류
Session event listener threw exception
Cannot invoke "com.example.app.mapper.StatsMapper.selectStatsCurdate()" because "this.statsMapper" is null
???
Listener에서 @Autowired가 작동하지 않는 듯?
-> 직접 주입
// bean 주입에 @Autowired를 사용할 수 없어서 코드로 찾아서 직접 주입
WebApplicationContext ctx
= WebApplicationContextUtils.getWebApplicationContext(se.getSession().getServletContext());
this.statsService = (StatsService)ctx.getBean("statsService");
* 이전 totalCount -> currentCount 이름 변경
@Slf4j
@Controller
public class HomeController {
@Autowired StatsService statsService;
@GetMapping({"/","/home"}) // /이나 /home 요청 -> 배열
public String home(Model model) {
Integer todayCount = statsService.getStatsAmountByToday();
Integer totalCount = statsService.getStatsAmountByTotal();
model.addAttribute("todayCount",todayCount);
model.addAttribute("totalCount",totalCount);
log.debug("home() 실행");
return "home";
}
}
<h1>HOME</h1>
<br>
<div>
<a href="/addMember">회원가입</a>
<a href="/login">로그인</a>
</div>
<div>
<div>현재 접속자 수 : ${currentCount}</div> <!-- 서버에 세션이 몇개 만들어져 있는지 -->
<div>오늘 접속자 수 : ${todayCount}</div> <!-- DB -->
<div>누적 접속자 수 : ${totalCount}</div> <!-- DB -->
</div>
--> 오류
현재 접속자 수 카운트 안됨
@SpringBootApplication에서 @ServletComponentScan 제거 후
@WebListener에서 -> @Component로 수정 후
리스너에서도 @Autowired 애노테이션을 사용 가능 하도록 수정
@Autowired 사용가능, 현재 접속자 수 count 해결!