基于 SpringBoot + MyBatis 的博客系统

文章目录

  • 1. 项目设计
  • 2. 效果展示
  • 3. 创建项目并配置文件
    • 1.1 创建 Spring 项目
    • 1.2 配置文件
  • 4. 数据库实现用户和博客管理
    • 4.1 设计数据库
    • 4.2 使用 MyBatis 操作数据库
      • UserMapper.xml
      • BlogMapper.xml
      • User 实体类 和 Blog 实体类
      • UserMapper 接口 和 BlogMapper 接口
      • UserService 类 和 BlogService 类
  • 5. 前后端交互接口设计
  • 6. 导入前端代码
  • 7. 实现博客主页
    • 7.1 实现后端代码
    • 7.2 实现前端代码
    • 7.3 测试代码
    • 7.4 解决页面内容太多超出当前浏览器
    • 7.5 解决页面顺序不是按最新时间排序
    • 7.6 解决内容太多, 导致显示的时候占位太多.
    • 7.7 再次测试代码
  • 8. 实现博客详情页
    • 8.1 实现后端代码
    • 8.2 实现前端代码
    • 8.3 测试代码
    • 8.4 这里展示为markdown语法的正文
  • 9. 实现博客登录界面
    • 9.1 实现后端代码
    • 9.2 实现前端代码
  • 10. 实现登录判断 --- 拦截器
      • 10.1 实现自定义拦截器
    • 10.2 将自定义拦截器加入到系统配置
  • 11. 实现注册功能
    • 11.1 实现后端代码
    • 11.2 实现前端代码
  • 12. 实现注销功能
    • 12.1 实现后端代码
  • 13. 实现博客编辑页
    • 13.1 实现后端代码
    • 13.2 实现前端代码
  • 14. 实现博客个人主页
    • 14.1 实现后端代码
    • 14.2 实现前端代码
  • 15. 实现展示用户信息的功能
    • 15.1 实现后端代码
    • 15.2 实现前端代码
  • 16. 实现博客的删除功能
    • 16.1 改进代码
    • 16.2 实现后端代码
  • 17. 实现博客的修改功能
    • 17.1 实现后端代码
    • 17.2 实现前端代码

1. 项目设计

前端使用 HTML+CSS+Javascript+JQuery
后端使用 Spring MVC+Spring Boot+MyBatis
在这里插入图片描述

2. 效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 创建项目并配置文件

1.1 创建 Spring 项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 配置文件

application.properties 配置内容

spring.profiles.active=dev

application-dev.properties 配置内容

spring.datasource.url=jdbc:mysql://localhost:3306/MyBlogSystem?characterEncoding=utf8&useSSL=truespring.datasource.username=rootspring.datasource.password=0000spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis.mapper-locations=classpath:mapper*.js")                .excludePathPatterns("*.jpg")                .excludePathPatterns("*.css")                .excludePathPatterns("*.png")                .excludePathPatterns("login.html")                .excludePathPatterns("register.html")                .excludePathPatterns("login")                .excludePathPatterns("register");    }}

11. 实现注册功能

这里的交互是 交互9

11.1 实现后端代码

实现一个 类 Register 来接收前端返回来的数据

class Register {    public String username;    public String password1;    public String password2;}

这里后端需要判断当前用户名是否已经被使用.

@RestControllerpublic class RegisterController {    @Autowired    private UserService userService;    @RequestMapping("/register")    public Object userRegister(@RequestBody Register register) {        HashMap<String,Object> map = new HashMap<>();        User user = userService.selectByName(register.username);        if (user != null) {            map.put("message","当前用户名已经存在了, 请更换!");            return map;        }        User user1 = new User();        user1.setUsername(register.username);        user1.setPassword(register.password1);        userService.addUser(user1);        return map;    }}

11.2 实现前端代码

要对输入内容去除前后空格,并且判空

        let submit = document.querySelector('.button');        submit.onclick = function() {            let username = document.querySelector('.user');            let password1 = document.querySelector('.password1');            let password2 = document.querySelector('.password2');            if(username.value.trim() == ""){                alert("请先输入用户名!");                username.focus();                return;            }            if(password1.value.trim() == ""){                alert('请先输入密码!');                password1.focus();                return;            }            if(password2.value.trim() == ""){                alert('请再次输入密码!');                password2.focus();                return;            }            if(password1.value.trim() != password2.value.trim()) {                alert('两次输入的密码不同!');                passwrod1.value="";                password2.value="";                return;            }            $.ajax({                url: "register",                method: "POST",                data: JSON.stringify({username: username.value.trim(), password1: password1.value.trim(),password2: password2.value.trim()}),                contentType: "application/json;charset=utf-8",                success: function(data,status){                    if(data.message != null){                        alert(data.message);                        username.value="";                        password1.value="";                        password2.value="";                        username.focus();                    }else{                        location.assign('login.html');                    }                }            })        }

