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

news2024/11/24 19:28:35

在这里插入图片描述

请添加图片描述

⭐️前言⭐️

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

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

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

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

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


请添加图片描述

📍内容导读📍

  • 🍅1.针对完成任务
    • 1.1博客列表页
    • 1.2博客详情页
    • 1.3登录功能
    • 1.4检验登录状态
    • 1.5正确显示用户信息
      • 1.5.1 博客列表页
      • 1.5.2 博客详情页
    • 1.6注销功能
    • 1.7发布博客
    • 1.8删除博客

请添加图片描述

🍅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);
    }
}

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>
    <!-- container作为页面的版心 -->
    <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>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>

        <!-- 右侧个人信息 -->
        <div class="right">
            <!-- <div class="blog">
                <div class="title">
                    我的第一篇博客
                </div>
                <div class="date">
                    2022-10-21 21:24:00
                </div>
                <div class="desc">
                    刷爆LeetCode!Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, hic ipsa veritatis adipisci rem, provident accusantium deserunt soluta magnam distinctio consequatur fugit, neque omnis explicabo deleniti reiciendis magni architecto eaque!
                </div>
                <a href="#">查看全文&gt;&gt;</a>
            </div> -->
        </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 = '查看全文 &gt;&gt;';
                        // 此处希望点击之后能够跳转到 博客详情页 !!
                        // 这个跳转过程需要告知服务器要访问的是哪个博客的详情页. 
                        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博客详情页

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">

    <!-- 引入 editor.md 的依赖 -->
    <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>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>

        <!-- 右侧个人信息 -->
        <div class="right">
            <!-- 使用该div来包裹整个博客的内容详情 -->
            <div class="blog-content">
                <!-- 与博客详情页逻辑不同的是,该页面不再需要创建标签,
                    直接在已经挂在DOM树上的标签中填写内容即可,因为该页面是固定区域的,
                    而列表页是多个列表 -->
                <!-- 博客标题 -->
                <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>

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.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>Document</title>
    <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>
        <!-- <a href="#">注销</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>

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;
}

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.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));
    }

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.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.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.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");
    }
}

用户有一个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");
    }

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>Document</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_edit.css">

    <!-- 引入 editor.md 的依赖 -->
    <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">

                <!-- <button>发布文章</button> -->
                <input type="submit" value="发布文章" id="submit">
            </div>
            <!-- 放置md编译器 -->
            <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>

注意对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");
    }
}


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

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/4757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matplotlib设置限制制作

Matplotlib自动到达要沿着图的x&#xff0c;y(以及3D图的情况下为z轴)轴显示的变量的最小值和最大值。但是&#xff0c;可以使用set_xlim()和set_ylim()函数显式设置限制。 在下图中&#xff0c;显示了x和y轴的自动缩放限制 - #! /usr/bin/env python #codingutf-8 import matp…

【关于Linux中----进程控制和进程替换】

文章目录一、进程创建二、进程终止2.1进程退出场景2.2进程退出方法三、进程等待3.1进程等待必要性3.2进程等待的方法3.3获取子进程status四、进程程序替换4.1替换原理4.2替换函数4.3命名理解五、总结一、进程创建 谈到创建进程&#xff0c;不得不提到一个函数----fork。 在li…

【Python】一个矩阵根据某一列选择大于或小于范围的数据

data_all data_all[data_all[:,3]>54201]data_all data_all[data_all[:, 3] < 54220] 上面就是根据数据的第3列&#xff0c;选取54201到54220的范围的数据&#xff1a;

单片机最小系统

单片机最小系统,或者称为最小应用系统,是指用最少的元件组成的单片机可以工作的系统. 对51系列单片机来说,最小系统一般应该包括:单片机、晶振电路、复位电路. 下面给出一个51单片机的最小系统电路图. 晶振电路&#xff1a; 单片机里都有晶振&#xff0c;在单片机系统里晶振作用…

2013年第四届C/C++ A组蓝桥杯省赛真题+解析+代码

目录 第一题&#xff1a;高斯日记 题目描述 思路分析 AC代码 第二题&#xff1a;排它平方数 题目描述 思路分析 AC代码 第三题&#xff1a;振兴中华 题目描述 思路分析 AC代码 第四题&#xff1a;颠倒的价牌 题目描述 思路分析 AC代码 第五题&#xff1a;前缀…

jsp就业管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 就业管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为Mysql&#xff0c;使用ja…

蓝桥杯备赛(三)

目录 前言&#xff1a; 一、门牌制作 解析&#xff1a; 代码实现 二、寻找2020 解析&#xff1a; 代码实现 三、蛇形填数 解析&#xff1a; 代码实现 四、成绩分析 解析&#xff1a; 代码实现 五、单词分析 解析&#xff1a; 代码实现 小结&#xff1a; 前言&am…

