2024-05-26 15:49:38 +08:00
|
|
|
|
## 任务名称: 点赞和收藏动态
|
|
|
|
|
### 目标:
|
2024-05-28 14:58:50 +08:00
|
|
|
|
- 巩固练习: 熟练掌握基于spring boot开发的基本步骤
|
2024-05-26 15:49:38 +08:00
|
|
|
|
|
|
|
|
|
### 预备知识:
|
|
|
|
|
|
|
|
|
|
### 操作步骤:
|
2024-05-28 14:58:50 +08:00
|
|
|
|
#### 1. API文档
|
|
|
|
|
|
|
|
|
|
[点赞和取消点赞接口](../api%20doc/点赞和取消点赞接口.md)
|
|
|
|
|
|
|
|
|
|
[获取当前用户对某个动态的点赞状态接口](../api%20doc/获取当前用户对某个动态的点赞状态接口.md)
|
|
|
|
|
|
|
|
|
|
[收藏和取消收藏接口](../api%20doc/收藏和取消收藏接口.md)
|
|
|
|
|
|
|
|
|
|
[获取当前用户对某个动态的收藏状态接口](../api%20doc/获取当前用户对某个动态的收藏状态接口.md)
|
|
|
|
|
|
|
|
|
|
#### 2. 数据模型设计和实现
|
|
|
|
|
|
|
|
|
|
##### 2.1 实体类
|
|
|
|
|
|
|
|
|
|
**PostStar**
|
|
|
|
|
```java
|
|
|
|
|
@Entity
|
|
|
|
|
public class PostStar extends BaseAuditingEntity{
|
|
|
|
|
|
|
|
|
|
@Comment("POST ID")
|
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
|
|
|
@JoinColumn(name = "post_id", nullable = false)
|
|
|
|
|
private Post post;
|
|
|
|
|
|
|
|
|
|
@Comment("用户ID")
|
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
|
|
|
@JoinColumn(name = "user_id", nullable = false)
|
|
|
|
|
private User user;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**PostCollection**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
@Entity
|
|
|
|
|
public class PostCollection extends BaseAuditingEntity{
|
|
|
|
|
|
|
|
|
|
@Comment("POST ID")
|
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
|
|
|
@JoinColumn(name = "post_id", nullable = false)
|
|
|
|
|
private Post post;
|
|
|
|
|
|
|
|
|
|
@Comment("用户ID")
|
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
|
|
|
@JoinColumn(name = "user_id", nullable = false)
|
|
|
|
|
private User user;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##### 2.2 DTO
|
|
|
|
|
|
|
|
|
|
**PostStarDTO**
|
|
|
|
|
```java
|
|
|
|
|
@Value
|
|
|
|
|
public class PostStarDto {
|
|
|
|
|
Long id;
|
|
|
|
|
PostDto post;
|
|
|
|
|
UserDto user;
|
|
|
|
|
@JsonSerialize(using = MillisecondToSecondSerializer.class)
|
|
|
|
|
Long createdOn;
|
|
|
|
|
@JsonSerialize(using = MillisecondToSecondSerializer.class)
|
|
|
|
|
Long modifiedOn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
**PostCollectionDTO**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
@Value
|
|
|
|
|
public class PostCollectionDto {
|
|
|
|
|
|
|
|
|
|
Long id;
|
|
|
|
|
PostDto post;
|
|
|
|
|
UserDto user;
|
|
|
|
|
@JsonSerialize(using = MillisecondToSecondSerializer.class)
|
|
|
|
|
Long createdOn;
|
|
|
|
|
@JsonSerialize(using = MillisecondToSecondSerializer.class)
|
|
|
|
|
Long modifiedOn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##### 2.3 Mapper
|
|
|
|
|
|
|
|
|
|
**PostStarMapper**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING)
|
|
|
|
|
public interface PostStarMapper {
|
|
|
|
|
PostStar toEntity(PostStarDto postStarDto);
|
|
|
|
|
|
|
|
|
|
PostStarDto toDto(PostStar postStar);
|
|
|
|
|
|
|
|
|
|
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
|
|
|
|
|
PostStar partialUpdate(PostStarDto postStarDto, @MappingTarget PostStar postStar);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**PostCollectionMapper**
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
|
|
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING)
|
|
|
|
|
public interface PostCollectionMapper {
|
|
|
|
|
PostCollection toEntity(PostCollectionDto postCollectionDto);
|
|
|
|
|
|
|
|
|
|
PostCollectionDto toDto(PostCollection postCollection);
|
|
|
|
|
|
|
|
|
|
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
|
|
|
|
|
PostCollection partialUpdate(PostCollectionDto postCollectionDto, @MappingTarget PostCollection postCollection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. JPA接口
|
|
|
|
|
|
|
|
|
|
**PostStarRepository**
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
|
|
public interface PostStarRepository extends JpaRepository<PostStar, Long> {
|
|
|
|
|
Optional<PostStar> findByUserIdAndPostId(Long postId, Long userId);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**PostCollectionRepository**
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public interface PostCollectionRepository extends JpaRepository<PostCollection, Long> {
|
|
|
|
|
Optional<PostCollection> findByUserIdAndPostId(Long userId, Long postId);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 4. 业务逻辑
|
|
|
|
|
|
|
|
|
|
在PostService中添加处理点赞的方法:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 判断当前用户是对指定文章否已点赞
|
|
|
|
|
* @param postId
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public boolean currentUserHasStarred(Long postId){
|
|
|
|
|
User user = authService.getCurrentUser();
|
|
|
|
|
return postStarRepository.findByUserIdAndPostId(user.getId(), postId).isPresent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 点赞文章
|
|
|
|
|
* @param postId 文章ID
|
|
|
|
|
* @return 如果点赞成功返回true,如果已点过赞则返回false
|
|
|
|
|
*/
|
|
|
|
|
public boolean toggleStar(long postId){
|
|
|
|
|
// 获取当前用户
|
|
|
|
|
User user = authService.getCurrentUser();
|
|
|
|
|
// 确认文章存在
|
|
|
|
|
Post post = postRepository.findById(postId).orElseThrow(()->new ResourceNotFoundException("Post","id="+postId));
|
|
|
|
|
// 确认用户是否已点赞
|
|
|
|
|
PostStar postStar = postStarRepository.findByUserIdAndPostId(user.getId(),postId).orElse(null);
|
|
|
|
|
if(postStar==null){
|
|
|
|
|
// 如果未点赞,则创建点赞记录并更新文章点赞数
|
|
|
|
|
postStar = new PostStar();
|
|
|
|
|
postStar.setPost(post);
|
|
|
|
|
postStar.setUser(user);
|
|
|
|
|
postStarRepository.save(postStar);
|
|
|
|
|
post.setUpvoteCount(post.getUpvoteCount()+1);
|
|
|
|
|
postRepository.save(post);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// 如果已点赞,则删除点赞记录并更新文章点赞数
|
|
|
|
|
postStarRepository.delete(postStar);
|
|
|
|
|
post.setUpvoteCount(post.getUpvoteCount()-1);
|
|
|
|
|
postRepository.save(post);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
对于收藏的处理与点赞类似,不再赘述。
|
|
|
|
|
|
|
|
|
|
#### 5. RestController
|
|
|
|
|
|
|
|
|
|
在PostController中添加点赞相关的接口:
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
|
|
@GetMapping("/post/star")
|
|
|
|
|
public DataResult<Map<String, Boolean>> currentHasStarred(@PathParam("id") Long postId) {
|
|
|
|
|
Map<String, Boolean> result = new HashMap<>();
|
|
|
|
|
result.put("status", postService.currentUserHasStarred(postId));
|
|
|
|
|
return ResultUtil.ok(result);
|
|
|
|
|
}
|
|
|
|
|
@PostMapping("/post/star")
|
|
|
|
|
public DataResult<Map<String, Boolean>> toggleStar(@RequestBody Map<String, Long> payload) {
|
|
|
|
|
boolean stared = postService.toggleStar(payload.get("id"));
|
|
|
|
|
Map<String, Boolean> result = new HashMap<>();
|
|
|
|
|
result.put("status", stared);
|
|
|
|
|
return ResultUtil.ok(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
收藏的接口与点赞类似,不再赘述。
|
|
|
|
|
|
|
|
|
|
|
2024-05-26 15:49:38 +08:00
|
|
|
|
|
|
|
|
|
### 技术/工具需求:
|
|
|
|
|
- [列出完成任务所需的技术栈、工具、软件版本等。]
|
|
|
|
|
|
|
|
|
|
### 成功标准:
|
|
|
|
|
- [明确完成任务的评判标准,如代码功能实现、性能指标、测试通过条件等。]
|
|
|
|
|
|
|
|
|
|
### 扩展学习(可选):
|
|
|
|
|
- [提供一些额外学习资源或挑战性任务,鼓励学有余力的学生进一步探索。]
|
|
|
|
|
|
|
|
|
|
### 评估与反馈:
|
|
|
|
|
- [说明如何提交作业、代码审查的标准、或任何反馈收集机制。]
|
|
|
|
|
|
|
|
|
|
### 时间估算:
|
|
|
|
|
- [给出预计完成该任务所需的时间,帮助学生合理安排学习计划。]
|