Server version blog system, front-end and back-end interaction 2

16831205:

5. Blog details page

After writing the blog list page, click "Jump to full text". The text that appears is the content we wrote during the test.

Click "Jump to full text": 127.0.0.1:8080/blog_system/ blog_detail.html?blogId=5

This is a request sent to get the blog details page . The page you want to get here will display the main content of the current blog~~

This text content will continue to ajaxbe obtained through. When the blog_detail.html page is loaded, an ajax request is triggered to access the server, and the obtained blog content will be filled in the blog details page again!

1. Agree on the interactive interface

ask:

GET /blog?blogId=1

response:

HTTP/1.1 200 OK
Content-Type:application/json;

{
    
    
	blogId: 1,
    title: "第一篇博客",
    content: "这个正文",
    userId: 1,
    postTime: '2022-05-25' 13:33:33'
}

The difference between getting the blog list:

  1. In the request, there is parameter blogld

  2. The response result is not a json array, but a single object

  3. The responsive blog text is no longer truncated.


2. Modify BlogServlet

The back-end code implementation is basically the same as the acquisition of the blog list page, so it can be implemented directly in a method. Use the blogld parameter to distinguish whether to get the blog list or details~

Get the blog list request GET /blog without parameters,

// 通过这个类, 来处理 /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");

        // 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情
        // 如果该参数不存在, 说明是要请求博客的列表.
        BlogDao blogDao = new BlogDao();
        String param = req.getParameter("blogId");
        if (param == null) {
    
    
            List<Blog> blogs = blogDao.selectAll();
            // 把 blogs 对象转成 JSON 格式.
            String respJson = objectMapper.writeValueAsString(blogs);
            // 构造响应的时候 这里的这两行代码 顺序不能颠倒.
            // 如果先 write 了 body, 再设置 ContentType,设置的 ContentType就会不生效!!
            // 包括说 即使不是写 body,构造 sendRedirect 这种, 其实也是类似的情况~~
            resp.getWriter().write(respJson);
        } else {
    
    
            // 有 blogId,获取博客详情
            int blogId = Integer.parseInt(param);
            Blog blog = blogDao.selectOne(blogId);
            String respJson = objectMapper.writeValueAsString(blog);
            resp.getWriter().write(respJson);
        }
    }
}

Postman constructs request test: 127.0.0.1:8080/blog_system/blog?blogId=3

body: Blog details obtained based on blogId

{
    
    
    "blogId": 3,
    "title": "这是第三篇博客",
    "content": "从前天开始, 我要认真学 Java",
    "userId": 1,
    "postTime": "2022-51-27 02:51:36"
}

3. Front-end code blog_detail.html

1). Modify the content on the right

Modify blog_detail.html so that when this page is loaded, the above interface can be called to obtain blog data from the server!

<!-- 右侧内容详情 -->
<div class="right">
    <!-- 包裹整个博客的内容详情 -->
    <div class="blog-content">
        <!-- 博客标题 -->
        <h3></h3>
        <!-- 博客日期 -->
        <div class="date"></div>
        <!-- 博客的正文内容 -->
        <div id="content">

        </div>	
    </div>
</div>

2). Add ajax below

On the front-end code side, if you want to construct a request to obtain blog details, you need to know the ID of the blog clicked by the current user!!
This ID is already included in the URL of the current blog_detail.html page!!

Question 1: How to get the blogId:location.search

Insert image description here

Insert image description here

Insert image description here

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
    function getBlogDetail() {
    
    
        $.ajax({
    
    
            type: 'get',
            // location.search 拿到了形如 '?blogId=5' 这样的一段内容
            url: 'blog' + location.search,
            success: function(body) {
    
     // body 中就是一个 js 对象
                // 根据 body 中的内容来构造页面
                // 1. 构造博客标题
                let h3 = document.querySelector('.blog-content>h3');
                h3.innerHTML = body.title;
                // 2. 构造博客发布时间
                let dateDiv = document.querySelector('.date');
                dateDiv.innerHTML = body.postTime;
                // 3. 构造博客正文
                let contentDiv = document.querySelector('#content');
                contentDiv.innerHTML = body.content;
            }
        });
    }
    getBlogDetail();
