이제 API 서버를 만드는 데 있어서 중요하다고 생각하는 로직들을 엔티티별로 분류하여 적어보도록 하겠다.
먼저, 약속 엔티티에 대해 설명하겠다. 컨트롤러에는 약속을 만드는 로직이 있는데, 프론트에서 약속에 대한 정보를 받아
AppointRepository
에save
한다.
이 때, 날짜와 시간을yyyy.mm.dd
,HH:mm:ss
형식 문자열로 받게 되는데, 이것을LocalDateTime
타입으로 바꿀 필요가 있었다.AppointController
@ResponseBody @PostMapping("/{user_id}") // 약속 만들기 public ResponseForm create( @PathVariable("user_id") Long user_id, Appoint appoint, Integer typeInteger, String date, String time) { return appointService.createAppoint(user_id, appoint, typeInteger, date, time); }
날짜와 시간을
String
으로 받아Service
에 넘겨주었다.AppointService
public ResponseForm createAppoint(Long user_id, Appoint appoint, Integer typeInteger, String date, String time) { ResponseForm res = new ResponseForm(); //.. 유효성 검사 및 값 세팅 로직 // dday 세팅 appoint.setDday(makeDateTime(date, time)); // appoint 저장 appoint = appointRepository.save(appoint); //.. myAppoint 세팅 및 인원 세팅 로직 return res.setSuccess(appoint.getId()); } private LocalDateTime makeDateTime(String date, String time) { String[] dates = date.split("\\."); String[] times = time.split(":"); Integer y = Integer.parseInt(dates[0]); Integer m = Integer.parseInt(dates[1]); Integer d = Integer.parseInt(dates[2]); Integer hh = Integer.parseInt(times[0]); Integer mm = Integer.parseInt(times[1]); return LocalDateTime.of(y, m, d, hh, mm, 00); }
makeDateTime
함수로String
으로 받은date
와time
을split
을 사용해 나누고LocalDateTime
을 만들어 내었다.
(기호.
을 기준으로split
할 때,.
대신\\.
을 사용해야 한다.)
참고로,
Appoint
엔티티에는type
이라는 Column이 있는데, 이것은Enum
타입이다.C
public class C { public enum appointType { FTF, NFTF, SOLO } }
AppointService
// type 세팅 C.appointType type; if (typeInteger == 0) type = C.appointType.FTF; else if (typeInteger == 1) type = C.appointType.NFTF; else type = C.appointType.SOLO; appoint.setType(type);
Enum 타입 변수를 통해
FTF
(만남),NFTF
(온라인),SOLO
(나만의)
약속을 세 가지 타입으로 구분하였다.( 자바의
Enum
을int
타입으로 형변환하려고 시도해 보았으나,Java
는C
나C++
과는 다르게int
로 형변환이 되지 않는다. )
처음 프로젝트를 기획했을떄는 친구끼리만 약속을 할 수 있게 하려 했지만, 친구가 아니어도 방을 검색해서 참여할 수 있는 플랫폼적인 성격을 갖도록 바꾸어 약속 검색 기능을 추가하였다.
그리고 효율적으로 데이터를 보내기 위해 페이징을 적용하였다.
AppointController
@ResponseBody @GetMapping("/search/{is_public}/{is_recruit}/{is_ftf}/{page}") // 약속 검색 public ResponseForm searchAppointList( String search, @PathVariable("is_public") Integer is_public, @PathVariable("is_recruit") Integer is_recruit, @PathVariable("is_ftf") Integer is_ftf, @PathVariable("page") Integer page) { return appointService.getSearchAppointList(search, is_public, is_recruit, is_ftf, page); }
공개방여부, 모집중여부, 만남여부, 검색어, 페이지를 인자로 받아 해당하는 페이지의 검색결과를 리턴하도록 만들었다.
AppointService
public ResponseForm getSearchAppointList( String search, Integer isPublic, Integer isRecruit, Integer isFtf, Integer page) { ResponseForm res = new ResponseForm(); //...카테고리 세팅 // 페이징 설정 int pageSize = 10; Pageable pageable = PageRequest.of(page, pageSize, Sort.by("id").descending()); // 조건에 맞는 appoint리스트 검색 Page<Appoint> appointList = appointRepository.findByIsPublicAndIsRecruitAndTypeAndTitleContainsAndDdayAfter( is_public, is_recruit, is_ftf, search, LocalDateTime.now() ,pageable); //...Null 체크 //...방장 정보 세팅 return res.setSuccess(appointList.getContent()); }
JPA Repository
함수로 작성하여 불가피하게 함수명이 길어졌지만,
PageRequest.of(page, pageSize, Sort.by("id").descending());
으로Pageable
객체를 만들어 페이징을 적용시킬 수 있었다.(
Paging
을 적용시킬 때에는 객체 타입이Page<>
타입이어야 한다. )
참고로,
Appoint
객체를DTO
의 역할도 동시에 수행할 수 있도록memo
변수에 방장의id
와name
을 담았다.AppointService
// 방장 이름 세팅 for(Appoint a : appointList.getContent()) { List<MyAppoint> ma = myAppointRepository.findByAppointIdAndIsMaster(a.getId(), true); if (ma == null || ma.size() == 0) { a.setMemo("0&unknown"); continue; } User u = userRepository.findById(ma.get(0).getUserId()).orElse(null); if (u == null) { a.setMemo("0&unknown"); continue; } a.setMemo(u.getId() + "&" + u.getName()); }
Appoint
엔티티에서 중요하다 싶은 로직은 대부분 설명한 듯 하다. 기본적인 CRUD 로직은 제외하였다.