일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- jpa
- db
- 김영한
- 스프링 핵심 기능
- springdatajpa
- Thymeleaf
- SpringBoot
- Exception
- kotlin
- QueryDSL
- spring
- http
- 스프링 핵심 원리
- 알고리즘
- 백준
- Greedy
- transaction
- 그리디
- AOP
- JDBC
- Android
- Spring Boot
- 자바
- 스프링
- JPQL
- 인프런
- java
- Servlet
- pointcut
- Proxy
- Today
- Total
개발자되기 프로젝트
[Server] 4단계: 실시간 도착정보 연동(버스) 본문
1. 대중교통 정류장 검색
특정 버스정류장의 실시간 도착정보를 알기 위해서는 해당 정류장의 arsID가 필요하다.
정류소의 상세 정보는 ODsay에서 제공하는 대중교통 정류장 검색 API를 사용하겠다.
위와 같이 간단하게 정류장 이름만 넘겨주면 된다.
하지만 문제가 있다.
예를들어 "잠실역" 버스정류장을 검색하면 여러 개가 조회된다.
아래 지도와 같이 세 정류장 모두 잠실역이다.
경로검색 api에서 arsID를 같이 제공하면 좋겠지만 현재는 제공하지 않는다.
*ODsay에서 제공하는 실시간 도착정보api를 사용하려면 stationId를 사용해야 한다.
그렇다면 검색 결과를 받았을 때, 내가 원하는 정류장인지 확인할 수 있는 방법이 필요하다.
다행히 Parameter 중 myLocation에 경도/위도를 넣으면 가장 가까운 정류소가 첫번째로 검색된다.
OdsayClient에 정류장 정보를 가지고오는 메서드를 만들어 주자.
여기서 주의할 점? apikey는 이미 인코딩 해서 입력을 했다. 이중 인코딩을 피하기 위해 build에 true를 넣어줬다.
하지만 StationName은 보통 한글로 들어올텐데 별도로 인코딩이 필요하다.
그러면 인코딩을 해서 넣으면 된다. -> URLEncoder를 사용하면 된다.
public String getStationId(String stationName, String X, String Y){
String uriString = UriComponentsBuilder.fromUriString(searchArsIdUri)
.queryParam("lang", 0)
.queryParam("stationName", URLEncoder.encode(stationName, StandardCharsets.UTF_8))
.queryParam("myLocation", X+":"+Y)
.queryParam("displayCnt", 1)
.queryParam("stationClass", 1)
.queryParam("apiKey", key).build(true).toUriString();
log.info("uri String = {}", uriString);
URI uri = UriComponentsBuilder.fromUriString(uriString).build(true).toUri();
log.info("[request StationInfo api] uri = {}", uri);
//Http Entity
var httpEntity = new HttpEntity<>(new HttpHeaders());
var responseType = new ParameterizedTypeReference<String>(){};
//ResponseEntity
var responseEntity= new RestTemplate().exchange(
uri, HttpMethod.GET, httpEntity, responseType
);
//log.info("result class : {}", responseEntity.getBody().getClass());
JSONObject jsonResult = new JSONObject(responseEntity.getBody());
int stationIdInt = (int) jsonResult.getJSONObject("result").getJSONArray("station").getJSONObject(0).get("stationID");
String stationId = String.valueOf(stationIdInt);
stationId = stationId.replace("-", "");
return stationId;
}
2. 실시간 도착정보 연동
실시간 도착 정보에 필요한 파라미터는 stationId와 추가로 routeIDs이다(노선ID).
노선 id를 넣어주면 해당 노선의 도착정보만 불러올 수 있다.
public SearchRealTimeStationRes getRealTimeBusStation(SearchRealTimeStationReq searchRealTimeStationReq){
String uriString = UriComponentsBuilder.fromUriString(realTimeStationUri)
.queryParam("lang", 0)
.queryParam("stationID", searchRealTimeStationReq.getArsId())
.queryParam("routeIDs", searchRealTimeStationReq.getBusNumber()).encode()
.queryParam("apiKey", key).build(true).toUriString();
URI uri = UriComponentsBuilder.fromUriString(uriString).build(true).toUri();
log.info("[request realTime Bus Station Info api] uri = {}", uri);
//Http Entity
var httpEntity = new HttpEntity<>(new HttpHeaders());
var responseType = new ParameterizedTypeReference<String>(){};
//ResponseEntity
var responseEntity= new RestTemplate().exchange(
uri, HttpMethod.GET, httpEntity, responseType
);
//log.info("result class : {}", responseEntity.getBody().getClass());
JSONObject jsonResult = new JSONObject(responseEntity.getBody());
return new SearchRealTimeStationRes(jsonResult);
}
3. 어느 시점에 호출?
여기서 중요한 점은 어느 시점에 정류소 정보와 해당 정류소의 실시간 도착 정보를 가져올까? 하는 것이다.
정류소 id와 실시간 도착 정보는 subPath 클래스에서 필요하다.
subPath클래스는 각 이동수단(?)의 정보를 가지고 있기 때문.(승하자 정류장/역 등등)
그러면 subPath생성 시점에 odsayClient에 요청하여 승차 정류장의 정보를 가지고 오면 될듯?
따라서 SubPath 클래스에서 OdsayClient 스프링 빈 주입이 필요하다.
주입받은 odsayClient를 통해 stationId와 해당 버스의 도착정보를 받는다.
@Autowired
public SubPath(JSONObject eachSubPath, int index, OdSayClient odSayClient) {
this.trafficType = (int) eachSubPath.get("trafficType");
this.distance = (int) eachSubPath.get("distance"); //왜 double로 안들어옴?
this.sectionTime = (int) eachSubPath.get("sectionTime");
this.odSayClient= odSayClient;
if (trafficType != 3){
this.stationCount = (int) eachSubPath.get("stationCount");
this.laneJasonArray = eachSubPath.getJSONArray("lane");
this.laneJson= (JSONObject) laneJasonArray.get(0);
this.lane= new Lane(laneJson, trafficType);
this.startName = (String) eachSubPath.get("startName");
this.startX = (double) eachSubPath.get("startX");
this.startY = (double) eachSubPath.get("startY");
this.endName = (String) eachSubPath.get("endName");
this.endX = (double) eachSubPath.get("endX");
this.endY = (double) eachSubPath.get("endY");
if (trafficType == 1){
//지하철의 경우에만
this.way = (String) eachSubPath.get("way");
if (index==0){
//지하철 첫 번 째 경로에만.
this.wayCode = (int) eachSubPath.get("wayCode");
}
this.door = (String) eachSubPath.get("door");
}else {
//버스의 경우
this.stationId = odSayClient.getStationId(startName, String.valueOf(startX), String.valueOf(startY));
SearchRealTimeStationReq searchRealTimeStationReq = new SearchRealTimeStationReq(stationId, this.lane.getBusID());
SearchRealTimeStationRes realTimeBusInfo = odSayClient.getRealTimeBusStation(searchRealTimeStationReq);
this.arrivalMin = realTimeBusInfo.getArrivalMin();
this.leftStation = realTimeBusInfo.getLeftStation();
}
this.startID = (int) eachSubPath.get("startID");
this.endID = (int) eachSubPath.get("endID");
this.passStopList = eachSubPath.getJSONObject("passStopList");
JSONArray stationList = passStopList.getJSONArray("stations");
stations = new ArrayList<>();
for (int i=0; i<stationList.length(); i++){
JSONObject stationJson = (JSONObject) stationList.get(i);
stations.add(new Station(stationJson, trafficType));
}
}
}
4. View
view에는 간단한게 도착 시간을 빨간색으로 표기.
<tr th:object="${subpath}" th:if="${subPath?.trafficType} == 2">
<!--span th:text="${subPath?.trafficType}?:'데이터 없음'"></span-->
<li th:text="|${subPath?.startName}정류장 ${subPath.lane.busNo}번 승차|">버스탑승</li>
<b><span style="color: red" th:text="|${subPath?.arrivalMin}분 후 탑승|"></span></b>
</tr>
5. 결과
- 승차 정류장에서 탑승해야 할 버스의 도착정보를 실시간으로 불러왔다.
- 하지만 api호출이 너무 많아진다.
- 왜냐? 모든 subPath생성시 odsayclient를 호출하고 있다.
- 이 중 각 path에서 2개씩만 사용하고있는데, 너무 resource 낭비이다.
- 별도 메서드를 통해 path추출 후 실시간 정보를 조회하도록 수정이 필요.
6. GitHub: 220130 realTimeInfo
'Project > 대중교통 길찾기' 카테고리의 다른 글
[Server] 단일책임 원칙 (0) | 2022.02.01 |
---|---|
[Server] 효율성 개선 (0) | 2022.01.31 |
[Server] 3단계 경유지 검색 추가 (0) | 2022.01.29 |
[Server] 2단계: 지역 명 검색 활용 (0) | 2022.01.26 |
프론트 개발 3 (th:block, th:each, th:each 중첩) (0) | 2022.01.24 |