1. 过滤敏感词
1)可以使用JDK自带的replace方法 替换敏感词,但在实际应用中敏感词比较多、字符串可能比较长(发布的一篇文章)这种情况下用replace去替换性能就比较差 。 2)使用前缀树 来实现过滤敏感词的算法。但前缀树方法也有一些局限性,不能实现对停顿词 、重复词 的检查,考虑到此可以优化为DFA算法过滤敏感词 。
1.1 目的
在发帖子的过程中,可能会有人发布一些敏感词信息,在提交到系统中需要先进行一次过滤,故需要开发过滤敏感词功能
1.2 实现方法
通过前缀树 ,然后书写过滤敏感词方法,能够实现敏感词的过滤功能。
1.3 前缀树
名称:Trie,字典树,查找树 特点:查找效率高,消耗内存大(以空间换时间) 应用:字符串检索,词频统计和字符串排序
1.4 敏感词过滤步骤(为发帖子做准备)
定义前缀树 1)敏感词文件:在resource中添加文件sensitive-words.txt 2)添加工具类sensitivefilter:(核心搞懂前缀树和过滤功能实现说明 ) (1):新建 前缀树:TrieNode(),私有 (2):初始化 前缀树:init() ,私有。用@PostConstruct标注,说明只是在类加载的时候运行一次。 (3):将一个敏感词添加 到前缀树中,addKeyword(String keyword),私有 (4):根据前缀树,对输入的字符串进行过滤 ,filter(String text),公有,需要考虑符号穿插。 (5):判断输入字符串是否为符号(符号课采取跳过原则,例如“★开★票★★”,还是能够被检测出来) 进行测试敏感词过滤效果 1)新建一个敏感词的测试类SensitiveTests,然后进行测试文本过滤效果 2)调用公有的铭感次过滤函数sensitiveFilter.filter(text),实现功能
2. 发布帖子
2.1 AJAX介绍
Astnchronous JavaScript and XML 异步的JavaScipt与XML,不是一门新技术,只是一个新的术语 使用AJAX,网页能够将增量更新呈现在页面上面,而不需要刷新整个页面 虽然X代表XML,但是现在使用JSON比XML更加广泛。
2.2 AJAX使用实例
导包:导入包fastjson(用于) Util层:在CommunityUtil类中实现 获取JSON字符串 的三个构造方法:getJSONString() 1) 直接在CommunityUtil类中测试获取json字符串的方法,Dao层(把接收到的信息传入数据库): 1)在DiscussPostMapper中增加插入数据的方法insertDiscussPost。 2)在mapper文件中增加insert方法的实现。 Service层:在DiscussPostService中增加调用的实现findDiscussPosts。 Controller层:增加DiscussPostController类,添加add访问请求,并修改index.js。 1)在add方法中,返回json信息而不是文本,故需要添加注解@ResponseBody 2)add的作用是添加帖子的功能,返回的是json信息,被前端读取后,能够在前端自己完成刷新功能,而不是整体刷新。 3)修改index.js使得前端能够完成一定的功能。(减轻服务器的压力,负载均衡) 4)修改index.html中弹出框 和提示框 的内容
3. 帖子详情
3.1 实现功能
通过点击帖子栏中帖子的标题,能够获取用户帖子的详情
3.2 实现过程
Dao层:在DiscussPostMapper中添加根据帖子id 查询到帖子对象功能 的sql方法申明,并在mapper.xml书写sql语句。 Service层:在DiscussPostService中添加根据帖子id 查询到帖子对象功能 方法(直接调用) Controller层:根据用户id获取帖子对象 和用户对象 ,传入model中方便在页面进行调用,然后页面跳转至详情页。 index.html:修改点击帖子标题,跳转到详情页面的连接 discuss-detail.html 1)处理静态资源的访问路径 2)复用index.html的heade区域 3)根据得到帖子的对象,在页面显示标题,作者,发布时间和帖子正文内容
4. 事务管理
4.1 事务介绍
事务是由N步数据库操作序列组成的逻辑执行单元 ,这系列操作要么全执行 ,要么全放弃 执行
4.2 事务四大特性
原子性 (Atomicity):事务是应用中不可再分的最小执行体。 一致性 (Consistency):事务执行的结果,须使数据从一个一致性状态 ,变为另一个一致性状态。隔离性 (Isolation):各个事务的执行互不干扰 ,任何事务的内部操作对其他的事务都是隔离的。持久性 (Durability):事务一旦提交,对数据所做的任何改变都要记录到永久存储器 中
4.3 事务的隔离性
并发异常 读取未提交都不能解决 1)第一类丢失更新 :一个查询回滚 ,一个查询更新,前者慢一点,会导致后者的更新丢失 2)脏读 :一个事务读取另一个事务未提交的数据(读取已提交能够解决 ) 3)第二类丢失更新 :两个都进行查询更新 ,会使得前者更新值丢失 4)不可重复度 :一个事务进行数据更新,另一个事务进行多次访问出现不一致。(可重复读能够解决 ) 5)幻读 :对数据的添加和删除,使得另一个事务在多次查询的时候感觉出现了幻觉(类似不可重复读,不过前者是数据更新,后者是数据修改或者删除)(序列化能够解决 )
4.4 事务的实现机制
悲观锁 (数据库自带) 1)共享锁(S锁):事务A对某数据加上共享锁后,其他事务只能对数据加共享锁,不能加排他锁 2)排它锁(X锁):事务A对某数据加上排他锁后,其他事务既不能给数据加上排他锁,也不能加上共享锁。乐观锁(自定义) 1)版本号,时间戳等 2)版本号工作原理:在更新数据之前,检查版本号是否发生变化,若变化则取消本次更新,否则就更新内容,且版本号+1。
4.4 事务的管理(Spring Boot)
申明式事务(XML+注解+方法)(更常用,编写简单 ) 1)通过XML配置 ,申明某方法 的事务特征 2)通过注解 ,申明某方法 的事务特征 编程式事务(TransactionTemplate+方法内部) 1)通过TransactionTemplate管理事务 2)并通过她执行数据库的操作 两者区别 1)更简单 :申明式事务只能申明方法的整体,不能对局部代码进行事务管理;但是事务管理非常方便,只需要添加注解 2)更精细 :编程式事务形成一个TransactionTemplate对象,把需要管理的代码可以局部圈起来。 管理事务的两个参数 1)隔离级别:在上述已经说明了(一般用可重复度) 2)关联方式:REQUIRED;REQUIRES_NEW;NESTED (1)REQUIRED:支持当前事务(外部事务),如果不存在则创建新事务. (2)REQUIRES_NEW创建一个新事务,并且暂停当前事务(外部事务). (3)NESTED:如果当前存在事务(外部事务),则嵌套在该事务中执行(独立的提交和回滚),否则就会REQUIRED一样. 两种管理事务方式例子 1)在AlphaService里面书写两种事务管理方式事例。 2)申明式事务:在方法上加上注解:@Transactional,里面有两个参数 3)新增用户,新增帖子,然后加上一个会报错的语句 4)如果有事务管理,会因为存在报错,而进行回滚,其他语句也不会执行。 5)新建一个测试类DiscusspostTests,执行两种方法,查看数据库的改变。数据库就没变。
5. 显示评论
评论表对象 :存在非常多种类型的评论,用参数entity_type进行区分。实体类 :定义评论entity:一实体一表,添加评论表。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层进行实现业务层Service :创建CommentService 1)处理查询评论的业务:直接调用Dao方法 2)处理查询评论数量的业务,直接调用Dao方法实现层Controller :这一层与帖子详情功能共享,在同一个页面 1)根获取不同类型评论对象:评论对象 和回复对象 (评论的评论,回复对象还有两种),传值给model。(思路简单,步骤繁琐了点).xtml
有两类评论,评论和回复两种类型,需要分别进行展示。通过循环操作。 在帖子详情里面,复用首页分页的功能
6. 添加评论(事务管理)
Dao层: (1)增加评论数据:在comment里书写:insertComment(Comment comment); (2)修改帖子的评论数量:在discussPost里书写:updateCommentCount (3)对应书写mapper.xml的文件 Service层: 1)处理添加评论的功能: 2)先增加评论,再更新帖子的评论数量(事务操作 ,两者连在一起):在DiscussPostService先书写更新帖子数量,然后再CommentService里面书写帖子个数。 Controller层: 1)处理添加评论数据的请求:书写方法:addComment html层:
设置添加评论的表单(有两个地方需要放入表单)
7. 私信列表+私信详情
7.0 功能说明
私信列表 :通过私信列表,能够查询到最近有谁给你发了消息,显示最新的一条消息(类似首页帖子)私信详情 :点击消息,能够直到消息的详情,把所有交流的内容都放出来。两者都支持分页展示 功能
7.1 私信列表+私信详情
查询当前用户的会话列表和私信详情列表 1)Entity实体类:创建Message实体类
private int id;
private int fromId;
private int toId;
private String conversationId;
private String content;
private int status;
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)Dao层 :添加MessageMapper (1)添加方法:新增消息 (2)添加方法:修改消息状态。出现在显示名单里的标记为已读状态。 2)**Dao层:**添加Message.xml书写对应sql文件 3)**Service层:**直接调用Dao的查询方法 4)Controller层 :添加add请求,采用异步通信方法,返回json格式,在前端的message.js中进行逻辑控制。 5)修改对应的.html文件。
9. 统一处理异常
9.1 处理异常的四种方式
@ControllerAdvice**(最常用)**
用于修饰类,表示该类是Controller的全局配置类。 在此类中,可以对Controller进行如下三种全局配置:异常处理方案、绑定数据方案、绑定参数方案。
@ExceptionHandler
用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常。
@ModelAttribute
用于修饰方法,该方法会在Controller方法执行前被调用,用于为Model对象绑定参数。
@DataBinder
用于修饰方法,该方法会在Controller方法执行前被调用,用于绑定参数的转换器。
9.2 统一处理异常步骤:
在template目录下新建一级文件 (1)把最容易出错的两个.xml文件存入:404(请求资源不存在)和500(服务端发生错误) 在Controller中新建文件夹advice,然后新建ExceptionAdvice (1)记录发生错误处的日志信息,并且逐行写下原因是什么 (2)根据发生错误处请求的方式,分为同步请求和异步请求,分别返回错误页面和错误消息json。 一旦系统中发送了错误,那么就会自动运行这个方法,进行统一异常的处理机制,非常方便,这就是框架的强大之处。
10. 统一记录日志
10.1 需求
比如一些请求执行的过程中,需要对其进行日志记录,但是一个个在求情中添加不是很方便,故使用功能切面编程技术去实现。
在Controller运行的时候,可以通过拦截器进行日志记录 在发生异常的时候,可以通过统一异常管理进行处理 在业务运行的时候,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)
JDK动态代理 (1)Java提供 的动态代理技术,可以在运行时 创建接口 的代理实例 (2)Spring AOP 默认采用 此种方式,在接口的代理实例 中置入代码。CGLib动态代理 (1)采用底层的字节码技术,在运行时 创建子类 代理实例 (2)当目标对象不存在接口 时,Spring AOP会采用此种方式,在子类实例中植入代码
10.5 项目实现
在一级目录下面新建文件夹aspect,存放切片文件 在上述文件夹下新建文件ServiceLogAspect 文件主要啷个部分: 1)申明该切片作用的对象,即运行哪些业务需要service。 2)申请业务那一部分添加切片,@Before,@After,@Round,@AfterReturning,@AfterThrowing,并书写需要额外实现的功能。 3)特点:使用起来非常方便,只需要新建一个文件就好,不需要额外修改其他的原始文件。
文章参考: 1. 从零开始—仿牛客网讨论社区项目(二) 5. 关于介绍AJAX的文章