仿牛客网项目第三章:开发社区核心功能(详细步骤和思路)

1. 过滤敏感词

1)可以使用JDK自带的replace方法替换敏感词,但在实际应用中敏感词比较多、字符串可能比较长(发布的一篇文章)这种情况下用replace去替换性能就比较差
2)使用前缀树来实现过滤敏感词的算法。但前缀树方法也有一些局限性,不能实现对停顿词重复词的检查,考虑到此可以优化为DFA算法过滤敏感词

1.1 目的

在发帖子的过程中,可能会有人发布一些敏感词信息,在提交到系统中需要先进行一次过滤,故需要开发过滤敏感词功能

1.2 实现方法

通过前缀树,然后书写过滤敏感词方法,能够实现敏感词的过滤功能。

1.3 前缀树

  1. 名称:Trie,字典树,查找树
  2. 特点:查找效率高,消耗内存大(以空间换时间)
  3. 应用:字符串检索,词频统计和字符串排序

1.4 敏感词过滤步骤(为发帖子做准备)

  1. 定义前缀树
    1)敏感词文件:在resource中添加文件sensitive-words.txt
    2)添加工具类sensitivefilter:(核心搞懂前缀树和过滤功能实现说明
    (1):新建前缀树:TrieNode(),私有
    (2):初始化前缀树:init() ,私有。用@PostConstruct标注,说明只是在类加载的时候运行一次。
    (3):将一个敏感词添加到前缀树中,addKeyword(String keyword),私有
    (4):根据前缀树,对输入的字符串进行过滤,filter(String text),公有,需要考虑符号穿插。
    (5):判断输入字符串是否为符号(符号课采取跳过原则,例如“★开★票★★”,还是能够被检测出来)
  2. 进行测试敏感词过滤效果
    1)新建一个敏感词的测试类SensitiveTests,然后进行测试文本过滤效果
    2)调用公有的铭感次过滤函数sensitiveFilter.filter(text),实现功能

2. 发布帖子

2.1 AJAX介绍

  1. Astnchronous JavaScript and XML
  2. 异步的JavaScipt与XML,不是一门新技术,只是一个新的术语
  3. 使用AJAX,网页能够将增量更新呈现在页面上面,而不需要刷新整个页面
  4. 虽然X代表XML,但是现在使用JSON比XML更加广泛。

2.2 AJAX使用实例

  1. 导包:导入包fastjson(用于)
  2. Util层:在CommunityUtil类中实现获取JSON字符串的三个构造方法:getJSONString()
    1) 直接在CommunityUtil类中测试获取json字符串的方法,
  3. Dao层(把接收到的信息传入数据库):
    1)在DiscussPostMapper中增加插入数据的方法insertDiscussPost。
    2)在mapper文件中增加insert方法的实现。
  4. Service层:在DiscussPostService中增加调用的实现findDiscussPosts。
  5. Controller层:增加DiscussPostController类,添加add访问请求,并修改index.js。
    1)在add方法中,返回json信息而不是文本,故需要添加注解@ResponseBody
    2)add的作用是添加帖子的功能,返回的是json信息,被前端读取后,能够在前端自己完成刷新功能,而不是整体刷新。
    3)修改index.js使得前端能够完成一定的功能。(减轻服务器的压力,负载均衡)
    4)修改index.html中弹出框提示框的内容

3. 帖子详情

3.1 实现功能

通过点击帖子栏中帖子的标题,能够获取用户帖子的详情

3.2 实现过程

  1. Dao层:在DiscussPostMapper中添加根据帖子id查询到帖子对象功能的sql方法申明,并在mapper.xml书写sql语句。
  2. Service层:在DiscussPostService中添加根据帖子id查询到帖子对象功能方法(直接调用)
  3. Controller层:根据用户id获取帖子对象用户对象,传入model中方便在页面进行调用,然后页面跳转至详情页。
  4. index.html:修改点击帖子标题,跳转到详情页面的连接
  5. discuss-detail.html
    1)处理静态资源的访问路径
    2)复用index.html的heade区域
    3)根据得到帖子的对象,在页面显示标题,作者,发布时间和帖子正文内容

