0


SpringBoot项目-个人博客系统的实现

1.博客系统简要分析

在这里插入图片描述
一共有6个网页,分别是博客列表页面,博客详情页面,发布博客页面,博客登陆页面,博客更新页面,修改个人信息页面(暂未实现),我们要实现的功能有,实现博客列表的展示页面,博客详情页面的展示功能,用户登录功能,显示用户信息功能,编辑博客功能,发布博客功能,删除博客功能,退出登录功能
我们现在就开始写吧

2.创建springBoot项目

1.创建项目,勾选需要的依赖

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

2.删除无用的目录及文件

在这里插入图片描述

4.创建框架

在这里插入图片描述

3.配置文件(选择yml)

application.xml

spring:profiles:active: dev
logging:file:path: logs/
  level:root: info

application-dev.xml

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/java_blog_spring?characterEncoding=utf8
    username: root
    password:111111driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:configuration:# 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case:true#自动驼峰转换mapper-locations: classpath:mapper/***Mapper.xml

application-prod.xml

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/java_blog_spring?characterEncoding=utf8
      username: root
      password:111111driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:#上线就不用打印mybatis执行日志configuration:map-underscore-to-camel-case:true#自动驼峰转换

3.数据库准备

这个项目的数据库表比较简单
只有两个表

1.设计表结构

在这里插入图片描述

2.建表sql

