博客系统(前后端分离)

这篇具有很好参考价值的文章主要介绍了博客系统(前后端分离)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

✏️作者:银河罐头
📋系列专栏:JavaEE

🌲“种一棵树最好的时间是十年前,其次是现在”

准备工作

创建项目,引入依赖,把之前写的前端页面拷贝进去。

依赖主要是:servlet, mysql, jackson

博客系统(前后端分离)

数据库设计

表设计

在当前的博客系统中,主要涉及到 2 个实体,博客 和 用户。

创建 2 张表,来表示博客和用户。用户和博客之间的关系是一对多。

博客系统(前后端分离)

把一些基本的数据库操作先封装好,以备后用。

-- 这个文件主要写建库建表语句
-- 建议 在建表的时候把 sql 语句保留下来,以便后续部署其他机器的时候就方便了。

create database if not exists java_blog_system;
use java_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,
    useId int
);

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

封装数据库的连接操作

public class DBUtil {
    private static DataSource dataSource = new MysqlDataSource();
    static {
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_blog_system?characterEncoding=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) {
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

创建实体类

实体类,和表中记录对应的类。

blog 表,Blog 类对应。Blog 的一个对象,就对应表中的一条记录。

user 表,User 类对应。User 的一个对象,就对应表中的一条记录。

实体类里要有哪些属性,是和表里的列是密切相关的。

public class Blog {
    private int blogId;
    private String title;
    private String content;
    private Timestamp postTime;
    private int userId;

    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 Timestamp getPostTime() {
        return postTime;
    }

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

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }
}
public class User {
    private int userId;
    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;
    }
}

封装数据库的增删改查

针对博客表,创建 BlogDao

针对用户表,创建 UserDao

提供一些方法,来进行增删改查。

Dao, Data Access Object 访问数据的对象

//通过这个类,封装对博客表的基本操作
public class BlogDao {
    //1.新增一个博客
    public void add(Blog blog) {

    }
    //2.根据 博客 id 来查询博客(博客详情页中)
    public Blog selectById(int blogId){
        return null;
    }
    //3.查询出数据库中所有的博客列表(博客列表页)
    public List<Blog> selectAll(){
        return null;
    }
    //4.删除指定博客
    public void delete(int blogId){

    }
}

博客系统(前后端分离)

//通过这个类,封装对博客表的基本操作
public class BlogDao {
    //1.新增一个博客
    public void add(Blog blog) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.建立连接
            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) {
            e.printStackTrace();
        }finally {
            //4.断开连接,释放资源
            DBUtil.close(connection, statement, null);
        }
    }
    //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 while blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3.执行 SQL
            resultSet = statement.executeQuery();
            //4.遍历结果集合
            //blogId 是自增主键,是唯一的。所以要么是没有查到,要么是查到了一条记录
            //此处可以不使用 where, 直接 if 判定即可
            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) {
            e.printStackTrace();
        }finally {
            //5.释放资源,断开连接
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    //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 语句
            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) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection, statement, resultSet);

        }
        return blogs;
    }
    //4.删除指定博客
    public void delete(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.建立连接
            connection = DBUtil.getConnection();
            //2.构建 SQL 语句
            String sql = "delete from blog while blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3.执行 sql
            statement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.关闭连接
            DBUtil.close(connection,statement,null);
        }
    }
}
//针对用户表提供的基本操作
//由于没写注册功能,此处就不写 add 了
//也没有用户删号这个功能,也就不必 delete
public class UserDao {
    //根据 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) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    //根据 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) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
}

实现博客列表页

当前博客列表页上的数据都是写死的,正确的做法应该是从服务器获取数据并显示到页面上。

让博客列表页,加载的时候,通过 ajax 给服务器发一个请求,服务器查数据库获取博客列表数据,返回给浏览器,浏览器根据数据构造页面内容。

这样的交互过程,称为 “前后端分离”。

前端只是向后端索要数据,而不是请求具体的页面。后端也仅仅是返回数据。

这样设定的目的就是让前端和后端更加解耦。

由浏览器进行具体的页面渲染,减少了服务器的工作量。