4. 事务管理

4.1 事务介绍

事务是由N步数据库操作序列组成的逻辑执行单元,这系列操作要么全执行,要么全放弃执行

4.2 事务四大特性

  1. 原子性(Atomicity):事务是应用中不可再分的最小执行体。
  2. 一致性(Consistency):事务执行的结果,须使数据从一个一致性状态,变为另一个一致性状态。
  3. 隔离性(Isolation):各个事务的执行互不干扰,任何事务的内部操作对其他的事务都是隔离的。
  4. 持久性(Durability):事务一旦提交,对数据所做的任何改变都要记录到永久存储器

4.3 事务的隔离性

  1. 并发异常
    读取未提交都不能解决
    1)第一类丢失更新:一个查询回滚,一个查询更新,前者慢一点,会导致后者的更新丢失
    2)脏读:一个事务读取另一个事务未提交的数据(读取已提交能够解决
    3)第二类丢失更新:两个都进行查询更新,会使得前者更新值丢失
    4)不可重复度:一个事务进行数据更新,另一个事务进行多次访问出现不一致。(可重复读能够解决
    5)幻读:对数据的添加和删除,使得另一个事务在多次查询的时候感觉出现了幻觉(类似不可重复读,不过前者是数据更新,后者是数据修改或者删除)(序列化能够解决

4.4 事务的实现机制

  1. 悲观锁(数据库自带)
    1)共享锁(S锁):事务A对某数据加上共享锁后,其他事务只能对数据加共享锁,不能加排他锁
    2)排它锁(X锁):事务A对某数据加上排他锁后,其他事务既不能给数据加上排他锁,也不能加上共享锁。
  2. 乐观锁(自定义)
    1)版本号,时间戳等
    2)版本号工作原理:在更新数据之前,检查版本号是否发生变化,若变化则取消本次更新,否则就更新内容,且版本号+1。

4.4 事务的管理(Spring Boot)

  1. 申明式事务(XML+注解+方法)(更常用,编写简单
    1)通过XML配置,申明某方法的事务特征
    2)通过注解,申明某方法的事务特征
  2. 编程式事务(TransactionTemplate+方法内部)
    1)通过TransactionTemplate管理事务
    2)并通过她执行数据库的操作
  3. 两者区别
    1)更简单:申明式事务只能申明方法的整体,不能对局部代码进行事务管理;但是事务管理非常方便,只需要添加注解
    2)更精细:编程式事务形成一个TransactionTemplate对象,把需要管理的代码可以局部圈起来。
  4. 管理事务的两个参数
    1)隔离级别:在上述已经说明了(一般用可重复度)
    2)关联方式:REQUIRED;REQUIRES_NEW;NESTED
    (1)REQUIRED:支持当前事务(外部事务),如果不存在则创建新事务.
    (2)REQUIRES_NEW创建一个新事务,并且暂停当前事务(外部事务).
    (3)NESTED:如果当前存在事务(外部事务),则嵌套在该事务中执行(独立的提交和回滚),否则就会REQUIRED一样.
  5. 两种管理事务方式例子
    1)在AlphaService里面书写两种事务管理方式事例。
    2)申明式事务:在方法上加上注解:@Transactional,里面有两个参数
    3)新增用户,新增帖子,然后加上一个会报错的语句
    4)如果有事务管理,会因为存在报错,而进行回滚,其他语句也不会执行。
    5)新建一个测试类DiscusspostTests,执行两种方法,查看数据库的改变。数据库就没变。