</script>

Question 2: Our current blog text is not just text!! It is actually markdown data with certain formatting!!

If we use the above logic in the code and directly set the content to innerHTML, it means that the final display effect of the interface is on the left side, and the effect we need is the format on the right side.

Insert image description here

In this case, how should we deal with it? Can the markdown text content here be rendered into an html fragment with a specific style? We still need to use editor.mdthis library to complete
this. This library not only provides a markdown editor, but also provides a rendering function. ~~

Complete code:

<!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/picture.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/picture.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-content">
                <!-- 博客标题 -->
                <h3></h3>
                <!-- 博客日期 -->
                <div class="date"></div>
                <!-- 博客的正文内容 -->
                <div id="content" style="opacity: 73%;">

                </div>
            </div>
        </div>
    </div>

    <script>
        function getBlogDetail() {
      
      
            $.ajax({
      
      
                type: 'get',
                // location.search 拿到了形如 '?blogId=5' 这样的一段内容
                url: 'blog' + location.search,
                success: function(body) {
      
       // body 中就是一个 js 对象
                    // 根据 body 中的内容来构造页面
                    // 1. 构造博客标题
                    let h3 = document.querySelector('.blog-content>h3');
                    h3.innerHTML = body.title;
                    // 2. 构造博客发布时间
                    let dateDiv = document.querySelector('.date');
                    dateDiv.innerHTML = body.postTime;
                    // 3. 构造博客正文
                    // let contentDiv = document.querySelector('#content');
                    // contentDiv.innerHTML = body.content;
                    // 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串
                    // 咱们需要的是渲染后的, 带有格式的效果

                    // 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下. 
                    editormd.markdownToHTML('content', {
      
      
                        markdown: body.content
                    });
                }
            });
        }

        getBlogDetail();
    </script>

</body>
</html>

4.——Verification

Visit the list page, click "View Full Text", and find that the page has not changed at this time.

Note: When performing program verification, always keep in mind that the browser cache may affect the results.
The blog_detail page has been visited before, so the browser may save this page locally and try to access it next time. Just access local content directly~~

Insert image description here

Add a sql:

insert into blog values(null, '这是第三篇博客', '# 一级标题\n ### 三级标题\n > 这是引用内容', 2, now());

Click on the full text, the blog pages are all in markdown format


6. Login page

1. Agree on the interactive interface

Request: The logic here can be submitted directly using the form form. There is no need to use ajax (it is perfectly fine to use ajax!!)

If you want to use a form, you need to change the button toinput type="submit"

POST /login
Content-Type:application/x-www-form-urlencoded

response:

HTTP/1.1 302
Location:blog_list_html

When the login is successful, it will automatically jump to the home page (blog list page)


2. Front-end code blog_login.html

This time I will write the client first and slightly adjust the login page~~

Modify login-container:

  1. Add a layer of formtags to the login-dialog code!

  2. Add nameattributes to input~

    • This added attribute is the key of the key-value pair for subsequent data submission ~

      username=zhangsan&password=123

  3. Replace button button with inputlabel~

<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">
                <!-- <button>提交</button> -->
                <input type="submit" id="submut" value="提交">
            </div>
        </div>
    </form>
</div>

Start running, the style of the submit button does not work

In the process of front-end page development, the HTML page structure is very important. Many subsequent CSS and JS rely on this page structure. Once the page structure is adjusted , it may cause the css or js to fail~~

Set the button id, adjust the style, and after adjustment, if there is no change, ctrl + f5

Original style:

.row button {
    
    
    width: 300px;
    height: 50px;
    border-radius: 10px;
    color: white;
    background-color: rgba(0, 128, 0);
    border: none;

    margin-top: 20px;
}

/* 鼠标按下未弹起 */
.row button:active {
    
    
    background-color: #666;
}

Adjustment:

.row #submit {
    
    
    width: 300px;
    height: 50px;
    border-radius: 10px;
    color: white;
    background-color: rgba(0, 128, 0);
    border: none;

    margin-top: 20px;
}

