基于服务器的博客系统

准备工作

(1) 创建项目
(2) 引入依赖(servlet、Jackson、mysql)
(3)创建必要的目录
(4)编写代码
(5、6) 打包部署(基于smart Tomcat)
(7)在浏览器中验证

编写服务器代码
View层:

在这里插入图片描述

编写数据库的操作代码

(1)创建数据库/表结构(数据库设计)

博客页面
1.博客列表页,显示博客的列表
2.博客详情页,点击博客列表页,上面列出的博客条目,跳转到的页面,显示博客的完整内容
3.登录页
4.博客编辑页,基于editor.md实现Markdown编辑器

存储博客:点击发布的时候,博客被发布到服务器上,就要被存起来
获取博客:在博客列表页和博客详情页,能够拿到博客的内容
还能够进行登录校验

博客表:用来存储所有的博客数据
用户表:用户登录

(2)封装 数据库
1.创建DBUtil封装数据库连接操作
2. 创建实体类
使用实体类表示数据库中的一条记录。
此处主要创建了Blog类和User类
3. 封装针对数据的增删改查

约定前后端交互接口

博客列表页

约定交互接口

这个页面要能够展示出数据库中的博客的列表
在这里插入图片描述

编写服务器代码

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

编写客户端编码

在页面加载的时候,让页面通过ajax访问服务器,获取到数据库中的博客数据,并且填到页面中。

<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
                    //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='data';
                        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>

博客详情页

约定交互接口

在这里插入图片描述

后端代码实现

后端代码实现和博客列表页的获取,基本相同,就直接放在一个方法中来实现。用blogId参数来区分是获取博客列表还是详情

 int blogId=Integer.parseInt(param);
            Blog blog=blogDao.selectOne(blogId);
            String respJson=objectMapper.writeValueAsString(blog);
            resp.getWriter().write(respJson);

实现前端代码

在这里插入图片描述

<script>
        function getBlogDetail() {
            $.ajax({
                type:'get',
                url:'blog'+location.search,
                success:function(body) {
                    //根据body中的内容来构造页面
                    //1.构造博客标题
                    let h3=document.querySelector(".blog-content>h3");
                    h3.innerHTML=body.title;
                    //2.构造博客发布时间
                    let dataDiv=document.querySelector(".data");
                    dataDiv.innerHTML=body.postTime;
                    //3.构造博客正文
                    //如果直接把content设为innerHTML,此时展示在界面上的内容,是原始的Markdown字符串
                    //需要的是渲染后的效果
                    // let content=document.querySelector("#content");
                    // content.innerHTML=body.content;
                    editormd.markdownToHTML('content',{
                        markdown:body.content
                    });

                }
            });

        }
        getBlogDetail();
    </script>
    

博客登录页

约定交互接口

在这里插入图片描述

前端代码

在这里插入图片描述

后端代码

在这里插入图片描述

@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");

    }
}

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

约定前后端交互接口。
在这里插入图片描述
前端代码:

 //通过 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 {
                        //登录失败
                        //让前端页面跳转到html
                        alert("当前您尚未登录,请登录后在访问博客列表");
                        location.assign('login.html');
                    }

                },
                error: function() {
                    alert("当前您尚未登录,请登录后在访问博客列表");
                    location.assign('login.html');
                }
            });
        } 

后端代码:

 //这个方法就让前端来检测当前的登录状态
    @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)在博客详情页,正确显示的信息是当前文章的作者信息。
让服务器提供一个接口,这个接口可以让客户端指定blogId,获取到指定blogId的作者信息。
在这里插入图片描述

实现“注销”功能

退出当前登录的状态。
当用户点击注销之后,就会在服务器上取消登录状态,并且能够跳转到登录页面。

约定前后端交互接口

在这里插入图片描述

@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("login.html");
    }
}

如何理解已经登录?
用户有一个session,同时session有一个user属性,两者同时具备,才是登录状态。
注销,只要破坏掉上面任意一个条件就行。此处选择的是破坏第二个条件

发布博客

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

约定前后端交互接口

在这里插入图片描述

服务器代码

在BlogServlet里面添加一个dopost方法,来处理上述post请求
核心操作,就是读取请求中的标题和正文,构造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);
        blog.setUserId(user.getUserId());
        BlogDao blogDao=new BlogDao();
        blogDao.insert(blog);
        //重定向到博客列表页
        resp.sendRedirect("blog_list.html");
                
    }

客户端代码

<form action="blog" method="post">
            <div class="title">
                <input type="text" placeholder="在此处输入标题" name="title">
                <!-- <button>发布文章</button> -->
                <input type="submit" value="发布文章">
            </div>
            <!-- 放置md编辑器 -->
            <div id="editor">
                <!-- 为了进行form的提交,此处添加一个textarea多行编辑框,借助这个编辑框来实现表单的提交 -->
                <textarea name="content" style="display:none"></textarea>
    
            </div>

        </form>

在这里插入图片描述
在这里插入图片描述

删除博客

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

界面

界面上的处理,在博客详情页这里去判断,看当前这个博客的作者,是否就是登录的用户,如果是,就在导航栏里显示一个“删除按钮”,如果不是,就不显示删除按钮。
在这里插入图片描述

在博客详情页这块,其实既从服务器获取了当前用户的登录信息,又获取了博客的作者信息。
在这里插入图片描述

服务器

用户点击删除按钮,触发一个HTTP请求,就会让服务器删除掉指定的博客,服务器收到请求后,就会把这个博客从数据库里给删掉。

在这里插入图片描述

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值