ブログ投稿と閲覧機能の実装
ブログ投稿処理
@PostMapping
public Result createBlogPost(@RequestBody BlogEntry blogEntry) {
UserDTO currentUser = UserContext.getCurrentUser();
blogEntry.setAuthorId(currentUser.getId());
blogService.save(blogEntry);
return Result.success(blogEntry.getId());
}
画像アップロード処理
@PostMapping("upload")
public Result uploadImageFile(@RequestParam("file") MultipartFile file) {
try {
String originalName = file.getOriginalFilename();
String newFileName = generateUniqueFileName(originalName);
file.transferTo(new File(Constants.IMAGE_DIRECTORY, newFileName));
return Result.success(newFileName);
} catch (IOException ex) {
throw new RuntimeException("画像アップロード失敗", ex);
}
}
ブログ詳細取得処理
@GetMapping("/{blogId}")
public Result getBlogDetails(@PathVariable Integer blogId) {
return blogService.getBlogDetails(blogId);
}
@Override
public Result getBlogDetails(Integer blogId) {
BlogEntry blog = getById(blogId);
if (blog == null) {
return Result.failure("ブログが存在しません");
}
populateAuthorInfo(blog);
return Result.success(blog);
}
private void populateAuthorInfo(BlogEntry blog) {
User author = userService.getById(blog.getAuthorId());
blog.setAuthorName(author.getDisplayName());
blog.setAuthorAvatar(author.getAvatarUrl());
}
いいね機能の実装
いいね状態管理
@PutMapping("/like/{blogId}")
public Result toggleLike(@PathVariable("blogId") Long blogId) {
return blogService.handleLikeAction(blogId);
}
@Override
public Result handleLikeAction(Long blogId) {
Long currentUserId = UserContext.getCurrentUser().getId();
String redisKey = Constants.BLOG_LIKES_PREFIX + blogId;
Boolean alreadyLiked = redisTemplate.opsForSet()
.isMember(redisKey, currentUserId.toString());
if (Boolean.FALSE.equals(alreadyLiked)) {
boolean updated = update().setSql("like_count = like_count + 1")
.eq("id", blogId).update();
if (updated) {
redisTemplate.opsForSet().add(redisKey, currentUserId.toString());
}
} else {
boolean updated = update().setSql("like_count = like_count - 1")
.eq("id", blogId).update();
if (updated) {
redisTemplate.opsForSet().remove(redisKey, currentUserId.toString());
}
}
return Result.success();
}
いいね状態の判定
private void checkLikeStatus(BlogEntry blog) {
UserDTO currentUser = UserContext.getCurrentUser();
if (currentUser == null) return;
String redisKey = Constants.BLOG_LIKES_PREFIX + blog.getId();
Boolean isLiked = redisTemplate.opsForSet()
.isMember(redisKey, currentUser.getId().toString());
blog.setLiked(Boolean.TRUE.equals(isLiked));
}
いいねランキング機能
トップいいねユーザー取得
@GetMapping("/likes/{blogId}")
public Result getTopLikers(@PathVariable Integer blogId) {
return blogService.getTopLikers(blogId);
}
@Override
public Result getTopLikers(Integer blogId) {
String redisKey = Constants.BLOG_LIKES_PREFIX + blogId;
Set<String> topLikerIds = redisTemplate.opsForZSet()
.range(redisKey, 0, 4);
if (topLikerIds == null || topLikerIds.isEmpty()) {
return Result.success(Collections.emptyList());
}
List<Long> userIds = topLikerIds.stream()
.map(Long::valueOf).collect(Collectors.toList());
List<UserDTO> topUsers = userService.listByIds(userIds).stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
return Result.success(topUsers);
}
フォロー機能の実装
フォロー状態管理
@RestController
@RequestMapping("/follow")
public class FollowController {
@PostMapping("/{targetUserId}/{follow}")
public Result updateFollowStatus(@PathVariable Long targetUserId,
@PathVariable Boolean follow) {
return followService.updateFollowStatus(targetUserId, follow);
}
}
@Service
public class FollowService {
public Result updateFollowStatus(Long targetUserId, Boolean shouldFollow) {
Long currentUserId = UserContext.getCurrentUser().getId();
String redisKey = Constants.FOLLOWS_PREFIX + currentUserId;
if (shouldFollow) {
FollowRelation relation = new FollowRelation();
relation.setFollowerId(currentUserId);
relation.setTargetUserId(targetUserId);
if (save(relation)) {
redisTemplate.opsForSet().add(redisKey, targetUserId.toString());
}
} else {
remove(new QueryWrapper<FollowRelation>()
.eq("follower_id", currentUserId)
.eq("target_user_id", targetUserId));
redisTemplate.opsForSet().remove(redisKey, targetUserId.toString());
}
return Result.success();
}
}
共通フォロー機能
共通フォローユーザー取得
@GetMapping("/common/{otherUserId}")
public Result getCommonFollows(@PathVariable Long otherUserId) {
return followService.getCommonFollows(otherUserId);
}
@Override
public Result getCommonFollows(Long otherUserId) {
Long currentUserId = UserContext.getCurrentUser().getId();
String currentUserKey = Constants.FOLLOWS_PREFIX + currentUserId;
String otherUserKey = Constants.FOLLOWS_PREFIX + otherUserId;
Set<String> commonFollowIds = redisTemplate.opsForSet()
.intersect(currentUserKey, otherUserKey);
if (commonFollowIds == null || commonFollowIds.isEmpty()) {
return Result.success(Collections.emptyList());
}
List<UserDTO> commonUsers = userService.listByIds(
commonFollowIds.stream().map(Long::valueOf).collect(Collectors.toList()))
.stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
return Result.success(commonUsers);
}