Skip to content

Commit

Permalink
feat : 버스 통계 서비스 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Gyaak committed Aug 23, 2024
1 parent f9b4e32 commit 5325d66
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.talkka.server.bus.dao;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -16,4 +17,7 @@ public interface BusLocationRepository extends JpaRepository<BusLocationEntity,
Integer getRowNum();

List<BusLocationEntity> findByApiCallNo(Integer apiCallNo);
}

List<BusLocationEntity> findByCreatedAtBetween(LocalDateTime startTime, LocalDateTime endTime);

}
73 changes: 73 additions & 0 deletions server/src/main/java/com/talkka/server/bus/dao/BusStatEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.talkka.server.bus.dao;

import java.time.LocalDateTime;
import java.util.Objects;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.talkka.server.bus.enums.PlateType;
import com.talkka.server.bus.util.PlateTypeConverter;

import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity(name = "bus_stat")
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class BusStatEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "route_id", nullable = false)
private String routeId;

@Column(name = "station_id", nullable = false)
private String stationId;

@Column(name = "before_seat", nullable = false)
private Integer beforeSeat;

@Column(name = "after_seat", nullable = false)
private Integer afterSeat;

@Column(name = "seat_diff", nullable = false)
private Integer seatDiff;

@Column(name = "plate_no", nullable = false, length = 32)
private String plateNo;

@Column(name = "before_time", nullable = false)
private LocalDateTime beforeTime;

@Column(name = "after_time", nullable = false)
private LocalDateTime afterTime;

@Column(name = "plate_type", nullable = false, length = 1)
@Convert(converter = PlateTypeConverter.class)
private PlateType plateType;

@Column(name = "created_at", nullable = false)
@CreatedDate
private LocalDateTime createdAt;

@Override
public int hashCode() {
return Objects.hash(routeId, stationId, beforeSeat, afterSeat, seatDiff, plateNo, beforeTime, afterTime,
plateType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.talkka.server.bus.dao;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BusStatRepository extends JpaRepository<BusStatEntity, Long> {
List<BusStatEntity> findByBeforeTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
}
103 changes: 103 additions & 0 deletions server/src/main/java/com/talkka/server/bus/service/BusStatService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.talkka.server.bus.service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.stereotype.Service;

import com.talkka.server.bus.dao.BusLocationEntity;
import com.talkka.server.bus.dao.BusLocationRepository;
import com.talkka.server.bus.dao.BusStatEntity;
import com.talkka.server.bus.dao.BusStatRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class BusStatService {
private final BusStatRepository busStatRepository;
private final BusLocationRepository busLocationRepository;

// 생성된 위치정보 중 start~end 기간에 있는 것들만 가공
@Transactional
public void makeStatDataBetween(LocalDateTime start, LocalDateTime end) {
List<BusLocationEntity> locationList = busLocationRepository.findByCreatedAtBetween(start, end);
Map<String, BusLocationEntity> locationMap = new HashMap<>();
// 가공하려는 기간에 속하는 통계정보를 가져와 엔티티의 해시코드를 set 에 저장
Set<Integer> statHashSet = new HashSet<>();
busStatRepository.findByBeforeTimeBetween(start, end).forEach(stat -> statHashSet.add(stat.hashCode()));

for (BusLocationEntity afterLocation : locationList) {
// 같은 버스의 위치정보가 map 에 없으면 넣고 넘김
if (!locationMap.containsKey(afterLocation.getPlateNo())) {
locationMap.put(afterLocation.getPlateNo(), afterLocation);
} else {
// 같은 버스의 직전 위치를 map 에서 가져옴
BusLocationEntity beforeLocation = locationMap.get(afterLocation.getPlateNo());

if (// 위치정보들 간 시간 차이가 1시간 미만이어야함
Duration.between(beforeLocation.getCreatedAt(), afterLocation.getCreatedAt()).toHours() < 1
// 위치정보들 간 정거장 차이가 1정거장 이하여야함
&& afterLocation.getStationSeq() - beforeLocation.getStationSeq() <= 1
// 위치정보들 둘다 좌석정보를 가지고 있어야함
&& beforeLocation.getRemainSeatCount() != -1 && afterLocation.getRemainSeatCount() != -1
) {
BusStatEntity statEntity = toBusStatEntity(beforeLocation, afterLocation);
// 이미 존재하는 통계 정보인지 확인한 후 db에 저장
if (!statHashSet.contains(statEntity.hashCode())) {
busStatRepository.save(statEntity);
}
}
// 위치정보 갱신
locationMap.put(afterLocation.getPlateNo(), afterLocation);
}
}
}

// 두개의 위치정보를 가지고 BusStatEntity 를 생성
private static BusStatEntity toBusStatEntity(BusLocationEntity before, BusLocationEntity after) {
return BusStatEntity.builder()
.routeId(after.getApiRouteId())
.stationId(before.getApiStationId())
.beforeSeat(before.getRemainSeatCount().intValue())
.afterSeat(after.getRemainSeatCount().intValue())
.seatDiff(after.getRemainSeatCount() - before.getRemainSeatCount())
.plateNo(after.getPlateNo())
.beforeTime(before.getCreatedAt())
.afterTime(after.getCreatedAt())
.plateType(after.getPlateType())
.build();
}

// old logic
// @Deprecated
// @Transactional
// public void process() {
// List<Integer> apiCallNoList = busLocationRepository.getDistinctApiCallNoList();
// apiCallNoList.sort(Comparator.naturalOrder());
// Map<String, BusLocationEntity> prev = new HashMap<>();
// System.out.println(apiCallNoList);
// for (Integer apiCallNo : apiCallNoList) {
// Map<String, BusLocationEntity> cur = new HashMap<>();
// List<BusLocationEntity> locationList = busLocationRepository.findByApiCallNo(apiCallNo);
// for (BusLocationEntity location : locationList) {
// BusLocationEntity beforeLocation;
// if ((beforeLocation = prev.get(location.getPlateNo())) != null
// // 두정거장 이상 넘어가면 체크하지 않음
// && location.getStationSeq() - beforeLocation.getStationSeq() <= 1 && (
// location.getRemainSeatCount() != -1 && beforeLocation.getRemainSeatCount() != -1)) {
// BusStatEntity statEntity = toBusStatEntity(beforeLocation, location);
// busStatRepository.save(statEntity);
// }
// cur.put(location.getPlateNo(), location);
// }
// prev = cur;
// }
// }
}

0 comments on commit 5325d66

Please sign in to comment.