博客系统的前端代码,我放在码云的,这里就不给大家重复展示了。
https://gitee.com/zhang-qinyang1/class102.git
目录
1.设计一个简单网站的基本思路
2.准备工作
3.编写数据库的代码
3.1数据库设计
3.2数据库封装
4.开发服务器controller和客户端的功能
4.1博客列表页的展示
4.2博客详情页的展示
4.3登录功能
4.4检测用户登录状态
4.5能够正确显示用户信息
4.6实现注销博客功能
4.7实现发布博客功能
4.8实现删除博客功能
5.小结
(1)设计前后端交互的接口
(2)实现服务器部分
(3)实现客户端部分
我们主要是采取客户端渲染来实现前后端分离
这里的准备工作实际上就是一个servlet使用前所需要的导入工作
①创建Maven项目
这里我给博客系统命名为blog_system
②引入依赖(servlet,Jackon,mysql)
这里是在中央仓库去找你需要的
Maven Repository: Search/Browse/Explore (mvnrepository.com)https://mvnrepository.com/③创建必要的目录
在main的目录下创建webapp这个目录文件,之后再webapp这个目录下创建WEB-INF这个目录文件,在WEB-INF这个目录下创建文件web.xml;并且对其进行配置固定内容如下:
Archetype Created Web Application ④编写代码
我们先试着随便输出一个来测试以上环境是否配置无误
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; @WebServlet("/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf8"); resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("这是用来测试环境的servlet"); } }
⑤⑥部署打包(用smart Tomcat)
⑦在浏览器中验证
这里的时候需要注意一级路径与二级路径分别是什么
数据库这里的操作大多是JDBC,因此大家首先需要对其熟悉,才能够看懂后续代码操作。
数据库设计在这里的话就是指的创建数据库/数据表的结构
对于我们博客的功能来说,我们需要发布博客,获取博客,以及用户登录。所以,建表的时候抓住实体,我们就很容易想到建博客表和用户表来进行操作。create database if not exists blog_system; use blog_system; --创建一个博客表 drop table if exists blog; create table blog( blogId int primary key auto_increment, title varchar(1024), content mediumtext,--对于blog而言,往往是较长的,所以我们这里用mediumtext来表示 userId int,--文章作者id postTime datetime--发布的时间 ); --创建一个user表 drop table if exists user; create table user( userId int primary key auto_increment, username varchar(1024) unique, password varchar(124) ); insert into user values(null,'zhangsan','123'); insert into user values(null,'lisi','123');
然后将它插入到数据库中去,显示如下:
插入的时候注意一些细节,比如去掉注释这些,不然的话就会报错
(1)先创建DBUtil封装数据库连接的操作
package model; import com.mysql.jdbc.Connection; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import javax.sql.DataSource; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; //使用这个类和数据库建立连接 public class DBUtil { //这个不用背,每次复制粘贴就行 private static final String URL = "jdbc:mysql://127.0.0.1:3306/my_blog?characterEncoding=utf8&useSSL=false"; private static final String USERNAME = "root"; //数据库密码 private static final String PASSWORD = "123456"; private static volatile DataSource dataSource=null; private static DataSource getDataSource(){ if (dataSource==null){ synchronized (DBUtil.class){ if (dataSource==null){ dataSource=new MysqlDataSource(); ((MysqlDataSource)dataSource).setURL(URL); ((MysqlDataSource)dataSource).setUser(USERNAME); ((MysqlDataSource)dataSource).setPassword(PASSWORD); } } } return dataSource; } public static Connection getConnection()throws SQLException { return (Connection) getDataSource().getConnection(); } public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException { if (resultSet!=null){ resultSet.close(); } if(statement!=null){ statement.close(); } if (connection!=null){ connection.close(); } } }
(2)创建实体类,使用实体来表示数据库中的一条内容,此处主要创建的是Blog类以及User类
这里只展示Blog类
package model; import java.sql.Timestamp; //每个Blog对象,对应blog表中的一条记录 public class Blog { //因为都是private,所以这里要重写get,set方法 private int BlogId; private String title; private String content; private int UserId; private Timestamp postTime; public void setBlogId(int blogId) { BlogId = blogId; } public int getBlogId() { return BlogId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getUserId() { return UserId; } public void setUserId(int userId) { UserId = userId; } public Timestamp getPostTime() { return postTime; } public void setPostTime(Timestamp postTime) { this.postTime = postTime; } }
(3)封装针对数据的增删查改,把提供增删查改的这样的类,称为DAO。这里也只展示BlogDao
package model; import com.mysql.jdbc.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; // 这个类用于去封装博客表的基本操作 public class BlogDao { // 1. 向博客列表中插入一个博客 public void insert(Blog blog) throws SQLException { // JDBC 基本代码 Connection connection=null; PreparedStatement statement=null; try { // ①和数据库建立连接. connection = DBUtil.getConnection(); // ② 构造 SQL 语句 String sql = "insert into blog values(null, ?, ?, ?, now())"; statement=connection.prepareStatement(sql); //第一个参数表示的是第几个?的位置 statement.setString(1, blog.getTitle()); statement.setString(2, blog.getContent()); statement.setInt(3,blog.getUserId()); // ③执行 SQL statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { // ④ 关闭连接, 释放资源 DBUtil.close(connection,statement,null); } } // 2. 能够获取到博客表中的所有博客的信息 (用于在博客列表页, 此处每篇博客不一定会获取到完整的正文) public List
selectAll() throws SQLException { List blogs=new ArrayList<>(); Connection connection=null; PreparedStatement statement=null; ResultSet resultSet=null; try { connection=DBUtil.getConnection(); String sql="select * from blog"; statement=connection.prepareStatement(sql); resultSet=statement.executeQuery(); //遍历整个集合 while(resultSet.next()){ Blog blog=new Blog(); blog.setBlogId(resultSet.getInt("blogId")); blog.setTitle(resultSet.getString("title")); blog.setContent(resultSet.getString("content")); blog.setUserId(resultSet.getInt("userId")); blog.setPostTime(resultSet.getTimestamp("postTime")); blogs.add(blog); } } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(connection, statement,resultSet ); } return blogs; } // 3. 能够根据博客 id 获取到指定的博客内容 (用于在博客详情页) public Blog selectOne(int blogId) throws SQLException { Connection connection=null; PreparedStatement statement=null; ResultSet resultSet=null; try { connection=DBUtil.getConnection(); String sql="select * from blog where blogId=?"; statement=connection.prepareStatement(sql); statement.setInt(1,blogId); resultSet=statement.executeQuery(); //由于id是唯一的,要么是0条,要么是唯一的,是主键作为查询条件的,所以直接用if if (resultSet.next()){ Blog blog=new Blog(); blog.setBlogId(resultSet.getInt("blogId")); blog.setTitle(resultSet.getString("title")); blog.setContent(resultSet.getString("content")); blog.setUserId(resultSet.getInt("userId")); blog.setPostTime(resultSet.getTimestamp("postTime")); return blog; } } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(connection,statement,resultSet); } return null; } // 4. 从博客表中, 根据博客 id 删除博客. public void delete(int blogId) throws SQLException { Connection connection=null; PreparedStatement statement=null; try { connection=DBUtil.getConnection(); String sql="delete from blog where blogId=?"; statement.setInt(1,blogId); statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(connection,statement,null); } } // 注意, 上述操作是 增删查, 没有改 }
①需求:
这个页面需要能够展示出数据库中的博客列表
②约定前后端的交互接口:
③编写服务器代码:
package controller; import com.fasterxml.jackson.databind.ObjectMapper; import model.Blog; import model.BlogDao; 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.util.List; @WebServlet("/blog") public class BlogServlet extends HttpServlet { private ObjectMapper objectMapper=new ObjectMapper(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //从数据库中查询到博客列表,转成json格式,直接返回 //查询数据库 BlogDao blogDao=new BlogDao(); List
blogs=blogDao.selectAll(); //将blogs转成json格式 String respJson=objectMapper.writeValueAsString(blogs); resp.setContentType("application/json;charset=utf8"); resp.getWriter().write(respJson); } } ④编写客户端代码:
在页面加载的时候,让页面通过ajax访问服务器,获取到数据库中的博客数据,并且填到页面中
!DOCTYPE html>
博客列表
展示效果:当我们在数据库中插入一条数据后,他会更新到列表页的最前面
值得注意的是:
a.db.sql中的代码并不会生效,我们需要把其添加到mysql中去
b.可以利用postman来看我们构造的响应body中返回的数据格式与希望的是不是一致的
c.转换时间格式:yyyy-MM-dd HH:mm:ss(分别指的是年月日 小时分钟秒钟)
d.要想插入的博客是按照时间约后发布越在上面,就不能忘了加上order by desc来进行降序的排列
①需求:
这里用来获取博客的详情页,发送的请求。希望得到的页面能够显示出博客对应的正文内容
而这个正文内容,我们通过ajax来进行获取。在blog_detail.html页面加载的时候,触发ajax请求来访问服务器,获取到博客内容,再次填充到博客详情页里面去。
②前后端的交互接口:注意:这里我们是通过某个博客的id来确定具体要访问哪个内容的。与博客列表页不同之处有以下三点:
(1)请求中带有参数blogId
(2)结果响应不是json数组,而是单一的对象(因为具体到了某一个)
(3) 响应博客的正文,不用进行截断了
③编写服务器代码:
此处服务器代码几乎和博客列表页一致,唯一不同的点就是有了个blogId来区分是博客列表还是详情,因此我们还是放到同一个方法中来实现
package controller; import com.fasterxml.jackson.databind.ObjectMapper; import model.Blog; import model.BlogDao; 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.util.List; @WebServlet("/blog") public class BlogServlet extends HttpServlet { private ObjectMapper objectMapper=new ObjectMapper(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //从数据库中查询到博客列表,转成json格式,直接返回 //查询数据库 BlogDao blogDao=new BlogDao(); // 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情页 // 如果该参数不存在, 说明是要请求博客的列表. //因为这里是get,我们直接可以在URL中判断该参数是否存在 String param=req.getParameter("blogId"); //当其不存在是则是获取列表页 if(param==null){ List
blogs=blogDao.selectAll(); //将blogs转成json格式 String respJson=objectMapper.writeValueAsString(blogs); resp.setContentType("application/json;charset=utf8"); resp.getWriter().write(respJson); }else {//存在参数,则是获取博客详情页 int blogId = Integer.parseInt(param);//包装类转换成Integer Blog blog = blogDao.selectOne(blogId); //用json对象来进行接收 String respJson = objectMapper.writeValueAsString(blog); resp.setContentType("application/json;charset=utf8"); resp.getWriter().write(respJson); } } } ④编写客户端代码:
前端代码这边,要想构造一个请求获取博客详情,就得知道当前用户的博客id,当然这个id已经在当前的blog_detail.html页面的url中了。在前端的时候,我们可以通过location.search来获取到blogId.
博客详情页 link注意!!!这里的难点主要有三个问题:
a.弄清楚blogId到底是怎么来的
b.为什么要引入editor.md?
因为我们编辑的时候用的是Markdown格式的,要想响应的时候也是,就需要引入相应的需求
c.为了防止出现乱码情况,我们一定要设置格式!!!而且要注意整体和局部之间的关系!!!
展示结果:
①需求:
实现登录,当登录之后跳转至博客列表页
②实现前后端交互:
很显然,我们这里决定基于form表单来实现,当然ajax也可以,只是这里用form表单
③服务器代码:
package controller; import model.User; import model.UserDao; 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 javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); //①获取到参数中的请求 String username=req.getParameter("username"); String password=req.getParameter("password"); if(username == null || "".equals(username) || password == null || "".equals(password)) { // 请求内容缺失,登录失败 resp.setContentType("text/html; charset=utf8"); resp.getWriter().write("当前的用户名或者密码为空"); return; } //②和数据库里面存储的数据进行比对 UserDao userDao=new UserDao(); User user=userDao.selectByName(username); if(user == null || !user.getPassword().equals(password)) { // 用户没有查到或者密码不匹配,登录失败 resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("用户名或密码错误"); return; } //③如果比较通过,则用会话记录下来,即创建会话 HttpSession session= req.getSession(true); //将信息存入会话中 session.setAttribute("user",user); //④跳转页面,页面重定向 resp.sendRedirect("blog_list.html"); } }
④客户端代码:
登录页面 结果展示:
注意!!!值得注意的是用form表单的时候,不要忘了添加name属性,还有css里面的格式会随着属性的改变可能会不同。并且form表单中提交按钮不能是button,要是type类型的submit。
①需求:
当登录功能完成后,我们要调节一下列表页和详情页,使得这两个页面只有登录了才能访问,要是没有登录就跳转到登录页面
②实现前后端交互接口:
③服务器代码:
我们就直接在上述代码中直接添加一个doGet方法,用来检验这个时候用户的登录状态就好。因此,我们这里的代码也就是直接连着的上面的
//用来检验用户的登录状态 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("application/json;charset=utf8"); //①获取开始存在的会话,看会话是否存在,会话都不存在的话,那么必然是没有登录 //因为false是不会创建新的会话的 HttpSession session=req.getSession(false); if (session==null){ //没有会话 //创建对象,里面为空,并返回,注意这里返回空,就不用和数据库进行连接,,但是仍然是json格式的,所以用mapper来转换 User user=new User(); resp.getWriter().write(objectMapper.writeValueAsString(user)); return; } //拿到了会话,但是会话里面的user为空值 User user= (User) session.getAttribute("user"); if (user==null){ //这个时候,仍然是没有登录,那么仍然返回空 user = new User(); resp.getWriter().write(objectMapper.writeValueAsString(user)); return; } //获取到了session,且里面的user并不为空,那么可以继续访问 //但是注意不要把密码返回给了前端 user.setPassword(""); resp.getWriter().write(objectMapper.writeValueAsString(user)); }
④客户端代码:
对于一些通用的代码,我们可以放到一个js里面来统一管理,然后其他页面直接调用它就好,这里我们把其命名为common.js。然后把这个js分别引入到列表页和详情页即可。
common.js
// 这个文件里放一些 页面公共的代码 // 加上一个逻辑,通过 GET/login 这个接口来获取下当前的登录状态 function getUserInfo() { $.ajax({ type: 'get', url: 'login', success: function(body) { // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0) if(body.userId && body.userId >0) { // 登录成功 // 不做处理 console.log("当前用户登录成功!用户名:" + body.username); }else{ // 登录失败 // 让前端页面,跳转到 login.html alert("当前你尚未登录!请登录后再访问博客列表!"); location.assign('blog_login.html'); } }, error: function() { alert("当前你尚未登录!请登录后再访问博客列表!"); location.assign('blog_login.html'); } }); } getUserInfo();
引入:
结果展示:(当我们直接访问列表页时)
当我们点击确定或者等待一段时间后,就会跳转到登录页面:
由于我们登录的人是可能与发布文章的博主是不同的人,但是我们发现,当我们进去的时候登录的用户是zhangsan,但是写博客的可能不是zhangsan,所以我们要实现能够根据具体情况进行转换。
①需求:
让在列表页显示的用户名称是用户的登陆者,而在详情页具体某篇博客时,显示的是作者本人。
博客列表页:
而我们可以发现针对博客列表页来说,其实前面已经处理过了,我们通过ajax得到了body,此时我们只需要在前端代码中稍作改动,拿到当前改动的这个名字,作为当前用户名即可。
所以我们只需要在common.js里面做改动
/// 这个文件里放一些页面公共的代码 // 加上一个逻辑, 通过 GET /login 这个接口来获取下当前的登录状态~ function getUserInfo() { $.ajax({ type: 'get', url: 'login', success: function(body) { // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0) if (body.userId && body.userId > 0) { // 登录成功! // 不做处理! console.log("当前用户登录成功! 用户名: " + body.username); // 根据当前用户登录的情况, 把当前用户名设置到界面上 changeUserName(body.username); } else { // 登录失败! // 让前端页面, 跳转到 login.html alert("当前您尚未登录! 请登录后再访问博客列表!"); location.assign('blog_login.html'); } }, error: function() { alert("当前您尚未登录! 请登录后再访问博客列表!"); location.assign('blog_login.html'); } }); } getUserInfo(); function changeUserName(username){ let h3=document.querySelector('.card>h3'); h3.innerHTML=username; }
此时我们在列表页看到的用户名就是我们登录时的用户名了
博客详情页:
根据上面的操作,我们发现,当我们进入任何一篇内容时,用户名都是zhangsan;
然而实际上第五篇的作者却是wangwu,所以说我们得在列表页与详情页作出区分。而如何区分呢?很显然,我们可以通过blogId来提供新的接口,这个接口可以让客户端指定blogId,从而获取指定blogId的作者信息
②前后端交互接口:
③后端服务器代码:
package controller; import com.fasterxml.jackson.databind.ObjectMapper; import model.Blog; import model.BlogDao; import model.User; import model.UserDao; 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; @WebServlet("/authorInfo") public class AuthorServlet extends HttpServlet { private ObjectMapper objectMapper=new ObjectMapper(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取指定博客的作者信息 resp.setContentType("application/json;charset=utf8"); String param=req.getParameter("blogId"); if(param==null || "".equals(param)){ resp.getWriter().write("{ \"ok\": false, \"reason\": \"参数缺失!\" }"); return; } //根据当前blogId,在数据库中进行查找,找到对应的blog对象,再进一步根据blog对象,找到作者信息 BlogDao blogDao=new BlogDao(); Blog blog=blogDao.selectOne(Integer.parseInt(param)); if(blog==null){ resp.setContentType("application/json;charset=utf8"); resp.getWriter().write("{ \"ok\": false, \"reason\": \"参数缺失!\" }"); return; } // 根据 blog 对象, 查询到用户对象 UserDao userDao = new UserDao(); User author = userDao.selectById(blog.getUserId()); if (author == null) { resp.getWriter().write("{ \"ok\": false, \"reason\": \"要查询的用户不存在!\" }"); return; } // 把 author 返回到浏览器这边 // 把密码给去掉 author.setPassword(""); resp.getWriter().write(objectMapper.writeValueAsString(author)); } }
④客户端代码: (这里主要是此处的核心代码)
//从服务器获取一下当前博客的作者信息,并且显示到界面上 function getAuthorInfo(){ $.ajax({ type:'get', url:'authorInfo'+location.search, success:function(body){ // 此处的 body, 就是服务器返回的 User 对象, 是文章的作者信息 if (body.username) { // 如果响应中的 username 存在, 就把这个值设置到页面上. changeUserName(body.username) }else{ console.log("获取作者信息失败"+body.reason); } } }); } getAuthorInfo();
common.js里面的内容也要稍作修改,代码如下:
// 这个文件里放一些页面公共的代码 // 加上一个逻辑, 通过 GET /login 这个接口来获取下当前的登录状态~ function getUserInfo(pageName) { $.ajax({ type: 'get', url: 'login', success: function(body) { // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0) if (body.userId && body.userId > 0) { // 登录成功! // 不做处理! console.log("当前用户登录成功! 用户名: " + body.username); // 根据当前用户登录的情况, 把当前用户名设置到界面上 if (pageName == 'blog_list.html') { changeUserName(body.username); } } else { // 登录失败! // 让前端页面, 跳转到 login.html alert("当前您尚未登录! 请登录后再访问博客列表!"); location.assign('blog_login.html'); } }, error: function() { alert("当前您尚未登录! 请登录后再访问博客列表!"); location.assign('blog_login.html'); } }); } function changeUserName(username) { let h3 = document.querySelector('.card>h3'); h3.innerHTML = username; }
结果展示:
我们就可以看到第五篇博客的作者是wangwu了
我们需要注意的点是,在完成局部功能函数后,一定不要忘记调用它,不然就毫无意义了。
①需求:
退出当前的登录状态,当我们点击注销按钮之后,就会在服务器上取消登录并且能够跳转到登录页面。②前后端交互接口:
③服务器后端代码:
我们希望点击注销后,能够给服务器发送一个HTTP请求,从而触发注销动作,具体来说就是这个动作把会话中的信息给删掉就行
package controller; 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 javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/logout") public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //先找到当前用户的会话 HttpSession session=req.getSession(false); if (session==null){ //用户没登录,就不用注销啦 resp.getWriter().write("当前用户没有登录,无法注销"); } //然后把这个用户的会话中的信息删掉 session.removeAttribute("user"); resp.sendRedirect("blog_login.html"); } }
什么叫做登录呢?
用户有一个session,同时session有一个user属性,两个同时具备,才叫做登录状态。注销,只需要破坏上面的任意一个条件就OK啦,此处选择的破坏第二个条件,也就是让session不具备user属性,把user属性从session中删了。为啥不删会话呢?因为没有提供删会话的API。我们可以看我们检测登录状态的代码,会看到两者必须同时具备;
无论删谁,都会返回null,也就是说都会被认为是未登录状态。
④客户端代码:
我们把博客列表页,详情页和编辑页的注销按钮的herf属性作出修改即可
结果展示:(此时当我们点击注销,就会回到登录页面)
注意!!!博客登录页不用设置注销按钮的。
①需求:
在博客编辑页中,当用户输入了博客标题和正文,点击发布后,此时就会把这些数据提交到服务器,由服务器存储到数据库中
②前后端交互接口:
③服务器代码:(在blogservlet中继续创建写在post请求中的)
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf8"); req.setCharacterEncoding("utf8"); HttpSession session=req.getSession(); if (session==null){ //当前用户未登录,不能提交 resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前用户未登录,不能提交博客!"); return; } User user= (User) session.getAttribute("user"); if (user==null){ //当前用户未登录,不能提交 resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前用户未登录,不能提交博客!"); return; } //先从请求中取出参数,博客的标题和正文 resp.setCharacterEncoding("utf8"); String title=req.getParameter("title"); String content=req.getParameter("content"); if (title==null||"".equals(title)||content==null||"".equals(content)){ //参数有误 resp.getWriter().write("提交博客失败,缺少必要的参数"); return; } //构造blog对象,把当前的信息填进去,并插入数据库中 //此处要设置的属性主要是title,content,userId;而postTime和blogId都是系统自动生成的 Blog blog=new Blog(); blog.setTitle(title); blog.setContent(content); blog.setUserId(user.getUserId());//作者id就是当前提交这个博客的用户的身份信息 BlogDao blogDao=new BlogDao(); blogDao.insert(blog); //新增成功后重定向到列表页 resp.sendRedirect("blog_list.html"); } }
④客户端代码:
博客编辑页 结果显示:(当我们写一篇新的文章提交后,会自动跳转到博客列表,并且刷新当前内容)
注意!!
form表单的添加与修改,以及为了延续Markdown使用的textarea的调节。还有别忘了在将button修改后应该注意对应在css中同样进行修改,不然样式就会有所改变。
①需求:
我们这里的删除博客,不考虑管理员删除,只考虑我们自己删除。因此,在博客详情页上我们就要进行判定,判定当前这个博客的作者,是否就是登录的用户,如果是,就在导航栏显示一个“删除按钮”,如果哦不是,就不显示删除按钮。而在博客详情页这里,其实既从服务器获取了当前用户的登录信息,又获取到了博客的作者信息,我们主要看这两个接口返回的用户信息是不是一样的。
②前后端交互:
③服务器代码:
package controller; import model.Blog; import model.BlogDao; import model.User; 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 javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/blogDelete") public class BlogDeleteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.检查用户是否登录 HttpSession session=req.getSession(); if (session==null){ resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前尚未登录,不能删除"); return; } User user= (User) session.getAttribute("user"); if (user==null){ resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前尚未登录,不能删除"); return; } //2.获取到参数中的blogId String blogId=req.getParameter("blogId"); if (blogId==null||"".equals(blogId)){ resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前blog参数不对"); return; } //3.获取要删除的博客信息 BlogDao blogDao=new BlogDao(); Blog blog=blogDao.selectOne(Integer.parseInt(blogId)); if (blog==null){ resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前要生成的博客不存在"); return; } //4.当前用户是不是作者 if (user.getUserId()!=blog.getUserId()){ resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("当前登录的用户不是作者,没有权限"); return; } //5.没有问题了,进行删除 blogDao.delete(Integer.parseInt(blogId)); //6.重定向到列表页 resp.sendRedirect("blog_list.html"); } }
④客户端代码:
博客详情页 结果如下:
当我们删了我是新文章后跳转到列表就没有这篇文章了。
注意!!!:
a.调用顺序,因为ajax是并发执行的,我们不知道谁会先执行完,我们就决定使用回调的方式来完成
这只是一个很简单的网站,可能很多地方没有考虑全面,仅供参考。详细代码,可以在页首查看我的码云地址。
感谢观看嘿嘿嘿~