数据库表
用户表 user
字段 | 类型 | 备注 |
---|---|---|
id | int | 主键、自增 |
username | varchar | 用户名,创建索引 |
password | varchar | 用户密码 |
salt | varchar | 加密盐值 |
varchar | 用户邮箱,创建索引 | |
type | int | 用户类型:0 普通、1 管理员、2 版主 |
status | int | 用户状态:0 未激活、1 已激活 |
activation_code | varchar | 激活码 |
header_url | varchar | 用户头像地址 |
create_time | timestamp | 注册时间 |
评论表 comment
字段 | 类型 | 备注 |
---|---|---|
id | int | 主键、自增 |
user_id | int | 评论的用户 id,创建索引 |
entity_id | int | 评论实体 id,创建索引 |
entity_type | int | 评论实体类型:1 帖子评论、2 评论回复 |
target_id | int | 评论目标 id |
content | text | 评论内容 |
status | int | 评论状态:0 有效、1 无效 |
create_time | timestamp | 评论发表时间 |
帖子表 discuss_post
字段 | 类型 | 备注 |
---|---|---|
id | int | 主键、自增 |
user_id | int | 发帖的用户 id,创建索引 |
title | varchar | 帖子表标题 |
content | text | 帖子内容 |
type | int | 帖子类型:0 普通、1 置顶 |
comment_count | int | 评论数量 |
status | int | 帖子状态:0 普通、1 精华、2 拉黑 |
create_time | timestamp | 评论发表时间 |
用户登录凭证表 login_ticket
字段 | 类型 | 备注 |
---|---|---|
id | int | 主键、自增 |
user_id | int | 登录用户 id |
ticket | varchar | 登录凭证,随机字符串 |
status | int | 登录状态:0 有效、1 无效 |
expired | timestamp | 过期时间 |
消息表 message
字段 | 类型 | 备注 |
---|---|---|
id | int | 主键、自增 |
from_id | int | 发消息的 id,创建索引 |
to_id | int | 收消息的 id,创建索引 |
conversation_id | varchar | 会话 id,由通信双方 id 拼接,创建索引 |
content | text | 消息内容 |
status | int | 消息状态:0 未读、1 已读、2 删除 |
create_time | timestamp | 消息发送时间 |
开发社区首页
搭建基本环境
构建 SpringBoot 的 maven 项目,引入 mysql 和 mybatis 依赖。
在 application.properties
配置文件中:
- 关闭 thymeleaf 缓存
- 配置数据库,设置基本连接信息、最大线程数,最小空闲线程数,最大空闲时间等
- mybatis,设置 mapper 文件的位置、实体类包名、使用主键等
创建 community 数据库和数据库表。
用户相关操作:
- 创建对应 user 表的 User 实体类
- 创建 UserMapper 接口,使用
@Mapper
注解 - 创建 user-mapper.xml,重复 sql 语句可以写在
<sql id = "xxx">
标签,通过<include refid="xxx"/>
引用。
开发社区首页(discuss_post 表)
功能拆分:开发社区首页,显示前 10 个帖子。开发分页组件,分页显示所有帖子。
用到的表是 discuss_post 数据库表,包括帖子 id、发帖人 id、标题、内容、类型、状态、发帖时间、评论数量(为了提高效率,避免关联查询,因此冗余存储)、分数(用于进行热度排名)。
开发数据层
帖子相关操作:
创建对应 discuss_post 表的 DisscussPost 实体类。
创建 DisscussPostMapper 接口,使用
@Mapper
注解。- 分页查询中用户 id 是可选参数,通过动态 SQL 选择,如果为 0 就不使用,在开发用户个人主页查询用户发帖记录时需要使用。
- 如果只有一个参数,并且在动态 SQL 的
<if>
里使用,必须使用@Param
加别名。
创建
disscusspost-mapper.xml
。where status != 2
拉黑的帖子不展现。<if test="userId!=0">
userID 为 0 时不使用,按照类型,发帖时间排序。
开发业务层
创建 DiscussPostService 类,可以分页查询帖子和帖子数量。
创建 UserService 类,实现根据 id 查询用户功能,因为显示帖子时不显示用户 id,而是显示用户名。
开发视图层
把静态资源 css、html、img、js 放到 static 目录下。
把模板 mail、site、index.html 放到 template 目录下。
创建 HomeController,getIndexPage
方法,用 map 集合把帖子和用户封装到一起。
修改 index.html
,使用 <th:text="${map.xxx.xxx}"
动态替换。
【问题】使用帖子关联查询用户时,给查询用户的 findUserById
方法传入了帖子的 getId
方法,应该是 getUserId
方法。
开发分页组件
创建 Page 实体类,封装分页信息,包括当前页码、显示限制、帖子总数、查询路径等。显示的起始页不能小于 1,最大页不能超过 total。
在 index.html
中,当 page.rows > 0
时显示分页信息。
如果 page.current
等于 1 或 page.total
,代表是首页或末页,此时不能点击上一页和下一页,用 disabled
属性实现。
开发注册登录模块
发送邮件
在新浪邮箱打开 SMTP 服务。
引入 spring-boot-starter-mail
依赖。
在配置文件配置主机、端口、发送邮箱、授权码等。
创建 MailClient 类,调用 JavaMailSender 发送邮件。
使用 thymeleaf 发送 HTML 邮件,调用 TemplateEngine 把信息封装到 HTML 模板。
【问题】发送邮件成功但没接收到,在垃圾箱中可找到。
注册功能
把 register.html 地址关联到首页的注册 href 属性。
设置域名、创建 CommunityUtil 工具类,在工具类创建生产随机字符串和 MD5 加密方法。
创建 LoginController,创建 getRegisterPage
方法,跳转注册页面。
在 UserService 中创建 register
方法,判断注册信息合规后插入数据库,发送激活邮件。
在 LoginController 创建 register
方法,调用 UserService 的 register
方法。
创建接口 CommunityConstant,定义激活码的三种状态,成功、重复、失败,让 UserService 和 LoginController 实现该接口。
点击激活邮件的 url 【本地服务器的url】后,服务器通过 LoginController 的 activation
方法查询数据库用户,如果 url 中的激活码和设置的一样,就把用户 status 改为 1。
生成验证码
在 pom.xml
导入 kaptcha 的 jar 包。
创建配置类 KaptchaConfig,设置验证码的大小、范围、长度等。
在 LoginController 类新增 getKaptcha
方法生成验证码图片。
在 login.html
中,将刷新验证码的链接绑定 refresh_kaptcha
方法,通过 id 选择器获取 img 组件,重新访问 getKaptcha
方法生成验证码图片。
【问题】由于访问同一个生成验证码路径,需要在 url 参数加上一个随机数字,保证会重新请求获取新图片。
登录退出功能(login_ticket 表)
登录成功时,需要生成一个登录凭证发送给客户端。凭证可以在多个业务中连续地验证用户的登陆状态,凭证信息存储在 login_ticket 数据库表中,status 的 0 和 1 表示有效和无序,expire 表示过期时间。
创建对应 login_ticket 表的 LoginTicket 实体类,对应 login_ticket 数据库表。
创建 LoginTicketMapper 接口,通过 @Insert
、@Select
、@Update
注解来插入、查询、更新凭证。
在 UserServce
创建
login
方法,验证账户合规后将凭证信息插入数据库,添加登录凭证到 map 中。创建
logout
方法,将对应凭证设为无效。
在 LoginController
创建
login
方法,判断验证码正确后调用 UserServce 的login
方法,如果 map 包含 ticket 代表登录成功,重定向跳转首页,否则添加错误信息并跳回登录页。创建
logout
方法,判断验证码正确后调用 UserServce 的logout
方法,跳转至登录页。
在 login.html
绑定登录链接,index.html
绑定退出登录链接。
【问题】登录成功后,创建了凭证,但忘记将凭证信息插入数据库。
显示登录信息
创建 CookieUtil 工具类,通过 name 查询对应 cookie 的 value。
在 UserService 中新增 findLoginTicket
方法,根据 ticket 查询 LoginTicket。
创建 HostHolder 类用来模拟 session 的功能,利用 ThreadLocal 实现,存储用户信息。
创建 LoginTicketInterceptor 拦截器,实现 HandlerInterceptor 接口。
- 在
preHandle
方法中通过 CookieUtil 的getValue
方法查询是否有凭证 cookie,如果有则通过 UserService 的findloginTicket
方法查询用户 ID,再通过用户 ID 查询用户。最后将用户放入 hostHolder 中。 - 在
postHandle
方法中通过 hostHolder 的get
方法获取用户,并将其存入视图中。 - 在
afterCompletion
方法中清除 hostHolder 中存放的用户信息。
创建 WebMvcConfig 配置类,实现 WebMvcConfigurer接口,配置 LoginTicketInterceptor,拦截除了静态资源之外的所有路径。
上传头像
在 UserService 新增 updateHeader
方法,更改指定用户的头像。
创建 UserController
新增
getSettingPage
方法访问账户设置setting.html
,并在index.html
的账号设置按钮关联该链接。新增
uploadHeader
方法更新用户头像,如果上传出现错误将错误信息存在 Model 对象中。如果没有错误,生成一个文件对象 dest,利用 MultipartFile 接口的
transferTo
方法将用户上传文件导入 dest,并从 hostHolder 中取出用户,更新用户的头像路径。新增
getHeader
方法获取用户头像,利用文件输入流读取图片数据,利用 HttpServletResponse 的字节输出流再进行输出。
调整 setting.html
的 form 表单, method="post",enctype="multipart/form-data",并设置提交路径。
修改密码
在 UserService 中新增 changePassword
方法,判断原密码是否正确,正确则修改密码并返回 1,否则返回 0。
在 UserController 中新增 changePassword
方法,根据 UserService 的 changePassword
方法的返回值判断原密码是否成功修改,封装为 JSON 数据并返回。
在 setting.html
中
- 首先在前端判断两次输入的新密码是否一致,如果不一致不允许点击提交并显示错误信息。
- 利用 ajax 向 UserController 的
changePassword
方法发送 POST 请求,得到 JSON 数据并解析,如果状态码为 0 提示错误,如果状态码为 1 弹出修改成功提示。
【问题】js 的虚拟路径问题,需要加上 ../
。
【问题】使用 ajax 请求时,表单按钮类型必须是 button,不能是 submit,否则 405 报错。
【问题】使用 ajax 请求时,Controller 中方法的返回值必须是 JSON 数据,并且需要加上 @ResponseBody
。
【问题】使用 ajax 请求时,回调函数需要先对返回的 JSON 数据进行解析再使用。
检查登录状态
利用拦截器,实现只处理带有自定义注解的方法,防止用户在未登录情况下通过 url 访问没有权限的页面。
创建 @LoginRequired
自定义注解,作用范围在方法上,有效期为运行时。
在 UserController 中需要在登录状态下调用的方法,访问设置页面、修改密码、上传头像等加上自定义注解。
创建 LoginRequiredInterceptor 拦截器,在 preHandle
方法中判断方法是否加了 @LoginRequired
注解,如果加了注解并且此时从 hostHolder 中获取不到用户则拒绝访问。
在 WebMvcConfig 配置类配置 LoginRequiredInterceptor,拦截除了静态资源之外的所有路径。
开发核心功能
敏感词过滤
利用字典树数据结构解决。
创建 SensitiveFilter 类
- 创建静态内部类 TrieNode ,通过 boolean 类型的结束符判断是否匹配到关键字尾部。
- 利用
@PostConstruct
注解,在构造方法执行后初始化字典树。 - 添加
filter
方法,利用双指针进行匹配,过滤敏感词。
【问题】判断子节点空时,直接添加了一个 new 的子节点,没有将对象赋值给子节点变量。
发布帖子
引入 fastjson 依赖,在 CommunityUtil 中新增 getJSONString
方法封装 JSON 信息。
在 DisscussPostMapper 接口新增 insertDiscussPost
方法,并在 disscusspost-mapper.xml
配置 insert 语句。
在 DiscussPostService 新增 addDiscussPost
方法调用 DisscussPostMapper 的 insertDiscussPost
方法,其中需要进行对标题内容和发帖内容进行 HTML 转义以及过滤敏感词。
创建 DiscussPostController 类,新增 addDiscussPost
方法,调用 DiscussPostService 的 addDiscussPost
方法发帖。
在 index.html
中为发帖按钮绑定函数,利用 Ajax 向 DiscussPostController 的 addDiscussPost
方法发送 POST 请求。
显示帖子内容
在 DisscussPostMapper 接口新增 selectDiscussPostById
方法,在 disscusspost-mapper.xml
配置 select 语句。
在 DiscussPostService 新增 findDiscussPostById
方法调用 DisscussPostMapper 的 selectDiscussPostById
方法。
在 DiscussPostController 新增 getDiscussPost
方法,调用 DiscussPostService 的 findDiscussPostById
方法查询帖子内容,将 DiscussPost 对象和 User 对象(通过 userId 查询,不在 DAO 层关联查询)数据存放到 Model 对象,返回模板 discuss-detail
。
在 discuss-detail.html
取出 Model 对象存放的数据绑定到对应组件显示。
显示评论(comment 表)
创建 comment 表对应的实体类 Comment。
创建 CommentMapper 接口
- 新增
selectCommentsByEntity
方法,根据实体查询一页的评论数据。 - 新增
selectCountByEntity
方法,根据实体查询评论的数量。 - 在
comment-mapper.xml
配置 select 语句。
创建 CommentService 类
- 新增
findCommentByEntity
方法,调用 CommentMapper 的selectCommentByEntity
方法。 - 新增
findCommentCount
方法,调用 CommentMapper 的selectCountByEntity
方法。
在 DiscussPostController 的 getDiscussPost
方法中增加查询帖子评论和回复的逻辑,将结果存储在 Model 对象。
【问题】sql 的 xml 文件中绑定参数时,应传入实体类属性名,拼错成数据库字段名(entityId 写成 entity_id)。
添加评论
在 CommentMapper 接口新增 insertComment
方法,添加评论数据,在 comment-mapper
配置对应 sql。
在 DiscussPostMapper 接口新增 updateCommentCount
方法,增加评论数量,在 discusspost-mapper
配置对应 sql。
在 DiscussPostService 类新增 updateCommentCount
方法,调用 DiscussPostMapper 的 updateCommentCount
方法。
在 CommentService 类新增 addComment
方法,调用 CommentMapper 的 insertComment
新增评论,并调用 DiscussPostService 的 updateCommentCount
更新评论数量,使用 @Transactional
注解保证事务。
创建 CommentController 类,新增 addComment
方法,从 hostHolder 获取用户信息,然后调用 CommentService 的 addComment
方法添加评论。
【问题】sql 的 xml 文件中绑定参数时,应传入实体类属性名,拼错成数据库字段名(entityId 写成 entity_id)。
显示私信列表 (message 表)
创建对应 message 表的实体类 Message。
创建 MessageMapper 接口,增加查询会话列表、会话数量、私信列表、私信数量、未读私信数量等方法,在 message-mapper.xml
中配置对应的 sql。
创建 MessageService,调用 MessageMapper 中的方法。
创建 MessgaeController
- 新增
getLetterList
方法,将会话列表信息存储到 Model 对象,返回letter
视图。 - 新增
getLetterDetail
方法,将每个会话具体的私信信息存储到 Model 对象,返回letter-datail
视图。
发送私信
在 MessageMapper
- 新增
insertMessage
方法插入私信记录,在message-mapper.xml
配置 insert 语句。 - 新增
updateMessgae
方法修改私信状态,在message-mapper.xml
配置 update 语句,利用 foreach 动态 sql。
在 MessageService
新增
addMessage
发送私信方法,过滤敏感词后,调用 MessageMapper 的insertMessage
。新增
readMessage
方法读取信息,调用MessageMapper 的updateMessgae
更新私信的状态为 1。
在 MessageController
新增
getLetterIds
方法,将私信集合中未读私信的 id 添加到 List 集合并返回,在getLetterDetail
方法调用该方法设置已读。新增
sendLetter
发送私信方法,设置私信信息后调用 MessageService 的addMessage
发送。
统一异常处理
在 HomeController 中增加 getErrorPage
方法,返回错误页面。
创建 ExceptionAdvice 类
- 加上
@ControllerAdvice
注解,表示该类是 Controller 的全局配置类。 - 创建
handleException
方法,加上@ExceptionHandler
注解,该方法在 Controller 出现异常后调用,处理捕获异常。如果是异步请求返回一个 JSON 数据,否则重定向至 HomeController 的getErrorPage
方法。
统一日志处理
在 pom.xml
引入 aspectj 的依赖。
创建 ServiceLogAspect 类,添加 @Aspect
切面注解,配置切入点表达式,拦截所有 service 包下的方法,利用 @Before
记录日志。
Redis
点赞
创建 RedisKeyUtil 工具类
- 定义分隔符
:
以及实体获得赞的 key 前缀常量like:entity
。 - 新增
getEntityLikeKey(int entityType,int entityId)
方法,通过实体类型和实体 id 生成对应实体获得赞的 key。
创建业务层的 LikeService 类
注入 RedisTemplate 实例。
新增
like
点赞方法,首先通过 RedisKeyUtil 工具类的getEntityLikeKey
方法获得实体点赞的 key,然后通过 RedisTemplate 对象对 set 集合的isMember
方法查询 userId 是否存在于对应 key 的 set 集合中,如果存在则移除出点赞的用户集合,如果不存在则添加到点赞的用户集合。新增
findEntityLikeCount
方法查询实体的点赞数量,通过调用 set 集合的size
方法查询元素个数。新增
findEntityLikeStatus
方法查询某用户对某实体的点赞状态,逻辑如like
方法,通过 set 集合的isMember
方法实现。
创建表现层的 LikeController 类
- 注入 LikeService 和 HostHolder 实例。
- 新增
like
点赞方法,调用业务层的like
方法进行点赞、调用findEntityLikeCount
和findEntityLikeStatus
查询点赞数量和点赞状态,封装到 map 集合,然后通过工具类封装成 JSON 数据返回。
(更新首页帖子点赞数量)在表现层的 HomeController 类
- 注入 LikeService 实例。
- 在
getIndexPage
方法在通过 LikeService 类的方法获得点赞数量,存储到 map 集合。
收到的赞
对点赞功能进行重构
在 RedisUnitl 工具类
新增用户获得赞 key 的前缀常量
like:user
新增
getUserLikeKey(int userId)
方法,通过用户 id 生成对应用户获得赞的 key。
在 LikeService 中
重构
like
方法,在参数列表中加入 entityUserId 表示被点赞用户的 id,用来更新用户的被点赞数量。通过 RedisTemplate 对象的
execute
方法实现事务,保证被点赞用户点和点赞用户的数据更新一致。通过isMember
方法查询用户的点赞状态,之后通过mutli
方法开启事务。当用户已点赞时,调用
remove
方法将当前用户从点赞用户的集合中移除,调用decrement
方法将被点赞用户的被点赞数减 1;当用户未点赞时,调用add
方法将当前用户添加到点赞用户的集合,调用increment
方法将被点赞用户的被点赞数加 1。
增加
findUserLikeCount
方法,以用户 id 作为 key,调用get
方法查询用户所获得的点赞数。
在 LikeController 中给 like
方法增加 entityUserId 参数即可。
关注
在 RedisUnitl 工具类
新增用户关注实体(帖子、评论、用户等)和粉丝(用户)的前缀常量
followee
和follower
新增
getFolloweeKey(int userId, int entityType)
方法,通过用户 id 和实体类型生成用户关注实体的 key。新增
getFollowerKey(int entityType, int entityId)
方法,通过实体类型和实体 id 生成实体用户粉丝的 key。
创建业务层的 FollowService 类
- 新增
follow
方法,当用户关注某实体时,- 调用
add
方法将当前实体 id 和时间作为 value 和 score加入用户的关注集合。 - 调用
add
方法将当前用户 id 和时间作为 value 和 score 加入实体的粉丝集合。
- 调用
- 新增
unfollow
方法,当用户取消关注某实体时,- 调用
remove
方法将当前实体从用户的关注集合移除。 - 调用
remove
方法将用户从实体的粉丝集合移除。
- 调用
个人主页
在业务层的 FollowService 类
- 新增
findFolloweeCount
方法,调用 zset 的zcard
方法查询某用户关注的实体数量。 - 新增
findFollowerCount
方法,调用 zset 的zcard
方法查询某实体的粉丝数量。 - 新增
hasFollowed
方法,根据 zset 的zscore
方法返回值查询当前用户是否关注某实体。
在 UserController 中新增 getProfilePage
方法获取个人主页。
- 调用 LikeService 的
findUserLikeCount
查询用户获赞数,并添加到 Model 中。 - 调用 FollowService 的
findFolloweeCount
、findFollowerCount
、hasFollowed
方法分别查询关注数量、粉丝数量、用户是否关注三项信息并添加到 Model 对象中存储。
关注列表和粉丝列表
在业务层的 FollowService 类
- 新增
findFollowees
方法,查询用户关注列表,主要通过 zset 的reverseRange
获取 value 即关注用户的 userId,再查询出其 user,之后通过score
获取关注时间,存入 map 集合,将 map 添加到 list 列表返回。 - 新增
findFollowers
方法,查询用户粉丝列表,主要通过 zset 的reverseRange
获取 value 即粉丝的 userId,再查询出其 user,之后通过score
获取关注时间,存入 map 集合,将 map 添加到 list 列表返回。
在表现层的 FollowController 类
- 新增
getFollowees
方法,获取关注列表,存入 Model 对象。 - 新增
getFollowers
方法,获取粉丝列表,存入 Model 对象。
优化登录模块
存储验证码
在 RedisUntil 工具类
- 新增验证码前缀常量
kaptcha
- 新增
getKaptchaKey
方法,通过一个用户凭证(由于未登录,利用 cookie 实现)获得对应验证码的 key 值(利用 string 存储验证码)。
在表现层的 LoginController 类
- 重构
getKaptcha
方法,将验证码存入 redis,key 值是当前随机生成的一个字符串,同时将该字符串存入 cookie。 - 重构
login
方法,从 cookie 中获得随机字符串,生成验证码的 key 值,然后获取对应的 value 值即验证码。
存储登录凭证
在 RedisUntil 工具类
- 新增登录凭证前缀常量
ticket
- 新增
getTicketKey
方法,通过字符串获得登录凭证的对应 key 值(利用 string 存储)。
在业务层的 UserService 类
- 重构
login
方法,将登录凭证存入 redis 中。 - 重构
logout
方法,先从 redis 中获取登录凭证对象,将状态设为无效再重新存储进 redis。 - 重构
findLoginTicket
方法,根据 ticket 字符串获得对应登录凭证的 key,然后从 redis 查询登录凭证。
缓存用户信息
在 RedisUntil 工具类
- 新增用户前缀常量
user
- 新增
getUserKey
方法,通过用户 id 获得用户的对应 key 值(利用 string 存储)。
在业务层的 UserService 类
新增
getCache
,从缓存获取用户信息。新增
initCache
,从 MySQL 查询用户信息并存入 redis。新增
clearCache
,用户信息变更(更新头像,激活)时清除缓存。重构
findUserById
方法,首先调用getCache
从缓存获取用户信息,如果获取为 null 则调用initCache
。
Kafka
发送系统通知
在 CommunityConstant 接口中新增三个常量,代表三个主题:评论、点赞、关注。
创建 Event 类,封装事件对象,包括主题、用户 id、实体类型、实体 id、实体用户 id 以及一个 map 集合存放其它信息。
触发事件
创建 EventProducer 事件生产者,新增 fireEvent(Event event)
方法,通过 Event 获取事件类型,并将其封装成 JSON 数据,然后调用注入的 KafkaTemplate 实例的 send 方法发送。
在 CommentController、LikeControler、FollowController 中注入 EventProducer 实例,分别重构 addComment
方法、like
方法、follow
方法,封装 Event 对象,然后调用 EventProducer 的fireEvent
方法发布通知。
消费事件
创建 EventConsumer 事件消费者,消费者是被动触发的。
- 注入 MessageService 实例。
- 增加
handleCommentMessage(ConsumerRecord record)
方法,通过@KafkaListener
注解,topic 包括了评论、点赞和关注。从 recored 中获取信息,封装成 Message 对象然后调用addMessage
方法插入数据库。
【问题】没有向数据库插入系统通知记录,原因是 ServiceLogAspect 类进行日志处理时要获取 ServletRequestAttributes 请求对象,Kafka 的消费事件是自动触发的,没有进行新的请求,产生了请求对象的空指针异常。
显示系统通知
通知列表
在 MessageMapper 接口中
新增
selectLatestNotice(int userId, String topic)
方法,查询某主题最新的通知。新增
selectNoticeCount(int userId, String topic)
方法,查询某主题通知的数量。新增
selectNoticeUnreadCount(int userId, String topic)
方法,查询未读通知的数量。在
message-mapper.xml
配置三个方法的 sql 语句,其中查询未读通知时使用 if 动态语句,如果没有传入 topic 就查询未读总量。
在业务层的 MessageService 中
- 新增
findLatestNotice
方法,调用selectLatestNotice
方法查询最新通知。 - 新增
findNoticeCount
方法,调用selectNoticeCount
方法查询某主题通知的数量。 - 新增
findNoticeUnreadCount
方法,调用selectNoticeUnreadCount
方法查询未读通知的数量。
在表现层的 MessageController 中新增 getNoticeList
方法,获取通知列表
- 调用业务层 MessageService 的方法查询评论、点赞、关注的通知,将其封装在一个 HashMap 集合中然后添加到 Model 对象里。
- 调用业务层 MessageService 的方法查询私信和通知的总未读数量,添加到 Model 对象里。
- 返回
notice.html
页面。
显示通知详情
在 MessageMapper 接口新增 selectNotices
方法,查询某个主题的通知列表,在 message-mapper.xml
配置 SQL。
在业务层的 MessageService 中新增 findNotices
方法,调用 selectNotices
方法。
在表现层的 MessageController 中新增 getNoticeDetail
方法
- 调用
findNotices
方法获取通知列表详情,封装到 List 集合并存入 Model 对象。 - 从通知集合中获取 id 集合,调用
readMessage
方法将消息设为已读。 - 返回
notice-detail.html
页面。
显示未读通知总数
创建 MessageInterceptor 拦截器
- 注入 MessageService 实例和 HostHolder 实例。
- 重写
postHandle
方法,查询私信和通知的未读数量和,然后添加到 ModelAndView 对象。
在 WebConfig 中注入 MessageInterceptor 实例,并在 addInterceptors
方法中添加该拦截器。
全部评论
(12) 回帖