-- 建表SQLcreatedatabaseifnotexists`java_blog_spring1`charset utf8mb4;-- 用户表droptableifexists`java_blog_spring`.`user`;CREATETABLE`java_blog_spring`.`user`(`id`INTNOTNULLAUTO_INCREMENT,`user_name`VARCHAR(128)NOTNULL,`password`VARCHAR(128)NOTNULL,`photo`VARCHAR(128)NOTNULL,`github_url`VARCHAR(128)NULL,`delete_flag`TINYINT(4)NULLDEFAULT0,`create_time`TIMESTAMPNULLDEFAULTcurrent_timestamp(),PRIMARYKEY(`id`),UNIQUEINDEX`user_name_UNIQUE`(`user_name`ASC))ENGINE=InnoDBDEFAULTCHARACTERSET= utf8mb4 COMMENT='用户表';-- 博客表droptableifexists`java_blog_spring`.`blog`;CREATETABLE`java_blog_spring`.`blog`(`id`INTNOTNULLAUTO_INCREMENT,`title`VARCHAR(200)NULL,`content`TEXTNULL,`user_id`INT(11)NULL,`delete_flag`TINYINT(4)NULLDEFAULT0,`create_time`TIMESTAMPNULLDEFAULTcurrent_timestamp(),PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET= utf8mb4 COMMENT='博客表';-- 新增用户信息insertinto`java_blog_spring`.`user`(`user_name`,`password`,`photo`,`github_url`)values("zhangsan","123456","pic/doge.jpg","https://gitee.com/bubble-fish666/class-java45");insertinto`java_blog_spring`.`user`(`user_name`,`password`,`photo`,`github_url`)values("lisi","123456","pic/doge.jpg","https://gitee.com/bubble-fish666/class-java45");insertinto`java_blog_spring`.`blog`(`title`,`content`,`user_id`)values("第一篇博客","111我是博客正文我是博客正文我是博客正文",1);insertinto`java_blog_spring`.`blog`(`title`,`content`,`user_id`)values("第一篇博客","222我是博客正文我是博客正⽂我是博客正文",2);use java_blog_spring;-- 查询两个表的数据select*fromuser;select*from blog;

4.接口设计

  1. 获取所有的博客列表

5.数据库相关查询操作

  1. 根据用户id查询用户信息
  2. 根据用户名称查询用户
  3. 查询所有未删除的博客(按照时间降序排列)
  4. 根据博客id查询博客详情
  5. 插入一条博客
  6. 根据博客id更新博客
  7. 删除博客
  8. 根据用户id查询博客数量

6.写代码准备工作

1.model包下,创建Java实体类

我们在配置文件中配置了数据库表字段到类属性的自动驼峰转换,所以可以不用进行重命名

自动驼峰映射

configuration:
 map-underscore-to-camel-case:true

1.User类

@DatapublicclassUser{// java中属性使用小驼峰命名// 我们配置了自动驼峰转换privateInteger id;privateString userName;privateString passWord;privateString photo;privateString githubUrl;privateByte deleteFlag;privateDate createTime;}

2.Blog类

@Data@DatapublicclassBlog{privateInteger id;privateString title;privateString content;privateInteger userId;privateInteger deleteFlag;privateDate createTime;}

2.mapper层

  • 简单的sql语句我们使用注解实现
  • 复杂的sql语句使用xml配置文件实现

1.userMapper接口

@MapperpublicinterfaceUserMapper{/**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */@Select("select user_name, password, photo, github_url from user where delete_flag = 0 and id = #{id}")UserselectById(Integer id);/**
     * 根据用户名称查询用户
     * @param userName
     * @return
     */@Select(("select user_name, password, photo, github_url from user where delete_flag = 0 and user_name = #{userName}"))UserselectByName(String userName);}

2.BlogMapper接口

@MapperpublicinterfaceBlogMapper{/**
     * 查询所有未删除的博客.按照时间降序排列
     * @return
     */@Select("select id, title, content, user_id, create_time from blog where delete_flag = 0 order by create_time;")List<Blog>selectAllBlog();/**
     * 根据博客id查询博客详情
     * @param blogId
     * @return
     */@Select("select id, title, content, user_id, create_time from blog where delete_flag = 0 and id = #{blogId}")BlogselectByBlogId(Integer blogId);/**
     * 插入一条博客
     * @param blog
     * @return
     */@Insert("insert into blog (title, content, user_id) values (#{title, #{content}, #{userId})")IntegerinsertBlog(Blog blog);/**
     * 根据博客id更新博客
     * 删除博客就是把delete_id改为1
     * @return
     */IntegerupdateBlog(Blog blog);/**
     * 根据用户id查询博客数量
     * @param userId
     * @return
     */@Select("select count(id) from blog where delete_flag = 0 and user_id = #{userId}")IntegerselectBlogCount(Integer userId);}

因为更新博客内容的sql语句比较复杂,我们就不采用注解的方式,使用配置文件的方式来写

3.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.springblog.mapper.BlogMapper"><updateid="updateBlog">
        update blog
        <set><iftest="title!=null">title=#{title},</if><iftest="content!=null">content=#{content},</if><iftest="deleteFlag!=null">delete_flag=#{deleteFlag},</if></set><where>
            id = #{id}
        </where></update></mapper>

3.Service包下

service层被称作业务层,它用来处理逻辑上的业务,而不去考虑具体的实现,这样controller层就不会直接去调用mapper层,可以将代码解耦,便于扩展

1.UserService类

@ServicepublicclassUserService{@Autowired// 将UserMapper对象注入进来privateUserMapper userMapper;/**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */publicUserselectById(Integer id){return userMapper.selectById(id);}/**
     * 根据用户名称查询用户
     * @param userName
     * @return
     */publicUserselectByName(String userName){return userMapper.selectByName(userName);}}

2.BlogService类

@ServicepublicclassBlogService{@AutowiredprivateBlogMapper blogMapper;/**
     * 查询所有未删除的博客.按照时间降序排列
     * @return
     */publicList<Blog>selectAllBlog(){return blogMapper.selectAllBlog();}/**
     * 根据博客id查询博客详情
     * @param blogId
     * @return
     */publicBlogselectByBlogId(Integer blogId){return blogMapper.selectByBlogId(blogId);}/**
     * 插入一条博客
     * @param blog
     * @return
     */publicIntegerinsertBlog(Blog blog){return blogMapper.insertBlog(blog);}/**
     * 根据博客id更新博客
     * 删除博客就是把delete_id改为1
     * @return
     */publicIntegerupdateBlog(Blog blog){return blogMapper.updateBlog(blog);}/**
     * 根据用户id查询博客数量
     * @param userId
     * @return
     */publicIntegerselectBlogCount(Integer userId){return blogMapper.selectBlogCount(userId);}}

4.测试

使用BlogMapper做演示,UserMapper同理

在mapper接口点击Fn+Alt+Insert(按钮因电脑而异,不行可以试下Alt+Insert)
然后在弹出框中点击Test

在这里插入图片描述
然后勾选需要测试的方法
在这里插入图片描述
此时就可以看到test包下出现了对应的类
在这里插入图片描述
然后我们就可以在这里写测试方法

1.BlogMapperTest测试类

@SpringBootTestclassBlogMapperTest{@AutowiredprivateBlogService blogService;@TestvoidselectAllBlog(){List<Blog> blogs = blogService.selectAllBlog();System.out.println(blogs.toString());}@TestvoidselectByBlogId(){System.out.println(blogService.selectByBlogId(2).toString());}@TestvoidinsertBlog(){Blog blog =newBlog();
        blog.setTitle("测试");
        blog.setContent("测试正文");
        blog.setUserId(1);System.out.println(blogService.insertBlog(blog));}@TestvoidupdateBlog(){Blog blog =newBlog();
        blog.setTitle("测试更新");
        blog.setId(1);System.out.println(blogService.updateBlog(blog));}@TestvoiddeleteBlog(){Blog blog =newBlog();
        blog.setDeleteFlag(1);
        blog.setId(1);System.out.println(blogService.updateBlog(blog));}@TestvoidselectBlogCount(){System.out.println(blogService.selectBlogCount(2));}}

2.UserMapperTest测试类

@SpringBootTestclassUserMapperTest{@AutowiredprivateUserService userService;@TestvoidselectById(){System.out.println(userService.selectById(1).toString());}@TestvoidselectByName(){System.out.println(userService.selectByName("zhangsan").toString());}}

3.测试结果

在这里插入图片描述

在这里插入图片描述

5.添加前端界面

把之前写好的博客系统静态页面拷贝到static⽬录下
在这里插入图片描述

6.添加公共模块

⼯具层(common) => 统⼀返回类, 统⼀异常处理类

1.添加统一返回类Result

@DatapublicclassResult{privateInteger code;privateString msg;privateObject data;/**
     * 业务执行成功返回的数据
     * @return
     */publicstaticResultsuccess(String msg,Object data){Result result =newResult();
        result.setCode(200);
        result.setMsg(msg);
        result.setData(data);return result;}/**
     * 业务执行成功返回的数据
     * @return
     */publicstaticResultsuccess(Object data){Result result =newResult();
        result.setCode(200);
        result.setMsg("执行成功");
        result.setData(data);return result;}/**
     * 业务执行失败返回的数据
     * @return
     */publicstaticResultfail(Integer code,String msg,Object data){Result result =newResult();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);return result;}/**
     * 业务执行失败返回的数据
     * @return
     */publicstaticResultfail(Integer code,String msg){Result result =newResult();
        result.setCode(code);
        result.setMsg(msg);return result;}}

2.添加统一异常处理类

使用code = -1表示出现异常

@ControllerAdvice@ResponseBodypublicclassErrorAdvice{@ExceptionHandlerpublicResult error (Exception e){returnResult.fail(-1, e.getMessage());}}

3.添加统一返回格式

在数据返回之前调用此方法,将返回数据格式统一
如果是String类型会报错,所以我们要处理一下,异常使用@SneakyThrows注解
如果返回的数据格式,已经是Result类型,就不需要处理,直接返回即可

@ControllerAdvicepublicclassResponseAdviceimplementsResponseBodyAdvice{/**
     * 内容是否需要重写
     * 返回true表示需要重写
     * @param returnType
     * @param converterType
     * @return
     */@Overridepublicbooleansupports(MethodParameter returnType,Class converterType){returntrue;}/**
     * 方法返回之前调用此方法
     *///@SneakyThrows@OverridepublicObjectbeforeBodyWrite(Object body,// 相应的正文内容MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response){//如果返回的数据格式,已经是Result类型,就不需要处理,直接返回即可if(body instanceofResult){return body;}// 如果是String类型会报错,所以我们要处理一下if(body instanceofString){ObjectMapper objectMapper =newObjectMapper();
            objectMapper.writeValueAsString(body);}returnResult.success(body);}}