12. 实现注销功能

这里的交互是 交互10

12.1 实现后端代码

因为 注销功能是点击注销的时候, 触发一个logout的url, 然后发送一个请求.
这里只需要实现后端代码既可

@Controllerpublic class LogoutController {    @RequestMapping("/logout")    public void userLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {        HttpSession session = request.getSession(false);        // 拦截器的拦截, 所以不可能出现session为空的情况        session.removeAttribute("user");        response.sendRedirect("login.html");    }}

13. 实现博客编辑页

这里的交互是 交互1

13.1 实现后端代码

@RestControllerpublic class EditController {    @Autowired    private BlogService blogService;    @RequestMapping("/edit")    public void postBlog(@RequestBody Blog blog, @SessionAttribute(value = "user",required = false)User user){        blog.setPostTime(new Timestamp(System.currentTimeMillis()));        blog.setUserId(user.getUserId());        blogService.postBlog(blog);    }}

13.2 实现前端代码

        let submit = document.querySelector('.publish');        submit.onclick = function() {            let title = document.querySelector('.title');            let content = document.querySelector('.content');            if(title.value.trim() == ""){                alert('当前文章标题为空,请输入!');                title.focus();                return;            }            if(content.value.trim() == ""){                alert('当前文章内容为空,请输入!');                content.focus();                return;            }            $.ajax({                url: "edit",                method: "POST",                data: JSON.stringify({title: title.value.trim(), content: content.value.trim()}),                contentType: "application/json;charset=utf-8",                success: function(data,status) {                    location.assign('home.html');                }            })        }

14. 实现博客个人主页

这里的交互是 交互7
这里的前端页面主要就是主页页面的改进

14.1 实现后端代码

@RestControllerpublic class PersonController {    @Autowired    private BlogService blogService;    @RequestMapping("/person")    public List<Blog> getMyBlog(@SessionAttribute(value = "user",required = false)User user) {        List<Blog> blogs = blogService.getAllBlogById(user.getUserId());        for (Blog blog : blogs) {            if (blog.getContent().length() > 80) {                blog.setContent(blog.getContent().substring(0,80) + " ...");            }        }        return blogs;    }}

14.2 实现前端代码

