注:新版本源码在另一篇博客中:点击跳转
一、开发环境
MyEclipse8.6+WampServer+MySQL
这里用到Apache,是因为我用了他来连接数据库。
项目中还用到了一个jar包,mysql-connector-java-5.1.13-bin.jar。
二、思路介绍
下图是回复信息在数据库中存储的基本结构:
这是博主自己想的一种思路,适合一些小型网站,如果需要在大型网站上运用,需要你们考虑下如何解决数据超载的问题。
三、数据库结构
数据库名称:blog
表内容:
(1)、user表
Field | Type | Comment |
uid | int(3) NOT NULL | 用户编号(主键) |
name | varchar(10) NOT NULL | 名字 |
pwd | varchar(12) NOT NULL | 密码 |
status | int(1) NOT NULL | 身份 |
condi | int(1) NOT NULL | 用户状态 |
friend | varchar(100) NULL | 用户好友 |
userimg | varchar(100) NULL | 头像路径 |
sex | int(1) NOT NULL | 性别(0未填写1男2女)0下同 |
age | int(3) NOT NULL | 年龄 |
constellation | int(2) NOT NULL | 星座 |
addres | varchar(15) NOT NULL | 地址 |
bloodtype | varchar(5) NOT NULL | 血型 |
sign | varchar(25) NOT NULL | 头像 |
(2)usermessage表
Field | Type | Comment |
MessageId | int(5) NOT NULL | 留言id(主键) |
wuid | int(5) NOT NULL | 留言者id |
guid | int(5) NOT NULL | 被留言者id |
MessageText | text NOT NULL | 留言内容 |
ReplyMessage | text NULL | 回复内容 |
writetime | varchar(20) NOT NULL | 留言时间 |
四、html模块
(1)、通过form表单跳转到留言功能预处理模块的serverlet,表单模块代码如下
<form action="SelectMessageServlet" method="post">
<!--
手动更改value的值测试效果
value根据自己项目更改为value="<%=userid %>"的形势
注:记得删除注释,不然jsp编译会出错
-->
<input type="hidden" name="userid" value="1"/>
<input class="formliinput" type="submit" value="留言"/>
</form>
注:表带中的uid是当前登录用户的ID信息(记得删除注释,不然编译会出错)
(2)SelectMessageServlet代码介绍
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//获取当前登录用户的id
String id=request.getParameter("userid");
MyBean a=new MyBean();
//查询该用户所有留言信息
ResultSet messageinfo=a.SelectUserMessage(id);
//查询该用户的留言回复信息
Map map=a.selectUserReplyMessage(id);
//当前用户的id,name等基本信息
ResultSet userinfo=a.selectoneuser(id);
//查询所有用户信息,不含密码
ResultSet alluserinfo=a.selectallusernopwd();
HttpSession session=request.getSession();
session.setAttribute("nowuserinfo", userinfo);
session.setAttribute("messageinfo", messageinfo);
session.setAttribute("userallinfo", alluserinfo);
session.setAttribute("replymessage", map);
try {
a.con().close();
} catch (SQLException e) {
e.printStackTrace();
}
request.getRequestDispatcher("message.jsp").forward(request, response);
}
MyBean()方法,代码如下:
package control;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
public class MyBean {
Connection conn;
public MyBean() {
this.conn = con();
}
public Connection con() {//链接数据库
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//后面进行了编码声明,防止中文乱码
String sqlcon = "jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8";
try {
conn = DriverManager.getConnection(sqlcon, "root", "");
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public ResultSet selectalluser(){//无参数,查询所有用户信息
ResultSet a = null;
String sql="select * from user order by uid";
Statement st;
try {
st=conn.createStatement();
a=st.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return a;
}
public ResultSet selectoneuser(String uid){//带参数,通过uid查询用户信息
ResultSet a = null;
String sql="select * from user where uid='"+uid+"' order by uid";
Statement st;
try {
st=conn.createStatement();
a=st.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return a;
}
public ResultSet selectallusernopwd(){//无参数,查询所有用户信息
ResultSet a = null;
String sql="select uid,NAME,userimg from user order by uid";
Statement st;
try {
st=conn.createStatement();
a=st.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return a;
}
public ResultSet SelectUserMessage(String gid){//查询该用户所有留言记录,并按时间排序
ResultSet rt=null;
String sql="select * from usermessage where guid="+gid+" order by writetime DESC";
try {
Statement st=conn.createStatement();
rt=st.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return rt;
}
public Map selectUserReplyMessage(String gid){//查询留言回复信息
ResultSet rs=SelectUserMessage(gid);
ResultSet userinfo=null;
String replymessage=null;
String onereply=null;
int be = 0,en,rbe = 0,ren;
int i=1,j=1;
int alllengthnow=0;
int lengthnow=0;
String messageid=null;
boolean check1=true,check2=true;
Map map=new HashMap();
try {
while(rs.next()){
replymessage=rs.getString("ReplyMessage");
if(replymessage!=null){
messageid=rs.getString("MessageId");
alllengthnow = replymessage.length();
j=1;
en=0;be=0;
ren=0;rbe=0;
check1=true;
check2=true;
while(check1){
i=1;
rbe=0;
be=be+0;
en=replymessage.indexOf(">",be+1);
if(en==-1) check1=false;
if(be==0)
onereply=replymessage.substring(be,en+1);
else
onereply=replymessage.substring(be+1,en+1);
lengthnow=onereply.length();
check2=true;
while(check2){
rbe=rbe+0;
ren=onereply.indexOf("<",rbe+1);
if(ren==-1&&ren!=lengthnow-1)
ren=lengthnow-1;
if(ren==-1)check2=false;
if(rbe==0)
map.put(messageid+":"+j+"."+i, onereply.substring(rbe, ren));
else
map.put(messageid+":"+j+"."+i, onereply.substring(rbe+1, ren));
userinfo=selectoneuser(map.get(messageid+":"+j+".1").toString());
if(userinfo.next()){
map.put(messageid+":"+j+"."+(i+1), userinfo.getString("name"));
map.put(messageid+":"+j+"."+(i+2), userinfo.getString("userimg"));
}else{
map.put(messageid+":"+j+"."+(i+1), "");
map.put(messageid+":"+j+"."+(i+2), "");
}
i++;
if(ren==lengthnow-1)check2=false;
rbe=ren;
}
j++;
if(en==alllengthnow-1)check1=false;
be=en;
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return map;
}
public int insertmessage(String wid,String gid,String content){
int i=0;
String time=gettimenow();
String sql="insert into usermessage (wuid,guid,MessageText,writetime) values (?,?,?,?)";
try {
PreparedStatement pd=conn.prepareStatement(sql);
pd.setString(1, wid);
pd.setString(2, gid);
pd.setString(3, content);
pd.setString(4, time);
i=pd.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return i;
}
//根据messageid查询回复信息
public ResultSet selectReplyByMessageId(String messageid){
ResultSet end = null;
String sql="select * from usermessage where MessageId="+messageid;
Statement st;
try {
st = conn.createStatement();
end=st.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return end;
}
//添加留言回复功能
public int updatetmessagereply(String messageid,String wid,String content){
int end=0;
String sql="update usermessage set ReplyMessage=? where MessageId=?";
content=content.replaceAll("<", "<");
content=content.replaceAll(">", ">");
String time=gettimenow();
StringBuffer oldMessageReply=new StringBuffer();
ResultSet oldmessageinfo=selectReplyByMessageId(messageid);
try {
if(oldmessageinfo.next()){
if(oldmessageinfo.getString("ReplyMessage")!=null||oldmessageinfo.getString("ReplyMessage")==""){
oldMessageReply.append(oldmessageinfo.getString("ReplyMessage"));
}
oldMessageReply.append(wid+"<"+content+"<"+time+">");
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1, oldMessageReply.toString());
ps.setString(2, messageid);
end=ps.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
return end;
}
public String gettimenow(){//获取当前系统时间
Date a=new Date();
SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dataString=formatter.format(a);
System.out.println(dataString);
System.out.println(a.getTime());
return dataString;
}
}
注:bean方法中的留言回复功能,有时间我发一条详解,2执行完后跳转至message.jsp
(3)、message.jsp页面代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.sql.ResultSet" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>留言板</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/message.css">
</head>
<script type="text/javascript" src="js/jquery1111.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script>
var ti;
$(document).ready(
function (){
$("#userinfo").mouseover(function(){
$("#usernameshow").fadeIn(200);
});
$("#usernameshow").mouseover(function(){
clearTimeout(ti);
$("#usernameshow").show();
});
$("#usernameshow").mouseout(function(){
$("#usernameshow").hide();
});
$("#userinfo").mouseout(function(){
$("#usernameshow").stop(false,true);
ti=setTimeout(function(){
$("#usernameshow").hide();
},100);
});
$(".messageuserreply").click(function(){
var a=this.id;
$("[id$='div"+a+"']").toggle();
});
$(".cancelinput").click(function(){
$(this).parents(".messageuserreplydiv").hide();
});
});
</script>
<body>
<%
String name="NULLUSER";
ResultSet userinfo=null;
ResultSet messageinfo=null;
ResultSet userallinfo=null;
Map map=new HashMap();
Iterator it=null;
Set keySet=null;
int i=1;
if(session.getAttribute("nowuserinfo")!=null){
userinfo=(ResultSet)session.getAttribute("nowuserinfo");
userinfo.beforeFirst();
userinfo.next();
name=userinfo.getString("name");
}
if(session.getAttribute("messageinfo")!=null){
messageinfo=(ResultSet)session.getAttribute("messageinfo");
}
if(session.getAttribute("userallinfo")!=null){
userallinfo=(ResultSet)session.getAttribute("userallinfo");
}
if(session.getAttribute("replymessage")!=null){
map=(Map)session.getAttribute("replymessage");
keySet=map.keySet();//获取键的集合
it=keySet.iterator();//迭代键的集合
while(it.hasNext()){
Object key=it.next();
Object value=map.get(key);//获取每个键所对应的值
System.out.println(key+":"+value);
}
}
%>
<div id="bigtop">
<div id="top">
<div id="topcontentleft">
<div class="topbg">
<a>博客首页</a>
</div>
</div>
<div id="topcontentright">
<div id="userlogininfo">
<span class="welcomeuser">欢迎你,</span>
<span id="userinfo"><%=name %></span>
<div class="showdivuserinfo">
<ul id="usernameshow" style="display:none">
<li>个人中心</li>
<li>这是测试</li>
<li style="border:0px">注销登录</li>
</ul>
</div>
</div>
<div>
<ul class="topul">
<li>
<div class="nrmessage">消息中心<span class="badge">3</span></div>
</li>
<li style="border-right: none"><a href="#">退出登陆</a></li>
</ul>
</div>
</div>
</div>
</div>
<div id="content">
<div><!-- 留言展示内容 -->
<div class="MessagecontentBigBox"><!-- 内容外层div -->
<div class="MessagecontentBigBox-top">
<font>留言板</font>
</div>
<script type="text/javascript">
function checkdata(){
var a=document.getElementById("messagecontent").value;
if(a==null||a==""){
alert("输入不能为空!发布失败。");
return false;
}
}
</script>
<div class="messageinfodiv">
<div class="publishmessage">
<form action="AddMessageBy" method="post" onsubmit="return checkdata()">
<div class="publishmessagein"><textarea maxlength="60" rows="" cols="" id="messagecontent" name="messagecontent"></textarea></div>
<div class="publishmessagebutton"><input type="submit" value="发送">
<input type="reset" value="取消"> </div>
</form>
</div>
<ul>
<%
int idi=1;
while(messageinfo.next()){
String thisuserid=null;
String thisusername=null;
String thislogurl=null;
String thismessagecontent=null;
String thismessagereply=null;
String thismessageid=null;
if(messageinfo.getString("wuid")!=null||messageinfo.getString("wuid")!=""){
thisuserid=messageinfo.getString("wuid");
while(userallinfo.next()){
if(userallinfo.getString("uid").equals(messageinfo.getString("wuid"))){
thisusername=userallinfo.getString("name");
thislogurl=userallinfo.getString("userimg");
thismessagecontent=messageinfo.getString("MessageText");
thismessagereply=messageinfo.getString("ReplyMessage");
thismessageid=messageinfo.getString("MessageId");
break;
}
}
userallinfo.beforeFirst();
}
%>
<li class="thismessageinfodiv">
<img src="<%=thislogurl %>" class="messageuserimg"/>
<font class="messageusername"><%=thisusername %></font>
<br/>
<p class="messageusercontent">
<c:out value="<%=thismessagecontent %>" escapeXml="true" default="加载失败,请重试!"></c:out>
</p>
<p class="messageusertime"><%=messageinfo.getString("writetime") %></p>
<font class="messageuserreply" id="<%=idi %>">回复</font>
<%
if(thismessagereply!=null){
i=1;
keySet=map.keySet();//获取键的集合
it=keySet.iterator();//迭代键的集合
//System.out.print(it.hasNext());
%>
<div class="messagereplydiv">
<%
while(it.hasNext()){
Object key=it.next();
Object value=map.get(key);//获取每个键所对应的值
Object srcurl=map.get(thismessageid+":"+i+".5");
Object thisname=map.get(thismessageid+":"+i+".4");
Object thisreplycontent=map.get(thismessageid+":"+i+".2");
Object thisreplytime=map.get(thismessageid+":"+i+".3");
System.out.print(thisname);
if(srcurl==null)break;
%>
<img class="messagereplyimg" src="<%=srcurl %>">
<font class="messagereplyname"><%=thisname %></font>
<font class="messagereplycontent"><%=thisreplycontent %></font>
<p class="messagereplytime"><%=thisreplytime %></p>
<% i++; } %>
</div>
<% } %>
<div class="messageuserreplydiv" id="replybigdiv<%=idi %>" style="display: none">
<form action="MessageUserReply" method="post" id="replymessageform">
<!-- <form action="" method="post" id="replymessageform<%=thismessageid %>"> -->
<input type="hidden" name="thismessageid" value="<%=thismessageid %>" />
<textarea rows="" cols="" id="replycontent" name="replycontent"></textarea><br/>
<input type="submit" value="确定">
<input type="reset" value="取消" class="cancelinput">
</form>
<script>
$(document).ready(function(){
$('#replymessageform<%=thismessageid %>').submit(function(){
$msid=$("#replymessageform<%=thismessageid %> input[name='thismessageid']").val();
if($msid!=<%=thismessageid %>){return false;}
});
});
</script>
</div>
</li>
<% idi++; } %>
</ul>
</div>
</div>
</div>
</div>
</body>
</html>
注:1、id="replybigdiv<%=idi %>"的表单为回复模块的前端代码
(3)发表留言功能,AddMessageBy代码介绍。这部分需根据自己的项目灵活更改,我这里做了一个用户自己给自己留言的方法。如需要在用户好友的留言板上留言,需要做一个好友互访的模块,然后根据这部分代码为参考,实现好友互相留言的功能。
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
HttpSession session=request.getSession();
ResultSet userinfo = (ResultSet)session.getAttribute("nowuserinfo");
String wid = null,id = null;
try {
userinfo.beforeFirst();
userinfo.next();
wid = userinfo.getString("uid");
id=userinfo.getString("uid");
userinfo.beforeFirst();
} catch (SQLException e1) {
e1.printStackTrace();
}
String content=request.getParameter("messagecontent");
MyBean a=new MyBean();
// uid为当前登录用户的id,即留言者的id
//wid为被留言者的id
//这里的留言者id和被留言者id为同一个,因为我么有做好友交互的界面
//通过好友交互的界面,将好友的id赋值给wid即可
int end=a.insertmessage(wid, id, content);
ResultSet messageinfo=a.SelectUserMessage(id);
ResultSet alluserinfo=a.selectallusernopwd();
session.setAttribute("nowuserinfo", userinfo);
session.setAttribute("messageinfo", messageinfo);
session.setAttribute("userallinfo", alluserinfo);
try {
a.con().close();
} catch (SQLException e) {
e.printStackTrace();
}
if(end==1){
out.print("<script>");
out.print("alert('留言发布成功!');");
out.print("window.location.href='message.jsp';");
out.print("</script>");
}else{
out.print("<script>");
out.print("alert('Erron!留言失败!');");
out.print("window.location.href='message.jsp';");
out.print("</script>");
}
}
(4)、留言回复功能,MessageUserReply代码介绍
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
HttpSession session=request.getSession();
ResultSet userinfo=(ResultSet)session.getAttribute("nowuserinfo");
String wid = null;
try {
userinfo.beforeFirst();
userinfo.next();
wid=userinfo.getString("uid");
} catch (SQLException e) {
e.printStackTrace();
}
String content=request.getParameter("replycontent");
String messageid=request.getParameter("thismessageid");
MyBean a=new MyBean();
int end=a.updatetmessagereply(messageid, wid, content);
ResultSet messageinfo=a.SelectUserMessage(wid);
//ResultSet userinfo=a.selectoneuser(wid);
ResultSet alluserinfo=a.selectallusernopwd();
Map map=a.selectUserReplyMessage(wid);
session.setAttribute("nowuserinfo", userinfo);
session.setAttribute("messageinfo", messageinfo);
session.setAttribute("userallinfo", alluserinfo);
session.setAttribute("replymessage", map);
request.getRequestDispatcher("message.jsp").forward(request, response);
}
注:Mybean a = new MyBean();中mybean方法在2步骤中
五、css样式部分
项目中引入了bootstrap.min.css样式,我这里就没有列了,可去起步网官网下载下载。下面我展示的是message.css的内容。
@CHARSET "UTF-8";
*{
margin:0px;
padding:0px;
letter-spacing:0.2em;
}
body{
line-height: inherit;
background-image:url(../img/back.jpg);
}
a:link{
color:#FFF;
text-decoration:none;
}
a:visited{
color:#FFF;
text-decoration:none;
}
a:hover{
color:#FFF;
text-decoration:underline;
}
a:active{
color:#FFF;
text-decoration:none;
}
#bigtop{
width: 100%;
height: 45px;
background-color: rgba(20, 20, 20, 0.9);
position: fixed;
top: 0px;
left: 0px;
z-index: 999;
}
#top{
width:960px;
height:45px;
margin:0px auto;
color:#FFF;
}
#bigtopdiv{
margin:0px auto;
height:45px;
}
#topcontent{
margin:0px auto;
background-color:#666;
height:auto;
}
#topcontentleft{
width:40%;
height:auto;
float:left;
}
#topcontentright{
font-size:12px;
line-height:45px;
width: 35%;
height:45px;
float:right;
text-align:left;
}
.topbg{
float:left;
line-height:45px;
cursor: pointer;
}
.topbg a{
}
.topul{
float:left;
margin-bottom: 0px;
}
.topul li{
list-style:none;
height:45px;
float:left;
padding: 2px;
border-right:2px solid #595353;
}
.topul li:hover{
background-color:#000000;
}
.topul li div{
padding:0px 5px;
height:45px;
}
.topul li div img{
height:28px;
vertical-align: middle;
margin-top:8px;
}
.nrmessage span{
position: relative;
left: -3px;
top: -8px;
}
#userlogininfo{
height:45px;
float:left;
padding:0px 5px;
border-right:2px solid #595353;
display:inline-flex;
display: -webkit-inline-flex;
}
.welcomeuser{
float: left;
}
#userinfo{
display: block;
margin:0px 5px;
width:auto;
height:45px;
padding:0px 10px;
cursor:pointer;
background-color:#ff0000;
color: #ffffff;
border-bottom:5px solid #5D5D5D;
box-shadow:0px -8px 8px #000000;
float: left;
}
#userinfo img{
height:30px;
width:30px;
border-radius:100%;
margin-right:5px;
padding-top:7px;
}
#userinfo:hover{
background-color:#000000;
}
#content{
width:960px;
height:auto;
margin:0px auto;
margin-bottom:50px;
}
.showdivuserinfo{
position:absolute;
color:black;
margin-top:50px;
width: 120px;
z-index: 9999;
margin-left: 65px;
}
.showdivuserinfo ul{
width:120px;
box-shadow: 0px 0px 10px;
border-radius:5px;
background-color:rgba(255, 255, 255, 0.93);
}
.showdivuserinfo li{
list-style:none;
border-bottom:1px dashed #CCC;
text-align:center;
font-size:18px;
z-index: 100;
cursor: pointer;
}
.MessagecontentBigBox{
width:960px;
margin-top:110px;
background-color: white;
padding-bottom: 15px;
}
ul{
list-style: none;
}
.MessagecontentBigBox-top{
widows: 100%;
height: 40px;
background-color: rgba(236,236,236,0.39);
padding:13px 0px 0px 5px;
}
.MessagecontentBigBox-top font{
font-size: 14px;
font-weight: bold;
}
.messageinfodiv{
width: 100%;
margin:0px auto 20px auto;
}
.publishmessage{
margin: 0px auto 10px auto;
padding:5px;
}
.publishmessage form{
margin: 0px auto;
width: 96%;
}
.publishmessagein{
}
.publishmessagebutton{
margin-top: 10px;
}
.publishmessagebutton input{
border:0px;
background-color: #7B8C9E;
color: white;
padding:5px;
}
.publishmessage textarea{
font-size: 18px;
letter-spacing: 0.2em;
width: 100%;
height: 100px;
max-width: 100%;
max-height: 240px;
min-width: 100%;
min-height: 70px;
}
.thismessageinfodiv{
padding: 5px;
width: 96%;
border-bottom: 1px solid #CCC;
margin: 0px auto 5px auto;
}
.messageuserimg{
width: 50px;
height: 50px;
float: left;
margin-left: 5px;
border-radius: 5px;
}
.messageusername{
font-size: 16px;
margin-left: 5px;
}
.messageusercontent{
padding-bottom: 5px;
padding-left: 65px;
font-size: 18px;
letter-spacing: 0.3em;
margin-top: 20px;
overflow-wrap: break-word;
}
.messageusertime{
clear: both;
display: inline;
padding-left: 60px;
}
.messageuserreply{
margin-left: 20px;
color: blue;
cursor: pointer;
}
.messageuserreplydiv{
clear: both;
margin-left:55px;
padding-bottom: 5px;
}
.messageuserreplydiv textarea{
width: 320px;
height:30px;
}
.messageuserreplydiv input{
margin-top:5px;
}
.messagereplydiv{
width: 90%;
border-top: 1px solid #CCC;
margin: 5px auto 0px auto;
padding:5px;
}
.messagereplyimg{
width: 40px;
height: 40px;
}
.messagereplyname{
color: blue;
}
.messagereplytime{
padding-left: 46px;
}
#replycontent{
height: 80px;
width: 450px;
max-height: 160px;
max-width: 100%;
}
六、运行效果
七、结语
内容有点长,后续我会持续更新,进行缩减。最后感谢大家的支持。如果有什么问题不懂得或者有更好的建议,欢迎看官评论或私信。如果各位需要整个项目源码的,请加qq群在群文件里面自行免费下载。群号:100372253