7.实现博客列表显示

1.约定前后端交互的接口

【请求】

  • blog/getList

【响应】

  1. [200]
  • [200]返回数据成功,显示博客列表
  • [-1]目前没有博客
  1. [401]没有权限访问
  2. [error]访问出现错误,打印异常信息

浏览器给服务器发送一个blog/getList这样的Http请求,服务器返回给浏览器一个json格式的数据

2.实现服务器代码

@RestController@RequestMapping("/blog")publicclassBlogController{@AutowiredprivateBlogService blogService;@RequestMapping("/getList")publicList<Blog>getList(){// 获取博客列表List<Blog> blogs = blogService.selectAllBlog();if(blogs ==null){returnnull;}return blogs;}}

使用postman测试成功,服务器正确返回数据
在这里插入图片描述

3.实现客户端代码

修改 blog_list.html, 删除之前写死的博客内容(即

), 并新增js 代码处理 ajax 请求.

  1. 使用ajax给服务器发送数据
  2. 服务器返回一个json数据格式的响应
  3. 前端根据这个响应使用DOM API构造页面内容
  4. 响应中的时间为时间戳,需要修改
  5. 列表中拿到的content应该是已经裁剪过的摘要
  6. 跳转到博客详情页的url应该在后面加上参数blogId=1,这样可以让博客详情页知道当前访问的是哪篇博客
<scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>
        $.ajax({type:"get",url:"/blog/getList",success:function(result){if(result.code ==200&& result.data !=null&& result.data.length >0){//循环拼接数据到documentvar 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);}elseif(result.code ==-1){alert(result.mag);}},error:function(){
                console.log("后端返回失败");}});</script>

4.处理日期显示问题

SimpleDateFormat 格式化
创建一个DateUtil工具类

publicclassDateUtil{publicstaticStringformat(Date date){SimpleDateFormat simpleDateFormat =newSimpleDateFormat("yy-MM-dd HH:mm:ss");return simpleDateFormat.format(date);}}

重新获取博客创建时间

@DatapublicclassBlog{privateInteger id;privateString title;privateString content;privateInteger userId;privateInteger deleteFlag;privateDate createTime;publicStringgetCreateTime(){returnDateUtil.format(createTime);}}

5.处理裁剪摘要问题

博客列表页面应该显示的是正文的摘要,并非全部显示出来,在博客的详情页面才需要全部显示出来
修改Blog Service中的方法

/**
     * 查询所有未删除的博客.按照时间降序排列
     * @return
     */publicList<Blog>selectAllBlog(){List<Blog> blogs = blogMapper.selectAllBlog();// 遍历如果博客的正文长度超过100,就裁剪for(Blog blog : blogs){if(blog.getContent().length()>100){
                blog.setContent(blog.getContent().substring(0,100)+"...");}}return blogs;}

4.博客列表界面显示成功

在这里插入图片描述

8.实现博客详情

点击查看全文能进入当前博客详情页面,根据博客id动态的获取博客详情

1.约定前后端交互接口

【请求】

  • blog/getBlogDetails

【响应】

  1. [200]
  • [200]返回数据成功,显示博客详情
  • [-1]该博客不存在
  1. [401]没有权限访问
  2. [error]访问出现错误,打印异常信息

浏览器给服务器发送一个blog.getDetails的Http请求,服务器返回给浏览器一个json格式的数据

2.实现服务器代码

@RequestMapping("/blog/getBlogDetails")publicResultgetDetails(Integer blogId){// 判合法if(blogId ==null|| blogId <=0){returnResult.fail(-1,"博客不存在");}Blog blog = blogService.selectByBlogId(blogId);if(blog ==null){returnResult.fail(-1,"博客不存在");}returnResult.success(blog);}

使用postman测试成功,服务器正确返回数据
在这里插入图片描述

3.实现客户端代码

  1. 使用ajax,根据当前页面的URL中的blogId参数(使⽤ location.search 即可得到形如 ?blogId=1 的数据),给服务器发送请求
  2. 服务器返回一个json数据格式的响应
  3. 前端根据这个响应使用通过 editor.md 转换成 html, 并显示

1. 引⼊ editor.md

<!-- 引⼊ editor.md 的依赖 --><linkrel="stylesheet"href="blog-editormd/css/editormd.css"/><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><scriptsrc="blog-editormd/lib/marked.min.js"></script><scriptsrc="blog-editormd/lib/prettify.min.js"></script><scriptsrc="blog-editormd/editormd.js"></script>

2.新增 js 代码, 从服务器获取博客详情数据

<script>
        $.ajax({type:"get",url:"/blog/getBlogDetails"+ location.search,success:function(result){
                console.log(result);if(result.code ==200&& result.data !=null){$(".title").text(result.data.title);$(".date").text(result.data.createTime);
                    editormd.markdownToHTML("content",{markdown: result.data.content,});}else{alert(result.msg);}},error:function(){
                console.log('访问出错');}});</script>

4.博客列表界面显示成功

9.实现登陆

  • 登录页面提供一个form表单,通过form的方式把用户名密码提交给服务器
  • 服务器端验证⽤户名密码是否正确
  • 如果密码正确, 则在服务器端创建 Session , 并把 sessionId 通过 Cookie 返回给浏览器
  • 前后端分离的项⽬中, 虽然主要使⽤ ajax 进⾏前后端交互, 但是也不是完全不能⽤ form

1.约定前后端交互接口

【请求】

  • user/login

【响应】

  1. [200]
  • [200] 登陆成功
  • [-1] 用户名或密码不能为空
  • [-2] 用户名或密码错误
  1. [error]访问出现错误,打印异常信息

2.实现服务器代码

创建 UserController

@RequestMapping("/user")@RestControllerpublicclassUserController{@AutowiredprivateUserService userService;@RequestMapping("/login")publicResultlogin(String username,String password){// 判空if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){returnResult.fail(-1,"用户名或密码不能为空");}// 判断用户名密码是否匹配User user = userService.selectByName(username);if(user ==null||!user.getPassWord().equals(password)){returnResult.fail(-2,"用户名或密码错误");}returnResult.success("登陆成功");}}

使用postman测试登录成功

在这里插入图片描述

3.实现客户端代码

<scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>functionlogin(){
            $.ajax({type:"post",url:"/user/login",data:{"username":$("#username").val(),"password":$("#password").val()},success:function(result){if(result.code ==200&& result.data ==1){
                        location.assign("blog_list.html");}elseif(result.code ==-1){alert("⽤户名或密码不能为空");return;}elseif(result.code ==-2){alert("⽤户名或密码错误");return;}},error:function(error){
                    console.log(error.msg);}})}</script>

3.实现客户端代码

<scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>functionlogin(){
            $.ajax({type:"post",url:"/user/login",data:{"username":$("#username").val(),"password":$("#password").val()},success:function(result){if(result.code ==-1){alert(result.msg);}elseif(result.code ==-2){alert(result.msg);}elseif(result.code ==200&& result.data !=null){
                        location.assign("blog_list.html");}},error:function(error){
                    console.log(error.msg);}})}</script>

4.登陆功能实现成功

在这里插入图片描述
剩下的功能在下篇博客实现~

标签: java spring boot

本文转载自: https://blog.csdn.net/m0_57248981/article/details/132085502
版权归原作者 小锦鲤yaw 所有, 如有侵权,请联系我们删除。

“SpringBoot项目-个人博客系统的实现”的评论:

还没有评论