上述是实现博客列表页的基本思路。

接下来需要:

1.约定前后端交互接口

获取博客列表功能,前端要发啥请求,后端要返回啥响应。

2.开发后端代码

3.开发前端代码

约定前后端交互接口

博客系统(前后端分离)

开发后端代码

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

博客系统(前后端分离)

把 servlet 放到 api 包里,api 不一定非得是 类/方法,也可以是 “网络请求”(处理 http 请求,返回 http 响应)

开发前端代码

在博客列表页加载过程中,通过 ajax 访问服务器数据,再把拿到的数据构造到页面中。

博客系统(前后端分离)

<script src="./js/jquery.min.js"></script>
    <script>
        //在页面加载的时候,向服务器发起请求,获取博客列表数据
        function getBlogs() {
            $.ajax({
                type:'get',
                url: 'blog',
                success: function(body) {
                    //响应的正文是 json 字符串,已经被 jquery 自动解析成 js 对象数组了
                    // for 循环遍历即可
                    let containerRight = document.querySelector('.container-right');
                    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');
                        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;';
                        //希望点击之后能跳转到博客详情页
                        //为了让博客详情页知道是点了哪个博客,把 blogId 传过去
                        a.href = 'blog_detail.html?blogId=' + blog.blogId;
                        blogDiv.appendChild(a);

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

此时,博客列表页实现完成。

博客系统(前后端分离)

此时看的的博客列表页是空着的,因为博客列表的数据来自于数据库,而现在数据库是空着的。

博客系统(前后端分离)

-- 构造测试数据
insert into blog values(1, '这是我的第一篇博客', '从今天开始我要认真敲代码', now(),1);
insert into blog values(2, '这是我的第二篇博客', '从昨天开始我要认真敲代码', now(),1);
insert into blog values(3, '这是我的第三篇博客', '从前天开始我要认真敲代码', now(),1);

此处只是把 idea 当做是个 记事本,来记录下 sql 而已。真正要执行,要复制到 sql 客户端里执行。

博客系统(前后端分离)

博客系统(前后端分离)

有 2 个 bug,

1.不应该显示时间戳,而应该显示格式化时间

需要用到一个 格式化时间的类,转换一下。

SimpleDateFormat

博客系统(前后端分离)

public Timestamp getPostTimestamp() {
    return postTime;
}

public String getPostTime(){
    //把时间戳转换成格式化时间
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    return simpleDateFormat.format(postTime);
}

2.顺序,新的博客在上面,老的博客在下面。

博客系统(前后端分离)

博客系统(前后端分离)

实现博客详情页

接下来实现博客详情页,点击"查看全文"按钮,就能跳转到博客详情页中。跳转之后,在博客详情页中,对服务器发起 ajax 请求,从服务器获取数据,然后显示出来。

博客系统(前后端分离)

约定前后端交互接口

博客系统(前后端分离)

开发后端代码

博客系统(前后端分离)

@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();
        //尝试获取下 query string 中的 blogId字段
        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            //说明 query string 不存在,说明这次请求是在获取博客列表页

            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 存在,说明这次请求是在获取博客详情页
            Blog blog = blogDao.selectById(Integer.parseInt(blogId));
            if(blog == null) {
                System.out.println("当前 blogId = " + blogId + " 对应的博客不存在!");
            }
            String respJson = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }
}

开发前端代码

在 blog_datail.html 中,加入 ajax,来获取数据。

博客系统(前后端分离)

博客系统(前后端分离)

博客系统(前后端分离)

博客系统(前后端分离)

<script src="js/jquery.min.js"></script>
<!-- 保证 这几个 js 的加载要在 jquery 之后,因为 edit.md 依赖 jquery-->
<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('.title');
        titleDiv.innerHTML = body.title;
        //2.更新日期
        let dateDiv = document.querySelector('.date');
        dateDiv.innerHTML = body.postTime;
        //3.更新博客正文
        //此处不应该直接把博客内容填充到标签里
        editormd.markdownToHTML('content',{ markdown: blog.content });
    }
});
</script>

博客系统(前后端分离)