5. 显示评论

  1. 评论表对象:存在非常多种类型的评论,用参数entity_type进行区分。
  2. 实体类:定义评论entity:一实体一表,添加评论表。
  3. Dao层:创建CommentMapper
    1)根据评论类型和帖子id,查询一页评论的数据(需进行翻页展示):
    (1):根据四个参数,从帖子数据库中获取所需帖子:
    selectCommentsByEntity(int entityType, int entityId, int offset, int limit)
    2)根据实体查询评论的数量:
    (1):根据评论类型和帖子id,获取评论的数量:
    selectCountByEntity(int entityType, int entityId)
    3)新建comment-mapper.xml,对Dao层进行实现
  4. 业务层Service:创建CommentService
    1)处理查询评论的业务:直接调用Dao方法
    2)处理查询评论数量的业务,直接调用Dao方法
  5. 实现层Controller:这一层与帖子详情功能共享,在同一个页面
    1)根获取不同类型评论对象:评论对象回复对象(评论的评论,回复对象还有两种),传值给model。(思路简单,步骤繁琐了点)
  6. .xtml
  1. 有两类评论,评论和回复两种类型,需要分别进行展示。通过循环操作。
  2. 在帖子详情里面,复用首页分页的功能

6. 添加评论(事务管理)

  1. Dao层:
    (1)增加评论数据:在comment里书写:insertComment(Comment comment);
    (2)修改帖子的评论数量:在discussPost里书写:updateCommentCount
    (3)对应书写mapper.xml的文件
  2. Service层:
    1)处理添加评论的功能:
    2)先增加评论,再更新帖子的评论数量(事务操作,两者连在一起):在DiscussPostService先书写更新帖子数量,然后再CommentService里面书写帖子个数。
  3. Controller层:
    1)处理添加评论数据的请求:书写方法:addComment
  4. html层:
  1. 设置添加评论的表单(有两个地方需要放入表单)

7. 私信列表+私信详情

7.0 功能说明

  1. 私信列表:通过私信列表,能够查询到最近有谁给你发了消息,显示最新的一条消息(类似首页帖子)
  2. 私信详情:点击消息,能够直到消息的详情,把所有交流的内容都放出来。
  3. 两者都支持分页展示功能

7.1 私信列表+私信详情

  1. 查询当前用户的会话列表和私信详情列表
    1)Entity实体类:创建Message实体类
    private int id;                    //自动生成的id
    private int fromId;                //发送者id
    private int toId;                  //接收者id
    private String conversationId;     //会话id(第几次会话了)
    private String content;           //会话内容
    private int status;                //状态(0未读,1已读,2删除)
    private Date createTime;           //交流时间

2)Dao层:创建MessageMapper
书写五个查询方法
(1)私信列表:查询当前用户的会话列表,针对每个对话只返回最新一条的私信(sql注意)
(2)私信列表:查询当前用户的会话数量
(3)私信详情:查询某个会话所包含的私信列表
(4)私信详情:查询某个会话所包含的私信数量
(5)私信列表:查询未读私信的数量
3)Dao层:创建对应的。xml文件书写sql语句
4)Service层:创建MessageService:直接调用对应Dao方法(比较简单,核心逻辑放到表现层);在UserService中添加方法:根据用户的名字查找用户对象。
5)Controller层:创建MessageController
(1)私信列表请求:分页信息,私信列表信息,私信数量,发送私信对象,未读私信数量,把以上几个数据都查找出来,然后通过写入Model中,传递给前端页面。
(2)私信详情请求:分页信息,私信详情列表,私信详情发送对象,设置已读(把在私信详情列表中出现过的数据)
(3)私信发送请求:发送私信,从前端得到的消息,使用异步方式,故需要注解 @ResponseBody。功能交给前端处理。
(4):小方法一:根据消息的conversationId,结合当前用户判断收信人是谁
(5):小方法二:根据消息,返回消息发送人的id。(用于设置消息的未读转为已读)
6)修改html
(1)修改index.html文件:点击消息,能够跳转页面。
(2)修改letter.html文件:因为是异步的方式,所以还需要修改letter.js文件,设置响应方式。
(3)修改letter_detail.html文件

8. 发送私信

