diff --git a/src/main/java/io/spring/Util.java b/src/main/java/io/spring/Util.java index d2512acca..ceeb28028 100644 --- a/src/main/java/io/spring/Util.java +++ b/src/main/java/io/spring/Util.java @@ -1,6 +1,20 @@ package io.spring; -public class Util { +/** + * String utility methods for common operations. + */ +public final class Util { + + private Util() { + // Utility class - prevent instantiation + } + + /** + * Checks if a string is null or empty. + * + * @param value the string to check + * @return true if the string is null or empty, false otherwise + */ public static boolean isEmpty(String value) { return value == null || value.isEmpty(); } diff --git a/src/main/java/io/spring/api/ArticleApi.java b/src/main/java/io/spring/api/ArticleApi.java index c80afa31d..ca1b850aa 100644 --- a/src/main/java/io/spring/api/ArticleApi.java +++ b/src/main/java/io/spring/api/ArticleApi.java @@ -1,5 +1,7 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.articleResponse; + import io.spring.api.exception.NoAuthorizationException; import io.spring.api.exception.ResourceNotFoundException; import io.spring.application.ArticleQueryService; @@ -10,8 +12,6 @@ import io.spring.core.article.ArticleRepository; import io.spring.core.service.AuthorizationService; import io.spring.core.user.User; -import java.util.HashMap; -import java.util.Map; import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; @@ -77,12 +77,4 @@ public ResponseEntity deleteArticle( }) .orElseThrow(ResourceNotFoundException::new); } - - private Map articleResponse(ArticleData articleData) { - return new HashMap() { - { - put("article", articleData); - } - }; - } } diff --git a/src/main/java/io/spring/api/ArticlesApi.java b/src/main/java/io/spring/api/ArticlesApi.java index 50584bd6d..4d1ec48c8 100644 --- a/src/main/java/io/spring/api/ArticlesApi.java +++ b/src/main/java/io/spring/api/ArticlesApi.java @@ -1,12 +1,13 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.articleResponse; + import io.spring.application.ArticleQueryService; import io.spring.application.Page; import io.spring.application.article.ArticleCommandService; import io.spring.application.article.NewArticleParam; import io.spring.core.article.Article; import io.spring.core.user.User; -import java.util.HashMap; import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; @@ -30,11 +31,7 @@ public ResponseEntity createArticle( @Valid @RequestBody NewArticleParam newArticleParam, @AuthenticationPrincipal User user) { Article article = articleCommandService.createArticle(newArticleParam, user); return ResponseEntity.ok( - new HashMap() { - { - put("article", articleQueryService.findById(article.getId(), user).get()); - } - }); + articleResponse(articleQueryService.findById(article.getId(), user).get())); } @GetMapping(path = "feed") diff --git a/src/main/java/io/spring/api/CommentsApi.java b/src/main/java/io/spring/api/CommentsApi.java index c5f7e77e9..4cc575b14 100644 --- a/src/main/java/io/spring/api/CommentsApi.java +++ b/src/main/java/io/spring/api/CommentsApi.java @@ -1,5 +1,8 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.commentResponse; +import static io.spring.api.ResponseFactory.commentsResponse; + import com.fasterxml.jackson.annotation.JsonRootName; import io.spring.api.exception.NoAuthorizationException; import io.spring.api.exception.ResourceNotFoundException; @@ -11,9 +14,7 @@ import io.spring.core.comment.CommentRepository; import io.spring.core.service.AuthorizationService; import io.spring.core.user.User; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import lombok.AllArgsConstructor; @@ -56,12 +57,7 @@ public ResponseEntity getComments( Article article = articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new); List comments = commentQueryService.findByArticleId(article.getId(), user); - return ResponseEntity.ok( - new HashMap() { - { - put("comments", comments); - } - }); + return ResponseEntity.ok(commentsResponse(comments)); } @RequestMapping(path = "{id}", method = RequestMethod.DELETE) @@ -83,14 +79,6 @@ public ResponseEntity deleteComment( }) .orElseThrow(ResourceNotFoundException::new); } - - private Map commentResponse(CommentData commentData) { - return new HashMap() { - { - put("comment", commentData); - } - }; - } } @Getter diff --git a/src/main/java/io/spring/api/CurrentUserApi.java b/src/main/java/io/spring/api/CurrentUserApi.java index e096aec0b..d4e28de6e 100644 --- a/src/main/java/io/spring/api/CurrentUserApi.java +++ b/src/main/java/io/spring/api/CurrentUserApi.java @@ -1,5 +1,8 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.userResponse; +import static io.spring.api.security.TokenExtractor.extractToken; + import io.spring.application.UserQueryService; import io.spring.application.data.UserData; import io.spring.application.data.UserWithToken; @@ -7,8 +10,6 @@ import io.spring.application.user.UpdateUserParam; import io.spring.application.user.UserService; import io.spring.core.user.User; -import java.util.HashMap; -import java.util.Map; import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; @@ -33,26 +34,19 @@ public ResponseEntity currentUser( @AuthenticationPrincipal User currentUser, @RequestHeader(value = "Authorization") String authorization) { UserData userData = userQueryService.findById(currentUser.getId()).get(); - return ResponseEntity.ok( - userResponse(new UserWithToken(userData, authorization.split(" ")[1]))); + String token = extractToken(authorization).orElse(""); + return ResponseEntity.ok(userResponse(new UserWithToken(userData, token))); } @PutMapping public ResponseEntity updateProfile( @AuthenticationPrincipal User currentUser, - @RequestHeader("Authorization") String token, + @RequestHeader("Authorization") String authorization, @Valid @RequestBody UpdateUserParam updateUserParam) { userService.updateUser(new UpdateUserCommand(currentUser, updateUserParam)); UserData userData = userQueryService.findById(currentUser.getId()).get(); - return ResponseEntity.ok(userResponse(new UserWithToken(userData, token.split(" ")[1]))); - } - - private Map userResponse(UserWithToken userWithToken) { - return new HashMap() { - { - put("user", userWithToken); - } - }; + String token = extractToken(authorization).orElse(""); + return ResponseEntity.ok(userResponse(new UserWithToken(userData, token))); } } diff --git a/src/main/java/io/spring/api/ProfileApi.java b/src/main/java/io/spring/api/ProfileApi.java index 1cf7bca3b..fac512b72 100644 --- a/src/main/java/io/spring/api/ProfileApi.java +++ b/src/main/java/io/spring/api/ProfileApi.java @@ -1,12 +1,13 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.profileResponse; + import io.spring.api.exception.ResourceNotFoundException; import io.spring.application.ProfileQueryService; import io.spring.application.data.ProfileData; import io.spring.core.user.FollowRelation; import io.spring.core.user.User; import io.spring.core.user.UserRepository; -import java.util.HashMap; import java.util.Optional; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; @@ -30,7 +31,7 @@ public ResponseEntity getProfile( @PathVariable("username") String username, @AuthenticationPrincipal User user) { return profileQueryService .findByUsername(username, user) - .map(this::profileResponse) + .map(profile -> ResponseEntity.ok(profileResponse(profile))) .orElseThrow(ResourceNotFoundException::new); } @@ -43,7 +44,8 @@ public ResponseEntity follow( target -> { FollowRelation followRelation = new FollowRelation(user.getId(), target.getId()); userRepository.saveRelation(followRelation); - return profileResponse(profileQueryService.findByUsername(username, user).get()); + return ResponseEntity.ok( + profileResponse(profileQueryService.findByUsername(username, user).get())); }) .orElseThrow(ResourceNotFoundException::new); } @@ -51,28 +53,17 @@ public ResponseEntity follow( @DeleteMapping(path = "follow") public ResponseEntity unfollow( @PathVariable("username") String username, @AuthenticationPrincipal User user) { - Optional userOptional = userRepository.findByUsername(username); - if (userOptional.isPresent()) { - User target = userOptional.get(); - return userRepository - .findRelation(user.getId(), target.getId()) - .map( - relation -> { - userRepository.removeRelation(relation); - return profileResponse(profileQueryService.findByUsername(username, user).get()); - }) - .orElseThrow(ResourceNotFoundException::new); - } else { - throw new ResourceNotFoundException(); - } - } - - private ResponseEntity profileResponse(ProfileData profile) { - return ResponseEntity.ok( - new HashMap() { - { - put("profile", profile); - } - }); + User target = userRepository.findByUsername(username) + .orElseThrow(ResourceNotFoundException::new); + + return userRepository + .findRelation(user.getId(), target.getId()) + .map( + relation -> { + userRepository.removeRelation(relation); + return ResponseEntity.ok( + profileResponse(profileQueryService.findByUsername(username, user).get())); + }) + .orElseThrow(ResourceNotFoundException::new); } } diff --git a/src/main/java/io/spring/api/ResponseFactory.java b/src/main/java/io/spring/api/ResponseFactory.java new file mode 100644 index 000000000..1c55dabf1 --- /dev/null +++ b/src/main/java/io/spring/api/ResponseFactory.java @@ -0,0 +1,39 @@ +package io.spring.api; + +import java.util.Collections; +import java.util.Map; + +/** + * Factory class for creating standardized API response structures. + * Centralizes response creation to follow DRY principle. + */ +public final class ResponseFactory { + + private ResponseFactory() { + // Utility class - prevent instantiation + } + + public static Map singletonMap(String key, Object value) { + return Collections.singletonMap(key, value); + } + + public static Map userResponse(Object userData) { + return singletonMap("user", userData); + } + + public static Map articleResponse(Object articleData) { + return singletonMap("article", articleData); + } + + public static Map profileResponse(Object profileData) { + return singletonMap("profile", profileData); + } + + public static Map commentResponse(Object commentData) { + return singletonMap("comment", commentData); + } + + public static Map commentsResponse(Object commentsList) { + return singletonMap("comments", commentsList); + } +} diff --git a/src/main/java/io/spring/api/UsersApi.java b/src/main/java/io/spring/api/UsersApi.java index d91321e82..de1e006fb 100644 --- a/src/main/java/io/spring/api/UsersApi.java +++ b/src/main/java/io/spring/api/UsersApi.java @@ -1,5 +1,6 @@ package io.spring.api; +import static io.spring.api.ResponseFactory.userResponse; import static org.springframework.web.bind.annotation.RequestMethod.POST; import com.fasterxml.jackson.annotation.JsonRootName; @@ -12,8 +13,6 @@ import io.spring.core.service.JwtService; import io.spring.core.user.User; import io.spring.core.user.UserRepository; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; import javax.validation.Valid; import javax.validation.constraints.Email; @@ -46,23 +45,19 @@ public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam @RequestMapping(path = "/users/login", method = POST) public ResponseEntity userLogin(@Valid @RequestBody LoginParam loginParam) { - Optional optional = userRepository.findByEmail(loginParam.getEmail()); - if (optional.isPresent() - && passwordEncoder.matches(loginParam.getPassword(), optional.get().getPassword())) { - UserData userData = userQueryService.findById(optional.get().getId()).get(); - return ResponseEntity.ok( - userResponse(new UserWithToken(userData, jwtService.toToken(optional.get())))); - } else { + Optional userOptional = userRepository.findByEmail(loginParam.getEmail()); + if (!userOptional.isPresent()) { throw new InvalidAuthenticationException(); } - } - private Map userResponse(UserWithToken userWithToken) { - return new HashMap() { - { - put("user", userWithToken); - } - }; + User user = userOptional.get(); + if (!passwordEncoder.matches(loginParam.getPassword(), user.getPassword())) { + throw new InvalidAuthenticationException(); + } + + UserData userData = userQueryService.findById(user.getId()).get(); + return ResponseEntity.ok( + userResponse(new UserWithToken(userData, jwtService.toToken(user)))); } } diff --git a/src/main/java/io/spring/api/security/JwtTokenFilter.java b/src/main/java/io/spring/api/security/JwtTokenFilter.java index 1b5c50146..c7cdf1a12 100644 --- a/src/main/java/io/spring/api/security/JwtTokenFilter.java +++ b/src/main/java/io/spring/api/security/JwtTokenFilter.java @@ -1,10 +1,11 @@ package io.spring.api.security; +import static io.spring.api.security.TokenExtractor.extractToken; + import io.spring.core.service.JwtService; import io.spring.core.user.UserRepository; import java.io.IOException; import java.util.Collections; -import java.util.Optional; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -17,15 +18,17 @@ @SuppressWarnings("SpringJavaAutowiringInspection") public class JwtTokenFilter extends OncePerRequestFilter { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + @Autowired private UserRepository userRepository; @Autowired private JwtService jwtService; - private final String header = "Authorization"; @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - getTokenString(request.getHeader(header)) + extractToken(request.getHeader(AUTHORIZATION_HEADER)) .flatMap(token -> jwtService.getSubFromToken(token)) .ifPresent( id -> { @@ -46,17 +49,4 @@ protected void doFilterInternal( filterChain.doFilter(request, response); } - - private Optional getTokenString(String header) { - if (header == null) { - return Optional.empty(); - } else { - String[] split = header.split(" "); - if (split.length < 2) { - return Optional.empty(); - } else { - return Optional.ofNullable(split[1]); - } - } - } } diff --git a/src/main/java/io/spring/api/security/TokenExtractor.java b/src/main/java/io/spring/api/security/TokenExtractor.java new file mode 100644 index 000000000..d26e4583a --- /dev/null +++ b/src/main/java/io/spring/api/security/TokenExtractor.java @@ -0,0 +1,38 @@ +package io.spring.api.security; + +import java.util.Optional; + +/** + * Utility class for extracting JWT tokens from Authorization headers. + * Centralizes token parsing logic to follow DRY principle. + */ +public final class TokenExtractor { + + private static final String BEARER_PREFIX = "Bearer "; + private static final int TOKEN_INDEX = 1; + private static final int MIN_PARTS = 2; + + private TokenExtractor() { + // Utility class - prevent instantiation + } + + /** + * Extracts the token from an Authorization header string. + * Expected format: "Bearer {token}" + * + * @param authorizationHeader the full Authorization header value + * @return Optional containing the token if present and valid, empty otherwise + */ + public static Optional extractToken(String authorizationHeader) { + if (authorizationHeader == null) { + return Optional.empty(); + } + + String[] parts = authorizationHeader.split(" "); + if (parts.length < MIN_PARTS) { + return Optional.empty(); + } + + return Optional.ofNullable(parts[TOKEN_INDEX]); + } +} diff --git a/src/main/java/io/spring/application/ArticleQueryService.java b/src/main/java/io/spring/application/ArticleQueryService.java index 653a0dca4..e88514bb3 100644 --- a/src/main/java/io/spring/application/ArticleQueryService.java +++ b/src/main/java/io/spring/application/ArticleQueryService.java @@ -31,24 +31,24 @@ public Optional findById(String id, User user) { ArticleData articleData = articleReadService.findById(id); if (articleData == null) { return Optional.empty(); - } else { - if (user != null) { - fillExtraInfo(id, user, articleData); - } - return Optional.of(articleData); } + + if (user != null) { + fillExtraInfo(id, user, articleData); + } + return Optional.of(articleData); } public Optional findBySlug(String slug, User user) { ArticleData articleData = articleReadService.findBySlug(slug); if (articleData == null) { return Optional.empty(); - } else { - if (user != null) { - fillExtraInfo(articleData.getId(), user, articleData); - } - return Optional.of(articleData); } + + if (user != null) { + fillExtraInfo(articleData.getId(), user, articleData); + } + return Optional.of(articleData); } public CursorPager findRecentArticlesWithCursor( @@ -59,100 +59,100 @@ public CursorPager findRecentArticlesWithCursor( User currentUser) { List articleIds = articleReadService.findArticlesWithCursor(tag, author, favoritedBy, page); - if (articleIds.size() == 0) { + if (articleIds.isEmpty()) { return new CursorPager<>(new ArrayList<>(), page.getDirection(), false); - } else { - boolean hasExtra = articleIds.size() > page.getLimit(); - if (hasExtra) { - articleIds.remove(page.getLimit()); - } - if (!page.isNext()) { - Collections.reverse(articleIds); - } - - List articles = articleReadService.findArticles(articleIds); - fillExtraInfo(articles, currentUser); + } - return new CursorPager<>(articles, page.getDirection(), hasExtra); + boolean hasExtra = articleIds.size() > page.getLimit(); + if (hasExtra) { + articleIds.remove(page.getLimit()); } + if (!page.isNext()) { + Collections.reverse(articleIds); + } + + List articles = articleReadService.findArticles(articleIds); + fillExtraInfo(articles, currentUser); + + return new CursorPager<>(articles, page.getDirection(), hasExtra); } public CursorPager findUserFeedWithCursor( User user, CursorPageParameter page) { - List followdUsers = userRelationshipQueryService.followedUsers(user.getId()); - if (followdUsers.size() == 0) { + List followedUsers = userRelationshipQueryService.followedUsers(user.getId()); + if (followedUsers.isEmpty()) { return new CursorPager<>(new ArrayList<>(), page.getDirection(), false); - } else { - List articles = - articleReadService.findArticlesOfAuthorsWithCursor(followdUsers, page); - boolean hasExtra = articles.size() > page.getLimit(); - if (hasExtra) { - articles.remove(page.getLimit()); - } - if (!page.isNext()) { - Collections.reverse(articles); - } - fillExtraInfo(articles, user); - return new CursorPager<>(articles, page.getDirection(), hasExtra); } + + List articles = + articleReadService.findArticlesOfAuthorsWithCursor(followedUsers, page); + boolean hasExtra = articles.size() > page.getLimit(); + if (hasExtra) { + articles.remove(page.getLimit()); + } + if (!page.isNext()) { + Collections.reverse(articles); + } + fillExtraInfo(articles, user); + return new CursorPager<>(articles, page.getDirection(), hasExtra); } public ArticleDataList findRecentArticles( String tag, String author, String favoritedBy, Page page, User currentUser) { List articleIds = articleReadService.queryArticles(tag, author, favoritedBy, page); int articleCount = articleReadService.countArticle(tag, author, favoritedBy); - if (articleIds.size() == 0) { + if (articleIds.isEmpty()) { return new ArticleDataList(new ArrayList<>(), articleCount); - } else { - List articles = articleReadService.findArticles(articleIds); - fillExtraInfo(articles, currentUser); - return new ArticleDataList(articles, articleCount); } + + List articles = articleReadService.findArticles(articleIds); + fillExtraInfo(articles, currentUser); + return new ArticleDataList(articles, articleCount); } public ArticleDataList findUserFeed(User user, Page page) { - List followdUsers = userRelationshipQueryService.followedUsers(user.getId()); - if (followdUsers.size() == 0) { + List followedUsers = userRelationshipQueryService.followedUsers(user.getId()); + if (followedUsers.isEmpty()) { return new ArticleDataList(new ArrayList<>(), 0); - } else { - List articles = articleReadService.findArticlesOfAuthors(followdUsers, page); + } - List articleIds = new ArrayList<>(); + List articles = articleReadService.findArticlesOfAuthors(followedUsers, page); - for (ArticleData articleData : articles) { - articleIds.add(articleData.getId()); - } + List articleIds = new ArrayList<>(); - List favoritesCounts = - articleFavoritesReadService.articlesFavoriteCount(articleIds); - Map countMap = new HashMap<>(); - for (ArticleFavoriteCount item : favoritesCounts) { - countMap.put(item.getId(), item.getCount()); - } - for (ArticleData articleData : articles) { - articleData.setFavoritesCount(countMap.get(articleData.getId())); - } - if (user != null) { - setIsFavorite(articles, user); + for (ArticleData articleData : articles) { + articleIds.add(articleData.getId()); + } - List profileDataIds = new ArrayList<>(); - for (ArticleData articleData : articles) { - if(articleData.getProfileData() != null) { - profileDataIds.add(articleData.getProfileData().getId()); - } + List favoritesCounts = + articleFavoritesReadService.articlesFavoriteCount(articleIds); + Map countMap = new HashMap<>(); + for (ArticleFavoriteCount item : favoritesCounts) { + countMap.put(item.getId(), item.getCount()); + } + for (ArticleData articleData : articles) { + articleData.setFavoritesCount(countMap.get(articleData.getId())); + } + if (user != null) { + setIsFavorite(articles, user); + + List profileDataIds = new ArrayList<>(); + for (ArticleData articleData : articles) { + if(articleData.getProfileData() != null) { + profileDataIds.add(articleData.getProfileData().getId()); } + } - Set followingAuthors = - userRelationshipQueryService.followingAuthors(user.getId(), profileDataIds); - for (ArticleData articleData : articles) { - if (followingAuthors.contains(articleData.getProfileData().getId())) { - articleData.getProfileData().setFollowing(true); - } + Set followingAuthors = + userRelationshipQueryService.followingAuthors(user.getId(), profileDataIds); + for (ArticleData articleData : articles) { + if (followingAuthors.contains(articleData.getProfileData().getId())) { + articleData.getProfileData().setFollowing(true); } } - int count = articleReadService.countFeedSize(followdUsers); - return new ArticleDataList(articles, count); } + int count = articleReadService.countFeedSize(followedUsers); + return new ArticleDataList(articles, count); } private void fillExtraInfo(List articles, User currentUser) { diff --git a/src/main/java/io/spring/application/user/UserService.java b/src/main/java/io/spring/application/user/UserService.java index 48c6735b8..1a6c119dd 100644 --- a/src/main/java/io/spring/application/user/UserService.java +++ b/src/main/java/io/spring/application/user/UserService.java @@ -17,6 +17,9 @@ @Service @Validated public class UserService { + + private static final String EMPTY_BIO = ""; + private UserRepository userRepository; private String defaultImage; private PasswordEncoder passwordEncoder; @@ -37,7 +40,7 @@ public User createUser(@Valid RegisterParam registerParam) { registerParam.getEmail(), registerParam.getUsername(), passwordEncoder.encode(registerParam.getPassword()), - "", + EMPTY_BIO, defaultImage); userRepository.save(user); return user; diff --git a/src/main/java/io/spring/graphql/ArticleDatafetcher.java b/src/main/java/io/spring/graphql/ArticleDatafetcher.java index 37c82939a..a6a941072 100644 --- a/src/main/java/io/spring/graphql/ArticleDatafetcher.java +++ b/src/main/java/io/spring/graphql/ArticleDatafetcher.java @@ -36,6 +36,8 @@ @AllArgsConstructor public class ArticleDatafetcher { + private static final String PAGINATION_PARAM_ERROR = "first 和 last 必须只存在一个"; + private ArticleQueryService articleQueryService; private UserRepository userRepository; @@ -46,9 +48,7 @@ public DataFetcherResult getFeed( @InputArgument("last") Integer last, @InputArgument("before") String before, DgsDataFetchingEnvironment dfe) { - if (first == null && last == null) { - throw new IllegalArgumentException("first 和 last 必须只存在一个"); - } + validatePaginationParams(first, last); User current = SecurityUtil.getCurrentUser().orElse(null); @@ -92,9 +92,7 @@ public DataFetcherResult userFeed( @InputArgument("last") Integer last, @InputArgument("before") String before, DgsDataFetchingEnvironment dfe) { - if (first == null && last == null) { - throw new IllegalArgumentException("first 和 last 必须只存在一个"); - } + validatePaginationParams(first, last); Profile profile = dfe.getSource(); User target = @@ -142,9 +140,7 @@ public DataFetcherResult userFavorites( @InputArgument("last") Integer last, @InputArgument("before") String before, DgsDataFetchingEnvironment dfe) { - if (first == null && last == null) { - throw new IllegalArgumentException("first 和 last 必须只存在一个"); - } + validatePaginationParams(first, last); User current = SecurityUtil.getCurrentUser().orElse(null); Profile profile = dfe.getSource(); @@ -196,9 +192,7 @@ public DataFetcherResult userArticles( @InputArgument("last") Integer last, @InputArgument("before") String before, DgsDataFetchingEnvironment dfe) { - if (first == null && last == null) { - throw new IllegalArgumentException("first 和 last 必须只存在一个"); - } + validatePaginationParams(first, last); User current = SecurityUtil.getCurrentUser().orElse(null); Profile profile = dfe.getSource(); @@ -252,9 +246,7 @@ public DataFetcherResult getArticles( @InputArgument("favoritedBy") String favoritedBy, @InputArgument("withTag") String withTag, DgsDataFetchingEnvironment dfe) { - if (first == null && last == null) { - throw new IllegalArgumentException("first 和 last 必须只存在一个"); - } + validatePaginationParams(first, last); User current = SecurityUtil.getCurrentUser().orElse(null); @@ -381,4 +373,10 @@ private Article buildArticleResult(ArticleData articleData) { .updatedAt(ISODateTimeFormat.dateTime().withZoneUTC().print(articleData.getUpdatedAt())) .build(); } + + private void validatePaginationParams(Integer first, Integer last) { + if (first == null && last == null) { + throw new IllegalArgumentException(PAGINATION_PARAM_ERROR); + } + } }