代码改完之后,重新启动服务器,发现此时博客详情页的结果还是之前未修改的状态。

博客系统(前后端分离)

始端用户访问加速节点时,如果该节点有缓存住了要被访问的数据时就叫做命中,如果没有的话需要回原服务器取,就是没有命中。

博客系统(前后端分离)

缓冲问题解决了,但是页面仍然不是预期的效果。

博客系统(前后端分离)

博客系统(前后端分离)

博客系统(前后端分离)

修改上述代码之后,发现正文有了,但是标题没出来。

就需要抓包,看下服务器返回结果是否符合预期,就可以确定是前端问题还是后端问题了。

博客系统(前后端分离)

响应结果是正确的,后端代码应该没问题。

接下来检查前端代码。

博客系统(前后端分离)

解决方案,把选择器写的更准确一些。

博客系统(前后端分离)

博客系统(前后端分离)

博客系统(前后端分离)

博客系统(前后端分离)

实现博客登录页

博客系统(前后端分离)

此处输入用户名,密码,点击登录,就会触发一个 http 请求。服务器验证用户名和密码,如果登陆成功,就跳转到博客列表页。

当前还只是一个 输入框,还不能提交请求,需要给改成 form 表单。

约定前后端交互接口

博客系统(前后端分离)

开发前端代码

在页面里加上 form 表单,使点击登录操作能 触发请求。

<!-- 垂直水平居中的登录对话框 -->
<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="登录">
        </div>
    </form>
</div>

博客系统(前后端分离)

博客系统(前后端分离)

请求已经构造出来了。

开发后端代码

此处需要价格 servlet 来处理 登录请求。

@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.读取参数中的用户名,密码
        //注意,如果用户名密码中存在中文,这里读取可能会乱码
        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("username", username);
        //4.进行重定向,跳转到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

这样还是无法登录成功,因为数据库没有保存用户名密码。

博客系统(前后端分离)

构造一些测试数据,保存到数据库里。

博客系统(前后端分离)

博客系统(前后端分离)

登陆成功。

实现强制要求登陆

当用户访问博客列表页/详情页/编辑页,要求用户必须是已登录的状态,如果用户还没有登录,就会强制跳转到登录页面。

博客系统(前后端分离)

约定前后端交互接口

博客系统(前后端分离)

开发后端代码

博客系统(前后端分离)

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("application/json;charset=utf8");
    //使用这个方法来获取用户的登录状态
    HttpSession session = req.getSession(false);
    if(session == null){
        User user = new User();
        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);
}

开发前端代码

博客系统(前后端分离)

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

把这段代码加到 列表页,详情页,编辑页的代码中。

重启服务器之后,之前的登录状态就没了。

博客系统(前后端分离)

实现显示用户信息

目前页面的用户信息部分是写死的.

博客系统(前后端分离)

这个地方时写死的,希望能够动态生成。

1.如果是博客列表页,此处显示登录用户的信息。

2.如果是博客详情页,此处显示该文章的作者。

比如我以"张三"的身份登录,查看博客列表页时,左侧应该显示"张三"的用户信息,然后我点开李四写的博客,跳转到博客详情页,应该显示作者"李四"的信息。

约定前后端交互接口

博客系统(前后端分离)

列表页

function checkLogin() {
    $.ajax({
        type: 'get',
        url: 'login',
        success: function(body) {
            if(body.userId && body.userId > 0){
                //登陆成功
                console.log("当前用户已登录!");
                //把当前用户的名字显示到界面上
                let h3 = document.querySelector('.container-left .card h3');
                h3.innerHTML = body.username;
            } else {
                //当前未登录,强制跳转到登录页
                location.assign('blog_login.html');
            }
        }
    });
}

博客系统(前后端分离)

详情页

@WebServlet("/author")
public class AuthorServlet extends HttpServlet {
    private 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);
    }
}
function getAuthor() {
    $.ajax({
        type: 'get',
        url: 'author',
        success: function(body) {
            //把 username 设置到界面上
            let h3 = document.querySelector('.container-left .card h3');
            h3.innerHTML = body.username;
        }
    });
}
getAuthor();

