Blog system Java Web development (Servlet)

Table of contents

1. Preparation work

2. Design database

3. Write database code

1. Create table sql

2. Encapsulate database connection operations

3. Create entity class

4. Encapsulate some additions, deletions, modifications and queries of the database

(1)BlogDao

New blog: 

Query the specified blog based on the blog id (for blog details page)

Directly query the list of all blogs in the database

Delete blog

(2)UserDao

Query user information based on userId

 Query user information based on username (when logging in)

4. Implement the function of obtaining the blog list around the blog list page

1. Agree on the front-end and back-end interaction interfaces

2. Write back-end code

3. Write front-end code

5. Blog details page

1. Agree on the front-end and back-end interaction interfaces

2. Implement back-end code

3. Implement front-end code

6. Implement the login page

1. Agree on the front-end and back-end interaction interfaces

2. Modify the front-end code

3. Modify the backend code

7. Forced login to the page

1. Agree on the front-end and back-end interaction interfaces

2. Write back-end code

3. Implement front-end code

8. Display user information

1. Agree on the front-end and back-end interaction interfaces

 2. Write back-end code

3. Write front-end code

9. Log out of login status

1. Agree on the front-end and back-end interfaces

2. Write back-end code

3. Write front-end code

10. Publish a blog

1. Agree on the front-end and back-end interaction interfaces

Edit

2. Write server code

3. Write client code


1. Preparation work

Create a project, introduce dependencies, and copy the front-end page you wrote before

The dependencies to be introduced are: servlet, mysql, jackson

After introducing the dependencies, create a directory and copy and paste the contents of web.xml into it

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
        <display-name>Archetype Created Web Application</display-name>
</web-app>

Then copy and paste the front-end code written before into the webapp directory

 At this point, the preparation work is completed


2. Design database

Combined with the previous requirements, the current blog system mainly involves two entities: blog and user

We can create two tables to represent blogs and users

What is the relationship between these two entities?

One-to-many relationship, one user can write multiple blogs, but one blog can only belong to one user


3. Write database code

1. Create table sql

Encapsulate some basic database operations for subsequent use

In the src directory, create a db.sql and write the database and table creation statements of the database in it.

    --这个文件,主要用来写建库建表语句
    --一般在建表的时候,把建表的 sql 保留下来,以备后续部署其它及其的时候就方便了

    create database if not exists blog_system;
    use blog_system;

    --删除旧表,重新创建新表,防止之前的残留数据面对后续的程序有负面影响
    drop table if exists user;
    drop table if exists blog;

    --进行建表
    create table blog(
        blogId int primary key auto_increment,
        title varchar(128),
        content varchar(4096),
        postTime datetime,
        userId int
    };

    create table user(
        userId int primary key auto_increment,
        username varchar(20) unique , --要求用户名和别人不同
        password varchar(20)
    );

2. Encapsulate database connection operations

In the java directory, create a DBUtil class

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

//通过这个类,把数据库连接过程封装一下
//此处,把 DBUtil 作为一个工具类,提供 static 方法,供其它方法来调用
public class DBUtil {
    //静态成员是跟随类对象的,类对象在整个进程中,只有唯一一份
    //静态成员相当于也是唯一的实例(单例模式,饿汉模式)
    private static DataSource dataSource = new MysqlDataSource();

    static {
        //使用静态代码块,针对 dataSourse 进行初始化
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java?charactorEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");
    }

