【项目】教你手把手完成博客系统(二)获取博客列表 | 获取博客详情页 | 实现登录功能 | 强转登录


教你手把手完成博客系统(二)

源码链接在文末~

3.获取博客列表

在博客列表页加载时,通过ajax给服务器发起请求,从服务器数据库拿到博客列表数据,并且显示到页面上。

1.约定前后端的交互接口
//请求
GET/blog

//响应
HTTP/1.1 200 OK 
Content-Type:application/json
[
    {
        blogId : 1,
        title : "这是标题",
        content : "这是正文",
        postTime :"2024-5-21 12:00:00",
        userId : 1
    }
]
2.浏览器向服务器发起请求
<script>
    // 通过函数进行封装
    function getBlogs() {
        $.ajax({
            type:'get',
            url:'blog',
            success:function(body){
                //服务器成功响应后调用的回调函数
                //TODO,根据返回的数据,构造页面的片段
            }
        });
    }
    //进行函数调用
    getBlogs();

</script>
3.服务器处理请求,返回响应数据

​ 查询数据库

package servlet;

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;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Author: Weng-Jiaming
 * Date: 2024-05-21
 * Time: 17:03
 */
@WebServlet("/html/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.getBlogs();

        String respJson = objectMapper.writeValueAsString(blogs);
        System.out.println("respJson = "+respJson);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

4.前端代码处理响应的数据

把得到的数据构成html片段,显示到页面上

        $.ajax({
            type: 'get',
            url: 'blog',
            success: function (body) {
                //服务器成功响应后调用的回调函数
                //TODO,根据返回的数据,构造页面的片段
                let container_right = document.querySelector('.container_right');

                for (let i = 0; i < body.length; i++) {
                    let blog = body[i]; // {blogId :1,title:'这是标题'...}
                    // 取出每一个blog元素
                    //构建博客
                    let blogDiv = document.createElement('div');
                    blogDiv.className = 'blog';
                    //构建标题
                    let titleDiv = document.createElement('div')
                    titleDiv.className = 'title'
                    titleDiv.innerHTML = blog.title;
                    //构建日期
                    let dateDiv = document.createElement('div')
                    dateDiv.className = 'date'
                    dateDiv.innerHTML = blog.postTime;
                    //构建摘要
                    let descDiv = document.createElement('div')
                    descDiv.className = 'desc'
                    descDiv.innerHTML = blog.content;
                    //构造查看全文按钮
                    let a = document.createElement('a')
                    a.className = 'detail';
                    a.innerHTML = '查看全文&gt;&gt;'
                    //点击不同的博客,要跳转到不同的博客详情页
                    a.href = './blog_content.html?blogId' + blog.blogId;

                    //创建好节点后,进行组装
                    blogDiv.appendChild(titleDiv);
                    blogDiv.appendChild(dateDiv);
                    blogDiv.appendChild(descDiv);
                    blogDiv.appendChild(a);
                    container_right.appendChild(blogDiv);
                }
            }
        });

在这里插入图片描述

  • 可以看到,前端加载时发出的请求,经过服务器的处理,从数据库中取出博客数据返回给前端。前端把得到的数据构造成html片段,显示在页面上。

在blog实体类中,重新设置获取的时间,把时间戳转换成标准时间

    public String getPostTime() {
        //Java标准库提供了一个SimpleDateFormat类,来完成时间戳到格式化时间的转换。
        //
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        return simpleDateFormat.format(postTime);
    }
  • 同时需要对返回的博客列表进行排序
            String sql = "select * from blog order by postTime desc";//进行降序排序
4.博客详情页
  • 点击查看全文后,会跳转到博客详情页

                      a.href = 'blog_content.html?blogId=' + blog.blogId;
    
    http://127.0.0.1:8080/blog_system/html/blog_content.html?blogId=4
    

    点击不同的博客,跳转之后会带有不同blogId的query string

    ​ 在博客详情页中,给服务器发送ajax请求,根据得到了blogId,查询数据库,得到博客的具体内容后返回给前端。前端再把具体的内容构造出来

1.约定前后端交互的接口
//请求
GET/blog?blogId=1
//响应
HTTP/1.1 200 OK
Content-Type:application/json
{
    blogId:1,
    title:"这是第一篇博客",
    postTime:"2024-5-21 12:00:00",
    userId:1
}
2.前端通过ajax发起请求

通过js代码,拿到url中query String当中的blogId

location.search
<script>
  function getBlog() {
    $.ajax({
      type: 'get',
      url: 'blog' + location.search,//拼贴上blogId
      success: function (body) {
        //返回一篇博客的内容{blogId:1,title:'这是标题'...}
        
      }
    })
  }
  getBlog();
</script>
3.让服务器处理请求
package servlet;

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;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Author: Weng-Jiaming
 * Date: 2024-05-21
 * Time: 17:03
 */
@WebServlet("/html/blog")
//路径和前端请求的路径一一对应
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String blogId = req.getParameter("blogId");
        BlogDao blogDao = new BlogDao();
        String respJson = null;
        if (blogId == null) {
            //blogId为空,说明请求来自博客列表页
            //查询数据库,得到博客列表,把博客列表数据按照json数据格式返回回去
            List<Blog> blogs = blogDao.getBlogs();

            respJson = objectMapper.writeValueAsString(blogs);

        } else {
            //blogId存在,说明请求来自博客详情页
            Blog blog = blogDao.getBlog(Integer.parseInt(blogId));//类型转换
           respJson = objectMapper.writeValueAsString(blog);
        }
        System.out.println("respJson = " + respJson);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

一个servlet来处理两种不同的请求

4.前端拿到数据后,构造html片段,显示在页面上
resp.setContentType("application/json;charset=utf8");

响应中带有ContentType:application/json。jquery自动把字符串转换成js对象,直接通过.的方式访问属性

  function getBlog() {
    $.ajax({
      type: 'get',
      url: 'blog' + location.search,//拼贴上blogId
      success: function (blog) {
        //返回一篇博客的内容{blogId:1,title:'这是标题'...}
        let title = document.querySelector('.blog .title');
        title.innerHTML=blog.title;
        let date = document.querySelector('.blog .date');
        date.innerHTML = blog.postTime;
        let desc = document.querySelector('.blog .desc');
        desc.innerHTML = blog.content;
      }
    })
  }
  getBlog();
  • 由于会存在浏览器缓存,可以用Fn+F5进行强制刷新

在这里插入图片描述

当前显示的是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>
  • 引入editor.md的依赖
        editormd.markdownToHTML('content',{markdown:blog.content})
        //第一个参数必须是html标签的id,表示位置         //要渲染的内容
  • 对md格式进行渲染

在这里插入图片描述

5.实现登录

在登录页面输入用户名和密码,点击登录,给服务器发送请求

服务器处理登录请求,读取用户名和密码,并在数据库中查询,进行匹配

如果正确,就登录成功,创建会话,跳转到博客列表页

1.约定前后端交互接口
//请求
POST/login
Content-Type:application/x-www-form-urlencoded
username=zhangsan&password=123
//响应
HTTP/1.1 302
Location:blog_list.html
  • form表单,提交成功可以直接使用302重定向跳转。如果使用ajax,ajax处理响应就需要写代码来完成跳转
2.让前端发起请求

form

            <form action="login" method="post">
                <div class="row">
                    <span>用户名</span>
                    <input type="text" class="username" name="username">
                    <!-- input标签中的name属性,就是query String当中的key -->
                </div>
                <div class="row">
                    <span>密码</span>
                    <input type="text" class="password" name="password">
                </div>
                <div class="row">
                    <button>提交</button>
                </div>
            </form>
3.让服务器处理请求,返回响应
package servlet;

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;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Author: Weng-Jiaming
 * Date: 2024-05-21
 * Time: 22:22
 */
@WebServlet("/html/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.读取参数中的用户名和密码
        req.setCharacterEncoding("utf8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null || username.length() == 0 || password == null || password.length() == 0) {
            resp.setContentType("text/html;charsets=utf8");
            resp.getWriter().write("您输入的用户名或者密码为空");
            return;
        }
        //2.查询数据库,判断是否正确

        UserDao userDao = new UserDao();
        User user = userDao.getUserByName(username);
        if (user == null) {
            //用户名不存在
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("您输入的用户名或密码不正确");
            return;
        }
        if (!password.equals(user.getPassword())){
            //密码不正确
            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");
    }
}

6.实现强制登录
  • 如果是未登录状态,需要先登录才能进行使用

在博客列表页、详情页、编辑页判定当前用户是否登录,如果未登录则强制跳转到登录页

在这几个页面加载时,给服务器发送ajax,从服务器获取一下登录的状态

1.约定前后端交互的接口
//请求
GET/login
//响应
登陆成功:HTTP/1.1 200
登录失败:HTTP/1.1 403

2.前端代码发起请求
    //定义新的函数获取登录状态
    function getLoginStatus(){
        $.ajax({
            type:'get',
            url:'login',
            success:function(body){
                //已经登录的状态
                console.log("已经登录了");
            },
            error: function(){
                //状态码不是2XX的时候触发这个回调函数
                //当服务器返回403时,就会触发这个部分的逻辑
                //强转要求页面跳转到登录页
                location.assign('login.html');

            }
        })
    }
    getLoginStatus();
    //ajax是并发执行的
3.处理请求
    /**
     * 反馈用户的登录状态
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //反馈当前的登录状态
        //要求会话要存在,还要求会话中保存user对象
        HttpSession session = req.getSession(false);
        if (session==null){
            //会话不存在,用户属于未登录状态
            resp.setStatus(403);
            //返回403响应
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user==null){
            //user对象也不存在,同样属于未登录状态
            resp.setStatus(403);
            //返回403响应
            return;
        }
        //两个都存在,返回200
        resp.setStatus(200);//200可以不写,默认是200
    }

  • 登录之后如果重启服务器,会被判定为未登录状态。登录状态是通过服务器这里的session来存储的。session是服务器内存中类似于Hash表的结构,如果服务器重启,hash表中原有的数据就没有了

  • 解决方法:

    1.把会话进行持久化保存(文件、数据库)

    2.使用令牌的方式(把用户信息在服务器加密,还是保存在浏览器这边)相当于服务器没有在内存中存储当前的用户身份

    由于每个页面都需要实现,强制登录的功能。将这段js函数代码单独存放一个js文件,进行复用

<script src="../js/app.js"></script>

查看源代码,请点击:博客系统完整代码

点击移步博客主页,欢迎光临~

偷cyk的图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值