牛客网项目总结

牛客网项目总结

数据库

用户表,包括 id、用户名、密码、盐值、邮箱、类型(普通/管理员/版主)、状态(激活/未激活)、激活码(随机字符串)、头像 url、注册时间。

登录凭证表,包括 id、用户 id、登陆凭证(随机字符串)、登录状态(有效/无效)、过期时间。

评论表,包括 id、评论用户 id(索引)、评论实体 id(索引)、评论类型(帖子/回复)、被评论目标 id、评论内容、评论状态(有效/无效)、评论时间。

帖子表,包括 id、发帖用户 id(索引)、标题、帖子内容、类型(普通/置顶)、评论数量、状态(普通/精华/拉黑)、发帖时间。

消息表,包括 id、发消息 id(索引)、收消息 id(索引)、会话 id(由发消息双方 id 拼接,索引)、内容、状态(未读/已读/删除)、发消息时间。


注册

判断注册合法性

  • 利用 StringUtils 判断用户名、密码、邮箱是否非空。
  • 分别通过用户名和邮箱查询是否已经注册(为数据库的用户名和邮箱字段添加索引)。

通过 set 方法为用户设置各项信息,包括 MD5 加密后的密码、激活码等,然后插入数据库。

给用户发送激活邮件

  • 在新浪邮箱打开 SMTP 服务,引入 spring-boot-starter-mail 依赖。
  • 在配置文件配置主机(smtp.sina.com)、端口(465)、邮箱、授权码、协议(smtps),设置 smtp.ssl.enable = true。
  • 调用 JavaMailSender 的 API 发送邮件,激活 url 由用户 id 和用户的激活码拼接而成。点击激活 url 后由 controller 中的方法进行处理(成功/重复/失败),调用 Model 对象的 addAttribute 方法将结果返回前端。

登录

生成验证码

  • 引入 kaptcha 依赖,将验证码的大小、范围、长度等属性封装到 Properties 对象,作为参数构造 Config 对象,再用 Config 对象作为 DeafultKaptcha 对象 setConfig 方法的参数为验证码设置属性。
  • 在登录的 controller 处理验证码,设置页面的响应类型为 png,通过 ImageIO 的 write 方法将图片输出到浏览器。

判断验证码正确后,调用业务层处理

  • 利用 StringUtils 判断用户名、密码是否非空,之后判断用户是否存在、用户是否激活、密码是否正确,将错误信息存到 map 集合。
  • 如果全部合法,为用户生成一个包含过期时间的登录凭证,将凭证存入 redis 和 map 集合。

根据返回的 map 是否包含登陆凭证判断登陆状态

  • 如果登录成功,将凭证存入 cookie 并重定向至首页。
  • 如果登陆失败,将 map 中的错误信息添加到 Model 对象,返回登录页。

检查登录状态

只处理带有自定义注解的方法,防止用户在未登录情况下通过 url 访问没有权限的页面。

利用 ThreadLocal 创建 HostHolder 类,包括 setgetremove 方法,模拟 session 存储用户信息。

通过实现 HandlerInterceptor 接口创建一个拦截器,在 preHandle 方法中通过查询是否有登录凭证的 cookie,如果有则通过登录凭证查询用户 ID,再通过用户 ID 查询用户。最后将用户放入 hostHolder 中,在本次请求中持有用户信息。

创建 @LoginRequired 自定义注解,作用范围在方法上,有效期为运行时。为需要在登录状态下调用的方法,例如修改密码、上传头像等方法上等加上自定义注解。

创建拦截器,在 preHandle 中判断方法是否添加了 @LoginRequired 注解,如果加了并且从 hostHolder 获取不到用户则拒绝访问。


发帖、评论、私信

敏感词过滤

  • 创建静态内部类 TrieNode ,通过 boolean 结束符判断是否匹配到关键字尾部。
  • 利用 @PostConstruct 注解,在构造方法执行后初始化字典树。
  • 添加 filter 方法,利用双指针进行匹配,过滤敏感词。

发帖、评论、私信

  • 对内容进行 HTML 转义以及过滤敏感词。
  • 将信息插入数据库的帖子/评论/消息表。

点赞

创建 RedisKeyUtil 工具类,通过实体类型和实体 id 生成对应实体获得赞的 key。

点赞/取消点赞:

  • 通过 RedisKeyUtil 获得实体点赞的 key,然后通过 RedisTemplate 的 API 操作,调用集合的 isMember 方法查询 userId 是否存在于对应集合中,如果存在则移除出点赞的用户集合,如果不存在则添加到点赞的用户集合。
  • 通过 RedisTemplate 的 execute 方法实现事务,保证被点赞用户点和点赞用户的数据更新一致。通过 isMember 方法查询用户的点赞状态,之后通过 mutli 方法开启事务。

点赞数量:通过调用 set 集合的 size 方法查询元素个数。

点赞状态:通过 set 集合的 isMember 方法实现。


关注和粉丝

在 RedisUnitl 工具类增加两个方法

  • 通过用户 id 和实体类型获得用户关注的实体集合的 key。
  • 通过实体类型和实体 id 获得实体拥有的粉丝集合的 key。

当用户关注某实体时,

  • 将实体 id 和时间作为 value 和 score 加入用户的关注集合。
  • 将用户 id 和时间作为 value 和 score 加入实体的粉丝集合。

当用户取消关注某实体时,将实体从用户的关注集合移除,用户从实体的粉丝集合移除。

关注列表和粉丝列表

  • 用户的关注列表,通过 zset 的 reverseRange 获取 value 即关注用户的 userId,再查询出 user,通过 score 获取关注时间。
  • 用户的粉丝列表,通过 zset 的 reverseRange 获取 value 即粉丝的 userId,再查询出 user,通过 score 获取关注时间。
  • 列表信息封装在 list 集合中,再将 list 添加到 Model 对象里。

Kafka

发送系统通知

创建 Event 类,封装事件对象,包括主题(评论、点赞、关注)、用户 id、实体类型、实体 id,以及一个 map 集合存放其它信息。

触发事件

通过 Event 获取事件类型,并将其封装成 JSON 数据,然后调用注入的 KafkaTemplate 实例的 send 方法发送。

消费事件

通过 @KafkaListener 注解,topic 包括了评论、点赞和关注。从 recored 中获取信息,封装成 Message 对象然后调用 addMessage 方法插入数据库。


你可能感兴趣的:(java)