feed and tag
This commit is contained in:
@@ -56,13 +56,21 @@ public class ArticlesApi {
|
||||
}});
|
||||
}
|
||||
|
||||
@GetMapping(path = "feed")
|
||||
public ResponseEntity getFeed(@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
@RequestParam(value = "limit", defaultValue = "20") int limit,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return ResponseEntity.ok(articleQueryService.findUserFeed(user, new Page(offset, limit)));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity getArticles(@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
@RequestParam(value = "limit", defaultValue = "20") int limit,
|
||||
@RequestParam(value = "tag", required = false) String tag,
|
||||
@RequestParam(value = "favorited", required = false) String favoritedBy,
|
||||
@RequestParam(value = "author", required = false) String author) {
|
||||
return ResponseEntity.ok(articleQueryService.findRecentArticles(tag, author, favoritedBy, new Page(offset, limit)));
|
||||
@RequestParam(value = "author", required = false) String author,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return ResponseEntity.ok(articleQueryService.findRecentArticles(tag, author, favoritedBy, new Page(offset, limit), user));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
src/main/java/io/spring/api/TagsApi.java
Normal file
28
src/main/java/io/spring/api/TagsApi.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package io.spring.api;
|
||||
|
||||
import io.spring.application.tag.TagsQueryService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "tags")
|
||||
public class TagsApi {
|
||||
private TagsQueryService tagsQueryService;
|
||||
|
||||
@Autowired
|
||||
public TagsApi(TagsQueryService tagsQueryService) {
|
||||
this.tagsQueryService = tagsQueryService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity getTags() {
|
||||
return ResponseEntity.ok(new HashMap<String, Object>() {{
|
||||
put("tags", tagsQueryService.allTags());
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.and()
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.GET, "/articles/feed").authenticated()
|
||||
.antMatchers(HttpMethod.POST, "/users", "/users/login").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/articles/**", "/profiles/**").permitAll()
|
||||
.anyRequest().authenticated();
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package io.spring.application.article;
|
||||
|
||||
import io.spring.core.user.User;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mapper
|
||||
@Component
|
||||
public interface ArticleFavoritesQueryService {
|
||||
boolean isUserFavorite(@Param("userId") String userId, @Param("articleId") String articleId);
|
||||
|
||||
int articleFavoriteCount(@Param("articleId") String articleId);
|
||||
|
||||
List<ArticleFavoriteCount> articlesFavoriteCount(@Param("ids") List<String> ids);
|
||||
|
||||
Set<String> userFavorites(@Param("ids") List<String> ids, @Param("currentUser") User currentUser);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,19 @@ package io.spring.application.article;
|
||||
import io.spring.application.Page;
|
||||
import io.spring.application.profile.UserRelationshipQueryService;
|
||||
import io.spring.core.user.User;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
@Service
|
||||
public class ArticleQueryService {
|
||||
@@ -49,6 +56,56 @@ public class ArticleQueryService {
|
||||
}
|
||||
}
|
||||
|
||||
public ArticleDataList findRecentArticles(String tag, String author, String favoritedBy, Page page, User currentUser) {
|
||||
List<String> articleIds = articleReadService.queryArticles(tag, author, favoritedBy, page);
|
||||
int articleCount = articleReadService.countArticle(tag, author, favoritedBy);
|
||||
if (articleIds.size() == 0) {
|
||||
return new ArticleDataList(new ArrayList<>(), articleCount);
|
||||
} else {
|
||||
List<ArticleData> articles = articleReadService.findArticles(articleIds);
|
||||
fillExtraInfo(articles, currentUser);
|
||||
return new ArticleDataList(articles, articleCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillExtraInfo(List<ArticleData> articles, User currentUser) {
|
||||
setFavoriteCount(articles);
|
||||
if (currentUser != null) {
|
||||
setIsFavorite(articles, currentUser);
|
||||
setIsFollowingAuthor(articles, currentUser);
|
||||
}
|
||||
}
|
||||
|
||||
private void setIsFollowingAuthor(List<ArticleData> articles, User currentUser) {
|
||||
Set<String> followingAuthors = userRelationshipQueryService.followingAuthors(
|
||||
currentUser.getId(),
|
||||
articles.stream().map(articleData1 -> articleData1.getProfileData().getId()).collect(toList()));
|
||||
articles.forEach(articleData -> {
|
||||
if (followingAuthors.contains(articleData.getProfileData().getId())) {
|
||||
articleData.getProfileData().setFollowing(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFavoriteCount(List<ArticleData> articles) {
|
||||
List<ArticleFavoriteCount> favoritesCounts = articleFavoritesQueryService.articlesFavoriteCount(articles.stream().map(ArticleData::getId).collect(toList()));
|
||||
Map<String, Integer> countMap = new HashMap<>();
|
||||
favoritesCounts.forEach(item -> {
|
||||
countMap.put(item.getId(), item.getCount());
|
||||
});
|
||||
articles.forEach(articleData -> articleData.setFavoritesCount(countMap.get(articleData.getId())));
|
||||
}
|
||||
|
||||
private void setIsFavorite(List<ArticleData> articles, User currentUser) {
|
||||
Set<String> favoritedArticles = articleFavoritesQueryService.userFavorites(articles.stream().map(articleData -> articleData.getId()).collect(toList()), currentUser);
|
||||
|
||||
articles.forEach(articleData -> {
|
||||
if (favoritedArticles.contains(articleData.getId())) {
|
||||
articleData.setFavorited(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fillExtraInfo(String id, User user, ArticleData articleData) {
|
||||
articleData.setFavorited(articleFavoritesQueryService.isUserFavorite(user.getId(), id));
|
||||
articleData.setFavoritesCount(articleFavoritesQueryService.articleFavoriteCount(id));
|
||||
@@ -58,11 +115,22 @@ public class ArticleQueryService {
|
||||
articleData.getProfileData().getId()));
|
||||
}
|
||||
|
||||
public ArticleDataList findRecentArticles(String tag, String author, String favoritedBy, Page page) {
|
||||
List<String> articleIds = articleReadService.queryArticles(tag, author, favoritedBy, page);
|
||||
int articleCount = articleReadService.countArticle(tag, author, favoritedBy);
|
||||
return new ArticleDataList(
|
||||
articleIds.size() == 0 ? new ArrayList<>() : articleReadService.findArticles(articleIds),
|
||||
articleCount);
|
||||
public ArticleDataList findUserFeed(User user, Page page) {
|
||||
List<String> followdUsers = userRelationshipQueryService.followedUsers(user.getId());
|
||||
if (followdUsers.size() == 0) {
|
||||
return new ArticleDataList(new ArrayList<>(), 0);
|
||||
} else {
|
||||
List<ArticleData> articles = articleReadService.findArticlesOfAuthors(followdUsers, page);
|
||||
fillExtraInfo(articles, user);
|
||||
int count = articleReadService.countFeedSize(followdUsers);
|
||||
return new ArticleDataList(articles, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
class ArticleFavoriteCount {
|
||||
private String id;
|
||||
private int count;
|
||||
}
|
||||
@@ -19,4 +19,8 @@ public interface ArticleReadService {
|
||||
int countArticle(@Param("tag") String tag, @Param("author") String author, @Param("favoritedBy") String favoritedBy);
|
||||
|
||||
List<ArticleData> findArticles(@Param("articleIds") List<String> articleIds);
|
||||
|
||||
List<ArticleData> findArticlesOfAuthors(@Param("authors") List<String> authors, @Param("page") Page page);
|
||||
|
||||
int countFeedSize(@Param("authors") List<String> authors);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package io.spring.application.profile;
|
||||
|
||||
import io.spring.application.article.ArticleData;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
@Mapper
|
||||
public interface UserRelationshipQueryService {
|
||||
boolean isUserFollowing(@Param("userId") String userId, @Param("anotherUserId") String anotherUserId);
|
||||
|
||||
Set<String> followingAuthors(@Param("userId") String userId, @Param("ids") List<String> ids);
|
||||
|
||||
List<String> followedUsers(@Param("userId") String userId);
|
||||
}
|
||||
|
||||
12
src/main/java/io/spring/application/tag/TagReadService.java
Normal file
12
src/main/java/io/spring/application/tag/TagReadService.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package io.spring.application.tag;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Mapper
|
||||
public interface TagReadService {
|
||||
List<String> all();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.spring.application.tag;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class TagsQueryService {
|
||||
private TagReadService tagReadService;
|
||||
|
||||
public TagsQueryService(TagReadService tagReadService) {
|
||||
this.tagReadService = tagReadService;
|
||||
}
|
||||
|
||||
public List<String> allTags() {
|
||||
return tagReadService.all();
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,30 @@
|
||||
<select id="articleFavoriteCount" resultType="java.lang.Integer">
|
||||
select count(1) from article_favorites where article_id = #{articleId}
|
||||
</select>
|
||||
<select id="articlesFavoriteCount" resultMap="favoriteCount">
|
||||
select A.id, count(A.id) as favoriteCount from articles A
|
||||
left join article_favorites AF on A.id = AF.article_id
|
||||
where id in
|
||||
<foreach collection="ids" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
group by A.id
|
||||
</select>
|
||||
<select id="userFavorites" resultType="java.lang.String">
|
||||
select
|
||||
A.id
|
||||
from articles A
|
||||
left join article_favorites AF on A.id = AF.article_id
|
||||
where id in
|
||||
<foreach collection="ids" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
and AF.user_id = #{currentUser.id}
|
||||
</select>
|
||||
|
||||
<resultMap id="favoriteCount" type="io.spring.application.article.ArticleFavoriteCount">
|
||||
<id column="id" property="id"/>
|
||||
<result column="favoriteCount" property="count"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
@@ -82,6 +82,20 @@
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="findArticlesOfAuthors" resultMap="articleData">
|
||||
<include refid="selectArticleData"/>
|
||||
where A.user_id in
|
||||
<foreach index="index" collection="authors" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
limit #{page.offset}, #{page.limit}
|
||||
</select>
|
||||
<select id="countFeedSize" resultType="java.lang.Integer">
|
||||
select count(1) from articles A where A.user_id in
|
||||
<foreach collection="authors" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<resultMap id="articleId" type="string">
|
||||
<id javaType="string" column="articleId"/>
|
||||
|
||||
7
src/main/resources/mapper/TagReadService.xml
Normal file
7
src/main/resources/mapper/TagReadService.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.spring.application.tag.TagReadService">
|
||||
<select id="all" resultType="string">
|
||||
select name from tags
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -4,4 +4,15 @@
|
||||
<select id="isUserFollowing" resultType="java.lang.Boolean">
|
||||
select count(1) from follows where user_id = #{userId} and follow_id = #{anotherUserId}
|
||||
</select>
|
||||
<select id="followingAuthors" resultType="java.lang.String">
|
||||
select F.follow_id from follows F
|
||||
where F.follow_id in
|
||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
and F.user_id = #{userId}
|
||||
</select>
|
||||
<select id="followedUsers" resultType="java.lang.String">
|
||||
select F.follow_id from follows F where F.user_id = #{userId}
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user