-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] 팔로잉, 팔로워 목록 조회를 구현한다 (#28)
* feature: NoOffset 구현을 위한 VO 클래스, 유틸 추가 * fix: LongIdList, PageArgumentResolver에 예외 상황 추가 * feature: ProfileService 도메인 서비스 작성 * feature: 팔로잉, 팔로워 조회 구현 * feature: 팔로워 삭제 구현
- Loading branch information
Showing
16 changed files
with
354 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package daybyquest.global.query; | ||
|
||
import java.util.List; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class LongIdList { | ||
|
||
private final List<Long> ids; | ||
|
||
public LongIdList(final List<Long> ids) { | ||
this.ids = ids; | ||
} | ||
|
||
public Long getLastId() { | ||
if (ids.isEmpty()) { | ||
return Long.MAX_VALUE; | ||
} | ||
return ids.get(ids.size() - 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package daybyquest.global.query; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class NoOffsetIdPage { | ||
|
||
private final Long lastId; | ||
|
||
private final int limit; | ||
|
||
public NoOffsetIdPage(final Long lastId, final int limit) { | ||
this.lastId = lastId; | ||
this.limit = limit; | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/main/java/daybyquest/global/query/NoOffsetIdPageArgumentResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package daybyquest.global.query; | ||
|
||
import daybyquest.global.error.exception.BadRequestException; | ||
import jakarta.annotation.Nonnull; | ||
import java.util.regex.Pattern; | ||
import org.springframework.core.MethodParameter; | ||
import org.springframework.web.bind.support.WebDataBinderFactory; | ||
import org.springframework.web.context.request.NativeWebRequest; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.method.support.ModelAndViewContainer; | ||
|
||
public class NoOffsetIdPageArgumentResolver implements HandlerMethodArgumentResolver { | ||
|
||
private static final int MAX_LIMIT = 15; | ||
private static final Pattern NUMBER = Pattern.compile("^[0-9]*$"); | ||
|
||
|
||
@Override | ||
public boolean supportsParameter(MethodParameter parameter) { | ||
return parameter.getParameterType().equals(NoOffsetIdPage.class); | ||
} | ||
|
||
@Override | ||
public Object resolveArgument(@Nonnull MethodParameter parameter, ModelAndViewContainer mavContainer, | ||
@Nonnull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { | ||
final String lastIdArgument = webRequest.getParameter("lastId"); | ||
final String limitArgument = webRequest.getParameter("limit"); | ||
return new NoOffsetIdPage(convertAndValidateLastId(lastIdArgument), | ||
convertAndValidateLimit(limitArgument)); | ||
} | ||
|
||
private Long convertAndValidateLastId(String lastId) { | ||
if (lastId == null) { | ||
return 0L; | ||
} | ||
if (!NUMBER.matcher(lastId).matches()) { | ||
throw new BadRequestException(); | ||
} | ||
return Long.parseLong(lastId); | ||
} | ||
|
||
private int convertAndValidateLimit(String limit) { | ||
if (limit == null || !NUMBER.matcher(limit).matches()) { | ||
throw new BadRequestException(); | ||
} | ||
final int parsedLimit = Integer.parseInt(limit); | ||
if (parsedLimit > MAX_LIMIT) { | ||
throw new BadRequestException(); | ||
} | ||
return parsedLimit; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/daybyquest/relation/application/DeleteFollowerService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package daybyquest.relation.application; | ||
|
||
import daybyquest.relation.domain.Follow; | ||
import daybyquest.relation.domain.Follows; | ||
import daybyquest.user.domain.Users; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class DeleteFollowerService { | ||
|
||
private final Follows follows; | ||
|
||
private final Users users; | ||
|
||
public DeleteFollowerService(final Follows follows, final Users users) { | ||
this.follows = follows; | ||
this.users = users; | ||
} | ||
|
||
public void invoke(final Long loginId, final String targetUsername) { | ||
final Long targetId = users.getUserIdByUsername(targetUsername); | ||
final Follow follow = follows.getByUserIdAndTargetId(targetId, loginId); | ||
follows.delete(follow); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/java/daybyquest/relation/application/GetFollowersService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package daybyquest.relation.application; | ||
|
||
import daybyquest.global.query.LongIdList; | ||
import daybyquest.global.query.NoOffsetIdPage; | ||
import daybyquest.relation.query.FollowDao; | ||
import daybyquest.user.dto.response.PageProfilesResponse; | ||
import daybyquest.user.dto.response.ProfileResponse; | ||
import daybyquest.user.query.ProfileService; | ||
import java.util.List; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class GetFollowersService { | ||
|
||
private final FollowDao followDao; | ||
|
||
private final ProfileService profileService; | ||
|
||
public GetFollowersService(final FollowDao followDao, final ProfileService profileService) { | ||
this.followDao = followDao; | ||
this.profileService = profileService; | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public PageProfilesResponse invoke(final Long loginId, final NoOffsetIdPage page) { | ||
final LongIdList targetIds = followDao.getFollowerIds(loginId, page); | ||
final List<ProfileResponse> profiles = profileService.getProfilesByIdIn(loginId, targetIds.getIds()); | ||
return new PageProfilesResponse(profiles, targetIds.getLastId()); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/java/daybyquest/relation/application/GetFollowingsService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package daybyquest.relation.application; | ||
|
||
import daybyquest.global.query.LongIdList; | ||
import daybyquest.global.query.NoOffsetIdPage; | ||
import daybyquest.relation.query.FollowDao; | ||
import daybyquest.user.dto.response.PageProfilesResponse; | ||
import daybyquest.user.dto.response.ProfileResponse; | ||
import daybyquest.user.query.ProfileService; | ||
import java.util.List; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class GetFollowingsService { | ||
|
||
private final FollowDao followDao; | ||
|
||
private final ProfileService profileService; | ||
|
||
public GetFollowingsService(final FollowDao followDao, final ProfileService profileService) { | ||
this.followDao = followDao; | ||
this.profileService = profileService; | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public PageProfilesResponse invoke(final Long loginId, final NoOffsetIdPage page) { | ||
final LongIdList targetIds = followDao.getFollowingIds(loginId, page); | ||
final List<ProfileResponse> profiles = profileService.getProfilesByIdIn(loginId, targetIds.getIds()); | ||
return new PageProfilesResponse(profiles, targetIds.getLastId()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package daybyquest.relation.query; | ||
|
||
import daybyquest.global.query.LongIdList; | ||
import daybyquest.global.query.NoOffsetIdPage; | ||
|
||
public interface FollowDao { | ||
|
||
LongIdList getFollowingIds(final Long userId, final NoOffsetIdPage page); | ||
|
||
LongIdList getFollowerIds(final Long targetId, final NoOffsetIdPage page); | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/java/daybyquest/relation/query/FollowDaoQuerydslImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package daybyquest.relation.query; | ||
|
||
import static daybyquest.relation.domain.QFollow.follow; | ||
|
||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import daybyquest.global.query.LongIdList; | ||
import daybyquest.global.query.NoOffsetIdPage; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public class FollowDaoQuerydslImpl implements FollowDao { | ||
|
||
private final JPAQueryFactory factory; | ||
|
||
public FollowDaoQuerydslImpl(final JPAQueryFactory factory) { | ||
this.factory = factory; | ||
} | ||
|
||
@Override | ||
public LongIdList getFollowingIds(final Long userId, final NoOffsetIdPage page) { | ||
return new LongIdList(factory.select(follow.targetId) | ||
.from(follow) | ||
.where(follow.userId.eq(userId).and(follow.targetId.gt(page.getLastId()))) | ||
.limit(page.getLimit()) | ||
.fetch()); | ||
} | ||
|
||
@Override | ||
public LongIdList getFollowerIds(final Long targetId, final NoOffsetIdPage page) { | ||
return new LongIdList(factory.select(follow.userId) | ||
.from(follow) | ||
.where(follow.targetId.eq(targetId).and(follow.userId.gt(page.getLastId()))) | ||
.limit(page.getLimit()) | ||
.fetch()); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/main/java/daybyquest/user/dto/response/PageProfilesResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package daybyquest.user.dto.response; | ||
|
||
import java.util.List; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class PageProfilesResponse { | ||
|
||
private List<ProfileResponse> users; | ||
|
||
private Long nextId; | ||
|
||
public PageProfilesResponse(final List<ProfileResponse> users, final Long nextId) { | ||
this.users = users; | ||
this.nextId = nextId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,14 @@ | ||
package daybyquest.user.query; | ||
|
||
import daybyquest.user.domain.Profile; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
public interface ProfileDao { | ||
|
||
Profile getByUsername(final Long userId, final String username); | ||
|
||
Profile getMine(final Long userId); | ||
|
||
List<Profile> findAllByUserIdIn(final Long userId, final Collection<Long> targetIds); | ||
} |
Oops, something went wrong.