레코드 기능 추가

강한친구·2022년 7월 25일
0

레코드 조회 기능이 조금 더 강화되었다.

우선 검색의 편의성을 위해 Records에 Date 컬럼을 day, month, year로 분리하였다.

전체 코드

@RestController
@RequiredArgsConstructor
public class RecordController {

    private final RecordService recordService;

    @PostMapping("/send/data")
    public int receiveRecord (@RequestBody RecordsDto recordsDto, HttpServletRequest request, HttpServletResponse response) {
        String username = getUsername(request);
        recordService.save(username, recordsDto);
        return response.getStatus();
    }

    @GetMapping("/showRecords")
    public void showTodayRecord(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = getUsername(request);
        String timeStamp = LocalDate.now().toString();
        findRecord(username, timeStamp, response);
    }

    // 지정 날짜로 검색
    // 항상 ?date=YYYY-MM-DD 형식을 지킬것
    @GetMapping("/showRecords/d")
    public void showRecordByDate(@RequestParam("date") String date, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = getUsername(request);
        findRecord(username, date, response);
    }

    @GetMapping("/records/monthly")
    public List<Integer> monthlyRecords(@RequestParam String month, HttpServletRequest request, HttpServletResponse response) throws IOException {
        List<Integer> monthly = recordService.findMonthly(month, getUsername(request));
        if (monthly.isEmpty()) {
            response.sendError(400);
        }
        return monthly;
    }

    // 월별 데이터 반환 (날짜와 총 집중시간)
    @GetMapping("/records/monthly/v2")
    public List<MonthlyRecordsDto> monthlyRecordsV2(@RequestParam String month, HttpServletRequest request, HttpServletResponse response) throws IOException {
        List<MonthlyRecordsDto> monthly = recordService.findMonthlyV2(month, getUsername(request));
        if (monthly.isEmpty()) {
            response.sendError(400);
        }
        return monthly;
    }

    //친구 일일 기록
    //정렬로 보내는건 미구현
    @GetMapping("/records/friendDailyRanking")
    public List<MyFollowersDto> dailyRanks(HttpServletRequest request) {
        return recordService.dailyRanks(getUsername(request));
    }

    private void findRecord(String username, String timeStamp, HttpServletResponse response) throws IOException {
        Records record = recordService.findRecordByTimeStamp(username, timeStamp);
        if (record == null) {
            response.setStatus(204);
            response.sendError(400, "No data");
            return;
        }
        RecordReturnerDto recordReturnerDto = new RecordReturnerDto(record);
        String json = new Gson().toJson(recordReturnerDto);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(json);
    }

    private String getUsername (HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        SecurityContextImpl context = (SecurityContextImpl)session.getAttribute("SPRING_SECURITY_CONTEXT");
        return context.getAuthentication().getName();
    }
}

ShowRecords

레코드를 보여주는 기능을 담당하고 있다.
총 2가지가 있는데
하나는 오늘날짜의 records를 바로 보여주는 방식이고,
다른 하나는 날짜를 @RequestParam으로 보내면 이를 받아서 처리하는 경우이다.

DTO

@Getter @Setter
public class RecordReturnerDto {

    private int brokenCounter;
    private int maxConcentrationTime;
    private int total_time;
    private String timeStamp;

    public RecordReturnerDto(Records records) {
        this.brokenCounter = records.getBrokenCounter();
        this.maxConcentrationTime = records.getMaxConcentrationTime();
        this.total_time = records.getTotal_time();
        this.timeStamp = records.getYear() + "-" + records.getMonth() + "-" + records.getDay();
    }
}

조회를 통해 찾아온 records를 반환하려고 사용하는 DTO이다.

생성자를 통해 한번에 받아서 처리한다.

Controller

    @GetMapping("/showRecords")
    public void showTodayRecord(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = getUsername(request);
        String timeStamp = LocalDate.now().toString();
        findRecord(username, timeStamp, response);
    }

    // 지정 날짜로 검색
    // 항상 ?date=YYYY-MM-DD 형식을 지킬것
    @GetMapping("/showRecords/d")
    public void showRecordByDate(@RequestParam("date") String date, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = getUsername(request);
        findRecord(username, date, response);
    }
    
    private void findRecord(String username, String timeStamp, HttpServletResponse response) throws IOException {
        Records record = recordService.findRecordByTimeStamp(username, timeStamp);
        if (record == null) {
            response.setStatus(204);
            response.sendError(400, "No data");
            return;
        }
        RecordReturnerDto recordReturnerDto = new RecordReturnerDto(record);
        String json = new Gson().toJson(recordReturnerDto);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(json);
    }

Service의 findByTimeStamp로 연결해준다.
param이 없는경우는 현 시간이 date가 되는것이고, param이 있으면 그 param이 대상이 된다.

Service & Repository

    public Records findRecordByTimeStamp(String username, String date) {
        Member member = memberRepository.findByUsername(username);
        return recordRepository.findRecordByTimeStamp(member, date);
    }
    public Records findRecordByTimeStamp(Member member, String timeStamp) {
        String year = timeStamp.substring(0, 4);
        String month = timeStamp.substring(5, 7);
        String day = timeStamp.substring(8,10);
        List<Records> resultList = em.createQuery("select r from Records r where r.member = :member and r.year = :year and r.month = :month and r.day = :day", Records.class)
                .setParameter("member", member)
                .setParameter("year", year)
                .setParameter("month", month)
                .setParameter("day", day)
                .getResultList();
        return resultList.get(0);
    }

레포지토리에서는 subString을 이용하여 year, month, day로 나눠서 검색을 진행한다.

테스트

월별 검색

깃허브의 잔디를 아는가?