    //通过这个方法来建立连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //通过这个方法来断开连接,释放资源
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet)  {
        //此处的三个 try catch 分开写更好,避免前面的异常导致后面的代码无法执行
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

3. Create entity class

Entity class is the class corresponding to the record in the table

What attributes are required in the entity class are closely related to the columns in the current table.

Therefore, we need to create two classes, blog and user, based on the columns in the previous table:

And, manually add a get set accessor to each property inside.


4. Encapsulate some additions, deletions, modifications and queries of the database

Create a BlogDao for the blog table

For the user table, create a UserDao

They provide some methods to add, delete, modify and query

(1)BlogDao

 There are four methods in total:

1. Add a new blog

2. Query the specified blog according to the blog id (for blog details page)

3. Directly query the list of all blogs in the database

4. Delete blog

New blog: 

    //1、新增一个博客
    public void add(Blog blog){
        Connection connection = null;
        PreparedStatement statement = null;
        //1、和数据库建立连接
        try {
             connection = DBUtil.getConnection();
            //2、构造 Sql
            String sql = "insert into blog values(null,?,?,?,?)";
             statement = connection.prepareStatement(sql);
             statement.setString(1,blog.getTitle());
             statement.setString(2,blog.getContent());
             statement.setTimestamp(3,blog.getPostTime());
             statement.setInt(4,blog.getUserId());
            //3、执行 sql
            statement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }

Query the specified blog based on the blog id (for blog details page)

    //2、根据博客 id 来查询指定博客(用于博客详情页)
    public Blog selectById(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try{
            //1、和数据库建立连接
            connection = DBUtil.getConnection();
            //2、构造 SQL 语句
            String  sql = "select *from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3、执行 sql
            resultSet = statement.executeQuery();
            //4、遍历结果集合,由于此处的 blogId ,在 blog 表中是唯一的(主键)
            //此时的查询结果,要么是没有查到任何数据,要么是只有一条记录
            //所以,此处使用 if 即可,不用使用 while
            if (resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                blog.setContent(resultSet.getString("content"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                return blog;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            //5、释放必要的资源
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

Directly query the list of all blogs in the database

Note: The blog content displayed on the blog list page here should only be a simple summary (a small part of the article content)

Instead of the entire article, the complete article should be displayed on the blog details page

Therefore, we can crop the longer text

    //3、直接查询出数据库中所有的博客列表(用于博客列表页)
    public List<Blog> selectAll(){
        List<Blog> blogs = new ArrayList<>();
        
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try{
            //1、和服务器建立连接
            connection = DBUtil.getConnection();
            //2、构造 sql 语句
            String sql = "select *from blog";
            statement = connection.prepareStatement(sql);
            //3、执行 sql
            resultSet =  statement.executeQuery();
            //4、遍历结果集合
            while (resultSet.next())  {
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                //这里的正文,在博客列表页中,不需要把整个正文显示出来
                String content = resultSet.getString("content");
                if (content.length() >= 100){
                    content = content.substring(0,100) + "...";
                }
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                blogs.add(blog);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return  blogs;
    }

Delete blog

    //4、删除指定博客
    public void delete(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        try{
            //1、和数据库建立连接
            connection = DBUtil.getConnection();
            //2、构造 sql 语句
            String sql = "delete from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3、执行 sql
            statement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            //进行关闭
            DBUtil.close(connection,statement,null);
        }
    }

(2)UserDao

There are two methods in total:

1. Query user information based on userId

2. Query user information based on username (when logging in)

Query user information based on userId

    //1、根据 userId 来查询用户信息
    public User selectById(int userId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1、和数据库建立连接
            connection = DBUtil.getConnection();
            //2、构造 sql
            String sql = "select *from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            //3、执行 sql
            resultSet = statement.executeQuery();
            //4、遍历结果集合
            if (resultSet.next()){
                User user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                return user;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

 Query user information based on username (when logging in)

    //2、根据 username 来查询用户信息(登录的时候)
    public User selectByUsername(String username){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1、和数据库建立连接
            connection = DBUtil.getConnection();
            //2、构造 sql
            String sql = "select *from user where username = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1,username);
            //3、执行 sql
            resultSet = statement.executeQuery();
            //4、遍历结果集合
            if (resultSet.next()){
                User user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                return user;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

By writing this, the database operations have been encapsulated.


4. Implement the function of obtaining the blog list around the blog list page

Next, we focus on the blog list page to implement the function of obtaining the blog list

Currently, the data on our blog list page are all fixed, which is obviously unscientific.

The correct approach should be to read the data through the database and display it on the page 

Here, it is necessary to open up the front-end and back-end interaction operations.

Let the blog list page, when loading, send a request to the server through ajax. The server checks the database, obtains the blog list data, and returns it to the browser. The browser then constructs the page content based on the data.

Such an interactive process is also called "front-end and back-end separation"

The front end only requests data from the back end, not specific pages, and the back end only returns data. The purpose of this setting is to further decouple the front end and back end.

The above is the basic idea for implementing a blog list page

Next, we need:

1. Agree on the front-end and back-end interaction interfaces

2. Develop back-end code

3. Develop front-end code

1. Agree on the front-end and back-end interaction interfaces

On the blog list page, under the function of obtaining the blog list, what request the front end will send and what response the back end will return need to be agreed upon.

After determining the front-end and back-end interfaces, the front-end and back-end are developed according to this format respectively.


2. Write back-end code

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        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);
    }
}

At this time, we will find that the more classes we write here, the more we write them, and they will look more messy.

At this time, we can classify them and deal with them

model: the part that manages data/operates data

Put this Servlet into the API. The API must be a class/method, or it can be a "network interface" (processing HTTP requests and returning HTTP responses)


3. Write front-end code

On the blog list page, during the loading process, ajax is triggered to access the data in the server.

Then construct the obtained data into the page

When constructing the page content, we can refer to the html code written before to construct it.

 <script src="./js/jquery.mini.js"></script>
    <script>
        //在页面加载时 ,向服务器发起一个请求,获取博客列表数据
        function getBlogs(){
            $.ajax({
                type:'get',
                url:'blog',
                success:function(body){
                    //响应的 body 是一个 json 字符串,此处已经被 jquery 自动解析成 js 对象数组了
                    //直接 for 循环遍历即可
                    let containerRight = document.querySelector('.containner');
                    for(let blog of body){
                        //构造页面内容,就参考之前写好的 html 代码
                        //构造整个博客 div 
                        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');
                        datteDiv.className = 'date';
                        dateDiv.innerHTML = blog.postTime;
                        blogDiv.appendChild(dateDiv);
                        //构造博客摘要
                        let descDiv = document.createElement('div');
                        descDiv.className = 'desc';
                        desc.innerHTML = blog.content;
                        blogDiv.appendChild(descDiv);
                        //构造查看全文按钮
                        let a  = document.createElement('a');
                        a.innerHTML = '查看全文 &gt;&gt;';
                        //期望点击之后,可以跳转到博客详情页,为了让博客详情页知道点了哪个博客,把  blogId 传过去
                        a.href = 'blog_detail.html?blogId=' + blog.blogId;
                        blogDiv.appendChild(a);

                        //把 blogDiv 给加到父元素中
                        containerRight.appendChild(blogDiv);
                    }
                }
            });
        }
        //要记得调用
        getBlogs();
    </script>

At this point, the blog list page function is completed.

At this point, when we insert a test case, we will find two problems:

 1. Timestamp: The timestamp should not be displayed, but the formatted time should be displayed.

We need to use a class for formatting time. SimpleDateFormat can help us convert it. 

2. In order, the new blog is at the top and the old blog is at the bottom.

Just add an order by directly to sql


5. Blog details page

Next, implement the blog details page

Click the "View Full Text" button to jump to the blog details page

After jumping to the past, initiate an ajax in the blog details page, obtain the specific content of the current blog from the server, and then display it.

1. Agree on the front-end and back-end interaction interfaces

Note: Since the blog details are obtained here, the content here is complete and does not need to be truncated like the blog list page. 

2. Implement back-end code

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //尝试获取一下 query string 中的 blogId 字段
        String blogId = req.getParameter("blogId");
        BlogDao blogDao = new BlogDao();
        if (blogId == null){
            //queryString 不存在,该请求是获取博客列表页
            List<Blog> blogs =  blogDao.selectAll();
            //需要把 blogs 转成符合要求的 json 格式的字符串
            String respJson = objectMapper.writeValueAsString(blogs);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }else {
            //query string 存在,本次请求是获取指定 id 的博客
            Blog blog = blogDao.selectById(Integer.parseInt(blogId));
            if (blog == null){
                System.out.println("当前 bligId = " + blogId + "对应博客不存在!");
            }
            String respJson = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }

3. Implement front-end code

In blog_detail.html, add ajax to obtain the above data

location.search is to get the query string of the current page

The location here is not the location in the http header, but a global object in the js code, similar to document

 Note: The current blog content is organized in markdown format. For example, the blog content is

The content will contain some markdown symbols and will eventually be displayed on the web page. We hope that the user will see the result after rendering, that is, # will be converted into a first-level title.

The content saved in the database is the content before rendering, but it is ultimately displayed to the user. We hope that the user will see the content after rendering.

Here you need to use editor.md to convert markdown content

How to convert it specifically?

editor.md provides a method: editormd.markdownToHTML. The effect is to convert the md string into an html fragment and output it to the #content tag (remember to introduce the dependency of editor.md when using it)

After changing the code, restart the server and find that the result of the blog details page is still the same as before.

This content is still the content that was hard-coded before, but in fact, the code has deleted this content.

This is because the browser itself also has a cache. The browser obtains the page from the server. This operation is completed through network transmission, and the speed is relatively slow.

The browser will cache the page content locally (on the hard drive of the client computer), and then access the same page directly and read the cache directly.  

This brings about a problem: if the server code changes, the client may not be able to detect the change in time after hitting the cache.

Solution: Force refresh, ctrl + f5. At this time, the local cache is ignored and the server is 100% revisited.

After the caching problem was solved, I found that although the current page had changed, the result was still not ideal. Check the error message and you would find that the code of editormd was written incorrectly. Make the modification and refresh the page again:

After modifying it, I found that the main text was there, but the title was not.

By capturing packets to see if the results returned by the server are as expected, we can determine whether it is a front-end problem or a back-end problem.

According to the response result, we can judge that there should be no problem with the back-end code. The response result is correct. Next, check the front-end code. 

We will find that this is because there are two titles in the front-end code. The querySelector returns the first title by default, which then causes the title to be modified in the wrong place.

Solution: Just write the selector more accurately

Restart the server and refresh the page again. You will find that the title now appears correctly.

        <!-- 右侧信息 -->
        <div class="containner-right">
            <!-- 博客标题 -->
            <h3 class="title"></h3>
            <!-- 博客发布时间 -->
            <div class="date"></div>
            <!-- 博客正文  为了配合 editormd 进行格式转换,此处一定要改成 id -->
            <div id="content">

            </div>
        </div>
    </div>
    <script src="js/jquery.mini.js"></script>
        <!-- 引入 editor.md 的依赖 -->
        <!-- 要保证这个几个 js 的加载,在 jquery 之后,因为 edit.md 依赖了 jquery -->
        <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>
    <script>
        $.ajax({
            type:'get',
            url:'blog' + location.search,
            success:function(body){
                //处理响应结果,此处的 body 就是表示一个博客的 js 对象
                //1、更新标题
                let titleDiv = document.querySelector('.containner-right .title');
                titleDiv.innerHTML = body.title;
                //2、更新日期
                let dateDiv = document.querySelector('.date');
                dateDiv.innerHTML = body.postTime;
                //3、更新博客正文
                //此处,不应该直接把博客正文填充到这个标签里
                editormd.markdownToHTML('content',{markdown: body.content});

            }
        });
    </script>

6. Implement the login page

Enter your username and password here, click Login, and an HTTP request will be triggered.

The server verifies the username and password, and then determines whether the login is successful based on the results. If the login is successful, it jumps to the blog list page.

Currently, it is just a simple input box and cannot submit requests, so we need to change it into a form.

1. Agree on the front-end and back-end interaction interfaces

2. Modify the front-end code

Add a form to the page so that clicking on the login operation can trigger a request

1. Add the form tag and wrap the input in it

2. Input plus name attribute

3. Change the button to input submit type

        <!-- 垂直水平居中的对话框 -->
        <div class="login-dialog">
            <form action="login" method="post">
                <h3>登录</h3>
                <div class="row">
                    <span>用户名</span>
                    <input type="text" id = "username" placeholder="手机号 / 邮箱" 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="登录"></button>
                </div>
            </form>
        </div>

3. Modify the backend code

Here you need to add a Servlet to handle the login request

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求的编码,告诉 servlet 按照什么格式来理解请求
        req.setCharacterEncoding("utf8");
        //设置响应的编码,告诉 servlet 按照什么格式来构造请求
        //resp.setCharacterEncoding("utf8");
        resp.setContentType("text/html;charset=utf8");
        //1、读取参数中的用户名和密码
        //注意!!如果用户名密码包含中文,此处的读取可能会乱码,所以设置一下 utf8
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null || "".equals(username) || password == null || "".equals(password)){
            //登录失败
            String html = "<h3> 登陆失败! 缺少 username 或者 password 字段! </h3>";
            resp.getWriter().write(html);
            return;
        }
        //2、读数据库,看看用户名是否存在并且密码是否匹配
        UserDao userDao = new UserDao();
        User user = userDao.selectByUsername(username);
        if (user ==null){
            //用户不存在
            String html = "<h3> 登陆失败! 用户名 或 密码 错误!! </h3>";
            resp.getWriter().write(html);
            return;
        }
        if (!password.equals(user.getPassword())){
            //密码不对
            String html = "<h3> 登陆失败! 用户名 或 密码 错误!! </h3>";
            resp.getWriter().write(html);
            return;
        }
        //3、如果用户名和密码验证通过,登录成功,接下来创建会话,使用该会话来保存用户信息
        HttpSession session = req.getSession(true);
        session.setAttribute("user",user);
        //4、进行重定向,跳转到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

7. Forced login to the page

When a user accesses the blog list page/details page/edit page, the user must be logged in.

If the user is not logged in yet, force the user to jump to the login page.

The essence is a requirement. If you want to use the system, you must log in first.

Implementation ideas:

When the page is loading, a new ajax is specifically initiated (N ajax can be initiated in one page)

Take the blog list page as an example:

First send a request to get the blog list, and then send an ajax to get the user's login status. If the user is already logged in, it will be fine. If the user is not logged in, the page will jump to the login page.

1. Agree on the front-end and back-end interaction interfaces


2. Write back-end code

    @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 user = new User();
            String respJson = objectMapper.writeValueAsString(user);
            resp.getWriter().write(respJson);
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null){
            user = new User();
            String respJson = objectMapper.writeValueAsString(user);
            resp.getWriter().write(respJson);
            return;
        }
        //确实成功去除了 user 对象,直接返回即可
        String respJson = objectMapper.writeValueAsString(user);
        resp.getWriter().write(respJson);
    }

3. Implement front-end code

                function checkLogin(){
                    $.ajax({
                        type:'get',
                        url:'login',
                        success:function(body){
                            if(body.userId && body.userId > 0){
                                //登录成功
                                console.log("当前用户已经登录")
                            }else{
                                //当前未登录
                                //强制跳转到登录页
                                location.assign('login.html');
                            }
                        }
                    });
                }

                checkLogin();

8. Display user information

This user information is currently hard-coded. We hope to enable it to dynamically generate user information.

1. If it is a blog list page, the logged-in user information is displayed here.

2. If it is a blog details page, the author of the article is actually present at this time.

1. Agree on the front-end and back-end interaction interfaces

Blog list page code adjustment:

For the code of the blog details page, we rewrite a servlet 

When do you need to write a new servlet?

Mainly see the path of the current request, whether it is new or existing


 2. Write back-end code

@WebServlet("/author")
public class authorServlet extends HttpServlet {
    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String blogId = req.getParameter("blogId");
        if (blogId == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("参数非法,缺少 blogId ");
            return;
        }
        //根据 blogId 查询 Blog 对象
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectById(Integer.parseInt(blogId));
        if (blog == null){
            //博客不存在
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("没有找到指定博客:blogId = " + blogId);
            return;
        }
        //根据 blog 中的 userId 找到对应的用户信息
        UserDao userDao = new UserDao();
        User author = userDao.selectById(blog.getUserId());
        String respJson = objectMapper.writeValueAsString(author);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

3. Write front-end code

        function getAuthor(){
            $.ajax({
                type:'get',
                url:'author' + location.search,
                success: function(body){
                    //把 username 给设置到页面上
                    let h3 = document.querySelector('.containner-left .card h3');
                    h3.innerHTML = body.username;
                }
            });
        }

        getAuthor();

9. Log out of login status

Logout here refers to logging out, not deleting the account.

Determine login status:

1. Check if the http session object can be found

2. Check whether there is a user object in the session object.

To log out, either kill the http session or kill the user. Just choose one of the two.

If there is a session but no user object, it is also considered not logged in.

If you want to kill the http session, it will be more troublesome, so we choose to kill the user object.


1. Agree on the front-end and back-end interfaces


2. Write back-end code

@WebServlet("/logout")
public class logoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession httpSession = req.getSession(false);
        if (httpSession == null){
            //未登录状态
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前未登录!");
            return;
        }
        httpSession.removeAttribute("user");
        resp.sendRedirect("login.html");
    }
}

3. Write front-end code


10. Publish a blog

1. Agree on the front-end and back-end interaction interfaces

To use a form, you must have multiple form tags on the page, and at the same time, the form must be able to perceive the content of the blog.


2. Write server code

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //发布博客
        //读取请求,构造出 blog 对象,插入数据库
        HttpSession httpSession = req.getSession(false);
        if (httpSession == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前未登录,无法发布博客");
            return;
        }
        User user = (User) httpSession.getAttribute("user");
        if (user == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前未登录,无法发布博客");
            return;
        }
        //确保登录之后,就可以把作者给拿到了

        //获取博客标题和正文
        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 blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        blog.setUserId(user.getUserId());
        //发布时间
        blog.setPostTime(new Timestamp(System.currentTimeMillis()));
        //插入数据
        BlogDao blogDao = new BlogDao();
        blogDao.add(blog);
        
        //跳转到博客列表页
        resp.sendRedirect("blog_list.html");
    }

3. Write client code

Make adjustments to the code:

1. Add form tag

2. Add the name attribute to the input tag

3. Change button to input label, and type to submit

4. Editor.md document requires writing method: add textarea

editor.md also supports form forms, that is, you can put a hidden textarea in the form, and editor.md will automatically fill in the markdown content entered by the user into the textarea, and then click submit to automatically submit it.

 At this point, let’s run the code again to see the results

At this time we discovered a problem: after the code was changed, the editor had a genetic mutation.

There is a problem with the front-end code style. We can only find the problem by observing the chrome developer tools.

We can see that there is a problem with the current form

 The specific analysis is as follows:

Solution: Set the height of the form

At this point, we can publish the blog normally, but at this time there is a garbled problem:

There are two situations of garbled characters:

1. Garbled characters when submitting the blog

2. Garbled characters when retrieving the blog

We only need to look at the database to know which situation is the case; 

At this time, you can find that the code was garbled when submitting.

Note: When obtaining the title and body, you need to specify the requested character set, which means telling the servlet which character set to use to parse the request.

At this point, click Submit again to publish the blog normally.

Guess you like

Origin blog.csdn.net/weixin_73616913/article/details/132514383