博客系统(前后端分离)

博客系统(前后端分离)

抓包后发现是少了 query string.

改下前端代码。

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

博客系统(前后端分离)

退出登录状态

注销(sign out)

判定登录状态:

1.看是否能查到 http session 对象;

2.看 session 对象里有没有 user 对象

博客系统(前后端分离)

实现退出登录,要么把 session 干掉,要么把 user 干掉。只要干掉一个就可以。

HttpSession 对象要想干掉,麻烦点。getSession 能够创建/获取会话,没有删除会话的方法。直接删除还不好删,可以通过设置会话的过期时间来达到类似的效果,但并不优雅。

更好的办法是把 user 干掉,通过 removeAttribute 就删了。

之前的逻辑中, httpSession 和 user 是一荣俱荣一损俱损的情况,但是引入注销逻辑后,就出现有 httpSession 没 user 的情况。

明确思路之后,先设计前后端交互接口。

约定前后端交互接口

博客系统(前后端分离)

博客系统(前后端分离)

开发后端代码

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

开发前端代码

把 blog_detail.html, blog_edit.html, blog_list.html 这几个的 a 标签改下就行。

博客系统(前后端分离)

发布博客

博客系统(前后端分离)

写博客写了一些内容,点击"发布文章",没有反应。

约定前后端交互接口

博客系统(前后端分离)

开发后端代码

@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();
        //尝试获取下 query string 中的 blogId字段
        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            //说明 query string 不存在,说明这次请求是在获取博客列表页

            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 存在,说明这次请求是在获取博客详情页
            Blog blog = blogDao.selectById(Integer.parseInt(blogId));
            if(blog == null) {
                System.out.println("当前 blogId = " + blogId + " 对应的博客不存在!");
            }
            String respJson = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }

    @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());
        //发布时间,在 java 中生成 / 在数据库中生成都行
        blog.setPostTime(new Timestamp(System.currentTimeMillis()));
        //插入数据库
        BlogDao blogDao = new BlogDao();
        blogDao.add(blog);
        //跳转到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

开发前端代码

把页面改造下,能够构造出请求。

博客系统(前后端分离)

<div class="blog-edit-container">
    <form action="blog" method="post">
        <!-- 博客标题编辑区 -->
        <div class="title">
            <input type="text" id="title" placeholder="输入文章标题" name="title">
            <input type="submit" id="submit" value="发布文章">
        </div>
        <!-- 博客编辑器, 这里用 id 是为了和 markdown 编辑器对接 -->
        <div id="editor">
            <textarea name="content" style="display: none;"></textarea>
        </div>
    </form>
</div>

博客系统(前后端分离)

代码改完之后,再次运行,发现只显示一小段了。

前端代码有问题,看 chrome 开发者工具。

博客系统(前后端分离)

之前给编辑器设置的高度。

博客系统(前后端分离)

<form action="blog" method="post" style="height: 100%;">

博客系统(前后端分离)

发现乱码了?!

乱码是提交博客的时候乱的,还是获取博客的时候乱的?

这里大概率是提交的时候乱的,因为获取数据这个功能前面已经测试过了,而提交这个功能还没有测试过。

只要看下数据库是不是乱的。

博客系统(前后端分离)

应该是提交的时候就乱了。

把乱码的第4条删掉。

博客系统(前后端分离)

//获取博客标题和正文
req.setCharacterEncoding("utf8");
String title = req.getParameter("title");
String content = req.getParameter("content");

博客系统(前后端分离)文章来源地址https://www.toymoban.com/news/detail-412795.html