8.1 发送私信+设置已读

  1. 采用异步的方式发送私信
    1)Dao层:添加MessageMapper
    (1)添加方法:新增消息
    (2)添加方法:修改消息状态。出现在显示名单里的标记为已读状态。
    2)**Dao层:**添加Message.xml书写对应sql文件
    3)**Service层:**直接调用Dao的查询方法
    4)Controller层:添加add请求,采用异步通信方法,返回json格式,在前端的message.js中进行逻辑控制。
    5)修改对应的.html文件。

9. 统一处理异常

9.1 处理异常的四种方式

  1. @ControllerAdvice**(最常用)**
  • 用于修饰类,表示该类是Controller的全局配置类。
  • 在此类中,可以对Controller进行如下三种全局配置:异常处理方案、绑定数据方案、绑定参数方案。
  1. @ExceptionHandler
  • 用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常。
  1. @ModelAttribute
  • 用于修饰方法,该方法会在Controller方法执行前被调用,用于为Model对象绑定参数。
  1. @DataBinder
  • 用于修饰方法,该方法会在Controller方法执行前被调用,用于绑定参数的转换器。

9.2 统一处理异常步骤:

  1. 在template目录下新建一级文件
    (1)把最容易出错的两个.xml文件存入:404(请求资源不存在)和500(服务端发生错误)
  2. 在Controller中新建文件夹advice,然后新建ExceptionAdvice
    (1)记录发生错误处的日志信息,并且逐行写下原因是什么
    (2)根据发生错误处请求的方式,分为同步请求和异步请求,分别返回错误页面和错误消息json。
  3. 一旦系统中发送了错误,那么就会自动运行这个方法,进行统一异常的处理机制,非常方便,这就是框架的强大之处。

10. 统一记录日志

10.1 需求

比如一些请求执行的过程中,需要对其进行日志记录,但是一个个在求情中添加不是很方便,故使用功能切面编程技术去实现。

  1. 在Controller运行的时候,可以通过拦截器进行日志记录
  2. 在发生异常的时候,可以通过统一异常管理进行处理
  3. 在业务运行的时候,Service,需要通过AOP进行统一的管理。

10.2 AOP概念和术语

详情见我以前写的文章记录。

10.3 AOP的实现

1. AspectJ
(1)语言级的实现,拓展了java语言,定义了AOP语法(一种新的语言)
(2)在编译器植入代码,有一个专门的编译器,用来生成遵守Java字节码规范的class文件。
2. Spring AOP
(1)纯java实现,不需要专门的编译过程,不需要特殊的类装载器
(2)在运行时通过代理的方式植入代码,只支持方法类型的连接点
(3)支持对 AspectJ的集成
3. 两者区别:
(1):功能:AspectJ功能更强大,但是需要额外语言和编译期;Spring AOP使用更方便,但是有一定局限性,比如只支持方法类型的连接点。
(2):植入代码的时期:AspectJ为编译期,Spring AOP为运行期。

10.4 动态代理的种类(Spring AOP)

  1. JDK动态代理
    (1)Java提供的动态代理技术,可以在运行时创建接口的代理实例
    (2)Spring AOP 默认采用此种方式,在接口的代理实例中置入代码。
  2. CGLib动态代理
    (1)采用底层的字节码技术,在运行时创建子类代理实例
    (2)当目标对象不存在接口时,Spring AOP会采用此种方式,在子类实例中植入代码

10.5 项目实现

  1. 在一级目录下面新建文件夹aspect,存放切片文件
  2. 在上述文件夹下新建文件ServiceLogAspect
  3. 文件主要啷个部分:
    1)申明该切片作用的对象,即运行哪些业务需要service。
    2)申请业务那一部分添加切片,@Before,@After,@Round,@AfterReturning,@AfterThrowing,并书写需要额外实现的功能。
    3)特点:使用起来非常方便,只需要新建一个文件就好,不需要额外修改其他的原始文件。

文章参考:
1. 从零开始—仿牛客网讨论社区项目(二)
5. 关于介绍AJAX的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值