说在开头
本项目参考自github用户timlessmoney的开源项目,附上项目地址
地址
本文主要是学习前辈的开源项目,记录自己学习开源项目的过程,分享自己遇到的一些问题。
什么是二级评论
为什么提及这一点,因为一开始我对这个概念的理解是有偏差的,大家可以看看bilibili的评论模块就是一个典型的二级评论,简单讲二级评论实现了用户可以回复评论,评论之间可以相互回复。
目标读者
javaweb开发新手,虽然已经学过相关的基础知识和一些框架的基本用法,但是缺少实际的项目经验。我相信在你学习了这个项目之后,你会在对工程有些许自己的见解。
项目技术栈
这是一个前后端分离的项目,这也是现在很流行的开发方式,如果新手们还在学习jsp,我希望你们能够就此打住,这种前后端杂糅的开发方式实在是out了。
后端采用的是:maven+springboot+mybatis+mysql。通过maven构建工程,解决依赖问题,springboot整合spring和mybtis。
前端:bootstrap+angularjs
当然,我主要学习的方向是后端开发,所以我
我修复了什么bug
1.插入评论无时间戳
2.新增的一级评论下无法及时显示二级评论
效果
数据库设计
由三张表构成:说说表,一级评论表,二级评论表
说说表:
这个表相当于在模拟一条微博或者一篇文章,包含了内容,作者,头像,赞数等信息,后面的评论都是基于对这个说说表做出的。
一级评论表:
这张表用于记录一级评论,通过说说id来和说说进行关联,实现评论的功能
二级评论表:
记录的一级评论的id字段、回复者和回复谁的字段是实现评论回复的关键。
后端部分
后端语言采用的是java,针对这一评论系统的设计也是采用典型的三层架构:表现层、业务层和持久层。其中表现层采用的是mvc的设计思想。
通过idea创建springboot项目
idea内置springboot方式创建项目,其本质是一个maven工程,通过maven工程自动导入了很多springboot需要的依赖,并且提前配置好一些springboot的启动类。
一个标准的maven工程目录应该是这样的:
java中放放置项目源代码,resources中放置项目需要的配置文件,webapp中放置web服务的资源文件。
值得注意的是target目录:
项目构建生成的字节码文件都会放入到这个目录下面的classes文件夹下,同时resources文件夹下的配置文件也会放入这个文件夹下。平常我们可能会用到的classpath,其实指的就是这个目录。
编写配置文件搭建开发环境
springboot的优点是自动配置和坐标打包,但这仅仅是帮我们减轻了花在配置上的时间,有些配置还是需要我们自己完成的。比如我们需要自己导入mybatis整合springboot的依赖。我们不再需要想spring整合mybatis一样需要管理工厂,注入数据库等等,编写一大堆的配置文件。我们只需要在resources目录下新建application.properties文件(springboot会扫描其中的配置并替换默认的配置),写上数据库连接池的相关信息,配置m要扫描mapper配置文件的目录就可以。当然,为了方便我们还会配置bean类的别名。
编写bean
三张表对应三个bean类,各个属性和数据库字段相匹配
在Saying类中包含了一级表的集合,一级表中包含了二级表的集合,这是能够做到展示所有评论信息的关键所在。
编写mapper
由于saying表中包含了集合对象,集合对象中又嵌套了一层集合,所以在编写mybatis的mapper.xml文件时需要格外的注意:
编写controller
我在这里跳过了servcie层,因为业务不复杂,基本上service层做的工作就是直接调用mapper。
表现层使用的是springmvc,控制层通过控制访问的url来调用相应的方法,在处理妥善后把json格式的数据返回给前端,这也是前后端分离开发的关键所在。
springmvc框架的参数绑定能够自动把请求参数自动绑定到对象的相应属性上,这点真的很方便。还有,当我们使用@responsebody时,当我们给前端返回一个对象,它可以把这个对象以json格式返回给前端。这真的省去了我们很多时间,传统的方式我们需要先把对象转换成json格式的数据,但是现在都不用了。
@RequestMapping("/comment")//一级请求路径
@RestController//@controller+@responsebody
public class CommentController {
@Autowired
private CommentService commentService;
@RequestMapping(value = "/add/first", method = RequestMethod.POST)
public FirstLevelComment addFirst(FirstLevelComment flc) {
System.out.println("增加一级评论!!!");
//修复新评论无法显示时间的bug
flc.setCommentTime(new Date());
commentService.addFlcComment(flc);
return flc;
}
@RequestMapping(value="/delete/first/{sayingId}/{commentId}")
public void removeFirstLevelCommment(@PathVariable int sayingId, @PathVariable int commentId) {
System.out.println("进入删除一级评论的控制器");
System.out.println("sayingid"+sayingId+"===commentid"+commentId);
commentService.removeFlcComment(commentId, sayingId);
}
@RequestMapping(value="/add/second", method=RequestMethod.POST)
public SecondLevelComment addSecondLevelCommment(SecondLevelComment secondLevelComment) {
//修复无法插入二级评论的bug
//原因很简单:无法插入数据库,因为时间字段要求不为空
//时间字段的插入在后端部分解决就好
System.out.println("来到了插入二级评论的控制器!!");
secondLevelComment.setReplyTime(new Date());
commentService.addSlcComment(secondLevelComment);
System.out.println(secondLevelComment);
return secondLevelComment;
}
@RequestMapping(value="/delete/second/{sayingId}/{commentId}")
public void removeSecondLevelCommment(@PathVariable int sayingId, @PathVariable int commentId) {
System.out.println("来到删除二级评论的控制器");
System.out.println("sayingid="+sayingId+"======slcid="+commentId);
commentService.removeSlcComment(commentId, sayingId);
}
@RequestMapping("/saying")
@RestController
public class SayingController {
@Autowired
private SayingService service;
//这里采用的是restful风格的url请求
//同一个url通过不同的请求方式调用不同的方法
@RequestMapping("/get/comment/{id}")
public Saying showCommment(@PathVariable(value = "id") int id) {
System.out.println("============这里是sayingController=================");
return service.selectOneById(id);
}
@RequestMapping(value="/likes", method= RequestMethod.POST)
public void changeLikes(@RequestParam int id, @RequestParam String likes) {
System.out.println("=========更新赞数============");
service.upadateLikesById(id, likes);
}
}
后端小结
1、编写和数据库各表对应的bean,为后续的mapper做准备
2、编写和数据库打交道的mapper,在其中编写各种操作数据库的方法
3、编写service,service的功能可能是几个mapper功能的组合
4、编写controller,根据不同的请求url,调用不同的方法。把前端发过来的请求数据进行处理加工,期间可能会依赖于service层,把最后的结果以json的格式返回给前端。
前端部分
前端采用的是jq+bootstrap+angular
我在前端方面是非常菜鸡的,所以这个项目的前端部分我仅仅是做到看懂而已,抱歉!(ps:虽然我的后端也很菜)
angular相关
angular中最重要的三个概念:作用域、模块、控制器
我的粗浅理解是我们可以创建很多的模块,在模块里在创建很多的作用域,模块的作用域包含了控制器的作用域。
myapp就是一个模块,我们在这个模块里又创建了一个mycontroller的控制器,模块的作用域包含了控制器。同时我们在控制器这个对象里头又创建了firsttname这个属性,既然这是一个对象我们当然还可以创建方法
这个就是一个方法属性了。
angular的httpservice服务
这是使用angular框架实现前后端分离中用到的一个很重要的服务。
可以想象这样一个场景:假设一个angular应用,当我们需要查看某些信息时我们往往会点击一个按钮,当我们点击按钮是必然会触发一个事件,这个事件通过使用angular的httpservice向服务器请求资源,服务器返回来json格式的数据,angular在把json解析成javascript对象填充到某个控制器的某个属性中,然后再通过angular表达式把这些内容呈现在页面上,完成最终页面的动态展示。
实际用法就像这样子:
我们把json格式的数据data直接填充到saying这个控制器属性中
html中再通过遍历这个属性的方式把最终的方式呈现出来。
更多
编写出一个美观的前端页面实在很难,我就不班门弄斧了,具体的实现可以看源代码
最后
我会在这个项目的基础上继续完善,首先会加入的是用户登录功能和后台管理功能。如果可以的话我会摸索如何把这个评论系统嵌入到静态博客中,实现类似多说和畅言这种评论系统的功能。
这是我修改后的源码地址:源码
如果你们对这个项目感兴趣或者有任何问题
欢迎私信。
如果有人对我的完善计划感兴趣,欢迎加群:624017389