用springboot实现一个具备评论功能的页面(从前端HTML到后端MySQL完整代码)
关于该部分的说明:因为最近用springboot写了网站项目(目前部署到Linux上出现了不少问题),就从我写的项目中挑出实现评论功能这部分的代码进行展示,那么该部分就给新手们在练习springboot时提供了一个思路(通过左上角码龄看得出来我也是新手,哈哈)
要实现评论功能
第一:评论的哪篇文章得知道,什么时候评论的,评论的什么内容(我直接访问数据库了)
第二:还得知道评论的人是谁,头像是什么(我下面给的是四个随机头像,6个随机网名)
第三:评论内容字数内容是否要进行限制(我也只是写死了几个词汇进行对比)
效果展示1
效果展示2
效果展示3
效果展示4
内容 | 名字 | 描述 |
主页面展示 | main.html | 文章部分与评论部分整体 |
主页面css | main.css | 修饰整个页面整体部分 |
评论功能整体CSS | commentStyle.css | 确定评论区大小,所处的位置等 |
评论后展示出来的CSS | getSQLcomment.css | 确定评论展示出来内容的位置,等 |
写评论过程中的js | check,js | 每提交一次评论随机产生一个头像及网名,以及生成提交时个时间 |
验证码js | commentCheck.js | 生成四个0-9之间的数字的验证码 |
页面main.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>CSDN.specialwu</title>
<link type="text/css" rel="styleSheet" th:href="@{/css/main.css}" href="css/main.css" />
<link href="css/commentStyle.css" rel="stylesheet">
<link href="css/getSQLcomment.css" rel="stylesheet">
</head>
<body>
<div class="containAll">
<!--主体内容-->
<div class="middle">
<!-- 文章部分 -->
<div class="middle-left">
<!--点击后放大-->
<div th:each="alltiltes:${articles}">
<a class="big" th:attr="href='show?id='+${alltiltes.articleId}">
<!--文本框:涉及文章图片、标题、等内容,这个部分不做主要阐述-->
<table cellspacing="0" cellpadding="0" height="148" width="930" class="artitle" >
<tr class="title-picture">
<td rowspan="3" width="324" height="148">
<img src="images/mofei.jpg" width="324" height="148"/>
</td>
<td colspan="3" bgcolor="#e8e5ff">
<h1 th:text="${alltiltes.title}" th:name="title">ssss</h1>
</td>
</tr>
<tr align="center">
<td height="40" width="130" bgcolor="#99a7ff">
浏览:<span th:text="${alltiltes.clickCount}">10</span>次
</td>
</td>
<td bgcolor="#b5c9ff">
评论:<span th:text="${alltiltes.commentNumber}">10</span>条
</td>
<td width="260" bgcolor="#c6d1ff">
发表时间:<span th:text="${alltiltes.writeTime}" th:width="260">2020-10-05 17:45</span>
</td>
</tr>
<tr>
<td th:switch="${alltiltes.typeId}"bgcolor="#eff3ff" th:name="articleId" colspan="3">
<span th:case="1">类型1</span>
<span th:case="2">类型2</span>
<span th:case="3">类型3</span>
</td>
</tr>
</table>
</a>
</div>
</div>
<!-- 评论部分 -->
<div class="middle-right">
<div class="commentBlock">
<header><span>评论</span></header>
<section>
<ul></ul>
<table th:each="comments:${articleComments}">
<tr>
<td colspan="2" align="center">
<span th:text="${comments.commentsTime}">2020-09-9</span>
</td>
</tr>
<tr height="20">
<td class="gettouxiang">
<img src="/comment/images/tou01.png" th:src="${comments.givePicture}" />
</td>
<td class="gettouScreenName" th:switch="${comments.giveScreenName}">
<!-- 在点击评论后产生0-5之间的数字并存到数据库,从数据库里拿出来后再进行对照,根据需要可进行修改-->
<span th:case="0">这是一个网名</span>
<span th:case="1">孤狼</span>
<span th:case="2">似水流年</span>
<span th:case="3">冰与火</span>
<span th:case="4">皮卡丘的皮</span>
<span th:case="5">永恒的心</span>
</td>
</tr>
<tr height="20">
<td colspan="2" class="getContent">
<h1 th:text="${comments.commentContent}">数据库来的评论</h1>
</td>
</tr>
</table>
</section>
<div class="post" align="center">
<form action="/manageComments/addComment" th:action="@{/manageComments/addComment}" method="post" th:object="${commentObject}" onsubmit="return trueFales()">
<input class="writeCommentContent"id="writeContent" placeholder="内容(1-50个字符)" type="text">
<input hidden id="writeContent1" th:field="*{commentContent}" name="commentContent" type="text">
<input hidden th:text="${giveArticleId}" th:field="*{articleId}" name="articleId" type="text">
<input hidden th:field="*{commentsTime}" id="getTime" name="commentsTime" type="text">
<input hidden th:field="*{givePicture}" id="getPicture"name="givePicture" type="text">
<input hidden th:field="*{giveScreenName}" id="getScreenName" name="giveScreenName" type="text">
<canvas id="canvas" width="150px" height="50px"></canvas><br>
<input id="givevalue" type="text" hidden>
<span><font color="aqua">点击刷新验证码</font></span><br>
<input id="checking" type="text">
<input type="submit" class="btn" value="发布">
</form>
</div>
</div>
</div>
</body>
<script src="js/check.js"></script>
<script src="js/commentCheck.js"></script>
</html>
页面CSS main.css
*{
margin: 0;
padding: 0;
}
body{
background-color: black;
height: 100%;
font-family:"宋体";
font-weight:normal;
font-style:normal;
}
/*中间部分*/
.middle{
width: 100%;
margin-top: 0px;
}
/*中间左侧*/
.middle-left{
float: left;
width: 75%;
height: 100%;
}
/* 涉及标题等其他信息 */
.artitle{
margin-top: 20px;
margin-left: 30px;
color: black;
background-color: black;
}
/*点击后旋转360放大1.1倍*/
.big table:hover{
-moz-transform: rotate(360deg) scale(1.1);
-webkit-transform: rotate(360deg) scale(1.1);
-o-transform: rotate(360deg) scale(1.1);
-ms-transform: rotate(360deg) scale(1.1);
transform: rotate(360deg) scale(1.1);
}
/*中间右侧*/
.middle-right{
width: 25%;
float: right;
}
评论部分整体的显示commentStyle.css
/* 整个宽度 width */
.commentBlock{
margin: 0 auto;
width: 300px;
position: relative;font-family: "bodoni mt";
color: white;
}
header{
padding: 5px 0;
border-bottom: 1px solid #cecece;
}
header span{
display:inline-block;
width: 220px;
height: 50px; color: #fff;
background: #009966;
font-size: 18px;
font-weight: bold;
text-align: center;
line-height: 50px;
border-radius: 8px;
cursor: pointer;
}
/* 评论前填写的部分 */
.post{
position: absolute;
background: #ffffff;
border: 1px #999999 solid;
width: 300px;
top:70px; padding: 10px;
font-size: 14px;
z-index: 999999;
display: none;
}
/*修饰发布字体、内容这部分*/
.post .writeCommentContent{
width: 300px;
height:30px;
line-height: 30px;
display: block;
border: 1px #aaaaaa solid;
margin-bottom: 10px;
}
/* “发布”字体 */
.post .btn{
width: 160px;
height: 35px;
color: #fff;
background: #009966;
border: none;
font-size: 14px;
font-weight: bold;
text-align: center;
line-height: 35px;
border-radius: 8px;
cursor: pointer;
}
.commentBlock section ul li{
padding: 10px 0;
border-bottom: 1px #999999 dashed;
overflow: hidden;
}
/*头像栏*/
.commentBlock section ul li div{
float: left;
width: 50px;
margin-right: 10px;
}
/* 网名栏 */
.bbs section ul li div span{
float: left;
width: 150px;
margin-right: 10px;
margin-top: 5px;
}
/*图片显示*/
.commentBlock section ul li div img{
border-radius:50%;
width: 40px;
}
/*评论内容*/
.commentBlock section ul li h1{
float: left;
width: 300px;
font-size: 16px;
line-height: 35px;
}
从数据库插入后评论内容的展示getSQLcomment.css
.commentBlock section table{padding: 5px 0; border-bottom: 1px #999999 dashed;
overflow: hidden;font-family: "bodoni mt"}
/* 图片栏 */
.commentBlock .gettouxiang{float: left; width: 50px; margin-right: 10px;margin-top: 5px;}
/* 网名栏 */
.commentBlock .gettouScreenName{float: left; width: 150px; margin-right: 10px;margin-top: 5px;}
/* 图片圆 */
.commentBlock img{ border-radius:50%; width: 40px;}
/* 评论内容字体大小 */
.commentBlock h1{float: left; width: 300px; font-size: 16px; line-height: 25px;}
评论相关commentCheck.js
提交时,内容不能为空,验证码需正确,不能涉及敏感信息都满足了方可提交
在处理提交内容时去掉评论内容两端的空格,方便存储,以及做个简单敏感信息验证,>实际生产中是通过敏感信息数据库来完成的
为什么要自己生成网名,头像,为做到用户的快速评论,以及避免存储太多无关紧要信息,从而自己生成较为便利
/**
* Changed by specialwu on 2020/10/02
*/
$(document).ready(function(){
$(".commentBlock header span").click(function(){
/* 调取验证码获得数字赋值*/
drawPic();
$(".commentBlock .post").show();
});
})
function trueFales() {
/*加载时图片无法显示得改成.png*/
/* 获取到验证码的值 */
var giveValue=document.getElementById("givevalue").value;
/* 输入的值与验证码的值进行对比 */
var inputValue=document.getElementById("checking").value;
/* 内容 */
var writeContent=document.getElementById("writeContent").value;
/* 此段大概提供个思路,也可以把一些敏感词存到数据库,如果库中有则不能存储 */
var guolv=new Array("SB","垃圾","神经","政治");
var trueFale=0;
for(var i=0; i<guolv.length;i++){
/* 去除空格 */
moveblack = writeContent.replace(/\s*/g,"");
/* 去除逗号 */
str = moveblack.replace(/,/g, "");
if(str==guolv[i]){
trueFale=1;
}
/* 此段希望每两个词为一组进行对比,以此过滤关键词*/
/* for(var j=0;j<writeContent.length-2;j++){
var theEnd=writeContent.substring(j,j+2);
alert(theEnd)
if(str==guolv[i]){
trueFale=1;
}
} */
}
if(trueFale==1){
alert("请勿涉及敏感信息");
return false;
}else if(writeContent==''){
alert("内容不能为空");
return false;
}else{
if(giveValue==inputValue){
alert("提交中")
var sNumber=Math.floor(Math.random()*6); //0-5的随机数
/* 去除前后空格再显示 */
/* 去除空格 */
moveblack = writeContent.replace(/\s*/g,"");
/* 去除逗号 */
str = moveblack.replace(/,/g, "");
document.getElementById("writeContent1").value=str;
var myDate=new Date();
<!--提交后产生一个时间-->
var currentDate=myDate.getFullYear()+"-"+parseInt(myDate.getMonth()+1)+"-"+myDate.getDate()+" "+myDate.getHours()+":"+myDate.getMinutes();
document.getElementById("getTime").value=currentDate;
document.getElementById("getScreenName").value=sNumber;
if (sNumber==0){
<!-- 图片自己定义,同样存在数据库的只是地址,相当于一个引用,实际图片还是存储在项目中-->document.getElementById("getPicture").value="/comment/images/tou01.png";
}else if (sNumber==1){
document.getElementById("getPicture").value="/comment/images/tou02.png";
}else if (sNumber==2){
document.getElementById("getPicture").value="/comment/images/tou03.png";
}else if (sNumber==3){
document.getElementById("getPicture").value="/comment/images/tou04.png";
}else if (sNumber==4){
document.getElementById("getPicture").value="/comment/images/tou05.png";
}else {
document.getElementById("getPicture").value="/comment/images/tou06.png";
}
return true;
}else{
alert("验证码错误");
return false;
}
}
}
验证码check.js
验证码的作用就是避免有人恶意点击,频繁访问数据库;
//生成随机数
function randomNum(min,max){
return Math.floor(Math.random()*(max-min)+min);
}
//生成随机颜色RGB分量
function randomColor(min,max){
var _r = randomNum(min,max);
var _g = randomNum(min,max);
var _b = randomNum(min,max);
return "rgb("+_r+","+_g+","+_b+")";
}
//先阻止画布默认点击发生的行为再执行drawPic()方法
document.getElementById("canvas").onclick = function(e){
e.preventDefault();
drawPic();
};
function drawPic(){
//获取到元素canvas
var $canvas = document.getElementById("canvas");
var _str = "0123456789";//设置随机数库
var _picTxt = "";//随机数
var _num = 4;//4个随机数字
var _width = $canvas.width;
var _height = $canvas.height;
var ctx = $canvas.getContext("2d");//获取 context 对象
ctx.textBaseline = "bottom";//文字上下对齐方式--底部对齐
ctx.fillStyle = randomColor(180,240);//填充画布颜色
ctx.fillRect(0,0,_width,_height);//填充矩形--画画
for(var i=0; i<_num; i++){
var x = (_width-10)/_num*i+10;
var y = randomNum(_height/2,_height);
var deg = randomNum(-45,45);
var txt = _str[randomNum(0,_str.length)];
_picTxt += txt;//获取一个随机数
ctx.fillStyle = randomColor(10,100);//填充随机颜色
ctx.font = randomNum(16,40)+"px SimHei";//设置随机数大小,字体为SimHei
ctx.translate(x,y);//将当前xy坐标作为原始坐标
ctx.rotate(deg*Math.PI/180);//旋转随机角度
ctx.fillText(txt, 0,0);//绘制填色的文本
ctx.rotate(-deg*Math.PI/180);
ctx.translate(-x,-y);
}
for(var i=0; i<_num; i++){
//定义笔触颜色
ctx.strokeStyle = randomColor(90,180);
ctx.beginPath();
//随机划线--4条路径
ctx.moveTo(randomNum(0,_width), randomNum(0,_height));
ctx.lineTo(randomNum(0,_width), randomNum(0,_height));
ctx.stroke();
}
for(var i=0; i<_num*10; i++){
ctx.fillStyle = randomColor(0,255);
ctx.beginPath();
//随机画原,填充颜色
ctx.arc(randomNum(0,_width),randomNum(0,_height), 1, 0, 2*Math.PI);
ctx.fill();
}
//数字验证码的值传给一个隐藏的输入框,通过该框拿值再做对比
document.getElementById("givevalue").value=_picTxt;
return _picTxt;//返回随机数字符串
}
drawPic();
pojo
public class Comments {
/*分别代表评论内容编号、评论的时间、被评论的文章的id、评论的内容,
随机产生头像的编号,随机产生网名的编号,标题,评论的类型*/
//省略getter setter
private Integer commentsId;
private String commentsTime;
private Integer articleId;
private String commentContent;
private String givePicture;
private Integer giveScreenName;
private String title;
private Integer typeId;
}
Controller
@Controller
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ManageCommentsMapper manageCommentsMapper;
/*展示评论内容*/
@GetMapping("/show")
public String show(Model model, Integer id, HttpSession session) {
List<Comments> allComments = manageCommentsMapper.showComment(id);
model.addAttribute("commentObject",new Comments());
model.addAttribute("articleComments",allComments);
return "main";
}
}
/*写评论*/
@PostMapping("/addComment")
public String addComment(@ModelAttribute Comments comments,HttpSession session,String commentsTime,Integer articleId,String commentContent,String givePicture,Integer giveScreenName) {
Integer giveArticleId = (Integer)session.getAttribute("giveArticleId");
System.out.println("传来的id"+giveArticleId);
Integer integer = manageCommentsMapper.addComment(commentsTime,giveArticleId, commentContent, givePicture, giveScreenName);
return "redirect:/article/main";
}
dao
/*前台显示某篇文章的评论*/
@Repository
@Mapper
public interface ManageCommentsMapper {
@Select("<script>select * from comments" +
"<where>" +
" articleId = #{articleId}" +
"</where>" +
"</script>")
List<Comments> showComment(Integer articleId);
/*写评论*/
@Insert("<script> insert into comments" +
"(" +
" <if test=\"commentsTime != null\" >" +
" commentsTime," +
" </if>\n" +
" <if test=\"articleId != null\" >" +
" articleId," +
" </if>" +
" <if test=\"commentContent != null\" >" +
" commentContent," +
" </if>" +
" <if test=\"givePicture != null\" >" +
" givePicture," +
" </if>" +
" <if test=\"giveScreenName != null\" >" +
" giveScreenName" +
" </if>" +
")" +
" values" +
"(" +
" <if test=\"commentsTime != null\" >" +
" #{commentsTime}," +
" </if>\n" +
" <if test=\"articleId != null\" >" +
" #{articleId}," +
" </if>" +
" <if test=\"commentContent != null\" >" +
" #{commentContent}," +
" </if>" +
" <if test=\"givePicture != null\" >" +
" #{givePicture}," +
" </if>" +
" <if test=\"giveScreenName != null\" >" +
" #{giveScreenName}" +
" </if>" +
")" +
"</script>")
Integer addComment(String commentsTime,Integer articleId,String commentContent,String givePicture,Integer giveScreenName);
}
Mysql
它们的含义分别是:评论的id,评论的时间,被评论文章的id,评论的内容,给评论者的随机头像,给评论者的网名;
CREATE TABLE `comments` (
`commentsId` int(10) NOT NULL AUTO_INCREMENT,
`commentsTime` varchar(100) NOT NULL,
`articleId` int(10) DEFAULT NULL,
`commentContent` varchar(200) DEFAULT NULL,
`givePicture` varchar(100) DEFAULT NULL,
`giveScreenName` int(10) DEFAULT NULL,
PRIMARY KEY (`commentsId`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8