1)我们在java目录里面存放后端的Servlet代码,在webapp里面存放前端的代码
2)服务器渲染:所有的前端动态页面都是由服务器来进行动态生成的,就非常需要模板引擎;
优势:省事,浏览器拿到的就是一个完整的页面,不需要和服务器之间进行多次交互
缺点:没有进行完全分离,前后端耦合比较强,前端要写要关心后端代码;
3)前后端分离:静态页面和动态页面都是由浏览器进行渲染的,服务器只是给浏览器提供一些数据,然后浏览器会结合当前拿到的页面和服务器返回的数据进行综合分析,进行封装,构造前端页面
优势:前端和后端进行完全分离,只需要约定好交互接口就行了
劣势:浏览器和服务器之间可能要进行多次的数据交互,每次走的是HTTP,开销较大,比较吃带宽(合理设计来进行简化)(可以通过一些,尤其是大型项目,前后端分离十分必要,沟通成本太高;
1)比如说一个项目的实现,每一次模块的实现都是给基于前后端分离来进行实现的,如果不进行处理,每一次访问页面的特定功能加载都会特别卡,页面加载时间就会取决于最慢的那次请求;
2)如果这个板块进行折叠起来,就不去进行获取数据,当用户点击这个模块展开的时候,才会进行发送Http请求给服务器;
1)当浏览器发送数据给服务器的时候,会先进行访问入口服务器, 入口服务器与应用服务器之间相当于是基于前后端分离的方式来进行的,一个入口服务器可能会从多个应用服务器哪里来进行获取数据;
2)入口服务器会根据在多个应用服务器那边拿到的业务数据进行汇总,基于模板引擎的方式来进行渲染出页面,这样的页面渲染效果也是基于前端来进行实现的,然后浏览器会给服务器返回一个html字符串,在浏览器上面就可以进行显示了;
3)缺点:NodeJs技术还不够成熟,整体方案实施和部署比较复杂,门槛会更高
1.创建maven项目
2.创建目录结构并引入依赖
1)在main目录里面创建webapp目录(与Java目录是同级目录),再从webapp目录里面创建WEB-INF目录,创建web.xml文件
2)改pom.xml,我们要用到Servlet(3.1.0),MYSQL(5.1.47),Tymleaf,Jackson(2.13.0),Ajax(前端代码)
3.打包部署基于SmartTomact来进行
4.我们可以把服务器渲染的一些可以进行重用的代码给进行拷贝过来
1)数据库操作,数据库在两个版本的操作代码实现都是一样的,直接拷贝过来就可以了
2)前端代码,把之前写的纯前端页面给进行拷贝过来,全部拷贝到webapp目录里面
1)实现博客列表页
2)实现博客详情页
3)实现博客登录页
4)实现博客登陆检查
5)实现显示用户信息
6)实现注销功能
7)实现发布博客
8)实现删除博客
5. 实现博客列表页
1)让我们当前的这个博客列表页面,给服务器来进行发送一个ajax这样的请求,服务器进行处理这个请求,就会从数据库里面查询到博客列表,把数据以Json的形式来返回给浏览器
2)我们在让浏览器根据发送过来的Json数据,拼接HTML,得到最终的页面;所以我们要约定好前后端进行交互的接口,请求是啥样子的,响应是啥样子的,客户端和服务器就可以按照约定好的请求来进行开发
请求:GET/blog1Servlet
响应:Http/1.1 200 OK
Content-Type=application/json;charset=utf-8;
JSON格式的数据如下 { { blogID:1, content:TCP/IP, title:ABC, postTime:2022/12/2/10:25, userID:1, } { blogID:2, content:TCP/UDP, title:ABCDEFGHIGK, postTime:2023/1/1/23:09, userID:1, } }
1)我们在这里面客户端就要按照这个约定,来进行构造请求,服务器也需要按照这个约定,来进行解析请求,构造响应,此处的前后端交互接口的约定,可以有很多种不同的交互方式;
请求方法不用GET,用POST,都是可以;
2)Jackson会根据每个Blog成员字段的名字来进行构造Json格式的字符串,我们举一个例子,Blog里面有blogID这个属性,blogID这一个变量名,就作为Json数据中的Key,blogID这个对象的值,就作为Json数据的Value;
3)总而言之Json里面的Key的名字和实体类里面的属性名字要保持一致;
4)一个Blog对象对应的就是一个Json对象,一个List<Blog>得到的就是一个Json数组;
5)发现了当前的预期的时间是一个格式化时间,当前得到的是一个毫秒级的时间戳,这个问题,我们可以在服务器这边把时间戳转化成格式化的时间SimpleDataFormat类可以进行负责时间日期的格式化转换,这里我们在前端进行写一个函数来进行处理,把时间戳转换成时间格式化;
服务器代码:
import MYSQL.Blog;
import MYSQL.OperateBlog;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
@WebServlet("/blog1Servlet")
public class blog1Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
ObjectMapper mapper=new ObjectMapper();
OperateBlog operateBlog=new OperateBlog();
//1.从数据库里面查询数据
List<Blog> list = null;
try {
list = operateBlog.SelectAll();
} catch (SQLException e) {
e.printStackTrace();
}
//2把list中的Blog转成json数据数组返回到响应数组里面
// String jsonstring=mapper.writeValueAsString(list);
// resp.getWriter().write(jsonstring);
mapper.writeValue(resp.getWriter(),list);
}
}
客户端代码:
1)此时回调函数的function中的data参数表示响应的body,status就表示相应的状态码描述
2)我们要根据相应的body内容来进行构造出一个HTML片段,此时我们预期的data不是一个String数组,而是一个json数组,这一点是因为服务器返回的数据类型,application/json;
<!-- 先引入对Ajax的依赖 -->
<script
src="https://code.jquery.com/jquery-3.6.0.js"
integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
crossorigin="anonymous"></script>
<script>
// 我们这里是基于Ajax的方式来向服务器获取数据的
function load(){
//1通过ajax给服务器发送获取博客列表的请求
$.ajax({
type:"GET",
url:"blog1",
success:function(data,status)
{ for(let message of data){
console.log(status);
let right=document.querySelector(".right");
let blog=document.createElement("div");
blog.className="blog";
let h2=document.createElement("h2");
h2.className="title";
h2.innerHTML=message.title;
let date=document.createElement("div");
date.className="date";
date.innerHTML=getFormatDateTime(message.postTime);
let text=document.createElement("text");
text.className="text";
text.innerHTML=message.content;
let a=document.createElement("a");
a.className="detail";
a.target="_blank";
a.href="blog2.html?blogID="+message.blogID;
a.innerHTML="查看全文 > >";
blog.appendChild(h2);
blog.appendChild(date);
blog.appendChild(text);
blog.appendChild(a);
right.appendChild(blog);
}
function getFormatDateTime(Time){
var date = new Date(Time);//中的标准库的类,再通过访问属性获取到年月日,最后通过字符串进行拼接返回
var year= date.getFullYear();
var month = date.getMonth() + 1;//月份是从0开始的
var day = date.getDate();
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
return [year, '-', month , '-', day, ' ', hour , ':', minute, ':', second ].join('');
}
}
});
}
load();
</script>
1.我们可能遇到这种情况,可能说博客内容太多导致博客溢出,这时我们就需要加上overflow:auto;表明内容溢出是加上滚动条;
2.首先我们在网络上输入blog1.html,会首先给服务器发送一个GET请求,想要访问博客列表页,服务器会将blog1.html进行返回
3.浏览器解析html,执行JS代码,发送AJAX(这里的路径和WebServlet的路径要相同)请求,服务器再把博客列表数据以JSON的格式将博客列表数据进行返回
4浏览器在拿到博客列表数据之后,会把页面的内容给构造完整,就不会向模板渲染那样,直接从服务器那边拿到完整的数据了;
2.实现博客详情页
1)前后端交互接口
请求:a.href="blog2.html?blogID="+message.blogID;
1.1真正的请求是在博客列表页进行发送,当用户点击查看全文,先进行跳转到博客详情页,这个过程浏览器先给服务器发送了一个GET请求,请求得到blog2.html这个界面
1.2浏览器进行解析这个代码,执行到<script>标签里面的函数,再通过Ajax向服务器发送GET请求,服务器就会返回一个JSON格式的字符串;
响应:还是一个JSON格式的字符串,返回的是一篇博客,不是一个Json数组,然后浏览器自己进行字符串的拼接,响应的数据格式如下:
{ blogID:1, content:TCP/IP, title:ABC, postTime:2022/12/2/10:25, userID:1, }
实现后端代码:
1)我们提供一种思路,之前针对/blog1,是用来处理博客列表也的请求,现在我们希望这个类也能进行处理博客详情页的请求,我们就可以根据请求中的querystring是否带有blogID这样的参数,来区分是获取到博客列表页,还是详情页;
2)我们希望在这个页面进行加载的过程中,给服务器发送一个ajax请求,来进行获取到这篇博客的详细内容,并在页面上进行展示;
import MYSQL.Blog;
import MYSQL.OperateBlog;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
@WebServlet("/blog2")
public class blog2Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1先获取到querystring中的参数
resp.setContentType("application/json;utf-8");
String blogID=req.getParameter("blogID");
OperateBlog operateBlog=new OperateBlog();
ObjectMapper mapper=new ObjectMapper();
try {
//2根据请求中的参数
Blog blog=operateBlog.SelectOne(Integer.parseInt(blogID));
String jsonString= mapper.writeValueAsString(blog);
resp.getWriter().write(jsonString);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
实现前端代码的时候:
1)我们要注意一个问题,当我们进入到博客详情页的时候,就需要给服务器发送ajax请求来进行获取到博客数据,此时这个URL必须要在请求报文中有querystring,况且有blogID这个参数;那么怎么来进行获取到这个参数呢?
2)这个参数其实就在博客列表页中的a标签触发查看全文按钮之后,就带上了一个blogID这样的参数,我们把这个请求中的参数拿到,再进行拼接到ajax的请求即可;
3)我们拿到当前页面的querystring,在Js中就要通过location.search("?blogID=xxx")
浏览器会进行缓存我们之前写的HTML,当我们进行修改HTML的时候,必须进行强制刷新,如果不是缓存导致的问题,我们还可以通过Fidder抓包的方法来进行查看请求是啥样的,响应是啥样子的,看看请求和响应;
如果说请求不符合预期,那么就是前端的问题;
如果说响应不符合预期,那么就是后端的问题;
如果说请求和响应都符合预期,那么还是前端的问题;
4)调整代码让时间按照格式化时间来进行显示,让正文按照markDown的形式来进行渲染;
引入editor.md
5)我们还可以在id=contentx标签中加上background-color:transparent;
一:每一个博客列表页的a标签,当点击查看全文之后, 发送的请求类似于a href="blog2.html?blogID=1,2,3",每一篇博客的下面的查看全文按钮的blogID都是不一样的------客户端通过a标签里面的href属性访问博客详情页,然后服务器会返回一个html界面;
二:当浏览器拿到这个html界面之后,会执行script标签里面的代码,触发ajax请求,会给服务器发送GET请求,a href="blog2?blogID=1,2,3";后端代码会拿到一个BlogID,并通过查询数据库的方式,会返回一个Blog形式的Json格式的字符串;
三:当前端拿到这个JSON格式的数据之后,运用DOMAPI来进行前端页面的拼接;
<!-- 右侧是博客详情页,这个div表示右侧版新的整个背景 -->
<div class="right">
<div class="blog">
<!-- 文章标题 -->
<h3></h3>
<!-- 博客发布时间 -->
<div class="date"></div>
<!-- 博客正文 -->
<div class="content" id="content1"></div>
</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.6.0.js"
integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
crossorigin="anonymous"></script>
<script>
function load(){
$.ajax({
method:"GET",
url:'blog2'+location.search,
success:function(data,status)
{
console.log(status);
//结合HTML页面来进行字符串拼接
let right=document.querySelector(".right");
let blog=document.querySelector(".blog");
let h3=document.querySelector("h3");
h3.innerHTML=data.title;
let date=document.querySelector(".date");
date.innerHTML=getFormatDateTime(data.postTime);
let content=document.querySelector(".content");
content.innerHTML=data.content;
}
});
}
load();
function rendMo(){
//1先取出div里面的内容
let markDownDiv=document.querySelector("#content1");
let markdown=markDownDiv.innerHTML;
console.log(markdown);
//2把div里面的内容设成空
markDownDiv.innerHTML="";
//3进行替换,把得到的内容按照markdown的内容来进行渲染,放到id为content的标签页里面
editormd.markdownToHTML('content1',{
markdown:markdown
});//第一个参数表示ID
}
rendMo();
function getFormatDateTime(Time){
var date = new Date(Time);//中的标准库的类,再通过访问属性获取到年月日,最后通过字符串进行拼接返回
var year= date.getFullYear();
var month = date.getMonth() + 1;//月份是从0开始的
var day = date.getDate();
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
return [year, '-', month , '-', day, ' ', hour , ':', minute, ':', second ].join('');
}
</script>
3.实现博客登录页
一:当我们来写前后端分离的项目的时候,虽然在大部分情况下,浏览器和服务器的交互是通过JSON来进行完成的,但是也是可以通过form表单的方式来进行交互
二:我们在这里面实现的登陆界面的逻辑和之前是一样的,不需要通过ajax来向服务器进行获取数据,只需要让服务器来进行处理一下登录请求即可1)前后端交互的接口,在前端我们直接通过form表单提供的POST请求就可以直接传递用户名和密码了,我们还要个输入框的哪个标签加上name属性
请求格式 POST/login Content-Type:application/x-www-form-urlencoded name=admin&password=123 响应格式:登陆成功,直接重定向到博客列表页 HTTP/1.1 302 Location:blog1.html
但是服务器这边的代码,和我们之前写的登陆代码是相同的
<h3>登录</h3>
<form action="login" method="post">
<div class="row">
<span >用户名</span><input type="text" name="username">
</div>
<div class="row">
<span>密码</span><input type="password" name="password">
</div>
<div class="row">
<input type="submit" value="提交" id="submit">
</div>
</form>
WebServlet("/login")
public class loginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1先获取到请求中的参数包括用户名和密码
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String username=req.getParameter("username");
String password=req.getParameter("password");
System.out.println(username);
System.out.println(password);
if(username==null||username.equals("")||password==null||password.equals(""))
{ String html="<h3>当前的用户名错误或者密码错误</h3>";
resp.getWriter().write(html);
return;
}
//2获取到参数之后,我们再进行判断当前密码是否正确
OperateUser operateUser=new OperateUser();
User user=null;
try {
user=operateUser.selectByName(username);
} catch (SQLException e) {
e.printStackTrace();
}
if(user==null)
{
String html="<h3>当前的用户名或者密码错误</h3>";
resp.getWriter().write(html);
return;
}
if(!user.getPassword().equals(password))
{
String html="<h3>当前的用户名或者密码错误</h3>";
resp.getWriter().write(html);
return;
}
//3代码走到了这里,说明用户登陆成功了,咱们就可以具体进行设置HttpSession回话了
HttpSession httpSession=req.getSession(true);
httpSession.setAttribute("user",user);
resp.sendRedirect("blog1.html");
}
}
4.实现登陆检测---我们让博客列表页和博客登录页都让其在登陆状态下进行检测(检测httpsession中的user是否为空);
1)我们需要让博客列表页和博客详情页都能够在登陆状态下进行使用,如果用户没有进行登录,那么就直接重定向到博客列表页
2)我们先会进行访问博客列表页,当我们进行点击查看全文的时候,会发送一个ajax,当服务再进行处理ajax请求的时候,会进行检测用户是否登录,并会进行检测用户的登录状态
3)让前端页面来获取到这个登陆状态,如果没有进行登录,就直接跳转到登录页面;
4)实现服务器渲染的方式检测登陆状态是让服务器之间进行重定向,但是我们当前实现的前后端分离的方式是依靠前端代码来进行完成重定向操作;
5)那么我们该如何让客户端知道当前用户是出于未登录状态呢?
例如,我们可以通过状态码来进行设置,正常访问的时候,状态码是200,但是如果当前处于未登录的状态,我们就直接返回一个403的状态码;此时浏览器就会根据这个403的状态码来进行处理了;
如果说得到的状态码是200,那么我们接下来就继续进行渲染页面,如果说状态码是403
我们直接跳转到登陆界面;
后端代码:
resp.setContentType("application/json;utf-8");
HttpSession httpSession=req.getSession(false);
if(httpSession==null||httpSession.equals(""))
{
resp.setStatus(403);
String html="<h3>当前用户没有进行登录</h3>";
resp.getWriter().write(html);
return;
}
User user=(User)httpSession.getAttribute("user");
if(user==null||user.equals(""))
{
resp.setStatus(403);
String html="<h3>当前用户没有进行登录</h3>";
resp.getWriter().write(html);
return;
}
1)这时候服务器会给浏览器发送一个状态码为403,但是我们看之前写的AJAX代码就发现,里面有一个请求成功的回调函数success:function(data,status),但是在这里面服务器响应失败,这就不能算是响应成功,我们就要使用其他的函数
2)error,是一个请求失败的时候自动进行调用的回调函数,相当于我们在请求中的ajax里面加上了一个error这样的属性;
error:function(data,status) { console.log("进入到error函数:"+status); //此时我们就可以进行页面的重定向跳转即可 //这个操作就是在前端实现重定向 location.assign("blog3.html"); }
5.显示用户的登录信息和作者的信息(我们需要在博客列表页和博客详情页分别要发送两个AJAX来进行获取数据)
1)实现博客列表页的用户身份信息(HttpSession中的user对象就是当前用户的登陆者)
首先我们要约定好前后端进行交互的格式
请求:GET/User
响应:又是一个Json格式的字符串
获取到当前的登陆的用户的信息,这个要在博客列表页使用 { userID:1, name:"zhangsan", password:"12503487", }
2)实现显示博客详情页的作者的身份信息(根据传过来的BlogID来进行获取到当前当前文章的作者)
1)请求:GET/User?blogID=1,2,3,4......
响应:和上边的格式一样:
基于上述两种请求,我们是写一个Servlet来进行实现的,如果进行获取到的BlogID为空,那么这个请求说明就是博客列表页发送过来的请求;
如果获取到的BlogID不为空,那么就说明这个请求就是博客详情页发送过来的请求;我们基于if else语句来进行处理两份代码;
2)后端代码我们要写一份,但是前端代码我们要分别在博客列表页和博客详情页来进行编写
<script> $.ajax({ url:"user", method:"GET", //博客详情页是这样的url:"user"+location.search, //根据响应的中得到的Json数据,从而进行前端页面的拼接 success:function(data,status) { console.log(status); let username=document.querySelector(".username"); username.innerHTML=data.name; } }); </script>
客户端的前端代码是相同的
@WebServlet("/user") public class UserWriteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //先进行检测用户是否进行了登录 HttpSession session=req.getSession(false); if(session==null||session.equals("")) { resp.sendRedirect("blog3.html"); return; } User user=(User)session.getAttribute("user"); if(user==null||user.equals("")) { resp.sendRedirect("blog3.html"); return; } //获取请求中的参数 resp.setContentType("application/json;charset=utf-8"); String blogID=req.getParameter("blogID"); ObjectMapper mapper=new ObjectMapper(); if(blogID==null||blogID.equals("")) { //处理博客列表页发送过来的请求 String userreturn=mapper.writeValueAsString(user); resp.getWriter().write(userreturn); }else{ //处理博客详情页发送过来的请求 OperateUser operateUser=new OperateUser(); OperateBlog operateBlog=new OperateBlog(); //先根据BlogID来进行从数据库中获取到Blog,再根据blog中的userID来进行获取到User对象 Blog blog=null; User user1=null; try { blog=operateBlog.SelectOne(Integer.parseInt(blogID)); user1=operateUser.selectByUserID(blog.getUserID()); } catch (SQLException e) { e.printStackTrace(); } String userreturn= mapper.writeValueAsString(blog); resp.getWriter().write(userreturn); } } }
我们在这里面又发现了一个问题,我们进入博客列表页或者博客详情页的时候,坐上角的名字有一个快速闪烁的过程,这个名字,默认的是一个名字,但是随着响应的到来,里面的内容就进行了替换;Ajax的响应是非常慢的----删除里面的内容
6.实现注销功能
约定好前后端交互接口:
请求:GET/deleteuser
响应:Http/1.1 302
location:blog3.html
后端需要做的事情就是把session中的user对象给删了
@WebServlet("/deleteuser")
public class DeleteUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/htmk;charset=utf-8");
HttpSession httpSession=req.getSession(false);
if(httpSession.equals("")||httpSession==null)
{
System.out.println("当前用户没有进行登录");
resp.sendRedirect("blog3.html");
return;
}
User user=(User)httpSession.getAttribute("user");
if(user==null||user.equals(""))
{
System.out.println("当前用户没有进行登录");
resp.sendRedirect("blog3.html");
return;
}
httpSession.removeAttribute("user");
resp.sendRedirect("blog3.html");
}
}
7.实现发布博客
约定前后端进行交互的接口
请求:
POST/sendblog
Content-Type:application/x-www-form-urlencoded
title=xxxxxxx&content=XXXXX
响应:
Http/1.1 302
location:blog1.html
前端代码加上form表单,name属性,提交按钮;
@WebServlet("/sendblog") public class sendblog extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //先进行检测用户是否进行了登录 HttpSession session=req.getSession(false); if(session==null||session.equals("")) { resp.sendRedirect("blog3.html"); return; } User user=(User)session.getAttribute("user"); if(user==null||user.equals("")) { resp.sendRedirect("blog3.html"); return; } resp.setContentType("text/html;charset=utf-8"); req.setCharacterEncoding("utf-8"); String title=req.getParameter("title"); String content=req.getParameter("content"); if(title==null||title.equals("")||content.equals("")||content==null) { resp.getWriter().write("<h3>输入的文章标题和文章内容是有缺失的</h3>"); return; } //构造Blog对象插入到数据库中 Blog blog=new Blog(); blog.setPostTime(new Timestamp(System.currentTimeMillis())); blog.setTitle(title); blog.setContent(content); blog.setUserID(user.getUserID()); OperateBlog operateBlog=new OperateBlog(); try { operateBlog.insert(blog); resp.sendRedirect("blog1.html"); } catch (SQLException e) { e.printStackTrace(); } } }
<form action="sendblog" method="POST"> <div class="edit"> <div class="writetitle"> <input type="text" id="title" name="title"> <input type="submit" value="点击发布文章" id="submit"> </div> <div id="editor"> <textarea style="display:none" name="content"></textarea> </div> </div> </form> <script> //首先要初始化编译器 //先创建出一个textinner对象 //editormd相当于是一个函数,生成一个editor对象 //第一个参数是要指定放到哪一个html标签中,元一个html标签关联,参数就是对应的ID; var editor=editormd("editor", { //这里的尺寸必须在这里设置,不能依靠CSS进行设置 width:"100%", // 这是计算makdown正文的高度 height:"1000px", //编辑器的初始内容 markdown:"#在这里写一下第一篇博客", //编译器所用的插件所在的路径 path:"editor.md/lib/", saveHTMLToTextArea:true//把markdown把里面的内容放到textarea里面 });
8.实现删除博客
1)我们需要在博客详情页中的导航栏里面加一个删除按钮,如果说当前的登陆的用户是文章作者,那么就会删除按钮显示,否则就会被隐藏
2)点击删除按钮,发送一个HTTP请求,服务器调用数据库,进行删除博客;
3)我们在博客详情页中发送AJAX请求进行删除,在服务器返回的Json字段中加上isYourBlog属性(在请求获取文章信息的时候的AJAX),如果是1的话那么就是你自己写的博客,如果是0的话就说明不是自己写的博客,这个属性就决定了是否显示这个按钮;
第一个请求:
{ userID:1, name:"zhangsan", password:"12503487", isYourBlog:1 }
第二个接口:使用Http的Delete方法(触发了a标签的GET请求)
DELETE/deleteblog?blogID=1;
我们在服务器使用Http的DELETE方法来进行决定是否删除博客;
响应:
Http/1.1 200
1)先向User对象中加入isYourBlog这个字段,提供Set和Get方法
private int isYourBlog; public int getIsYourBlog() { return isYourBlog; } public void setIsYourBlog(int isYourBlog) { this.isYourBlog = isYourBlog; }
2)再进行修改博客详情页的代码
前端:
if(data.isYourBlog==1) { //说明当前的登录用户和文章作者是同一个人 let nav=document.querySelector(".nav"); let a=document.createElement("a"); a.target="_blank"; a.innerHTML="删除"; a.href="#"; nav.appendChild(a); a.onclick=function(){ $.ajax({ method:"DELETE", url:"deleteblog"+location.search, success:function(data,status) { //如果删除成功,就让页面重定向到博客列表页 console.log(1111111); location.assign("blog1.html"); } });
后端:修改请求获取到作者的Servlet代码
user1.setIsYourBlog(user.equals(user1)?0:1);
@WebServlet("/user") public class UserWriteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //先进行检测用户是否进行了登录 HttpSession session=req.getSession(false); if(session==null||session.equals("")) { resp.sendRedirect("blog3.html"); return; } User user=(User)session.getAttribute("user"); if(user==null||user.equals("")) { resp.sendRedirect("blog3.html"); return; } //获取请求中的参数 resp.setContentType("application/json;charset=utf-8"); String blogID=req.getParameter("blogID"); ObjectMapper mapper=new ObjectMapper(); if(blogID==null||blogID.equals("")) { //处理博客列表页发送过来的请求 String userreturn=mapper.writeValueAsString(user); resp.getWriter().write(userreturn); }else{ //处理博客详情页发送过来的请求 OperateUser operateUser=new OperateUser(); OperateBlog operateBlog=new OperateBlog(); //先根据BlogID来进行从数据库中获取到Blog,再根据blog中的userID来进行获取到User对象 Blog blog=null; User user1=null; try { blog=operateBlog.SelectOne(Integer.parseInt(blogID)); user1=operateUser.selectByUserID(blog.getUserID()); user1.setIsYourBlog(user.equals(user1)?0:1); } catch (SQLException e) { e.printStackTrace(); } String userreturn= mapper.writeValueAsString(user1); resp.getWriter().write(userreturn); } } }
1)user1表示在博客详情页根据blogID查询到的文章作者信息,user是根据Session中设置的键值对的得到的User对象,这里进行比较他们是不是相同,相同返回1,不相同返回0;
2)a标签只能触发GET请求,所以我们给a标签设置了一个点击回调函数,通过ajax给服务器发送DELETE请求;