0


基于 SpringBoot + MyBatis 的博客系统

文章目录

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=true
spring.datasource.username=root
spring.datasource.password=0000
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis.mapper-locations=classpath:mapper/**Mapper.xml

4. 数据库实现用户和博客管理

4.1 设计数据库

这里博客系统, 是一个用户表和博客表,

用户一般分为:

  • 用户Id (每个人一个且互不相同)
  • 用户名 (每个人的用户名不相同)
  • 密码
  • 用户头像(暂不实现)
  • 用户马云地址(暂不实现)

博客一般分为:

  • 博客Id (每篇博客一个且互不相同)
  • 标题
  • 正文
  • 创建时间
  • 修改时间 (这里没用到, 自己想加也可以)
  • 用户Id (可以设置一个外键,这里没设置)
createdatabaseifnotexists MyBlogSystem;use MyBlogSystem;droptableifexists blog;-- 创建一个博客表createtable blog (
    blogId intprimarykeyauto_increment,
    title varchar(1024),
    content mediumtext,
    postTime datetime,
    userId int);droptableifexistsuser;-- 创建一个用户信息表createtableuser(
    userId intprimarykeyauto_increment,
    username varchar(128)unique,
    password varchar(128));

4.2 使用 MyBatis 操作数据库

resources

下创建一个

mapper

包. 包下创建

UserMapper.xml

BlogMapper.xml
  • BlogMapper.xml 里是对博客表的数据库操作
  • UserMapper.xml 里是对用户表的数据库操作

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.mapper.UserMapper"><!--  注册一个用户  --><insertid="addUser"keyProperty="userId"keyColumn="userId">
        insert into user(username password) values (#{username}, #{password})
    </insert><!--  通过用户名查找用户信息  --><selectid="selectByName"resultType="com.example.demo.model.User">
        select * from user where username = #{username}
    </select><!--  通过用户Id查找用户信息  --><selectid="selectById"resultType="com.example.demo.model.User">
        select * from user where userId = #{userId}
    </select></mapper>

BlogMapper.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.mapper.BlogMapper"><!--  查找当前所有的文章  --><selectid="getAllBlog"resultType="com.example.demo.model.Blog">
        select * from blog
    </select><!--  通过博客id查找所有的文章  --><selectid="getBlogByBid"resultType="com.example.demo.model.Blog">
        select * from blog where blogId = #{blogId}
    </select><!--  发布一篇博客  --><insertid="postBlog"keyColumn="userId"keyProperty="userId">
        insert into blog(title,content,postTime,userId) values(#{title},#{content},#{postTime},#{userId})
    </insert><!--  删除一篇博客  --><deleteid="deleteBlog">
        delete from blog where blogId = #{blogId}
    </delete><!--  更新一篇博客  --><updateid="updateBlog">
        update blog set content = #{content},title = #{title} where blogId = #{blogId}
    </update><!--  根据当前用户Id获取所有的博客  --><selectid="getAllBlogById"resultType="com.example.demo.model.Blog">
        select * from blog where userId = #{userId}
    </select></mapper>

User 实体类 和 Blog 实体类

在 model 包下 创建 User 类 和 Blog 类

User 类

@DatapublicclassUser{publicint userId;publicString username;publicString password;}

Blog 类

@DatapublicclassBlog{publicint blogId;publicString title;publicString content;publicTimestamp postTime;publicint userId;}

UserMapper 接口 和 BlogMapper 接口

在 mapper 包下创建 UserMapper 和 BlogMapper 接口

UserMapper

@MapperpublicinterfaceUserMapper{voidaddUser(User user);UserselectByName(String username);UserselectById(Integer userId);}

BlogMapper

@MapperpublicinterfaceBlogMapper{List<Blog>getAllBlog();BloggetBlogByBid(Integer blogId);voidpostBlog(Blog blog);voiddeleteBlog(Integer blogId);voidupdateBlog(Blog blog);List<Blog>getAllBlogById();}

UserService 类 和 BlogService 类

service

包下创建 UserService类BlogService类

UserService
@ServicepublicclassUserService{@ResourceprivateUserMapper userMapper;publicvoidaddUser(User user){
        userMapper.addUser(user);}publicUserselectByName(String username){return userMapper.selectByName(username);}publicUserselectById(Integer userId){return userMapper.selectById(userId);}}
BlogService
@ServicepublicclassBlogService{@ResourceprivateBlogMapper blogMapper;publicList<Blog>getAllBlog(){return blogMapper.getAllBlog();}publicBloggetBlogByBid(Integer blogId){return blogMapper.getBlogByBid(blogId);}publicvoidpostBlog(Blog blog){
        blogMapper.postBlog(blog);}publicvoiddeleteBlog(Integer blogId){
        blogMapper.deleteBlog(blogId);}publicvoidupdateBlog(Blog blog){
        blogMapper.updateBlog(blog);}publicList<Blog>getAllBlogById(){return blogMapper.getAllBlogById();}}

5. 前后端交互接口设计

在这里插入图片描述
交互1
在这里插入图片描述
交互2
在这里插入图片描述

交互3
在这里插入图片描述

交互4
在这里插入图片描述

交互5
在这里插入图片描述

交互6
在这里插入图片描述

交互7
在这里插入图片描述

交互8
在这里插入图片描述

交互9
在这里插入图片描述

交互10
在这里插入图片描述

交互11
在这里插入图片描述

6. 导入前端代码

**导入前端代码到

resources

static

下**

在这里插入图片描述
具体代码查看 文章 博客系统前端界面
https://wangzhi430.blog.csdn.net/article/details/124649884

7. 实现博客主页

这里的交互接口是

交互6

7.1 实现后端代码

@RestControllerpublicclassIndexController{@AutowiredprivateBlogService blogService;@RequestMapping("/index")publicList<Blog>getAllBlog(){return blogService.getAllBlog();}}

7.2 实现前端代码

 $.ajax({url:"index",method:"GET",success:function(data,status){buildBlogs(data);}})functionbuildBlogs(blogs){let rightDiv = document.querySelector('.right');for(let blog of blogs){let blogDiv = document.createElement('div');
                blogDiv.className ='article';// 创建 titlelet h2 = document.createElement('h2');
                h2.className ='title';
                h2.innerHTML = blog.title;
                blogDiv.appendChild(h2);// 创建 postTimelet postTime = document.createElement('span');
                postTime.className ='date';
                postTime.innerHTML =DateFormat(blog.postTime);
                blogDiv.appendChild(postTime);// 创建 contentlet 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);}}// 把毫秒级时间戳转化成格式化日期functionDateFormat(timeStampMS){var date =newDate(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;}

7.3 测试代码

在这里插入图片描述

7.4 解决页面内容太多超出当前浏览器

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

7.5 解决页面顺序不是按最新时间排序

在这里插入图片描述

在BlogMapper.xml中修改当前sql语句.

在这里插入图片描述

7.6 解决内容太多, 导致显示的时候占位太多.

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

7.7 再次测试代码

在这里插入图片描述

8. 实现博客详情页

这里的交互是

交互5

8.1 实现后端代码

根据当前blogId来获取文章, 要判断blogId是否合法, 是否存在当前blogId的文章
这里使用, message来判断, 返回的message不为空就表示异常.

@RestControllerpublicclassDetailsController{@AutowiredprivateBlogService blogService;@RequestMapping("/details")publicObjectShowBlog(Integer blogId){HashMap<String,Object> map =newHashMap<>();if(blogId ==null|| blogId <1){
            map.put("message","blogId异常!");return map;}Blog blog = blogService.getBlogByBid(blogId);if(blog ==null){
            map.put("message","不存在当前blogId的文章");return map;}return blog;}}

8.2 实现前端代码

    $.ajax({url:"details"+location.search,method:"GET",success:function(data,status){if(data.message ==null){buildBlog(data);}else{alert(data.message);
                    location.assign("home.html");}}})functionbuildBlog(blog){// 1. 更新 titlelet titleDiv = document.querySelector('.title');
            titleDiv.innerHTML = blog.title;// 2. 更新 postTimelet postTime = document.querySelector('.date');
            postTime.innerHTML =DateFormat(blog.postTime);
            editormd.markdownToHTML('content',{markdown: blog.content});}// 把毫秒级时间戳转化成格式化日期functionDateFormat(timeStampMS){var date =newDate(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;}

8.3 测试代码

在这里插入图片描述

8.4 这里展示为markdown语法的正文

展示为 markdown 语法的正文.
注意这里的几段代码
在这里插入图片描述
在这里插入图片描述
这里还需要导入依赖包
在这里插入图片描述

9. 实现博客登录界面

这里的交互是

交互8

9.1 实现后端代码

这里要根据前端穿过来的 json 格式数据进行判断
判断当前是否存在用户, 以及当前用户密码是否正确
登录成功之后, 要创建一个session

@RestControllerpublicclassLoginController{@AutowiredprivateUserService userService;@RequestMapping("/login")publicObjectuserLogin(@RequestBodyUser user,HttpServletRequest request){HashMap<String,Object> map =newHashMap<>();if(user ==null){
            map.put("message","当前还没有输入用户名和密码,登录失败!");return map;}User user1 = userService.selectByName(user.getUsername());if(user1 ==null){
            map.put("message","当前用户名不存在!");return map;}if(!user.getPassword().equals(user1.getPassword())){
            map.put("message","当前用户名密码错误!");return map;}
        user.setUserId(user1.getUserId());HttpSession session = request.getSession(true);if(session !=null){
            session.setAttribute("user",user);}return map;}}

9.2 实现前端代码

这里前端去除了前后空格,以及为空的情况

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

10. 实现登录判断 — 拦截器

10.1 实现自定义拦截器

publicclassLoginInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{HttpSession session = request.getSession(false);if(session !=null&& session.getAttribute("user")!=null){returntrue;}
        response.setStatus(401);
        response.sendRedirect("/login.html");returnfalse;}}

10.2 将自定义拦截器加入到系统配置

@ConfigurationpublicclassAppConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(newLoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/**/*.js").excludePathPatterns("/**/*.jpg").excludePathPatterns("/**/*.css").excludePathPatterns("/**/*.png").excludePathPatterns("/**/login.html").excludePathPatterns("/**/register.html").excludePathPatterns("/**/login").excludePathPatterns("/**/register");}}

