Proyecto JavaWeb - Sistema de blogs

Directorio de artículos

Mostrar resultados

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí


1. Crea un proyecto experto

Cree los directorios necesarios e importe las dependencias requeridas

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

2. Base de datos de diseño

El sistema necesita almacenar la información de la publicación del blog y la información del usuario.

Crear una tabla de blog:

博客的 id,博客的标题,博客的内容,博客的日期,博文的博主 id

Crea la tabla de usuario:

用户 id 用户名 用户密码

-- 创建一个数据库
create database if not exists java102_blog;

use java102_blog;

-- 创建一个博客表.
drop table if exists blog;
create table blog (
    blogId int primary key auto_increment,
    title varchar(1024),
    content mediumtext,
    userId int,         -- 文章作者的 id
    postTime datetime   -- 发布时间
);

---- 给博客表中插入点数据, 方便测试.
insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第三篇博客', '从前天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 C++', 2, now());
insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 C++', 2, now());
insert into blog values(null, '这是第三篇博客', '# 一级标题\n ### 三级标题\n > 这是引用内容', 2, now());

-- 创建一个用户表
drop table if exists user;
create table user (
    userId int primary key auto_increment,
    username varchar(128) unique,    -- 后续会使用用户名进行登录, 一般用于登录的用户名都是不能重复的.
    password varchar(128)
);

insert into user values(null, 'zhangsan', '123');
insert into user values(null, 'lisi', '123');
insert into user values(null, 'ling', '123');

3. Encapsular el código de operación de la base de datos

Cree un modelo de paquete para almacenar el código de la base de datos

3.1 Crear clase DBUtil

Se utiliza para establecer una conexión con la base de datos.

package model;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 *这个类 封装 和 建立 数据库 连接 的 操作
 */
