从 0 开始实现一个博客系统 (SSM 项目)(上)

简介: 从 0 开始实现一个博客系统 (SSM 项目)

相关技术

Spring + Spring Boot + Spring MVC + MyBatis

Html + Css + JS

pom 文件我就不放出来了, 之前用的 jdk8 做的, MySQL 用的 5.7, 都有点老了, 你们自己看着配版本就好

实现功能

  1. 用户注册 - 密码加盐加密 (md5 加密)
  2. 前后端用户信息存储 - 令牌技术
  3. 用户登录 - (使用 拦截器 做登录校验)
  1. 博客的增删改查
  2. 后端数据返回前端, 采用 SpringBoot 做统一功能处理和统一异常处理

数据库设计

  1. 用户表
  2. 博客表

前端页面

博客登录页 (blog_login.html)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <me_ta 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/login.css">

</head>

<body>
    <div class="nav">
        <img src="pic/logo2.jpg" alt="">
        <span class="blog-title">我的博客系统</span>
        <div class="space"></div>
        <a class="nav-span" href="blog_list.html">主页</a>
        <a class="nav-span" href="blog_edit.html">写博客</a>
    </div>

    <div class="container-login">
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <input type="text" name="username" id="username">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" name="password" id="password">
            </div>
            <div class="row">
                <button id="submit" onclick="login()">提交</button>
            </div>
        </div>
    </div>
    <script src="js/jquery.min.js"></script>
    <script>
        function login() {
            // 发送 ajax 请求, 获取 token
            $.ajax({
                type: "post",
                url: "/user/login",
                data: {
                    "userName": $("#username").val(),
                    "password": $("#password").val()
                },
                success: function(result) {
                    if(result.code == 200 && result.data != null) {
                        // 存储 token 到本地
                        localStorage.setItem("user_token", result.data);
                        location.href = "blog_list.html";
                    }else{
                        alert("用户名或密码错误");
                    }
                }
            });
        }
    </script>
</body>

</html>

用户登录成功之后, 会将用户信息, 生成令牌, 存储到 request 中, 前后端都能从中获取当前登录用户的信息

博客列表页 (blog_list.html)

<!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/list.css">

</head>
<body>
    <div class="nav">
        <img src="pic/logo2.jpg" alt="">
        <span class="blog-title">我的博客系统</span>
        <div class="space"></div>
        <a class="nav-span" href="blog_list.html">主页</a>
        <a class="nav-span" href="blog_edit.html">写博客</a>
        <a class="nav-span" href="#" onclick="logout()">注销</a>
    </div>

    <div class="container">
        <div class="left">
            <div class="card">
                <img src="pic/doge.jpg" alt="">
                <h3></h3>
                <a href="#"></a>
                <div class="row">
                    <span>文章</span>
                    <span>分类</span>
                </div>
                <div class="row">
                    <span>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>
        <div class="right">
        </div>
    </div>
    <script src="js/jquery.min.js"></script>
    <script src="js/common.js"></script>
    <script>
        //显示用户信息
        var userUrl = "/user/getUserInfo";
        getUserInfo(userUrl);

        // 获取所有的博客信息
        $.ajax({
            type: "get",
            url: "/blog/getList",
            success: function(result) {
                console.log("result:" + result);
                if(result.code == 200 && result.data != null) {
                    var finalHtml = "";
                    for(var blog of result.data) {
                        finalHtml += '<div class="blog">';
                        finalHtml += '<div class="title">'+blog.title+'</div>';
                        finalHtml += '<div class="date">'+blog.createTime+'</div>';
                        finalHtml += '<div class="desc">'+blog.content+'</div>';
                        finalHtml += '<a class="detail" href="blog_detail.html?blogId='+blog.id+'">查看全文&gt;&gt;</a>';
                        finalHtml += '</div>';
                    }
                    $(".right").html(finalHtml);
                }
            },
            error: function(error) {
                console.log("error:" + error);
                location.href = "blog_login.html";
                if(error != null && error.state == 401) {
                    location.href = "blog_login.html";
                }
            }
        });
    </script>
</body>
</html>

当前页面会自动调用一个 ajax 请求, 用以获取数据库中 所有未删除博客 的信息进行展示 (博客正文会裁取前100字进行显示)

博客详情页 (blog_detail.html)

<!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/detail.css">

</head>