        $.ajax({            url: "person",            method: "GET",            success: function(data,status) {                buildBlogs(data);            }        })        function buildBlogs(blogs){            let rightDiv = document.querySelector('.right');            for(let blog of blogs){                let blogDiv = document.createElement('div');                blogDiv.className = 'article';                // 创建 title                let h2 = document.createElement('h2');                h2.className = 'title';                h2.innerHTML = blog.title;                blogDiv.appendChild(h2);                // 创建 postTime                let postTime = document.createElement('span');                postTime.className = 'date';                postTime.innerHTML = DateFormat(blog.postTime);                blogDiv.appendChild(postTime);                // 创建 content                let content = document.createElement('div');                content.className = 'desc';                content.innerHTML = blog.content;                blogDiv.appendChild(content);                // 创建 详情页的超链接                let detailA = document.createElement('a');                detailA.className = 'more';                detailA.href = 'art.html?blogId=' + blog.blogId;                detailA.innerHTML = '查看全文&gt;&gt;';                blogDiv.appendChild(detailA);                // 加入到 right 中                rightDiv.appendChild(blogDiv);            }        }        // 把毫秒级时间戳转化成格式化日期        function DateFormat(timeStampMS) {            var date = new Date(timeStampMS);             var year = date.getFullYear(),                month = date.getMonth()+1,//月份是从0开始的                day = date.getDate(),                hour = date.getHours(),                min = date.getMinutes(),                sec = date.getSeconds();            var newTime = year + '-' +                        (month < 10? '0' + month : month) + '-' +                        (day < 10? '0' + day : day) + ' ' +                        (hour < 10? '0' + hour : hour) + ':' +                        (min < 10? '0' + min : min) + ':' +                        (sec < 10? '0' + sec : sec);                    return newTime;        }

15. 实现展示用户信息的功能

这里的交互是 交互11

这里需要分情况考虑, 展示个人信息主要是 主页页面, 详情页面, 个人主页页面.
以带不带blogId来区分

15.1 实现后端代码

这里判断了 blogId丢失的情况以及,文章作者丢失情况(数据库表数据被删除的时候会出现这种错误)

@RestControllerpublic class UserController {    @Autowired    private UserService userService;    @Autowired    private BlogService blogService;    @RequestMapping("/user")    public Object getUser(Integer blogId, @SessionAttribute(value = "user",required = false)User user){        if(blogId == null) {            return user;        }else {            HashMap<String,Object> map = new HashMap<>();            Blog blog = blogService.getBlogByBid(blogId);            if(blog == null) {                map.put("message","不存在当前blogId的文章");                return map;            }            User author = userService.selectById(blog.getUserId());            if(author == null){                map.put("message","当前文章作者出错");                return map;            }            return author;        }    }}

15.2 实现前端代码

详情页的情况:

        $.ajax({            url: "user"+location.search,            method: "GET",            success: function(data,status) {                if(data.message == null){                    let username = document.querySelector('.name');                    username.innerHTML = data.username;                }else{                    alert(data.message);                    location.assign('home.html');                }            }        })

个人主页和主页的情况

        $.ajax({            url: "user",            method: "GET",            success: function(data,status){                let username = document.querySelector('.name');                username.innerHTML = data.username;            }        })

16. 实现博客的删除功能

这里需要用到 交互2
这里在详情页的时候进行构建, 在Blog实体类中加一项 isAuthor, 为1的时候就是当前文章就是作者.
前端接收到这个的时候, 进行判断, 如果为1就显示删除的按钮.

16.1 改进代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

16.2 实现后端代码

@Controllerpublic class DeleteController {    @Autowired    private BlogService blogService;    @RequestMapping("/delete")    public Object deleteBlog(Integer blogId) {        blogService.deleteBlog(blogId);        return "/home.html";    }}

17. 实现博客的修改功能

这里的交互是 交互3交互4
交互3是在新的页面进行加载

17.1 实现后端代码

@RestControllerpublic class UpdateController {    @Autowired    private BlogService blogService;    @RequestMapping("/updateLoad")    public Object updateLoad(Integer blogId){        HashMap<String, Object> map = new HashMap<>();        if(blogId == null) {            map.put("message","blogId丢失!");            return map;        }        Blog blog = blogService.getBlogByBid(blogId);        if(blog == null) {            map.put("blog","不存在当前blog的文章!");            return map;        }        return blog;    }    @RequestMapping("/update")    public Object Update(Integer blogId, @RequestBody Blog blog, @SessionAttribute(value = "user",required = false)User user) {        HashMap<String, Object> map = new HashMap<>();        if(blogId == null) {            map.put("message","blogId丢失!");            return map;        }        blog.setBlogId(blogId);        blog.setUserId(user.getUserId());        blogService.updateBlog(blog);        return map;    }}

17.2 实现前端代码

        $.ajax({            url: "updateLoad"+location.search,            method: "GET",            success: function(data,status) {                if(data.message == null) {                    let title = document.querySelector('.title');                    title.value=data.title;                    let content = document.querySelector('.content');                    content.value=data.content;                }else{                    alert(data.message);                    location.assign('home.html');                }            }        })        // 初始化编辑器        var editor = editormd("editor", {            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.            width: "100%",            // 高度 100% 意思是和父元素一样高. 要在父元素的基础上去掉标题编辑区的高度            height: "calc(100% - 60px)",            // 指定 editor.md 依赖的插件路径            path: "editor.md/lib/",            // 放到 textarea中            saveHTMLTotextarea: true        });        let submit = document.querySelector('.publish');        submit.onclick = function() {            let title = document.querySelector('.title');            let content = document.querySelector('.content');            if(title.value.trim() == ""){                alert('当前文章标题为空,请输入!');                title.focus();                return;            }            if(content.value.trim() == ""){                alert('当前文章内容为空,请输入!');                content.focus();                return;            }            $.ajax({                url: "update"+location.search,                method: "POST",                data: JSON.stringify({title: title.value.trim(), content: content.value.trim()}),                contentType: "application/json;charset=utf-8",                success: function(data,status) {                    if(data.message == null){                        location.assign('home.html');                    }else{                        alert(data.message);                        location.assign('home.html');                    }                }            })        }
 
友情链接
鄂ICP备19019357号-22