diff --git a/build.gradle b/build.gradle index 1ddeeba..1266a52 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,7 @@ dependencies { implementation 'org.hibernate.validator:hibernate-validator:6.0.13.Final' implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'com.vladsch.flexmark:flexmark-all:0.64.8' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' implementation 'org.springframework.boot:spring-boot-starter-data-redis' diff --git a/src/main/java/com/example/copykamanotes/mapper/NoteLikeMapper.java b/src/main/java/com/example/copykamanotes/mapper/NoteLikeMapper.java new file mode 100644 index 0000000..56589d6 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/mapper/NoteLikeMapper.java @@ -0,0 +1,14 @@ +package com.example.copykamanotes.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface NoteLikeMapper { + List findUserLikedNoteIds( + @Param("userId") Long userId, + @Param("noteIds") List noteIds + ); +} diff --git a/src/main/java/com/example/copykamanotes/mapper/NoteMapper.java b/src/main/java/com/example/copykamanotes/mapper/NoteMapper.java new file mode 100644 index 0000000..a0867e2 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/mapper/NoteMapper.java @@ -0,0 +1,14 @@ +package com.example.copykamanotes.mapper; + +import com.example.copykamanotes.model.dto.note.NoteQueryParams; +import com.example.copykamanotes.model.entity.Note; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface NoteMapper { + int countNotes(NoteQueryParams noteQueryParams); + + List findByQueryParam(NoteQueryParams noteQueryParams, int pageSize, int offset); +} diff --git a/src/main/java/com/example/copykamanotes/mapper/QuestionMapper.java b/src/main/java/com/example/copykamanotes/mapper/QuestionMapper.java new file mode 100644 index 0000000..09cd2d5 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/mapper/QuestionMapper.java @@ -0,0 +1,11 @@ +package com.example.copykamanotes.mapper; + +import com.example.copykamanotes.model.entity.Question; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Map; + +@Mapper +public interface QuestionMapper { + Map getQuestionMapByIds(Integer[] questionIds); +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/Category.java b/src/main/java/com/example/copykamanotes/model/entity/Category.java new file mode 100644 index 0000000..23e1e89 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Category.java @@ -0,0 +1,40 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; +import java.util.Date; + +/** + * @ClassName Category + * @Description 分类实体类 + * @Author Tong + * @LastChangeDate 2024-12-16 19:53 + * @Version v1.0 + */ +@Data +public class Category { + /* + * 分类ID(主键) + */ + private Integer categoryId; + + /* + * 分类名称 + */ + private String name; + + /* + * 上级分类ID + * 为0时表示当前分类是一级分类 + */ + private Integer parentCategoryId; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/Collection.java b/src/main/java/com/example/copykamanotes/model/entity/Collection.java new file mode 100644 index 0000000..61f9533 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Collection.java @@ -0,0 +1,40 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; +import java.util.Date; + +/** + * 收藏夹实体类 + */ +@Data +public class Collection { + /* + * 收藏夹ID(主键) + */ + private Integer collectionId; + + /* + * 收藏夹名称 + */ + private String name; + + /* + * 收藏夹描述 + */ + private String description; + + /* + * 收藏夹创建者ID + */ + private Long creatorId; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/CollectionNote.java b/src/main/java/com/example/copykamanotes/model/entity/CollectionNote.java new file mode 100644 index 0000000..b4223f8 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/CollectionNote.java @@ -0,0 +1,35 @@ +package com.example.copykamanotes.model.entity; + + +import lombok.Data; +import java.util.Date; + +/** + * @ClassName CollectionNote + * @Description 收藏夹-笔记关联实体类 + * @Author Tong + * @LastChangeDate 2024-12-16 20:11 + * @Version v1.0 + */ +@Data +public class CollectionNote { + /* + * 收藏夹ID(联合主键) + */ + private Integer collectionId; + + /* + * 笔记ID(联合主键) + */ + private Integer noteId; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/Comment.java b/src/main/java/com/example/copykamanotes/model/entity/Comment.java new file mode 100644 index 0000000..1b4328b --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Comment.java @@ -0,0 +1,56 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 评论实体类 + */ +@Data +public class Comment { + /** + * 评论ID + */ + private Integer commentId; + + /** + * 笔记ID + */ + private Integer noteId; + + /** + * 作者ID + */ + private Long authorId; + + /** + * 父评论ID + */ + private Integer parentId; + + /** + * 评论内容 + */ + private String content; + + /** + * 点赞数 + */ + private Integer likeCount; + + /** + * 回复数 + */ + private Integer replyCount; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/CommentLike.java b/src/main/java/com/example/copykamanotes/model/entity/CommentLike.java new file mode 100644 index 0000000..c4b47c4 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/CommentLike.java @@ -0,0 +1,31 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 评论点赞实体类 + */ +@Data +public class CommentLike { + /** + * 评论点赞ID + */ + private Integer commentLikeId; + + /** + * 评论ID + */ + private Integer commentId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; +} \ No newline at end of file diff --git a/src/main/java/com/example/copykamanotes/model/entity/Message.java b/src/main/java/com/example/copykamanotes/model/entity/Message.java new file mode 100644 index 0000000..409bc8a --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Message.java @@ -0,0 +1,55 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 消息实体类 + */ +@Data +public class Message { + /** + * 消息ID + */ + private Integer messageId; + + /** + * 接收者ID + */ + private Long receiverId; + + /** + * 发送者ID + */ + private Long senderId; + + /** + * 消息类型 + */ + private String type; + + /** + * 目标ID + */ + private Integer targetId; + + /** + * 消息内容 + */ + private String content; + + /** + * 是否已读 + */ + private Boolean isRead; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/src/main/java/com/example/copykamanotes/model/entity/NoteCollect.java b/src/main/java/com/example/copykamanotes/model/entity/NoteCollect.java new file mode 100644 index 0000000..cf89a7f --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/NoteCollect.java @@ -0,0 +1,30 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 笔记收藏实体类 + */ +@Data +public class NoteCollect { + /** + * 收藏ID + */ + private Integer collectId; + + /** + * 笔记ID + */ + private Integer noteId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/NoteComment.java b/src/main/java/com/example/copykamanotes/model/entity/NoteComment.java new file mode 100644 index 0000000..395d400 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/NoteComment.java @@ -0,0 +1,16 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; + +import java.util.Date; + +@Data +public class NoteComment { + private Integer id; + private Integer noteId; + private Long userId; + private String content; + private Date createdAt; + private Date updatedAt; + private Boolean isDeleted; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/NoteLike.java b/src/main/java/com/example/copykamanotes/model/entity/NoteLike.java new file mode 100644 index 0000000..34c8131 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/NoteLike.java @@ -0,0 +1,34 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; +import java.util.Date; + +/** + * @ClassName NoteLike + * @Description 笔记点赞关联实体类 + * @Author Tong + * @LastChangeDate 2024-12-16 20:04 + * @Version v1.0 + */ +@Data +public class NoteLike { + /* + * 笔记ID(联合主键) + */ + private Integer noteId; + + /* + * 点赞用户ID(联合主键) + */ + private Long userId; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/Question.java b/src/main/java/com/example/copykamanotes/model/entity/Question.java new file mode 100644 index 0000000..824347f --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Question.java @@ -0,0 +1,57 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + * @ClassName Question + * @Description 问题实体类 + * @Author Tong + * @LastChangeDate 2024-12-16 19:56 + * @Version v1.0 + */ +@Data +public class Question { + /* + * 问题ID(主键) + */ + private Integer questionId; + + /* + * 问题所属分类ID + */ + private Integer categoryId; + + /* + * 问题标题 + */ + private String title; + + /* + * 问题难度 + * 1=简单,2=中等,3=困难 + */ + private Integer difficulty; + + /* + * 题目考点 + */ + private String examPoint; + + /* + * 浏览量 + */ + private Integer viewCount; + + /* + * 创建时间 + */ + private LocalDateTime createdAt; + + /* + * 更新时间 + */ + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java b/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java new file mode 100644 index 0000000..448d1d2 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java @@ -0,0 +1,4 @@ +package com.example.copykamanotes.model.entity; + +public class QuestionList { +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/QuestionListItem.java b/src/main/java/com/example/copykamanotes/model/entity/QuestionListItem.java new file mode 100644 index 0000000..3e721e1 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/QuestionListItem.java @@ -0,0 +1,40 @@ +package com.example.copykamanotes.model.entity; + + +import lombok.Data; +import java.util.Date; + +/** + * @ClassName QuestionListItem + * @Description 题单-题目关联实体类 + * @Author Tong + * @LastChangeDate 2024-12-16 20:15 + * @Version v1.0 + */ +@Data +public class QuestionListItem { + /* + * 题单ID(联合主键) + */ + private Integer questionListId; + + /* + * 题目ID(联合主键) + */ + private Integer questionId; + + /* + * 题单内题目的顺序,从1开始 + */ + private Integer rank; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; +} diff --git a/src/main/java/com/example/copykamanotes/model/entity/Statistic.java b/src/main/java/com/example/copykamanotes/model/entity/Statistic.java new file mode 100644 index 0000000..8fffd6a --- /dev/null +++ b/src/main/java/com/example/copykamanotes/model/entity/Statistic.java @@ -0,0 +1,52 @@ +package com.example.copykamanotes.model.entity; + +import lombok.Data; + +import java.time.LocalDate; + +/** + * 统计信息实体,包含登录、注册、笔记等统计数据 + */ +@Data +public class Statistic { + /** + * 主键 ID + */ + private Integer id; + + /** + * 当天登录次数 + */ + private Integer loginCount; + + /** + * 当天注册人数 + */ + private Integer registerCount; + + /** + * 累计注册总人数 + */ + private Integer totalRegisterCount; + + /** + * 当天笔记数量 + */ + private Integer noteCount; + + /** + * 当天提交的笔记数量 + */ + private Integer submitNoteCount; + + /** + * 累计笔记总数量 + */ + private Integer totalNoteCount; + + /** + * 统计日期 + */ + private LocalDate date; +} + diff --git a/src/main/java/com/example/copykamanotes/model/vo/note/NoteVO.java b/src/main/java/com/example/copykamanotes/model/vo/note/NoteVO.java index d37bb18..02c5f8a 100644 --- a/src/main/java/com/example/copykamanotes/model/vo/note/NoteVO.java +++ b/src/main/java/com/example/copykamanotes/model/vo/note/NoteVO.java @@ -4,6 +4,7 @@ import lombok.Data; import java.time.LocalDateTime; + @Data public class NoteVO { private Integer noteId; diff --git a/src/main/java/com/example/copykamanotes/service/NoteLikeService.java b/src/main/java/com/example/copykamanotes/service/NoteLikeService.java index a38f780..7d3aca9 100644 --- a/src/main/java/com/example/copykamanotes/service/NoteLikeService.java +++ b/src/main/java/com/example/copykamanotes/service/NoteLikeService.java @@ -1,4 +1,8 @@ package com.example.copykamanotes.service; +import java.util.List; +import java.util.Set; + public interface NoteLikeService { + Set findUserLikedNoteIds(Long userId, List noteIds); } diff --git a/src/main/java/com/example/copykamanotes/service/NoteService.java b/src/main/java/com/example/copykamanotes/service/NoteService.java index 3d9e603..85896f4 100644 --- a/src/main/java/com/example/copykamanotes/service/NoteService.java +++ b/src/main/java/com/example/copykamanotes/service/NoteService.java @@ -1,15 +1,18 @@ package com.example.copykamanotes.service; +import com.example.copykamanotes.mapper.NoteMapper; import com.example.copykamanotes.model.base.ApiResponse; import com.example.copykamanotes.model.base.EmptyVO; import com.example.copykamanotes.model.dto.note.*; import com.example.copykamanotes.model.vo.note.CreateNoteVO; import com.example.copykamanotes.model.vo.note.DownloadNoteVO; import com.example.copykamanotes.model.vo.note.NoteVO; +import org.springframework.beans.factory.annotation.Autowired; import java.util.List; public interface NoteService { + ApiResponse> getNotes(NoteQueryParams noteQueryParams); ApiResponse createNote(CreateNoteRequest createNoteRequest); diff --git a/src/main/java/com/example/copykamanotes/service/QuestionService.java b/src/main/java/com/example/copykamanotes/service/QuestionService.java index 02ea561..32ebd27 100644 --- a/src/main/java/com/example/copykamanotes/service/QuestionService.java +++ b/src/main/java/com/example/copykamanotes/service/QuestionService.java @@ -1,4 +1,10 @@ package com.example.copykamanotes.service; +import com.example.copykamanotes.model.entity.Question; + +import java.util.List; +import java.util.Map; + public interface QuestionService { + Map getQuestionMapByIds(List questionIds); } diff --git a/src/main/java/com/example/copykamanotes/service/impl/NoteLikeServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/NoteLikeServiceImpl.java new file mode 100644 index 0000000..8e3edd5 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/service/impl/NoteLikeServiceImpl.java @@ -0,0 +1,23 @@ +package com.example.copykamanotes.service.impl; + +import com.example.copykamanotes.mapper.NoteLikeMapper; +import com.example.copykamanotes.service.NoteLikeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class NoteLikeServiceImpl implements NoteLikeService { + private final NoteLikeMapper noteLikeMapper; + + + @Override + public Set findUserLikedNoteIds(Long userId, List noteIds) { + List likedIds = noteLikeMapper.findUserLikedNoteIds(userId, noteIds); + return new HashSet<>(likedIds); + } +} diff --git a/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java index 038033d..39c7ff7 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java @@ -1,21 +1,125 @@ package com.example.copykamanotes.service.impl; +import com.example.copykamanotes.mapper.NoteMapper; import com.example.copykamanotes.model.base.ApiResponse; import com.example.copykamanotes.model.base.EmptyVO; +import com.example.copykamanotes.model.base.Pagination; import com.example.copykamanotes.model.dto.note.*; +import com.example.copykamanotes.model.entity.Note; +import com.example.copykamanotes.model.entity.Question; +import com.example.copykamanotes.model.entity.User; import com.example.copykamanotes.model.vo.note.CreateNoteVO; import com.example.copykamanotes.model.vo.note.DownloadNoteVO; import com.example.copykamanotes.model.vo.note.NoteVO; +import com.example.copykamanotes.scope.RequestScopeData; +import com.example.copykamanotes.service.NoteLikeService; import com.example.copykamanotes.service.NoteService; +import com.example.copykamanotes.service.QuestionService; +import com.example.copykamanotes.service.UserService; +import com.example.copykamanotes.utils.ApiResponseUtil; +import com.example.copykamanotes.utils.MarkdownUtil; +import com.example.copykamanotes.utils.PaginationUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; @Service public class NoteServiceImpl implements NoteService { + + @Autowired + private NoteMapper noteMapper; + + @Autowired + private UserService userService; + + @Autowired + private QuestionService questionService; + + @Autowired + private NoteLikeService noteLikeService; + + @Autowired + private RequestScopeData requestScopeData; + @Override public ApiResponse> getNotes(NoteQueryParams noteQueryParams) { - return null; + int offset = PaginationUtil.calculateOffset(noteQueryParams.getPage(), noteQueryParams.getPageSize()); + + int total = noteMapper.countNotes(noteQueryParams); + + Pagination pagination = new Pagination(noteQueryParams.getPage(), noteQueryParams.getPageSize(), total); + + List notes = noteMapper.findByQueryParam(noteQueryParams, noteQueryParams.getPageSize(), offset); + + List questionIds = notes.stream().map(Note::getQuestionId).distinct().toList(); + + List authorIds = notes.stream().map(Note::getAuthorId).distinct().toList(); + List noteIds = notes.stream().map(Note::getNoteId).toList(); + + Map userMapByIds = userService.getUserMapByIds(authorIds); + + Map questionMapByIds = questionService.getQuestionMapByIds(questionIds); + + Set userLikedNoteIds; + Set userCollectedNoteIds; + + if (requestScopeData.isLogin() && requestScopeData.getUserId() != null) { + Long currentUserId = requestScopeData.getUserId(); + userLikedNoteIds = noteLikeService.findUserLikedNoteIds(currentUserId, noteIds); + userCollectedNoteIds = noteLikeService.findUserLikedNoteIds(currentUserId, noteIds); + } else { + userLikedNoteIds = Collections.emptySet(); + userCollectedNoteIds = Collections.emptySet(); + } + + try { + List noteVOs = notes.stream().map(note -> { + NoteVO noteVO = new NoteVO(); + BeanUtils.copyProperties(note, noteVO); + + User author = userMapByIds.get(note.getAuthorId()); + + if (author != null) { + NoteVO.SimpleAuthorVO authorVO = new NoteVO.SimpleAuthorVO(); + BeanUtils.copyProperties(author, authorVO); + noteVO.setAuthor(authorVO); + } + + Question question = questionMapByIds.get(note.getQuestionId()); + if (question != null) { + NoteVO.SimpleQuestionVO questionVO = new NoteVO.SimpleQuestionVO(); + BeanUtils.copyProperties(question, questionVO); + noteVO.setQuestion(questionVO); + } + + NoteVO.UserActionsVO userActionsVO = new NoteVO.UserActionsVO(); + if (userLikedNoteIds != null && userLikedNoteIds.contains(note.getNoteId())) { + userActionsVO.setIsLiked(true); + } + if (userCollectedNoteIds != null && userCollectedNoteIds.contains(note.getNoteId())) { + userActionsVO.setIsCollected(true); + } + + if (MarkdownUtil.needCollapsed(note.getContent())) { + noteVO.setNeedCollapsed(true); + noteVO.setDisplayContent(MarkdownUtil.extractIntroduction(note.getContent())); + } else { + noteVO.setNeedCollapsed(false); + } + + noteVO.setUserActions(userActionsVO); + return noteVO; + }).toList(); + + return ApiResponseUtil.success("获取笔记列表成功", noteVOs, pagination); + } catch (Exception e) { + return ApiResponseUtil.error("获取笔记列表失败"); + } } @Override diff --git a/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java new file mode 100644 index 0000000..dbcf0ba --- /dev/null +++ b/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java @@ -0,0 +1,15 @@ +package com.example.copykamanotes.service.impl; + +import com.example.copykamanotes.model.entity.Question; +import com.example.copykamanotes.service.QuestionService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class QuestionServiceImpl implements QuestionService { + public Map getQuestionMapByIds(List questionIds) { + return null; + } +} diff --git a/src/main/java/com/example/copykamanotes/utils/MarkdownAST.java b/src/main/java/com/example/copykamanotes/utils/MarkdownAST.java new file mode 100644 index 0000000..83e52b7 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/utils/MarkdownAST.java @@ -0,0 +1,80 @@ +package com.example.copykamanotes.utils; + +import com.vladsch.flexmark.ast.Heading; +import com.vladsch.flexmark.ast.Image; +import com.vladsch.flexmark.ast.Paragraph; +import com.vladsch.flexmark.ast.Text; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.ast.Document; +import com.vladsch.flexmark.util.ast.Node; + +import java.util.ArrayList; +import java.util.List; + +public class MarkdownAST { + private final Document markdownAST; + private final String markdownText; + + public MarkdownAST( String markdownText) { + this.markdownText = markdownText; + + Parser parser = Parser.builder().build(); + this.markdownAST = parser.parse(markdownText); + } + + public String extractIntroduction(int maxChars) { + StringBuilder introText = new StringBuilder(); + + for (Node node : markdownAST.getChildren()) { + if (node instanceof Heading || node instanceof Paragraph) { + String renderedText = getNoteText(node); + + int remainingChars = maxChars - introText.length(); + introText.append(renderedText, 0, Math.min(remainingChars, renderedText.length())); + + if (introText.length() >= maxChars) { + break; + } + } + } + + return introText.toString().trim() + "..."; + } + + public List extractImages() { + List images = new ArrayList<>(); + + for (Node node : markdownAST.getChildren()) { + if (node instanceof Image imageNode) { + images.add(((Image) node).getUrl().toString()); + } + } + return images; + } + + public boolean shouldCollapse(int maxChars) { + return hasImages() || markdownText.length() > maxChars; + } + + public String getCollapseMarkdown() { + String introText = extractIntroduction(150); + return introText + "..."; + } + + private String getNoteText(Node node) { + StringBuilder text = new StringBuilder(); + + if (node instanceof Text) { + text.append(((Text) node).getChars()); + } + + for (Node child : node.getChildren()) { + text.append(getNoteText(child)); + } + return text.toString(); + } + + private boolean hasImages() { + return !extractImages().isEmpty(); + } +} diff --git a/src/main/java/com/example/copykamanotes/utils/MarkdownUtil.java b/src/main/java/com/example/copykamanotes/utils/MarkdownUtil.java new file mode 100644 index 0000000..b854242 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/utils/MarkdownUtil.java @@ -0,0 +1,13 @@ +package com.example.copykamanotes.utils; + +public class MarkdownUtil { + public static boolean needCollapsed(String markdown) { + MarkdownAST ast = new MarkdownAST(markdown); + return ast.shouldCollapse(250); + } + + public static String extractIntroduction(String markdown) { + MarkdownAST ast = new MarkdownAST(markdown); + return ast.extractIntroduction(250); + } +} diff --git a/src/main/resources/mapper/CategoryMapper.xml b/src/main/resources/mapper/CategoryMapper.xml new file mode 100644 index 0000000..89d4f1e --- /dev/null +++ b/src/main/resources/mapper/CategoryMapper.xml @@ -0,0 +1,84 @@ + + + + + + INSERT INTO category (name, parent_category_id) + VALUES (#{name}, #{parentCategoryId}) + + + + + INSERT INTO category (name, parent_category_id) + VALUES + + (#{category.name}, #{category.parentCategoryId}) + + + + SELECT 0 + + + + + + + + + + + + + DELETE + FROM category + WHERE category_id = #{categoryId} + + + + + DELETE + FROM category + WHERE category_id IN + + #{categoryId} + + + + DELETE FROM category WHERE 1 = 0 + + + + + UPDATE category + + + name = #{name}, + + + WHERE category_id = #{categoryId} + + diff --git a/src/main/resources/mapper/CollectionMapper.xml b/src/main/resources/mapper/CollectionMapper.xml new file mode 100644 index 0000000..78fa46b --- /dev/null +++ b/src/main/resources/mapper/CollectionMapper.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + INSERT INTO collection (name, description, creator_id) + VALUES (#{name}, #{description}, #{creatorId}) + + + + UPDATE collection + SET name = #{name}, + description = #{description} + WHERE collection_id = #{collectionId} + + + + DELETE + FROM collection + WHERE collection_id = #{collectionId} + + diff --git a/src/main/resources/mapper/CollectionNoteMapper.xml b/src/main/resources/mapper/CollectionNoteMapper.xml new file mode 100644 index 0000000..19f7e7d --- /dev/null +++ b/src/main/resources/mapper/CollectionNoteMapper.xml @@ -0,0 +1,55 @@ + + + + + + + + + INSERT INTO collection_note (collection_id, note_id) + VALUES (#{collectionId}, #{noteId}) + + + + DELETE + FROM collection_note + WHERE collection_id = #{collectionId} + + + + DELETE + FROM collection_note + WHERE collection_id = #{collectionId} + AND note_id = #{noteId} + + diff --git a/src/main/resources/mapper/CommentLikeMapper.xml b/src/main/resources/mapper/CommentLikeMapper.xml new file mode 100644 index 0000000..795d59a --- /dev/null +++ b/src/main/resources/mapper/CommentLikeMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + INSERT INTO comment_like ( + comment_id, user_id, created_at + ) VALUES ( + #{commentId}, #{userId}, #{createdAt} + ) + + + + + DELETE FROM comment_like + WHERE comment_id = #{commentId} AND user_id = #{userId} + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/CommentMapper.xml b/src/main/resources/mapper/CommentMapper.xml new file mode 100644 index 0000000..3f54d5c --- /dev/null +++ b/src/main/resources/mapper/CommentMapper.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + INSERT INTO comment ( + note_id, author_id, parent_id, content, + like_count, reply_count, created_at, updated_at + ) VALUES ( + #{noteId}, #{authorId}, #{parentId}, #{content}, + #{likeCount}, #{replyCount}, #{createdAt}, #{updatedAt} + ) + + + + + UPDATE comment + + content = #{content}, + like_count = #{likeCount}, + reply_count = #{replyCount}, + updated_at = CURRENT_TIMESTAMP + + WHERE comment_id = #{commentId} + + + + + DELETE FROM comment WHERE comment_id = #{commentId} + + + + + + + + + + + + + + UPDATE comment SET like_count = like_count + 1 + WHERE comment_id = #{commentId} + + + + + UPDATE comment SET like_count = like_count - 1 + WHERE comment_id = #{commentId} AND like_count > 0 + + + + + UPDATE comment SET reply_count = reply_count + 1 + WHERE comment_id = #{commentId} + + + + + UPDATE comment SET reply_count = reply_count - 1 + WHERE comment_id = #{commentId} AND reply_count > 0 + + \ No newline at end of file diff --git a/src/main/resources/mapper/MessageMapper.xml b/src/main/resources/mapper/MessageMapper.xml new file mode 100644 index 0000000..302a293 --- /dev/null +++ b/src/main/resources/mapper/MessageMapper.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + message_id, receiver_id, sender_id, type, target_id, content, is_read, created_at, updated_at + + + + INSERT INTO message ( + receiver_id, sender_id, type, target_id, content, is_read, created_at, updated_at + ) VALUES ( + #{receiverId}, #{senderId}, #{type}, #{targetId}, #{content}, #{isRead}, #{createdAt}, #{updatedAt} + ) + + + + + + + + UPDATE message + SET is_read = true, + updated_at = NOW() + WHERE message_id = #{messageId} + AND receiver_id = #{userId} + + + + UPDATE message + SET is_read = true, + updated_at = NOW() + WHERE receiver_id = #{userId} + AND is_read = false + + + + DELETE FROM message + WHERE message_id = #{messageId} + AND receiver_id = #{userId} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/NoteCollectMapper.xml b/src/main/resources/mapper/NoteCollectMapper.xml new file mode 100644 index 0000000..f07afff --- /dev/null +++ b/src/main/resources/mapper/NoteCollectMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + INSERT INTO note_collect (note_id, user_id) + VALUES (#{noteId}, #{userId}) + + + + + DELETE FROM note_collect + WHERE note_id = #{noteId} + AND user_id = #{userId} + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/NoteCommentMapper.xml b/src/main/resources/mapper/NoteCommentMapper.xml new file mode 100644 index 0000000..b458c4f --- /dev/null +++ b/src/main/resources/mapper/NoteCommentMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + id, note_id, user_id, content, created_at, updated_at, is_deleted + + + + INSERT INTO note_comment ( + note_id, user_id, content, created_at, updated_at, is_deleted + ) VALUES ( + #{noteId}, #{userId}, #{content}, #{createdAt}, #{updatedAt}, #{isDeleted} + ) + + + + UPDATE note_comment + SET updated_at = #{updatedAt}, + is_deleted = #{isDeleted} + WHERE id = #{id} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/NoteLikeMapper.xml b/src/main/resources/mapper/NoteLikeMapper.xml new file mode 100644 index 0000000..f46444f --- /dev/null +++ b/src/main/resources/mapper/NoteLikeMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + INSERT INTO note_like (user_id, note_id) + VALUES (#{userId}, #{noteId}) + + + + DELETE + FROM note_like + WHERE user_id = #{userId} + AND note_id = #{noteId} + + diff --git a/src/main/resources/mapper/NoteMapper.xml b/src/main/resources/mapper/NoteMapper.xml new file mode 100644 index 0000000..5845ad2 --- /dev/null +++ b/src/main/resources/mapper/NoteMapper.xml @@ -0,0 +1,296 @@ + + + + + + + + AND question_id = #{params.questionId} + + + AND author_id = #{params.authorId} + + + AND note_id IN (SELECT note_id FROM collection_note WHERE collection_id = #{params.collectionId}) + + + AND created_at >= DATE_SUB(CURRENT_DATE, INTERVAL #{params.recentDays} DAY) + + + + + + + + + + + + + + + + INSERT INTO note (question_id, author_id, content) + VALUES (#{questionId}, #{authorId}, #{content}) + + + + + + + + + + + + + + + + + + UPDATE note + SET content = #{content} + WHERE note_id = #{noteId} + + + + UPDATE note + SET like_count = like_count + 1 + WHERE note_id = #{noteId} + + + + UPDATE note + SET like_count = like_count - 1 + WHERE note_id = #{noteId} + + + + UPDATE note + SET collect_count = collect_count + 1 + WHERE note_id = #{noteId} + + + + UPDATE note + SET collect_count = collect_count - 1 + WHERE note_id = #{noteId} + + + + DELETE + FROM note + WHERE note_id = #{noteId} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE note + SET comment_count = comment_count + 1, + updated_at = CURRENT_TIMESTAMP + WHERE note_id = #{noteId} + + + + UPDATE note + SET comment_count = CASE + WHEN comment_count > 0 THEN comment_count - 1 + ELSE 0 + END, + updated_at = CURRENT_TIMESTAMP + WHERE note_id = #{noteId} + + + + + + + + + diff --git a/src/main/resources/mapper/QuestionListItemMapper.xml b/src/main/resources/mapper/QuestionListItemMapper.xml new file mode 100644 index 0000000..8bc284c --- /dev/null +++ b/src/main/resources/mapper/QuestionListItemMapper.xml @@ -0,0 +1,80 @@ + + + + + INSERT INTO question_list_item (question_list_id, question_id, `rank`) + VALUES (#{questionListId}, #{questionId}, #{rank}) + + + + + + + + + + + + + + + + + SELECT qli.question_list_id, + qli.rank, + q.question_id AS "question.question_id", + q.title AS "question.title", + q.view_count AS "question.view_count", + q.exam_point AS "question.exam_point", + q.difficulty AS "question.difficulty", + q.category_id AS "question.category_id" + FROM question_list_item qli + LEFT JOIN question q + ON qli.question_id = q.question_id + WHERE qli.question_list_id = #{questionListId} + ORDER BY qli.rank + + + + + + + + + + DELETE + FROM question_list_item + WHERE question_list_id = #{questionListId} + AND question_id = #{questionId} + + + + DELETE + FROM question_list_item + WHERE question_list_id = #{questionListId} + + + + + + UPDATE `question_list_item` + SET `rank` = #{rank} + WHERE `question_list_id` = #{questionListId} + AND `question_id` = #{questionId} + + + diff --git a/src/main/resources/mapper/QuestionListMapper.xml b/src/main/resources/mapper/QuestionListMapper.xml new file mode 100644 index 0000000..4078f66 --- /dev/null +++ b/src/main/resources/mapper/QuestionListMapper.xml @@ -0,0 +1,37 @@ + + + + + + INSERT INTO question_list (name, type, description) + VALUES (#{name}, #{type}, #{description}) + + + + UPDATE question_list + + + name = #{name}, + + + type = #{type}, + + + description = #{description}, + + + WHERE question_list_id = #{questionListId} + + + + DELETE FROM question_list WHERE question_list_id = #{questionListId} + + + + + + diff --git a/src/main/resources/mapper/QuestionMapper.xml b/src/main/resources/mapper/QuestionMapper.xml new file mode 100644 index 0000000..09438ea --- /dev/null +++ b/src/main/resources/mapper/QuestionMapper.xml @@ -0,0 +1,140 @@ + + + + + + INSERT INTO question (category_id, title, difficulty, exam_point) + VALUES (#{categoryId}, #{title}, #{difficulty}, #{examPoint}) + + + + + + + + + + (category_id = #{queryParam.categoryId} + OR category_id IN ( + SELECT category_id + FROM category + WHERE parent_category_id = #{queryParam.categoryId} + )) + + + + + + + + + + UPDATE question + + + title = #{question.title}, + + + difficulty = #{question.difficulty}, + + + exam_point = #{question.examPoint}, + + + WHERE question_id = #{question.questionId} + + + + UPDATE question + SET view_count = view_count + 1 + WHERE question_id = #{questionId} + + + + + + DELETE + FROM question + WHERE category_id = #{categoryId} + + + + + DELETE + FROM question + WHERE question_id = #{questionId} + + + + + DELETE + FROM question + WHERE category_id IN + + #{categoryId} + + + + DELETE FROM question WHERE 1 = 0 + + + diff --git a/src/main/resources/mapper/StatisticMapper.xml b/src/main/resources/mapper/StatisticMapper.xml new file mode 100644 index 0000000..0164470 --- /dev/null +++ b/src/main/resources/mapper/StatisticMapper.xml @@ -0,0 +1,22 @@ + + + + + INSERT INTO statistic (login_count, register_count, total_register_count, note_count, submit_note_count, + total_note_count, date) + VALUES (#{loginCount}, #{registerCount}, #{totalRegisterCount}, #{noteCount}, #{submitNoteCount}, + #{totalNoteCount}, #{date}) + + + + + +