<body>
    <div class="nav">
        <img src="pic/logo2.jpg" alt="">
        <span class="blog-title">我的博客系统</span>
        <div class="space"></div>
        <a class="nav-span" href="blog_list.html">主页</a>
        <a class="nav-span" href="blog_edit.html">写博客</a>
        <a class="nav-span" href="#" onclick="logout()">注销</a>
    </div>

    <div class="container">
        <div class="left">
            <div class="card">
                <img src="pic/doge.jpg" alt="">
                <h3></h3>
                <a href="#"></a>
                <div class="row">
                    <span>文章</span>
                    <span>分类</span>
                </div>
                <div class="row">
                    <span>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>
        <div class="right">
            <div class="content">
                <div class="title"></div>
                <div class="date"></div>
                <div class="detail" id="detail" style="background-color: transparent;">
                </div>
                <!-- <div class="operating">
                    <button onclick="window.location.href='blog_update.html'">编辑</button>
                    <button onclick="deleteBlog()">删除</button>
                </div> -->
            </div>

        </div>
    </div>

    <!-- 引入 editor.md 的依赖 -->
    <link rel="stylesheet" href="blog-editormd/css/editormd.css" />
    <script src="js/jquery.min.js"></script>
    <script src="blog-editormd/lib/marked.min.js"></script>
    <script src="blog-editormd/lib/prettify.min.js"></script>
    <script src="blog-editormd/editormd.js"></script>
    <script src="js/common.js"></script>
    <script>
        // 获取博客详情
        $.ajax({
            type: "get",
            url: "/blog/getBlogDetail"+location.search,
            success: function(result) {
                console.log(result);
                if(result.code == 200 && result.data != null) {
                    console.log("abc" + result);
                    var blog = result.data;
                    $(".right .content .title").text(blog.title);
                    $(".right .content .date").text(blog.createTime);
                    // $(".right .content .detail").text(blog.content);
                    editormd.markdownToHTML("detail", {
                        markdown: blog.content,
                    });
                    // 是否显示 编辑/删除 按钮
                    if(blog.isLoginUser == true) {
                        var html = "";
                        html += '<div class="operating">';
                        html += '<button onclick="window.location.href=\'blog_update.html'+location.search+'\'">编辑</button>';
                        html += '<button onclick="deleteBlog()">删除</button>';
                        html += '</div>';

                        $(".content").append(html);
                    }
                }
            },
            error: function(error) {
                if(error != null && error.status == 401) {
                    location.href = "blog_list.html";
                }
            }
        });
        
        //显示博客作者信息
        var userUrl = "/user/getAuthorInfo" + location.search;
        getUserInfo(userUrl);

        function deleteBlog() {
            $.ajax({
                type: "post",
                url: "/blog/delete" + location.search,
                success: function(result) {
                    if(result.code == 200 && result.data != null && result.data == true) {
                        location.href = "blog_list.html";
                    }
                }
            });
        }
    </script>
</body>

</html>

对于每篇博客, 会显示博客信息 (标题, 最后一次的修改时间, 博客正文), 和博客作者的信息 (用户名) (TODO: 作者头像, 作者的总文章数量, 博客的分类所属)

页面会自动校验登录用户是否为当前博客的作者, 如果是, 那么可以对当前博客进行编辑和删除, 如果不是, 这两个按钮不会显示

博客编辑页 (blog_edit.html)

<!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/edit.css">
    <link rel="stylesheet" href="blog-editormd/css/editormd.css" />

</head>

<body>
    <div class="nav">
        <img src="pic/logo2.jpg" alt="">
        <span class="blog-title">我的博客系统</span>
        <div class="space"></div>
        <a class="nav-span" href="blog_list.html">主页</a>
        <a class="nav-span" href="blog_edit.html">写博客</a>
        <a class="nav-span" href="#" onclick="logout()">注销</a>
    </div>
    <div class="content-edit">
        <div class="push">
            <input type="text" name="" id="title">
            <input type="button" value="发布文章" id="submit" onclick="submit()">
        </div>
        <!-- markdown 插件 html代码 -->
        <div id="editor">
            <textarea style="display:none;" id="content" name="content">##在这里写下一篇博客</textarea>
        </div>
    </div>

    <script src="js/jquery.min.js"></script>
    <script src="blog-editormd/editormd.min.js"></script>
    <script src="js/common.js"></script>
    <script type="text/javascript">

        $(function () {
            var editor = editormd("editor", {
                width: "100%",
                height: "550px",
                path: "blog-editormd/lib/"
            });
        });

        function submit() {
            $.ajax({
                type: "post",
                url: "/blog/add",
                data: {
                    title: $("#title").val(),
                    content: $("#content").val()
                },
                success: function(result) {
                    if(result.code == 200 && result.data != null && result.data == true) {
                        location.href = "blog_list.html";
                    }else {
                        alert("博客发布失败!");
                    }
                }
            });
        }
    </script>
</body>

</html>

博客编辑页使用了 gittee 上的一个开源 markdown 组件

对于未有博客的 “写博客” , 调用的是 “插入操作”

对于已有博客的 “编辑博客” , 调用的是 “更新操作”

“删除博客” 操作是逻辑删除, 即修改数据库的某一字段, 所以调用的也是 “更新操作”