11. 实现注册功能

这里的交互是

交互9

11.1 实现后端代码

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

classRegister{publicString username;publicString password1;publicString password2;}

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

@RestControllerpublicclassRegisterController{@AutowiredprivateUserService userService;@RequestMapping("/register")publicObjectuserRegister(@RequestBodyRegister register){HashMap<String,Object> map =newHashMap<>();User user = userService.selectByName(register.username);if(user !=null){
            map.put("message","当前用户名已经存在了, 请更换!");return map;}User user1 =newUser();
        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, 然后发送一个请求.
这里只需要实现后端代码既可

@ControllerpublicclassLogoutController{@RequestMapping("/logout")publicvoiduserLogout(HttpServletRequest request,HttpServletResponse response)throwsIOException{HttpSession session = request.getSession(false);// 拦截器的拦截, 所以不可能出现session为空的情况
        session.removeAttribute("user");
        response.sendRedirect("login.html");}}

13. 实现博客编辑页

这里的交互是

交互1

13.1 实现后端代码

@RestControllerpublicclassEditController{@AutowiredprivateBlogService blogService;@RequestMapping("/edit")publicvoidpostBlog(@RequestBodyBlog blog,@SessionAttribute(value ="user",required =false)User user){
        blog.setPostTime(newTimestamp(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 实现后端代码

@RestControllerpublicclassPersonController{@AutowiredprivateBlogService blogService;@RequestMapping("/person")publicList<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);}})functionbuildBlogs(blogs){let rightDiv = document.querySelector('.right');for(let blog of blogs){let blogDiv = document.createElement('div');
                blogDiv.className ='article';// 创建 titlelet h2 = document.createElement('h2');
                h2.className ='title';
                h2.innerHTML = blog.title;
                blogDiv.appendChild(h2);// 创建 postTimelet postTime = document.createElement('span');
                postTime.className ='date';
                postTime.innerHTML =DateFormat(blog.postTime);
                blogDiv.appendChild(postTime);// 创建 contentlet 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);}}// 把毫秒级时间戳转化成格式化日期functionDateFormat(timeStampMS){var date =newDate(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丢失的情况以及,文章作者丢失情况(数据库表数据被删除的时候会出现这种错误)

@RestControllerpublicclassUserController{@AutowiredprivateUserService userService;@AutowiredprivateBlogService blogService;@RequestMapping("/user")publicObjectgetUser(Integer blogId,@SessionAttribute(value ="user",required =false)User user){if(blogId ==null){return user;}else{HashMap<String,Object> map =newHashMap<>();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 实现后端代码

@ControllerpublicclassDeleteController{@AutowiredprivateBlogService blogService;@RequestMapping("/delete")publicObjectdeleteBlog(Integer blogId){
        blogService.deleteBlog(blogId);return"/home.html";}}

17. 实现博客的修改功能

这里的交互是

交互3

交互4

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

17.1 实现后端代码

@RestControllerpublicclassUpdateController{@AutowiredprivateBlogService blogService;@RequestMapping("/updateLoad")publicObjectupdateLoad(Integer blogId){HashMap<String,Object> map =newHashMap<>();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")publicObjectUpdate(Integer blogId,@RequestBodyBlog blog,@SessionAttribute(value ="user",required =false)User user){HashMap<String,Object> map =newHashMap<>();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');}}})}

本文转载自: https://blog.csdn.net/wwzzzzzzzzzzzzz/article/details/125356118
版权归原作者 独一无二的哈密瓜 所有, 如有侵权,请联系我们删除。

“基于 SpringBoot + MyBatis 的博客系统”的评论:

还没有评论