일기어플 개발 중 사용자가 쓴 일기에 대한 통계를 제공해주는 api를 만들게 되었다.


이렇게 달마다 데이터를 종합해서 보내주는 통지서와 전체 일기의 통계를 제공해주는 부분이 나뉜다.
전체 일기의 통계의 경우 요청 시 몇번 질의를 해주고 dto에 담아서 보내주면 되는 문제지만, 달마다의 통지서는 사용자가 직접 글을 써서 생성하는 부분이 있기에 따로 저장해주는 테이블을 만들고 api를 구현하였다.
ReportController
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/report")
public class ReportController {
private final DiaryService diaryService;
@GetMapping("/analysis")
public ResponseEntity<AnalysisResponse> getAnalysis(Principal principal)
{
AnalysisResponse result = diaryService.getAnalysis(principal.getName());
return ResponseEntity.ok()
.body(result);
}
@PostMapping("/create/{comment}")
public ResponseEntity<ReportDTO> createResponse(Principal principal, @PathVariable String comment)
{
ReportDTO result = diaryService.createReport(principal.getName(), comment);
return ResponseEntity.ok()
.body(result);
}
@GetMapping("/read")
public ResponseEntity<List<ReportResponse>> getReport(Principal principal)
{
List<ReportResponse> list = diaryService.getReports(principal.getName())
.stream()
.map(ReportResponse::new)
.toList();
return ResponseEntity.ok()
.body(list);
}
}
post로 create/{comment}을 받으면 그 달의 데이터를 수집해서 통지서를 만들고 반환해준다. get으로 /read를 호출하면 이때까지 생성된 모든 통지서를 list로 보내주고 /analysis를 호출하면 전체 통계를 반환해준다.
그냥 값들 호출해서 형식에 따라 dto에 담아서 보내주기만 하면 되는 작업이라 거의 단순 반복 노동이었는데 유일하게 어려웠던 부분이 년도와 달을 처리하는 부분이다.
LocalDateTime을 통해 일기의 작성일자를 저장하고 있었는데 해당 기능은 xxxx년 xx월을 기준으로 구분해야 해서 이걸 어떻게 구현할지 고민이 있었다.
그런데 알고보니 자바에서 YearMonth라는 타입을 지원하고 있어서 해당 부분을 해결할 수 있었다.
다른 부분은 단순 반복 노동이니 이 중 '가장 많은 일기를 쓴 달'을 구하는 부분의 코드만 올려보겠다.
public YearMonth getMostMonth(Long user_id)
{
ArrayList<YearMonth> ym = new ArrayList<YearMonth>();
List<Diary> data = diaryRepository.findByUserId(user_id);
int i;
for(i=0; i<data.size(); i++)
{
YearMonth buffer = YearMonth.from(data.get(i).getCreatedAt());
ym.add(buffer);
}
YearMonth result = findMostRepeatedValue(ym);
return result;
}
public YearMonth findMostRepeatedValue(ArrayList<YearMonth> list)
{
if(list==null) return null;
Map<YearMonth, Integer> frequencyMap = new HashMap<>();
for(YearMonth value : list)
{
frequencyMap.put(value, frequencyMap.getOrDefault(value, 0) + 1);
}
int maxFrequency = 0;
YearMonth mostRepeatedValue = null;
Set<Map.Entry<YearMonth, Integer>> entrySet = frequencyMap.entrySet();
for(Map.Entry<YearMonth, Integer> entry : entrySet)
{
if(entry.getValue() > maxFrequency)
{
maxFrequency = entry.getValue();
mostRepeatedValue = entry.getKey();
}
}
return mostRepeatedValue;
}
사용자의 id로 일기 저장 테이블에 질의해서 자기가 쓴 모든 일기를 불러온 후 각 일기의 작성일자를 YearMonth 형태로 변환해서 buffer에 저장한다. 그 후 HashMap을 사용해서 가장 많이 나온 YearMonth를 찾는 코드이다.
또한 이 기능을 구현하면서 DTO를 사용하는 이유에 대해 많이 배우게 됐는데, 처음엔 많이 나온 감정들을 각각 변수로 구현하여 주는걸로 구현했는데 프론트 쪽에서 Double형 List로 받아야 하는 상황이라 간단히 수정을 한 일이 있었다. 엔티티를 바로 사용했다면 이런 상황에서 큰 문제가 생겼을 것 같다.