public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java102_blog?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "707703";

    private volatile static DataSource dataSource = null;

    private static DataSource getDataSource() {
        if(dataSource == null) {
            synchronized (DBUtil.class) {
                if(dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl(URL);
                    ((MysqlDataSource)dataSource).setUser(USERNAME);
                    ((MysqlDataSource)dataSource).setPassword(PASSWORD);
                }
            }
        }
        return dataSource;
    }

    // 建立链接
    public static Connection getConnection() throws SQLException {
        return getDataSource().getConnection();
    }

    // 断开链接
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet)  {
        if(resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if(statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if(connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}


3.2 Crear blog (representando un blog)

package model;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;

// 每个 blog对象 ,对应 blog 表里的一条记录
public class Blog {
    private int blogId;
    private String title;
    private String content;
    private int userId;
    private Timestamp postTime;

    public int getBlogId() {
        return blogId;
    }

    public void setBlogId(int blogId) {
        this.blogId = blogId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }
    
    // 把这里 的 getter 方法给改了,不是返回一个 时间搓对象,而是返回一个 string(格式化的时间)
    public String getPostTime() {
        // 使用这个类 来完成时间戳到格式化日期的转换
        // 这个 转换过程,需要构造方法中制定要转换的格式,然后调用 format 来进行转换
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(postTime);
    }


    public void setPostTime(Timestamp postTime) {
        this.postTime = postTime;
    }
}

3.3 Crear usuario (en representación de un usuario)

package model;

// 每个 model.User 对象, 期望能够表示 user 表中的一条记录.
public class User {
    private int userId = 0;
    private String username = "";
    private String password = "";
    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

3.4 Crear clase BlogDao (operar en la tabla del blog)

Nota:
Al insertar y eliminar datos, ejecute sql:
inserte la descripción de la imagen aquí
Otras operaciones:
inserte la descripción de la imagen aquí
Orden de inserción:
inserte la descripción de la imagen aquí

package model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 这个类用于去封装博客表的 基本操作
 */
public class BlogDao {
    // 1.往博客表里,插入一个博客
    public void insert(Blog blog) {
        // JDBC 代码
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1. 先和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 构造 sql 语句
            String sql = "insert into blog values(null,?,?,?,now())";
            statement = connection.prepareStatement(sql);
            // 赋值
            statement.setString(1, blog.getTitle());
            statement.setString(2, blog.getContent());
            statement.setInt(3,blog.getUserId());
            // 3. 执行 sql
            statement.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            // 4. 关闭连接,释放资源
            DBUtil.close(connection,statement,null);
        }
    }

    // 2. 获取博客列表中的所有博客信息
    public List<Blog> selectAll() {
        List<Blog> blogs = new ArrayList<>();
        // JDBC 代码
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 先建立链接
            connection = DBUtil.getConnection();
            // 2. 构造 sql 语句
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);
            // 3. 执行 sql
            resultSet = statement.executeQuery();
            // 把查询到的数据 存储到 blogs 当中
            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() > 50) {
                    content = content.substring(0,50) + "..点进来吧我的宝";
                }
                blog.setContent(content);
                blog.setUserId(resultSet.getShort("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blogs.add(blog);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return blogs;
    }

    // 3. 能够根据博客 id 获取到制定的博客内容(用于博客详情页)
    public Blog selectOne(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();
            // 此处我们是使用 主键 来作为 查询条件,查询结果,要么是 1,要么是 0
            if(resultSet.next()) {
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                blog.setContent(resultSet.getString("content"));
                blog.setUserId(resultSet.getShort("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                return blog;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            // 4. 关闭连接 释放资源
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    // 4.  从博客列表中,根据博客 id 删除博客
    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 throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
}

3.5 Crear clase UserDao (operar en la tabla de usuario)

package model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 这个类用于 封装 用户表的 基本操作
 */
public class UserDao {

    // 1. 根据用户名 查找用户信息
    public User selectByName(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();
            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 throwables) {
            throwables.printStackTrace();
        }finally {
            // 4. 关闭连接 释放资源
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    // 2. 根据 用户 id 来找 用户信息
    // 博客详情页 就可以根据用户 id 来查询作者的名字,把作者名字显示出来
    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();
            // 此处的 username 使用 unique 约束,要么能查到一个,要么一个都查不到
            // 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 throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
}


4. Importe el código front-end que se ha escrito antes

inserte la descripción de la imagen aquí

5. Implementar la interfaz de la página de inicio del blog

5.1 Acuerdo sobre las interfaces interactivas front-end y back-end

inserte la descripción de la imagen aquí

5.2 Implementar BlogServlet

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;

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

5.3 Implementar código front-end

Implementar ajax en blog_list.html

Nota: importar dependencias

<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_detil.html?blogId=' + blog.blogId;
                        blogDiv.appendChild(a);

                        // 把 blogDiv 挂到 dom 树上!
                        rightDiv.appendChild(blogDiv);
                    }
                }, 
                error: function() {
                    alert("获取博客列表失败!");
                }
            });
        }

        getBlogList();
        </script>

6. Implementar la interfaz de detalles del blog

6.1 Acuerdo sobre la interfaz de interacción front-end y back-end

inserte la descripción de la imagen aquí

6.2 Implementar BlogServlet

Aquí, el código de back-end y la adquisición de la página de la lista del blog son básicamente los mismos, por lo que se pueden poner directamente en un método para lograrlo. Utilice el parámetro blogId para distinguir si desea obtener la lista de blogs o los detalles.Nota
: La página de lista de blogs también está implementada en BlogServlet.¿Cómo la distinguimos? :
inserte la descripción de la imagen aquí

package controller;

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;

/**
 * // doGet 获取博客列表页
 */
@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 param = req.getParameter("blogId");
        if (param == null) {
            // 不存在参数, 获取博客列表
            List<Blog> blogs = blogDao.selectAll();
            // 把 blogs 对象转成 JSON 格式.
            String respJson = objectMapper.writeValueAsString(blogs);
            resp.getWriter().write(respJson);
        } else {
            // 存在参数, 获取博客详情
            int blogId = Integer.parseInt(param);
            Blog blog = blogDao.selectOne(blogId);
            String respJson = objectMapper.writeValueAsString(blog);
            resp.getWriter().write(respJson);
        }
    }
}

6.3 Implementar código front-end

Modifique blog_detail.html, para que cuando se cargue la página, se pueda llamar a la interfaz anterior para obtener datos del blog del servidor

Aviso:
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

在博客详情页中引入 editor


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

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

        getBlogDetail();


    </script>

7. Implementar la interfaz de inicio de sesión

Nota aquí: ¿qué significa estar conectado?

El usuario tiene una sesión y la sesión tiene un atributo de usuario ~
ambos al mismo tiempo, se denomina estado de inicio de sesión

Aquí hay un presagio del cierre de sesión: comprenda cómo funciona el cierre de sesión:

Cierra la sesión siempre que infrinjas alguna de las condiciones anteriores.

7.1 Acuerdo sobre las interfaces interactivas front-end y back-end

inserte la descripción de la imagen aquí

7.2 Implementando LoginServlet

package controller;

import com.fasterxml.jackson.databind.ObjectMapper;
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 {
    private  ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        // 1. 获取到请求中的参数
        String username = req.getParameter("username");
        String password = req.getParameter("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");
    }
 }

