우리도 집을 살 수 있을까요 ??
염진호 | 이민재 |
---|---|
Web Frontend | Web Backend |
- 지역별 주변 아파트 검색
- 아파트 실거래과 현황 조회
- 아파트 관련 뉴스 확인
- 자유게시판, 무한 대댓글 가능
- 소셜 로그인
홈화면
랭킹시스템
아파트조회
🍪 클라이언트단에 JWT 보관장소
-
JWT 사용하게 됨으로써 클라이언트단에 토큰을 저장할 필요가 있었는데, 저희가 고려해본 저장소는 JS변수, 로컬스토리지, 세션 스토리지, 쿠키 입니다.
-
첫번째 JS변수는 재사용성이 떨어짐으로 제외하였고 로컬스토리지는 브라우저가 꺼져도 유지되므로 제외하였습니다.
-
최종적으로 세션스토리지, 쿠키가 남았는데 세션스토리지는 XSS에 취약하고, 쿠키는 CSRF에 취약하기에 무척 고민되었습니다. 결론적으로 말씀드리자면 완벽하게 대비하는것은 힘들겠지만, 두가지 공격을 대비하여 액세스 토큰 외로 리프레시 토큰을 발급받았습니다.
-
CSRF 공격을 대비한 세션스토리지에 액세스토큰을, XSS공격을 대비한 Httponly 쿠키에 리프레시 토큰을 담았습니다.
🥇 랭킹 시스템 최적화
- aptCode를 외래키로, count,precount,preRank,rankChange로 테이블을 구성하였습니다. 초기에는 다 0 값으로 초기화됩니다. 이후에 조회수가 증가하면 precount와 count의 차이만큼 랭킹이 정렬되고 이전 랭킹과 비교하여 순위변동까지 보여줄 수 있는 로직으로 구성하였습니다.
@Override
public void rankUpdate() throws Exception {
List<CountDto> list = countMapper.preCountList();
for (int i = 0; i < list.size(); i++) {
// ( preCount를 count로 업데이트 )
list.get(i).setPreCount(list.get(i).getCount());
// 현재 index - preRank 를 rankChange에 업데이트
list.get(i).setRankChange(-(i + 1 - list.get(i).getPreRank()));
// preRank는 현재 index로 업데이트
list.get(i).setPreRank(i + 1);
}
countMapper.rankUpdate(list);
}
- 랭킹시스템 서비스단 로직입니다. 정렬 갱신 갱신으로 상당히 시간적으로 손해가 큰 로직인데 저희는 설계를 실시간성이 아니라 10분단위로 생각하였기에, 데이터가 4만건인 테이블에서 그렇게까지 시간소비가 안될 것이라고 예상하였습니다. 결과는 예상대로 맥os환경에서는 2분이나… 윈도우에서는 무려 7분이 걸렸습니다.
@Override
public void visitApt(String aptCode) throws Exception {
if(countMapper.checkApt(aptCode) == 1) {
countMapper.visitApt(aptCode);
}else {
List<CountDto> list = countMapper.countList();
Map<String, Object> map = new HashMap<>();
map.put("size", list.size()+1);
map.put("aptCode", aptCode);
countMapper.visitInsertApt(map);
}
}
-
aptCount를 아예 다비우고, 조회가 발생한 아파트만 DB에 밀어넣는 방식으로 문제를 해결하였습니다.
-
저희 설계 상으로는 실시간성이아니라 문제는 해결되었지만, 만약 모든 아파트가 조회가 일정하게 되고, 그 안에 트래픽이 몰린다면, 어떻게 로직을 구성하면 좋을지 고민중입니다.