Compare commits

...

2 Commits

Author SHA1 Message Date
439e7e1633 Merge remote-tracking branch 'origin/master' 2025-03-31 22:25:29 +08:00
LingandRX
341aadfe5a feat(model): 添加多个视图对象和 Redis 配置
- 新增 CategoryVO、CollectionVO、CommentVO 等多个视图对象
- 添加 RedisConfig 配置类
- 更新 RedisServiceImpl,移除不必要的 Qualifier 注解
- 修改 NoteMapper.xml,更新命名空间和结果映射
2025-03-31 22:25:12 +08:00
24 changed files with 470 additions and 14 deletions

View File

@ -0,0 +1,32 @@
package com.example.copykamanotes.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用 String 序列化键key
template.setKeySerializer(new StringRedisSerializer());
// 使用 JSON 序列化值value
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 使用 String 序列化哈希键hash key和值hash value
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}

View File

@ -0,0 +1,19 @@
package com.example.copykamanotes.model.vo.category;
import lombok.Data;
import java.util.List;
@Data
public class CategoryVO {
private Integer categoryId;
private String name;
private Integer parentCategoryId;
private List<ChildrenCategoryVO> children;
@Data
public static class ChildrenCategoryVO {
private Integer categoryId;
private String name;
private Integer parentCategoryId;
}
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.category;
import lombok.Data;
@Data
public class CreateCategoryVO {
private Integer categoryId;
}

View File

@ -0,0 +1,21 @@
package com.example.copykamanotes.model.vo.collection;
import lombok.Data;
@Data
public class CollectionVO {
private Integer collectionId;
private String name;
private String description;
/**
* 查询收藏夹时可能会携带的 noteId 参数这个 noteStatus 可以用来判断该 note 是否被收藏
*/
private NoteStatus noteStatus;
@Data
public static class NoteStatus {
private Integer noteId;
private Boolean isCollected;
}
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.collection;
import lombok.Data;
@Data
public class CreateCollectionVO {
private Integer collectionId;
}

View File

@ -0,0 +1,73 @@
package com.example.copykamanotes.model.vo.comment;
import com.example.copykamanotes.model.vo.user.UserActionVO;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 评论视图对象
*/
@Data
public class CommentVO {
/**
* 评论ID
*/
private Integer commentId;
/**
* 笔记ID
*/
private Integer noteId;
/**
* 评论内容
*/
private String content;
/**
* 点赞数
*/
private Integer likeCount;
/**
* 回复数
*/
private Integer replyCount;
/**
* 创建时间
*/
private LocalDateTime createdAt;
/**
* 更新时间
*/
private LocalDateTime updatedAt;
/**
* 作者信息
*/
private SimpleAuthorVO author;
/**
* 用户操作信息
*/
private UserActionVO userActions;
/**
* 回复列表
*/
private List<CommentVO> replies;
/**
* 简单作者信息
*/
@Data
public static class SimpleAuthorVO {
private Long userId;
private String username;
private String avatarUrl;
}
}

View File

@ -0,0 +1,55 @@
package com.example.copykamanotes.model.vo.message;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 消息视图对象
*/
@Data
public class MessageVO {
/**
* 消息ID
*/
private Integer messageId;
/**
* 发送者信息
*/
private SimpleUserVO sender;
/**
* 消息类型
*/
private String type;
/**
* 目标ID
*/
private Integer targetId;
/**
* 消息内容
*/
private String content;
/**
* 是否已读
*/
private Boolean isRead;
/**
* 创建时间
*/
private LocalDateTime createdAt;
/**
* 简单用户信息
*/
@Data
public static class SimpleUserVO {
private Long userId;
private String username;
private String avatarUrl;
}
}

View File

@ -0,0 +1,16 @@
package com.example.copykamanotes.model.vo.message;
import lombok.Data;
@Data
public class UnreadCountByType {
/**
* 消息类型
*/
private String type;
/**
* 未读数量
*/
private Integer count;
}

View File

@ -0,0 +1,12 @@
package com.example.copykamanotes.model.vo.note;
import lombok.Data;
import java.time.LocalDate;
@Data
public class NoteHeatMapItem {
private LocalDate date;
private Integer count;
private Integer rank;
}

View File

@ -0,0 +1,12 @@
package com.example.copykamanotes.model.vo.note;
import lombok.Data;
@Data
public class NoteRankListItem {
private Long userId;
private String username;
private String avatarUrl;
private Integer noteCount;
private Integer rank;
}

View File

@ -0,0 +1,9 @@
package com.example.copykamanotes.model.vo.note;
import lombok.Data;
@Data
public class Top3Count {
private Integer lastMonthTop3Count;
private Integer thisMonthTop3Count;
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.notification;
import lombok.Data;
@Data
public class NotificationVO {
private String content;
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.question;
import lombok.Data;
@Data
public class CreateQuestionVO {
private Integer questionId;
}

View File

@ -0,0 +1,53 @@
package com.example.copykamanotes.model.vo.question;
import lombok.Data;
@Data
public class QuestionNoteVO {
/*
* 问题ID主键
*/
private Integer questionId;
/*
* 问题标题
*/
private String title;
/*
* 问题难度
* 1=简单2=中等3=困难
*/
private Integer difficulty;
/*
* 题目考点
*/
private String examPoint;
/*
* 浏览量
*/
private Integer viewCount;
/**
* 关于这道题用户的详细信息
*/
private UserNote userNote;
@Data
public static class UserNote {
/*
* 是否完成
*/
private boolean finished = false;
/**
* noteId
*/
private Integer noteId;
/**
* 笔记内容
*/
private String content;
}
}

View File

@ -0,0 +1,43 @@
package com.example.copykamanotes.model.vo.question;
import lombok.Data;
// 用于普通用户查询携带个人信息的问题 VO
@Data
public class QuestionUserVO {
/*
* 问题ID主键
*/
private Integer questionId;
/*
* 问题标题
*/
private String title;
/*
* 问题难度
* 1=简单2=中等3=困难
*/
private Integer difficulty;
/*
* 题目考点
*/
private String examPoint;
/*
* 浏览量
*/
private Integer viewCount;
/**
* 用户问题状态
*/
private UserQuestionStatus userQuestionStatus;
@Data
public static class UserQuestionStatus {
private boolean finished = false; // 用户是否完成过这道题
}
}

View File

@ -0,0 +1,18 @@
package com.example.copykamanotes.model.vo.question;
import lombok.Data;
import java.time.LocalDateTime;
// 用于管理员批量查询题目
@Data
public class QuestionVO {
private Integer questionId;
private Integer categoryId;
private String title;
private Integer difficulty;
private String examPoint;
private Integer viewCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

View File

@ -0,0 +1,9 @@
package com.example.copykamanotes.model.vo.question;
import lombok.Data;
@Data
public class SimpleQuestionVO {
private Integer questionId;
private String title;
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.questionList;
import lombok.Data;
@Data
public class CreateQuestionListVO {
private Integer questionListId;
}

View File

@ -0,0 +1,5 @@
package com.example.copykamanotes.model.vo.questionList;
public class QuestionListVO {
}

View File

@ -0,0 +1,8 @@
package com.example.copykamanotes.model.vo.questionListItem;
import lombok.Data;
@Data
public class CreateQuestionListItemVO {
private Integer rank;
}

View File

@ -0,0 +1,32 @@
package com.example.copykamanotes.model.vo.questionListItem;
import com.example.copykamanotes.model.vo.question.BaseQuestionVO;
import lombok.Data;
@Data
public class QuestionListItemUserVO {
/**
* 题单ID联合主键
*/
private Integer questionListId;
/**
* 题目ID联合主键
*/
private BaseQuestionVO question;
/**
* 用户是否完成了这道题
*/
private UserQuestionStatus userQuestionStatus;
/*
* 题单内题目的顺序从1开始
*/
private Integer rank;
@Data
public static class UserQuestionStatus {
private boolean finished;
}
}

View File

@ -2,7 +2,6 @@ package com.example.copykamanotes.service.impl;
import com.example.copykamanotes.service.RedisService; import com.example.copykamanotes.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@ -7,8 +7,8 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
server.port= 19090 server.port= 19090
# Redis?? # Redis
spring.data.redis.host=127.0.0.1 spring.data.redis.host=localhost
spring.data.redis.port=6379 spring.data.redis.port=6379
spring.data.redis.database=0 spring.data.redis.database=0
spring.data.redis.timeout=3000 spring.data.redis.timeout=3000

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?> <?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"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kama.notes.mapper.NoteMapper"> <mapper namespace="com.example.copykamanotes.mapper.NoteMapper">
<sql id="whereClause"> <sql id="whereClause">
<where> <where>
@ -24,7 +24,7 @@
<include refid="whereClause"/> <include refid="whereClause"/>
</select> </select>
<select id="findByQueryParams" resultType="com.kama.notes.model.entity.Note"> <select id="findByQueryParams" resultType="com.example.copykamanotes.model.entity.Note">
SELECT * FROM note SELECT * FROM note
<include refid="whereClause"/> <include refid="whereClause"/>
<choose> <choose>
@ -58,14 +58,14 @@
</if> </if>
</select> </select>
<select id="findByAuthorIdAndQuestionId" resultType="com.kama.notes.model.entity.Note"> <select id="findByAuthorIdAndQuestionId" resultType="com.example.copykamanotes.model.entity.Note">
SELECT * SELECT *
FROM note FROM note
WHERE question_id = #{questionId} WHERE question_id = #{questionId}
AND author_id = #{authorId} AND author_id = #{authorId}
</select> </select>
<select id="findByAuthorId" resultType="com.kama.notes.model.entity.Note"> <select id="findByAuthorId" resultType="com.example.copykamanotes.model.entity.Note">
SELECT * SELECT *
FROM note FROM note
WHERE author_id = #{authorId} WHERE author_id = #{authorId}
@ -76,7 +76,7 @@
VALUES (#{questionId}, #{authorId}, #{content}) VALUES (#{questionId}, #{authorId}, #{content})
</insert> </insert>
<resultMap id="BaseResultMap" type="com.kama.notes.model.entity.Note"> <resultMap id="BaseResultMap" type="com.example.copykamanotes.model.entity.Note">
<id column="note_id" property="noteId"/> <id column="note_id" property="noteId"/>
<result column="author_id" property="authorId"/> <result column="author_id" property="authorId"/>
<result column="question_id" property="questionId"/> <result column="question_id" property="questionId"/>
@ -128,13 +128,13 @@
WHERE note_id = #{noteId} WHERE note_id = #{noteId}
</delete> </delete>
<select id="findCollections" resultType="com.kama.notes.model.entity.Collection"> <select id="findCollections" resultType="com.example.copykamanotes.model.entity.Collection">
SELECT * SELECT *
FROM collection FROM collection
WHERE collection_id = #{collectionId} WHERE collection_id = #{collectionId}
</select> </select>
<resultMap id="NoteRankListItemMap" type="com.kama.notes.model.vo.note.NoteRankListItem"> <resultMap id="NoteRankListItemMap" type="com.example.copykamanotes.model.vo.note.NoteRankListItem">
<result property="userId" column="author_id"/> <result property="userId" column="author_id"/>
<result property="username" column="username"/> <result property="username" column="username"/>
<result property="avatarUrl" column="avatar_url"/> <result property="avatarUrl" column="avatar_url"/>
@ -155,7 +155,7 @@
ORDER BY author_notes_count DESC LIMIT 10 ORDER BY author_notes_count DESC LIMIT 10
</select> </select>
<resultMap id="submitNoteHeatMapMap" type="com.kama.notes.model.vo.note.NoteHeatMapItem"> <resultMap id="submitNoteHeatMapMap" type="com.example.copykamanotes.model.vo.note.NoteHeatMapItem">
<result property="count" column="note_count"/> <result property="count" column="note_count"/>
<result property="date" column="note_date"/> <result property="date" column="note_date"/>
<result property="rank" column="note_rank"/> <result property="rank" column="note_rank"/>
@ -185,7 +185,7 @@
WHERE author_id = #{authorId}; WHERE author_id = #{authorId};
</select> </select>
<resultMap id="submitNoteTop3CountMap" type="com.kama.notes.model.vo.note.Top3Count"> <resultMap id="submitNoteTop3CountMap" type="com.example.copykamanotes.model.vo.note.Top3Count">
<result property="thisMonthTop3Count" column="this_month_top_3"/> <result property="thisMonthTop3Count" column="this_month_top_3"/>
<result property="lastMonthTop3Count" column="last_month_top_3"/> <result property="lastMonthTop3Count" column="last_month_top_3"/>
</resultMap> </resultMap>
@ -268,7 +268,7 @@
</update> </update>
<!-- 搜索笔记 --> <!-- 搜索笔记 -->
<select id="searchNotes" resultType="com.kama.notes.model.entity.Note"> <select id="searchNotes" resultType="com.example.copykamanotes.model.entity.Note">
SELECT SELECT
n.*, n.*,
MATCH(n.search_vector) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) as relevance MATCH(n.search_vector) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) as relevance
@ -279,7 +279,7 @@
</select> </select>
<!-- 根据标签搜索笔记 --> <!-- 根据标签搜索笔记 -->
<select id="searchNotesByTag" resultType="com.kama.notes.model.entity.Note"> <select id="searchNotesByTag" resultType="com.example.copykamanotes.model.entity.Note">
SELECT DISTINCT SELECT DISTINCT
n.*, n.*,
MATCH(n.search_vector) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) as relevance MATCH(n.search_vector) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) as relevance