오늘 할 것은 누적, 투데이 수를 방문자 수를 받아 보려고 한다. react + spring으로 구성
스프링 시큐리티를 사용해서 로그인을 성공 했을때 누적을 할 것이다.
- 원래 세션을 이용할때는 HttpSessionListener를 사용하지만 시큐리티를 이용하기 떄문에 시큐리티에서 성공시에 CustomHandler를 이용해서 이벤트를 발생시킬 것이다.
- 로그인을 하면 오늘 방문을 했는지 파악을하고 없으면 1증가 있으면 카운트는 증가하지 않을 것 이다.
- 방문자수 증가
- 투데이 방문자수 가져오기
- 토탈 방문자수 가져오기
- 00시마다 투데이 방문자수 초기화 하기
그냥 저장소에서 email만 비교해서 가져오려고 했는데 그럼 다른날짜에 접속한 동일 인물이 있을 수 있다.
해결 -> 금일 날짜와 같이 비교를 해서 가져온다.
총 방문자수는 구할 수 있는데 투데이는 어떻게 계산할지 생각해봐야 한다.
일단 방문할때 날짜를 같이 적어 줬는데 지금 생각나는것은
1. SQL쿼리를 보낼때 날짜를 적어서 구하는 방법
2. 총 방문자를 다 구해오고 나서 자바코드에서 구별하기
해결 -> 총방문자수는 모든 칼럼을 카운트하고, 투데이는 금일 날짜와 비교후 가져온다.
방문자수를 매일 00시에 업데이트를 할건데 이것은 어떤 방식으로 업데이트 할건지 생각해야 한다.
해결 -> 금일 날짜로 카운트를 하면 해결된다.
엔티티
투데이 계산하기위해 날짜를 같이 넣는다.
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@EntityListeners(AuditingEntityListener.class)//@CreatedDate를 설정했을떄 변경되는지 판단한다.
public class Visitor {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long vid;
@CreatedDate
private LocalDateTime regDate;
private String email;
}
DTO
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@ToString
public class VisitorDTO {
int TotalVisitorCount;
int TodayVisitorCount;
String email;
LocalDateTime regDate;
}
JPQL을 사용했다.
1. 금일 로그인한 사람인지 파악하기위해 로그인시 email을 가져오고 금일 날짜와 AND로 비교해서 카운트를 증가시킴
2. 총 방문자수는 그냥 총 칼럼을 카운트해서 가져왔다.
3. 금일 방문자수는 오늘 날짜로 비교를 해서 카운트를 했다.
@Repository
public interface VisitorRepository extends JpaRepository<Visitor, Long> {
@Query(value = "select v " +
" from Visitor v" +
" where v.email = :email AND substring(v.regDate, 0, 10) like substring(:date, 0, 10)")
Optional<Visitor> findByEmailAndRegDataLike(@Param("email") String email, @Param("date") LocalDateTime date);
int countBy();
@Query(value = " select count(*)" +
" from Visitor v " +
" where substring(v.regDate, 0, 10) like substring(:date, 0, 10) ")
int countByTodayCount(@Param("date") LocalDateTime date);
}
incrementVisitorCount만 보면 오늘 로그인 했는지 안했는지 파악 후 없으면 오늘 방문자에 추가함.
@Service
@RequiredArgsConstructor
public class VisitorServiceImpl implements VisitorService{
private final VisitorRepository visitorRepository;
@Override
public void incrementVisitorCount(final String email) {
//오늘 방문자중에 같은 이메일과 시간이 있는지 체크 후 없으면 추가하고 있으면 방문자 수를 늘리지 않는다.
LocalDateTime date = LocalDateTime.now();
if (!(CheckTodayVisit(email,date))) {
VisitorDTO visitorDTO = VisitorDTO.builder()
.email(email)
.build();
visitorRepository.save(DtoToEntity(visitorDTO));
}
}
@Override
public Boolean CheckTodayVisit(String email, LocalDateTime date) {
Optional<Visitor> byEmailAndRegDataLike = visitorRepository.findByEmailAndRegDataLike(email, date);
return byEmailAndRegDataLike.isPresent();//비어있으면 금일 접속 기록이 없으니 true
}
@Override
public int getTotalVisitorCount() {
return visitorRepository.countBy();
}
@Override
public int getTodayVisitorCount() {
LocalDateTime date = LocalDateTime.now();
return visitorRepository.countByTodayCount(date);
}
}
로그인을 성공했을때 실행되는것인데 시큐리티에서 원래 자동으로 해주지만 상속을 받아서 커스텀해서 사용할 수 있다. 로그인 했을때는 UserDetails에 데이터가 저장되어 있는데 이것을 authentication에서 꺼내쓸 수 있어서 아래와 같이 실행하면 된다.
//로그인 성공시 실행되는 핸들러
@Component
@RequiredArgsConstructor
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final VisitorService visitorService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// 방문자 수 증가 로직을 수행
//로그인 성공시 UserDetails의 정보들을 가져온다.
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String username = userDetails.getUsername();
System.out.println("로그인성공핸들러 = " + username);
visitorService.incrementVisitorCount(username);
// 로그인 성공 후 처리할 로직을 추가할 수 있음
// 기본적으로는 홈페이지 또는 로그인 후 이동할 페이지로 리다이렉트
response.sendRedirect("/");
}
}