/* 鼠标按下未弹起 */
.row #submit:active {
    
    
    background-color: #666;
}

Complete code:

<!-- 导航栏 -->
<div class="nav">
    <img src="image/picture.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">
                <!-- <button>提交</button> -->
                <input type="submit" id="submit" value="提交">
            </div>
        </div>
    </form>
</div>

3. Backend code LoginServlet

The path agreed here is /loginthat this is a new path, and a new servlet needs to be used to process it ~

Create LoginServlet class

username=zhangsan&password=123 The data in the request is in this format, so you need to use

String username = req.getParameter("username");

getParameterWhen reading parameters using If the value of the parameter is in Chinese , reading the parameter directly at this time will easily cause garbled characters!!!

Chinese involves the character encoding
front-end page . The browser has been told that Chinese characters are utf8.<meta charset="UTF-8">

Therefore, the Chinese characters input by the browser in the input box will also be encoded using utf8, but the Servlet does not parse according to utf8 by default
, so you need to tell the servlet to also parse the request according to utf8!!

req.setCharacterEncoding("utf8");

This is set for the request, meaning that the request is parsed using utf8 format. If this encoding is not added to the request, this garbled code will appear and the database cannot be queried correctly.

resp.setCharacterEncoding("utf8");This is set for the response, which means that the constructed data must be constructed according to utf8

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

4.——Verification

Visit http://127.0.0.1:8080/blog_system/blog_login.html

Insert image description here


7. Check login status

After the login function is completed, you need to adjust the previous two pages (blog list and blog details)
so that these two pages can only be accessed after logging in~~

This restriction is made here (if you restrict it this way, it will be easier to implement some other functions later)

When entering the blog list page/details page, first check the user's login status. If the user is currently logged in, you can continue to use it.
If you are not logged in, force this to jump to the login page.

How to implement the above functions:

  • You can access the server through the blog list page/details page when loading to get the current login status and see if you can get it.ajax
  • If it is obtained, it means that you are currently logged in, and you can stay on this page at this time.
  • If it is not obtained, it means that you are not logged in and you need to jump to the login page.

1. Agree on the interactive interface

ask:

GET /login

response:

HTTP/1.1 200 OK
Content-Type:application/json;
   
{
    
    
	userId: 1,
	username: 'zhangsan',
}

If you are logged in, the currently logged-in user information will be directly returned; if you are not logged in, an object with userld = 0 will be directly returned (this is just a typical agreement method, and other methods can also be used to agree, such as using 403 to indicate that the user is not currently logged in. Log in…)


2. Modify LoginServlet

Add doGet method:

Add to class :

    private ObjectMapper objectMapper = new ObjectMapper();

Modify the User attribute:

    private int userId = 0;
    private String username = "";
    private String password = "";

doGet method:

If you get it from the server sessionand get it inside, userit is regarded as a successful login!
(If the login is successful, the server will return sessionld to the client, and the browser will save this sessionld and bring this id with the next request. )
When the server gets the sessionld, it can check it in the hash table and know who the current session object is~~

	// 这个方法用来让前端检测当前的登录状态.
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setContentType("application/json; charset=utf8"); // 加载的时候,通过 ajax ,访问一下服务器,获取当前的登录状态
        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. Modify the front-end code common.js

Create common.js

Front-end page jump method:location.assign('login.html');

// 这个文件里放一些页面公共的代码

// 加上一个逻辑, 通过 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();

Introduce in list page and detail page:

<!-- 在这里引入上述的 js 文件, 就可以执行到里面的代码, 也就进行了登录状态的监测了 -->
<script src="js/common.js"></script>

4.——Verification

Insert image description here

Restart the server and visit the list page again. At this time, the window pops up again. Click to log in.

Although we have just logged in, the session information is stored in the server memory (the hash table of HttpSession is in the memory). When the server process is restarted, the data in the memory will naturally be gone~~
So every time the server is restarted , , you have to log in again~~


Guess you like

Origin blog.csdn.net/qq_56884023/article/details/126788814