7.3 Implementar código front-end

Para modificar blog_login.html aquí, solo necesita colocar una capa de etiqueta de formulario en la operación de inicio de sesión original.
inserte la descripción de la imagen aquí

Debido a que el formulario se completa aquí sobre la base original, también tendremos algunos cambios en css

inserte la descripción de la imagen aquí

<!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_login.css">
</head>
<body>
     <!--这是导航栏 nav-->
     <div class = "nav">
        <img src="imge/ph.png" alt="">
        <!--标题 span-->
        <span>我的博客系统</span>
       <!--这是一个空白元素用来占位置-->
        <div class="spacer"></div>
        <!--链接标签<a>-->
        <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>
    </div>
</body>
</html>

8. Implementar la función de determinación del estado de inicio de sesión

inserte la descripción de la imagen aquí

8.1 Interfaz de interacción front-end y back-end acordada

inserte la descripción de la imagen aquí

8.2 Agregar código en LoginServlet

package controller;

import com.fasterxml.jackson.databind.ObjectMapper;
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 {
    private  ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        // 1. 获取到请求中的参数
        String username = req.getParameter("username");
        String password = req.getParameter("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)检测有无会话 2)检测有无属性
    @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) {
           // 1) 检测有无会话,无说明未登录
           // 创建对象--> 里面为空
           User user = new User();
           resp.getWriter().write(objectMapper.writeValueAsString(user));
           return;
       }
       User user = (User) session.getAttribute("user");
       if(user == null) {
           // 2)虽然有会话,但是会话里如果没有 user 对象,也视为未登录
           user = new User();
           resp.getWriter().write(objectMapper.writeValueAsString(user));
           return;
       }
       // 已经登录的状态!
        // 注意,此处不要把密码返回到前端
        user.setPassword("");
        resp.getWriter().write(objectMapper.writeValueAsString(user));
    }
}

8.3 Crear common.js en el código front-end

inserte la descripción de la imagen aquí

// 这个文件里放一些 页面公共的代码
// 加上一个逻辑,通过 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();

8.4 Modificar el código de front-end

blog_list.html blog_detil.htmlAl introducir el archivo js en , puede ejecutar el código que contiene y controlar el estado de inicio de sesión.

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

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

9. Realice la función de mostrar información del usuario.

9.1 Acuerdo sobre las interfaces de interacción front-end y back-end

9.2 Implementar el código AuthorServlet

package controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
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 java.io.IOException;


/**
 * 根据博客 id 查 博客信息
 * 根据 博客信息里的 作者 id 查 作者信息
 */
@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));

    }
}

9.3 Implementar código front-end

inserte la descripción de la imagen aquí

Hacer ediciones en la página de lista de blogs

Modificar el código en common.js
inserte la descripción de la imagen aquí

Para páginas de detalles del blog


