• 手把手带你搭建个人博客系统(二)


    在这里插入图片描述

    请添加图片描述

    ⭐️前言⭐️

    因文章篇幅较长,所以整个流程分两篇文章来完成。

    🍉博客主页: 🍁【如风暖阳】🍁
    🍉精品Java专栏【JavaSE】【备战蓝桥】、【JavaEE初阶】【MySQL】【数据结构】
    🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

    🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉

    🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

    🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)GitHub


    请添加图片描述

    请添加图片描述

    🍅1.针对完成任务

    在前端共涉及的四个页面,都需要分别完成“约定前后端交互接口”、“编写服务器代码”、“编写客户端代码”等任务流程。

    1.1博客列表页

    这个页面需要展示出数据库中的博客列表,按以下开发流程来进行操作

    1)约定接口
    在这里插入图片描述
    2)编写服务器代码

    //通过这个类来处理 /blog 路径对应的请求
    @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<Blog> blogs=blogDao.selectAll();
            //把blogs对象转成JSON格式
            String respJson=objectMapper.writeValueAsString(blogs);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    postman测试成功:
    在这里插入图片描述
    3)编写客户端代码
    这一步需要我们在之前写好的前端代码中进行调整,加入ajax请求,使得前端页面能够与服务器交互,并从数据库中获取到博客列表

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>博客列表title>
        <link rel="stylesheet" href="css/common.css">
        <link rel="stylesheet" href="css/blog_list.css">
    head>
    <body>
        <div class="nav">
            <img src="image/dd.jpg" alt="">
            <span>我的博客系统span>
            
            <div class="spacer">div>
            <a href="blog_list.html">主页a>
            <a href="blog_edit.html">写博客a>
            <a href="#">注销a>
        div>
        
        <div class="container">
            
            <div class="left">
                
                <div class="card">
                    <img src="image/2.jpg" alt="">
                    <h3>如风暖阳h3>
                    <a href="#">gitHub地址a>
                    <div class="counter">
                        <span>文章span>
                        <span>分类span>
                    div>
                    <div class="counter">
                        <span>2span>
                        <span>1span>
                    div>
                div>
            div>
    
            
            <div class="right">
                
            div>
        div>
    
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">script>
        <script>
            // 在页面加载的时候, 通过 ajax 给服务器发送数据, 获取到博客列表信息, 并且显示在界面上. 
            function getBlogList() {
                $.ajax({
                    type: 'get',
                    url: 'blog',
                    success: function(body) {
                        // 获取到的 body 就是一个 js 对象数组, 每个元素就是一个 js 对象, 根据这个对象构造 div
                        // 1. 先把 .right 里原有的内容给清空
                        let rightDiv = document.querySelector('.right');
                        rightDiv.innerHTML = '';
                        // 2. 遍历 body, 构造出一个个的 blogDiv
                        for (let blog of body) {
                            let blogDiv = document.createElement('div');
                            blogDiv.className = 'blog';
                            // 构造标题
                            let titleDiv = document.createElement('div');
                            titleDiv.className = 'title';
                            titleDiv.innerHTML = blog.title;
                            blogDiv.appendChild(titleDiv);
                            // 构造发布时间
                            let dateDiv = document.createElement('div');
                            dateDiv.className = 'date';
                            dateDiv.innerHTML = blog.postTime;
                            blogDiv.appendChild(dateDiv);
                            // 构造博客的摘要
                            let descDiv = document.createElement('div');
                            descDiv.className = 'desc';
                            descDiv.innerHTML = blog.content;
                            blogDiv.appendChild(descDiv);
                            // 构造 查看全文
                            let a = document.createElement('a');
                            a.innerHTML = '查看全文 >>';
                            // 此处希望点击之后能够跳转到 博客详情页 !!
                            // 这个跳转过程需要告知服务器要访问的是哪个博客的详情页. 
                            a.href = 'blog_detail.html?blogId=' + blog.blogId;
                            blogDiv.appendChild(a);
    
                            // 把 blogDiv 挂到 dom 树上
                            rightDiv.appendChild(blogDiv);
                        }
                    }, 
                    error: function() {
                        alert("获取博客列表失败!");
                    }
                });
            }
    
            getBlogList();
        script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    1.2博客详情页

    1)约定前后端交互接口
    在这里插入图片描述
    可以发现在博客详情页的请求中,与博客列表页不同的是多了?blogId=1这样的查询字符串;
    该查询字符串在blog_list.htmla链接标签中就加入了
    在这里插入图片描述
    2)编写客户端代码
    加入ajax请求,使得博客详情页的内容,可以通过请求,从服务器中根据查询字符串中的信息,找到对应的博客,展示在前端页面上。

    该操作还需要注意,博客正文要用markdown格式渲染,所以要引入editor.md依赖

    核心代码块:
    在这里插入图片描述
    完整前端代码:

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>博客详情页title>
        <link rel="stylesheet" href="css/common.css">
        <link rel="stylesheet" href="css/blog_detail.css">
    
        
        <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
        <script src="js/jquery.min.js">script>
        <script src="editor.md/lib/marked.min.js">script>
        <script src="editor.md/lib/prettify.min.js">script>
        <script src="editor.md/editormd.js">script>
    head>
    <body>
        <div class="nav">
            <img src="image/dd.jpg" alt="">
            <span>我的博客系统span>
            
            <div class="spacer">div>
            <a href="blog_list.html">主页a>
            <a href="blog_edit.html">写博客a>
            <a href="#">注销a>
        div>
    
        <div class="container">
            
            <div class="left">
                
                <div class="card">
                    <img src="image/2.jpg" alt="">
                    <h3>如风暖阳h3>
                    <a href="#">gitHub地址a>
                    <div class="counter">
                        <span>文章span>
                        <span>分类span>
                    div>
                    <div class="counter">
                        <span>2span>
                        <span>1span>
                    div>
                div>
            div>
    
            
            <div class="right">
                
                <div class="blog-content">
                    
                    
                    <h3>h3>
                    
                    <div class="date">div>
                    
                    <div id="content" style="opacity: 80%">
                    div>
                div>
    
                <script>
                    function getBlogDetail() {
                        $.ajax({
                            type:'get',
                            //location.search 拿到查询字符串
                            url:'blog'+location.search,
                            success:function(body) {
                                //body就是一个blog,根据body中的内容来构造页面
                                //1.构造博客标题
                                let h3=document.querySelector(".blog-content>h3");
                                h3.innerHTML=body.title;
                                //2.构造博客发布时间
                                let dateDiv=document.querySelector('.date');
                                dateDiv.innerHTML=body.postTime;
                                //3.构造博客正文,用markdown渲染
                                editormd.markdownToHTML('content',{
                                    markdown:body.content
                                });
                            }
                        });
                    }
    
                    getBlogDetail();
                script>
            div>
        div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    3)编写服务器代码,在BlogServlet类中修改doGet方法,使得浏览器发来的请求中,如果有查询字符串,就返回博客详情页json数据;如果没有查询字符串,就返回博客列表页json数据。

    //通过这个类来处理 /blog 路径对应的请求
    @WebServlet("/blog")
    public class BlogServlet extends HttpServlet {
        private ObjectMapper objectMapper=new ObjectMapper();
    
        //这个方法用来获取到数据库中的博客列表
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("application/json;charset=utf8");
            BlogDao blogDao=new BlogDao();
            //先尝试获取到req中的blogId参数,如果该参数存在,说明是要求请求博客详情
            //如果该参数不存在,说明是要请求博客的列表
            String parm=req.getParameter("blogId");
            if(parm==null) {
                //不存在参数,获取博客列表
                List<Blog> blogs=blogDao.selectAll();
                //把blogs对象转成JSON格式
                String respJson=objectMapper.writeValueAsString(blogs);
                resp.getWriter().write(respJson);
            }else {
                //存在参数,获取博客详情
                int blogId=Integer.parseInt(parm);
                Blog blog=blogDao.selectOne(blogId);
                String respJson=objectMapper.writeValueAsString(blog);
                resp.getWriter().write(respJson);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    效果预览
    在这里插入图片描述

    1.3登录功能

    1)约定接口
    在这里插入图片描述
    登录成功后,跳转到博客列表页。
    在前端登录实现部分中,我们使用的是input标签,所以通过form表单的方式来构造登录请求更方便。
    2)编写前端代码
    主要是加入form表单,并把提交按钮类型改为submit,还需要改提交按钮对应的css样式

    blog_login.html:

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Documenttitle>
        <link rel="stylesheet" href="css/common.css">
        <link rel="stylesheet" href="css/blog_login.css">
    head>
    <body>
        <div class="nav">
            <img src="image/dd.jpg" alt="">
            <span>我的博客系统span>
            
            <div class="spacer">div>
            <a href="blog_list.html">主页a>
            <a href="blog_edit.html">写博客a>
            
        div>
    
        <div class="login-container">
            <form action="login" method="post">
                <div class="login-dialog">
                    <h3>登录h3>
                    <div class="row">
                        <span>用户名span>
                        <input type="text" id="username" name="username">
                    div>
                    <div class="row">
                        <span>密码span>
                        <input type="password" id="password" name="password">
                    div>
                    <div class="row">
                        <input type="submit" id="submit" value="提交">
                    div>
                div>
            form>
        div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    blog_login.css:

    .login-container {
        width: 100%;
        /* 注意减号两边有空格 */
        height: calc(100% - 50px);
    
        /* 需要让里面的子元素, 垂直水平居中, 需要用到 flex 布局 */
        display: flex;
        align-items: center;
        justify-content: center;
    }
    
    .login-dialog {
        width: 400px;
        height: 350px;
        background-color: rgba(255,255,255,0.8);
        border-radius: 10px;
    }
    
    .login-dialog h3 {
        text-align: center;
        padding: 50px 0;
    }
    
    .login-dialog .row {
        height: 50px;
        width: 100%;
    
        display: flex;
        align-items: center;
        justify-content: center;
    }
    
    .login-dialog .row span {
        /* 把span设置为块级元素方便后续设置尺寸 */
        display: block;
        width: 100px;
        font-weight: 700;
    }
    
    #username,#password {
        width: 200px;
        height: 40px;
        font-size: 22px;
        line-height: 40px;
        padding-left: 10px;
        border-radius: 10px;
    }
    
    .row #submit {
        width: 300px;
        height: 50px;
        border-radius: 10px;
        color: white;
        background-color: rgb(0,128,0);
        border: none;
        outline: none;
    
        margin-top:50px ;
    }
    
    .row #submit:active {
        background-color: #666;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    3)编写服务器代码
    约定的路径是/login,需要新建一个Servlet类来处理这里的登录请求

    @WebServlet("/login")
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf8");
            resp.setCharacterEncoding("utf8");
            //1.获取到请求中的参数
            String username=req.getParameter("username");
            String password=req.getParameter("password");
            System.out.println("username="+username+",password="+password);
            if(username==null||"".equals(username)||password==null||"".equals(password)) {
                // 请求的内容缺失, 肯定是登录失败!!
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("当前的用户名或密码为空!");
                return;
            }
            //2.和数据库中的内容进行比较
            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;
            }
            //3.如果比较通过,就创建会话
            HttpSession session=req.getSession(true);
            //把刚才的用户信息,存储到会话中
            session.setAttribute("user",user);
    
            //4.返回一个重定向报文,跳转到博客列表页
            resp.sendRedirect("blog_list.html");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    效果预览
    请添加图片描述

    1.4检验登录状态

    在我们完成了登录功能后,需要对前边两个页面(博客列表页和博客详情页)进行调整,使得这两个页面必须登录后才能访问。

    要想实现上述的功能,就需要在博客列表页/详情页加载的时候,通过ajax访问一下服务器,获取当前的登录状态,看看能不能获取到,如果获取到了,就说明当前确实是已经登录了,此时就可以留在这个页面了;如果没有获取到,说明未登录,就需要跳转到登录页面。

    1)约定接口
    在这里插入图片描述
    如果登录了就返回当前登录的用户信息,未登录,就直接返回一个userId=0的对象。
    在这里插入图片描述
    2)编写服务器代码

    LoginServlet类中加上doGET方法

    //这个方法用来让前端检测当前的登录状态
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("application/json;charset=utf8");
            HttpSession session=req.getSession(false);
            if(session==null) {
                //检测下会话是否存在,不存在说明未登录
                User user=new User();
                resp.getWriter().write(objectMapper.writeValueAsString(user));
                return;
            }
            User user=(User) session.getAttribute("user");
            if(user==null) {
                //虽然会话存在,但是会话里没有user对象,也视为未登录
                user=new User();
                resp.getWriter().write(objectMapper.writeValueAsString(user));
                return;
            }
            //代码执行到这里说明已经登录
            
            //不把密码返回给前端
            user.setPassword("");
            resp.getWriter().write(objectMapper.writeValueAsString(user));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3)编写前端代码
    在博客详情页和博客列表页中加入ajax请求,在页面一加载出来的时候就向服务器发送请求来判定登录状态。

    因为两个页面都需要进行判断,所以把判断逻辑单独出一个js文件中,让这两个前端代码引入即可。

    //这个文件放一些页面公共的代码
    
    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);
    
                }else {
                    //登录失败!
                    //让前端页面跳转到login.html
                    alert("当前您尚未登录!请登录后再访问博客列表!");
                    location.assign('blog_login.html');
                }
            },
            error: function() {
                alert("当前您尚未登录! 请登录后再访问博客列表!");
                location.assign('blog_login.html');
            }
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    1.5正确显示用户信息

    该步骤需要注意两点:

    • 在博客列表页的用户名,要根据登录的用户来进行确定
    • 在博客详情页的用户名,要根据博客的作者来确定

    1.5.1 博客列表页

    因为在数据库中并没有存储个人的头像和文章数量等信息,所以只能对用户名做出变动,因为之前在1.4中完成了登录状态检测的步骤后,也就完成了后端代码,这一步只需要在前端进行微调,在页面是博客列表页时,能够将用户名做出修改即可。

    //这个文件放一些页面公共的代码
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    效果预览:在这里插入图片描述

    1.5.2 博客详情页

    要想完成博客详情页中用户名的更改,还需要重新约定接口编写前后端代码

    1)约定接口
    在这里插入图片描述
    2)编写前端代码

    关键代码
    前端代码中的两个ajax请求,是异步并发执行的,并不能确定先后顺序,所以在一个函数的回调函数中,调用另一个函数,让其变为串行执行,才能控制顺序。
    在这里插入图片描述

    在这里插入图片描述

    3)编写服务器代码

    @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.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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    1.6注销功能

    在导航栏中有一个“注销”按钮,当用户点击注销以后,就会在服务器上取消登录状态,并且能够跳转到登录页面。

    1)约定前后端交互接口

    在这里插入图片描述
    2)注销逻辑的服务器代码

    @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("当前用户尚未登录!无法注销!");
                return;
            }
            //把这个用户的会话中的信息给删掉即可
            session.removeAttribute("user");
            resp.sendRedirect("blog_login.html");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    用户有一个session,同时session中有一个user属性,两者同时兼备时,就是登陆状态,注销只要把其中一个条件破坏掉即可。
    在这里插入图片描述
    3)客户端代码修改
    把博客列表页、博客详情页、博客编辑页中的导航栏中的注销按钮中的herf属性,都做出修改,改成“logout”这个路径。

    1.7发布博客

    在博客编辑页中,当用户输入了博客标题和正文之后,点击发布,此时就会把博客数据提交到服务器,由服务器存储到数据库中。

    1)约定前后端交互接口
    在这里插入图片描述
    2)实现服务器代码

    BlogServlet里面添加一个doPost方法,来处理上述的post请求;
    核心操作,就是读取请求中的标题和正文,构造blog,构造Blog对象,并插入数据库

     @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            HttpSession session=req.getSession(false);
            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;
            }
            //一定要先指定好请求,按照哪种编码来解析
            req.setCharacterEncoding("utf8");
            //先从请求中取出参数(博客的标题和正文)
            String title=req.getParameter("title");
            String content=req.getParameter("content");
            if(title==null||"".equals(title)||content==null||"".equals(content)) {
                //直接告诉客户端,请求参数不对
                resp.setContentType("text/html;charset=utf8");
                resp.getWriter().write("提交博客失败!缺少必要的参数!");
                return;
            }
            //构造Blog对象,把当前的信息填进去,并插入数据库中
            //此处要给Blog设置的属性,主要是title,content,userId(作者信息)
            //postTime和blogId都不需要手动指定,都是插入数据库的时候自动生成的
            Blog blog=new Blog();
            blog.setTitle(title);
            blog.setContent(content);
            //作者id就是当前提交这个博客的用户的身份信息
            blog.setUserId(user.getUserId());
            BlogDao blogDao=new BlogDao();
            blogDao.insert(blog);
            //重定向到博客列表页
            resp.sendRedirect("blog_list.html");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3)调整客户端代码
    将整个文章内容用form表单套住,提交form表单

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Documenttitle>
        <link rel="stylesheet" href="css/common.css">
        <link rel="stylesheet" href="css/blog_edit.css">
    
        
        <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
        <script src="js/jquery.min.js">script>
        <script src="editor.md/lib/marked.min.js">script>
        <script src="editor.md/lib/prettify.min.js">script>
        <script src="editor.md/editormd.js">script>
    head>
    <body>
        <div class="nav">
            <img src="image/dd.jpg" alt="">
            <span>我的博客系统span>
            
            <div class="spacer">div>
            <a href="blog_list.html">主页a>
            <a href="blog_edit.html">写博客a>
            <a href="logout">注销a>
        div>
        
        <div class="blog-edit-container">
            <form action="blog" method="post" style="height: 100%;">
                <div class="title">
                    <input type="text" placeholder="在此处输入标题" name="title" id="title">
    
                    
                    <input type="submit" value="发布文章" id="submit">
                div>
                
                <div id="editor">
        
                    <textarea name="content" style="display:none">textarea>
                div>
            form>
        div>
    
        <script>
            // 初始化编辑器
            let editor = editormd("editor", {
                // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. 
                width: "100%",
                // 设定编辑器高度
                height: "calc(100% - 50px)",
                // 编辑器中的初始内容
                markdown: "# 在这里写下一篇博客",
                // 指定 editor.md 依赖的插件路径
                path: "editor.md/lib/",
                // 此处要加上一个重要的选项, 然后 editor.md 就会自动把用户在编辑器输入的内容同步保存到 隐藏的 textarea 中了!
                saveHTMLToTextarea: true,
            });
        script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    注意对css样式的选择器进行调整,保证提交按钮的样式不丢。
    在这里插入图片描述

    1.8删除博客

    只有自己能够删除自己的博客,不能够删除别人的博客。

    1)约定接口
    在这里插入图片描述
    2)调整前端代码

    我们需要在博客详情页中进行判定,当前博客的作者,是否就是登录的用户;

    如果是,就在导航栏里显示一个删除按钮,如果不是,就不显示删除按钮
    在这里插入图片描述
    3)编写服务器代码

    @WebServlet("/blogDelete")
    public class BlogDeleteServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.检查当前用户是否登录
            HttpSession session=req.getSession(false);
            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("当前blogId参数不对!");
                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");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    ⭐️最后的话⭐️
    总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

    请添加图片描述

  • 相关阅读:
    zabbix监控
    Ansible工具的初步使用
    Linux开发工具(4)——Makefile
    Environment Modules工具
    微服务简单实现最终一致性
    梳理RWKV 4,5(Eagle),6(Finch)架构的区别以及个人理解和建议
    Linux环境变量
    如何使用pywinauto打开Windows上指定的应用程序
    企业为何刚需CRM软件系统
    Redis数据库的简介、部署及常用命令----【重点!】
  • 原文地址:https://blog.csdn.net/qq_60856948/article/details/127753881