이런식으로 일별 기록을 월단위로 보여주는 기능이다. (완전 허접하다)

이를 위해서 월단위 데이터 조회기능을 만들기로 하였다.

위에서 언급한 date의 분리역시 이 때문에 시행되었다. 기존처럼 한 라인으로 2022-07-22 넣으니깐 월별 조회가 너무 어려웠다. 따라서 이를 분리하는 기능을 구현하였다.

Controller

    @GetMapping("/records/monthly")
    public List<Integer> monthlyRecords(@RequestParam String month, HttpServletRequest request, HttpServletResponse response) throws IOException {
        List<Integer> monthly = recordService.findMonthly(month, getUsername(request));
        if (monthly.isEmpty()) {
            response.sendError(400);
        }
        return monthly;
    }

    // 월별 데이터 반환 (날짜와 총 집중시간)
    @GetMapping("/records/monthly/v2")
    public List<MonthlyRecordsDto> monthlyRecordsV2(@RequestParam String month, HttpServletRequest request, HttpServletResponse response) throws IOException {
        List<MonthlyRecordsDto> monthly = recordService.findMonthlyV2(month, getUsername(request));
        if (monthly.isEmpty()) {
            response.sendError(400);
        }
        return monthly;
    }

보면 V1, V2가 있는데 V1은 Time만 반환하는 초기버전이고, V2는 MonthlyRecordDto라는 Dto에 넣어서 반환한다

DTO

@Getter @Setter
public class MonthlyRecordsDto {

    private String day;
    private int time;
}

날짜와 시간을 반환해준다. 시간만 반환해주면 반환값이 어느날의 데이터인지 알수가 없고, 기록이 없는 날을 구분 할 방법이 없어서 이런 방식을 택했다.

Service and Repository

    public List<Integer> findMonthly(String month, String username) {
        Member member = memberRepository.findByUsername(username);
        return recordRepository.findAllByMonth(month, member);
    }

    public List<MonthlyRecordsDto> findMonthlyV2(String month, String username) {
        Member member = memberRepository.findByUsername(username);
        return recordRepository.findAllByMonthV2(month, member);
    }
    public List<Integer> findAllByMonth(String month, Member member) {
        LocalDate now = LocalDate.now();
        String year = Integer.toString(now.getYear());
        List resultList = em.createQuery("Select r.maxConcentrationTime from Records r where r.member = :member and r.year = :year and r.month = :month")
                .setParameter("member", member)
                .setParameter("year", year)
                .setParameter("month", month)
                .getResultList();

        return resultList;
    }

    public List<MonthlyRecordsDto> findAllByMonthV2(String month, Member member) {
        LocalDate now = LocalDate.now();
        String year = Integer.toString(now.getYear());
        List<MonthlyRecordsDto> resultList = em.createQuery("Select r.day, r.maxConcentrationTime from Records r where r.member = :member and r.year = :year and r.month = :month", MonthlyRecordsDto.class)
                .setParameter("member", member)
                .setParameter("year", year)
                .setParameter("month", month)
                .getResultList();

        return resultList;
    }

구현을 발상하는게 어려웠지 구현자체는 어렵지 않았다.

단순히 year, month까지의 데이터로 처리하면 된다.

테스트


최초버전에서는 값만 넘어오지만

이렇게 며칠날의 기록인지 잘 나온다.

친구 일일 랭킹

그날 하루 내 친구들 중 누가 공부를 제일 많이 하는지 보여주는 기능이다.

Controller

    //친구 일일 기록
    //정렬로 보내는건 미구현
    @GetMapping("/records/friendDailyRanking")
    public List<MyFollowersDto> dailyRanks(HttpServletRequest request) {
        return recordService.dailyRanks(getUsername(request));
    }

이 또한 DTO로 감아서 받는다. 그냥 값만 받으면 누구껀지 알 길이 없기 때문이다.

DTO

@Getter @Setter
public class MyFollowersDto {

    private String username;
    private int maxConcentrationTime;

    public MyFollowersDto(String follower, int maxConcentrationTime) {
        this.maxConcentrationTime = maxConcentrationTime;
        this.username = follower;
    }
}

DTO에는 유저이름과 집중시간이 넘어온다. 이를 정렬해서 사용하면 된다.

Service

    public List<MyFollowersDto> dailyRanks(String username) {
        Member member = memberRepository.findByUsername(username);
        List<String> followers = followersRepository.findFollowers(member);
        return recordRepository.findFollowersDailyRecords(followers, member);
    }

서비스에서는 username을 기반으로 member 객체를 찾는다. 그리고 followersRepository에 있는 findFollowers를 통해서 followers 명단을 가지고 온다.

이 명단을 repository에 넘겨서 처리한다.

Repository

    public List<MyFollowersDto> findFollowersDailyRecords(List<String> followers, Member member) {
        List<MyFollowersDto> resultList = new ArrayList<>();
        for (String follower : followers) {
            Member findMember = memberRepository.findByUsername(follower);
            int maxConcentrationTime = findRecordByTimeStamp(findMember, LocalDateTime.now().toString()).getMaxConcentrationTime();
            MyFollowersDto myFollowersDto = new MyFollowersDto(follower, maxConcentrationTime);
            resultList.add(myFollowersDto);
        }
        return resultList;
    }

레포지토리는 받아온 리스트의 정보를 바탕으로 각 날짜별 그 유저의 기록을 조회하고, 그 기록을 가지고와서 result에 저장한다.

이를 반환하면 된다.

에러

친구들의 오늘 기록이 하나도 없으면 이런 에러가 발생한다.

따라서 실행전에 오류검사로직을 하나 추가해야한다.
(추후 오류처리에서 실행)

0개의 댓글