热门Java开发工具IDEA入门指南——了解并学习IDE

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。 本…

面试了1个月连续失败4次,自动化测试真没想象的那么简单

我干测试6年了&#xff0c;最近面试又碰壁了… 这大概是我这一个月来第4次面试失败了&#xff0c;起初我投简历比较勇猛&#xff0c;奔着薪资高的有点儿名气的企业就开始海投&#xff0c;碰上了2家还不错的邀约面试&#xff0c;前面交流还行&#xff0c;一问到自动化测试就傻眼…

怎么进行视频恢复?推荐使用这4种方法

电脑视频怎么恢复&#xff1f;很多朋友在使用电脑的过程中&#xff0c;如果系统或者是存储文件出现问题的话&#xff0c;可能会出现视频丢失的情况。因为在使用电脑运行视频软件时&#xff0c;系统或者存储文件存在一些质量问题从而导致视频丢失。那么想要进行视频恢复&#xf…

【Leetcode】拿捏链表(一)——206.反转链表、203.移除链表元素

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《Leetcode》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 206.反转链表 203.移除链表元素 206.反转链表 力扣https://leetcode…

“工程化”对于大型数据平台而言,意味着什么?StartDT Hackathon来了

日前&#xff0c;2022 第三季 StartDT Hackathon 正式落下帷幕&#xff0c;以“产品工程化与可扩展性提升”为主题&#xff0c;主攻数据云这个“庞然大物”的工程化难题。 本届黑客松共吸引到 9 组参赛&#xff0c;均在 72 小时内完成项目并提测通过。有“单排孤勇者”&#x…

.NET JIT

定义 即时编译器 (JIT) 是 .NET 中公共语言运行时 (CLR) 的一部分&#xff0c;它负责管理 .NET 程序的执行&#xff0c;而与任何 .NET 编程语言无关。 工作流 特定于语言的编译器将源代码转换为中间语言。 然后&#xff0c;这种中间语言由即时 (JIT) 编译器转换为机器代码。 …

一篇文章学会React

React基础 文章目录React基础React介绍React特点React基本使用安装使用React脚手架&#xff08;***&#xff09;生成的项目的目录结构src下的index.js入口文件介绍脚手架中使用ReactJSX什么是JSX产生原因介绍JSX概述JSX语法注意事项JSX语法原理JSX学习声明式渲染条件渲染循环渲…

YOLOX改进

这是yolox的第2季了 如何设计在 mAP 和延迟方面表现良好的单级轻量级检测器&#xff1f;新型的单阶段轻量检测器和各种操作的准确性和延迟。此基础上分别提出了GPU和CPU的最佳操作和架构。一份YOLOX改进的实验报告&#xff1a;如何设计性能优异的单阶段轻量级目标检测器 论文…

Android Studio App自定义控件中视图的构造和测量方法讲解及实战(附源码 实现下拉刷新功能 超详细必看)

需要全部源码或者图片集请点赞关注收藏后评论区留言~~~ 一、视图的构造方法 Android自带的控件往往外观欠佳&#xff0c;开发者常常需要修改某些属性&#xff0c;比如按钮控件Button就有好几个问题&#xff0c;其一字号太小&#xff0c;其二文字颜色太浅&#xff0c;其三字母默…

表白爱心代码

文章目录一、演示&#xff08;python版&#xff09;代码二、演示&#xff08;html版&#xff09;代码一、演示&#xff08;python版&#xff09; 代码 # 在等一句我愿意 import random from math import sin, cos, pi, log from tkinter import *CANVAS_WIDTH 640 # 画布的宽…

hive最近的学习汇总-20221110

下个项目可能要用hive比较多 之前对分区、分桶搞不明白 趁着最近又学习了一下 ps&#xff1a;之前说的prophet在年底前一定会放上来的 hive是基于Hadoop构建的一套数据仓库分析系统&#xff0c;它提供了丰富的SQL查询方式来分析存储在Hadoop分布式文件系统中的数据&#xff1…

MySQL管理常用工具介绍

1.mysql 该mysql不是指mysql服务&#xff0c;而是指mysql的客户端工具。 -e选项可以在Mysql客户端执行SQL语句&#xff0c;而不用连接到MySQL数据库再执行&#xff0c;对于一些批处理脚本&#xff0c; 这种方式尤其方便。 示例&#xff1a; 2、 mysqladmin mysqladmin 是一个…

大三Web课程设计——悬崖上的波妞(4页) HTML+CSS(可以很好的应付老师的作业)

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…