10. Implementar la función de cierre de sesión

Organice un botón de "cerrar sesión" en la barra de navegación. Cuando el usuario haga clic en cerrar sesión, el estado de inicio de sesión se cancelará en el servidor y podrá saltar a la página de inicio de sesión.

10.1 Acuerdo sobre la interfaz de interacción front-end y back-end

inserte la descripción de la imagen aquí

10.2 Implementando LogouServlet

package controller;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Enumeration;

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

10.3 Implementando el código front-end

Modifique la etiqueta de cierre de sesión en blog_detail.html blog_list.html bloh_edit.htm

inserte la descripción de la imagen aquí

11. Implementar la función de publicación de blog

En , cuando el 博客编辑页usuario ingresa 博客标题, y 正文luego de hacer clic发布
把博客数据提交到服务器,由服务器存储到数据中

11.1 Acuerdo sobre la interfaz de interacción front-end y back-end

inserte la descripción de la imagen aquí

11.2 Agregando el método doPost a BlogServlet

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

11.3 Implementando el código front-end

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

<!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_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.min.js"></script>
</head>
<body>
    <!-- 这是导航栏 -->
    <div class="nav">
        <img src="imge/ph.png" 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">
                <!-- <button>发布文章</button> -->
                <input type="submit" value="发布文章" id="submit">
            </div>
            <!-- 放置 md 编辑器 -->
            <div id="editor">
                    <!-- 为了进行 form的提交,此处搞一下 textarea 多行编辑框,借助这个编辑框来实现表单的提交-->
                    <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/",
            // 此处要加上一个重要的选项,然后 editr.md 就会自动把用户在编辑器输入的内容同步保存到 隐藏的 textarea中
            saveHTMLToTextarea:true,
        });
    </script>
</body>
</html>

12. Eliminar blog

inserte la descripción de la imagen aquí

12.1 Interfaz de interacción front-end y back-end del número de convención

inserte la descripción de la imagen aquí

12.1 Implementar código front-end

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

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

  // 加上一个逻辑,通过 GET /login 这个接口来获取下当前的登录状态          
    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);

                // 在getUserInfo 的回调函数中,来调用获取用户信息
                getAuthorInfo(body);

                
            }else {
                // 登录失败
                // 让前端页面,跳转到 login.html
                alert("当前您尚未登录!请登录后再访问博客列表");
                location.assign('blog_login.html');
            }
        },
        error: function() {
            alert("当前您尚未登录!请登录后再访问博客列表");
            location.assign('blog_login.html');
        }
        });
    }
  
    // 判定用户的登录状态
    getUserInfo('blog_detail.html');

     // 从服务器获取一下当前博客的作者信息, 并显示到界面上. 
    // 参数 user 就是刚才从服务器拿到的当前登录用户的信息
    
        function getAuthorInfo(user) {
                $.ajax({
                   type: 'get',
                   url: 'authorInfo' + location.search,
                   success: function(body) {
                       // 此处的body,就是服务器返回的User对象,是文章作者信息
                       if(body.username) {
                            getBlogDetail();
                           changeUserName(body.username);
                           if(body.username == user.username ) {
                               // 作业和登录的用户是一个人,则显示 删除按钮
                               let navDiv = document.querySelector('.nav');
                               let a = document.createElement('a');
                               a.innerHTML = '删除';
                               // 点击删除,构造一个 形如 blogDelete?blogId = 6 这样的请求
                               a.href = 'blogDelete' + location.search;
                               navDiv.appendChild(a);
                           }
                       }else{
                           console.log("获取信息失败" + body.reason);
                       }
                   }
                });
            }

            function changeUserName(username) {
            let h3 = document.querySelector('.card>h3');
            h3.innerHTML = username;
            }     
    </script>

12.2 Implementando BlogDeleteServlet

package controller;

import model.Blog;
import model.BlogDao;
import model.User;

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


Supongo que te gusta

Origin blog.csdn.net/Biteht/article/details/124969357
Recomendado
Clasificación