到了这里,关于博客系统(前后端分离)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【基于前后端分离的博客系统】Servlet版本

      🎉🎉🎉 点进来你就是我的人了 博主主页: 🙈🙈🙈 戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔 🤺🤺🤺 目录 一. 项目简介  1. 项目背景 2. 项目用到的技术 3. 项目功能简单介绍  二. 博客系统页面设计  三. 项目准备工作 前后端交互约定内容的分析  1. 接口

    2024年02月08日
    浏览(41)
  • 【Java EE】-博客系统一(前后端分离)

    作者 :学Java的冬瓜 博客主页 :☀冬瓜的主页🌙 专栏 :【JavaEE】 分享 : 谜一样的 沉默着的 故事你真的在听吗 ——《平凡之路》 主要内容 :准备工作:创建maven,引入依赖。设计数据库并编写数据库代码。前后端分离功能的实现。博客列表,博客详情,登录功能,注册功

    2024年02月12日
    浏览(43)
  • 【Java EE】-博客系统二(前后端分离)

    作者 :学Java的冬瓜 博客主页 :☀冬瓜的主页🌙 专栏 :【JavaEE】 分享 : 徘徊着的 在路上的 你要走吗 易碎的 骄傲着 那也曾是我的模样 ——《平凡之路》 主要内容 :显示用户信息、上传头像、新增博客、删除博客、修改博客。 分两个子功能:列表页显示登录用户信息;

    2024年02月11日
    浏览(43)
  • SSM项目前后端分离+IDEA运行环境(含前端源码)(个人博客系统)

    目录  后端项目环境配置 1、创建一个SpringBoot项目,添加MyBatis框架和数据库MySQL驱动依赖 2、配置项目文件:application.yml 3、创建数据库表 4、创建分层结构目录 返回统一数据格式  创建统一数据格式返回类:AjaxResult 创建实现统一数据返回的保底类:ResponseAdvice 统一处理 登录

    2024年02月13日
    浏览(75)
  • 川西旅游网系统-前后端分离(前台vue 后台element UI,后端servlet)

    前台:tour_forword: 川西旅游网前端----前台 (gitee.com) 后台:tour_back: 川西旅游网-------后台 (gitee.com) 后端 :tour: 川西旅游网------后端 (gitee.com)

    2024年02月07日
    浏览(40)
  • 基于Java+MySQL+Tomcat+Servlet+Maven+JQuery+jackson+开源Markdown编辑器实现前后端分离个人博客系统

    目录 项目简介 模块实现 设计实现数据库相关代码 博客列表页 博客详情页 注册页 登录页 检测登录状态 显示用户信息 退出登录 发布博客 删除博客 统计博客数量 效果展示 部分代码展示 小结:     项目中使用了Java ,MySQL ,Tomcat ,Servlet ,Maven ,JQuery ,jackson,开源MarkDo

    2024年02月02日
    浏览(49)
  • 博客项目(前后端分离)(servlet实战演练)

    作者简介:大家好,我是未央; 博客首页: 未央.303 系列专栏:实战项目 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!! 文章目录 前言 项目介绍 一、MVC模式简介 1.1  MVC 模式含义 1.2 MVC 的工作流程 二、项目概述 2.1 项目的几个页面 2.2 功能大概

    2024年02月07日
    浏览(40)
  • 大型医院云HIS系统:采用前后端分离架构,前端由Angular语言、JavaScript开发;后端使用Java语言开发 融合B/S版电子病历系统

    一套医院云his系统源码 采用前后端分离架构,前端由Angular语言、JavaScript开发;后端使用Java语言开发。融合B/S版电子病历系统,支持电子病历四级,HIS与电子病历系统均拥有自主知识产权。 文末卡片获取联系! 基于云计算技术的B/S架构的医院管理系统(简称云HIS),采用前后

    2024年02月03日
    浏览(50)
  • 前后端分离------后端创建笔记(02)

     本文章转载于【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论,如有侵权请联系 源码:https://gitee.com/green_vegetables/x-admin-project.git 素材:https://pan.baidu.com/s/1ZZ8c-kRPUxY6FWzsoOOjtA 提取码:up4c 项目概述笔记:https://blog

    2024年02月12日
    浏览(37)
  • 前后端分离------后端创建笔记(11)用户删除

     1.1 首先做一个删除的功能接口,第一步先来到后端,做一个删除的接口  3.1这里给他调一下删除方法,用下面这个 3.2 接口准备好了,但是这里存在了一个问题,它真的会把数据给改掉 9.1 10.1   12.1   15.1  18.1 在main.js中定义出来   25.1 把代码拿过来 27.1 删除成功了

    2024年02月12日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包