前端页面共同的 js (common.js)

$(document).ajaxSend(function(e, xhr, opt) {
    // 获取本地存储中的 token
    var user_token = localStorage.getItem("user_token");
    // 将 token 设置到每个 ajax 请求的 header 中
    xhr.setRequestHeader("user_token_header", user_token);
});

// 获取用户信息
function getUserInfo(url) {
    $.ajax({
        type: "post",
        url: url,
        success: function(result) {
            if(result.code == 200 && result.data != null) {
                $(".left .card h3").text(result.data.userName);
                $(".left .card a").attr("href", result.data.githubUrl);
            }
        }
    });
}

// 用户退出
function logout() {
    localStorage.removeItem("user_token");
    location.href = "blog_login.html";
}

主要就是获取当前登录用户的信息, 以及退出登录的逻辑

后端代码

项目的基本框架

实体类

BlogInfo
@Data
public class BlogInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer userId;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
    private Boolean isLoginUser = false;

    // 返回 String 类型的数据 (BlogInfo 里面存储的是 Date 类型数据)
    public String getCreateTime() {
        return DateUtils.formateDate(createTime);
    }

    public String getUpdateTime() {
        return DateUtils.formateDate(updateTime);
    }
}

对应数据的 blog 表

UserInfo
  @Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private String githubUrl;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

对应数据的 user 表

Result
@Data
public class Result {
    private int code;  //200成功  -1失败  -2未登录
    private String errMsg;
    private Object data;

    public static Result success(Object data) {
        Result result = new Result();
        result.setCode(Constant.SUCCESS_CODE);
        result.setErrMsg("");
        result.setData(data);
        return result;
    }


    public static Result fail(String errMsg) {
        Result result = new Result();
        result.setCode(Constant.FAIL_CODE);
        result.setErrMsg(errMsg);
        result.setData(null);
        return result;
    }


    public static Result fail(String errMsg, Object data) {
        Result result = new Result();
        result.setCode(Constant.FAIL_CODE);
        result.setErrMsg(errMsg);
        result.setData(data);
        return result;
    }

    public static Result unlogin() {
        Result result = new Result();
        result.setCode(Constant.FAIL_CODE);
        result.setErrMsg("用户未登录");
        result.setData(null);
        return result;
    }

    public static Result unlogin(String errMsg) {
        Result result = new Result();
        result.setCode(Constant.UNLOGIN_CODE);
        result.setErrMsg("用户未登录");
        result.setData(null);
        return result;
    }
}

用于统一数据格式返回 (不知道可以看一下我的另一篇博客 Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理) )

Constant 类 (常量值存储)

public class Constant {
    public final static Integer SUCCESS_CODE = 200;

    public final static Integer FAIL_CODE = -1;

    public final static Integer UNLOGIN_CODE = -2;

    public final static String USER_TOKEN_HEADER = "user_token_header";

    public final static String USER_CLAIM_ID = "id";

    public final static String USER_CLAIM_NAME = "name";
}

从 0 开始实现一个博客系统 (SSM 项目)(下):https://developer.aliyun.com/article/1520796

目录
相关文章
|
11天前
|
前端开发 JavaScript Java
计算机Java项目|SSM智能仓储系统
计算机Java项目|SSM智能仓储系统
|
5天前
|
前端开发
杨校老师之基于SSM开发的校园点餐配送系统
杨校老师之基于SSM开发的校园点餐配送系统
13 0
杨校老师之基于SSM开发的校园点餐配送系统
|
11天前
|
前端开发 JavaScript Java
计算机Java项目|SSM酒店客房预定管理系统
计算机Java项目|SSM酒店客房预定管理系统
|
5天前
|
前端开发 Java
基于SSM框架的手机商城项目
基于SSM框架的手机商城项目
11 0
|
5天前
|
前端开发 JavaScript Java
杨校老师项目之基于SSM大学生创新创业项目管理系统
杨校老师项目之基于SSM大学生创新创业项目管理系统
17 0
|
5天前
|
前端开发 Java 关系型数据库
杨校老师项目之基于SSM企业物流快递配送管理系统
杨校老师项目之基于SSM企业物流快递配送管理系统
18 0
|
5天前
|
前端开发 Java 关系型数据库
杨校老师项目之基于SSM社区疫情防控人员访客登记报备平台
杨校老师项目之基于SSM社区疫情防控人员访客登记报备平台
10 0
|
5天前
|
Java 关系型数据库 MySQL
基于Java和SSM框架的多人命题系统
基于Java和SSM框架的多人命题系统
|
11天前
|
前端开发 JavaScript Java
计算机Java项目|SSM实验室课程管理系统
计算机Java项目|SSM实验室课程管理系统
|
18天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的大学生校园兼职附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的大学生校园兼职附带文章和源代码部署视频讲解等
41 8