0


24.<Spring博客系统①(数据库+公共代码+持久层+显示博客列表+博客详情)>

项目整体预览

登录页面

主页

查看全文

编辑

写博客

PS:Service.impl(现在流行写法)

推荐写法。后续完成项目。会尝试这样写。

接口可以有多个实现。每个实现都可以不同。

这也算一种设计模式。叫做(策略模式)。

我们博客项目较为简单。Service层我们还是只写一层。如果后续有更复杂的项目。我们就会使用多层。

而。

Mapper.impl

Mapper里放的接口。

impl里面放的是接口的实现。(早期写法)

1.分析需求

2.技术方案设计

①画UML图、流程图、ER图

②数据库的设计、

数据库的表通常分两类。实体表、关系表。

实体表:可以认为就是一个对象。一个对象包含什么属性。比如人员表、员工表、部门表、图书表、博客表、这些都是实体表

关系表:表示实体之间的关系,比如员工属于什么部门。用户表、权限表、用户和权限相关关系。实体之间都是有关系的。对于简单的关系。该表可以省略。可以放在实体表之中。

比如一个用户可以有多个权限。

③接口设计、、

3.开发

4.测试

5.测试(QA)

6.联调

7.验收

8.上线

数据库的设计

用户表:用户名、密码、照片、昵称、github地址

博客表:标题、日期、内容、作者、分类。

这两者有很多关系。那么我们可以单独建立一个表

接口的设计

后端人员是主动地

登录接口

一、创建项目

创建细节就不一一演示了。这是是我们使用的IDEA中主要的依赖的版本。

  1. <properties>
  2. <java.version>1.8</java.version>
  3. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  4. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  5. <spring-boot.version>2.6.13</spring-boot.version>
  6. </properties>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-web</artifactId>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.mybatis.spring.boot</groupId>
  14. <artifactId>mybatis-spring-boot-starter</artifactId>
  15. <version>2.2.2</version>
  16. </dependency>

二、配置文件处理

修改为

三、建立数据库

  1. --创建数据库
  2. create database if not exists spring_blog charset utf8mb4;
  3. -- ⽤⼾表
  4. DROP TABLE IF EXISTS spring_blog.user;
  5. CREATE TABLE spring_blog.user(
  6. `id` INT NOT NULL AUTO_INCREMENT,
  7. `user_name` VARCHAR ( 128 ) NOT NULL,
  8. `password` VARCHAR ( 128 ) NOT NULL,
  9. `github_url` VARCHAR ( 128 ) NULL,
  10. `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
  11. `create_time` DATETIME DEFAULT now(),
  12. `update_time` DATETIME DEFAULT now(),
  13. PRIMARY KEY ( id ),
  14. UNIQUE INDEX user_name_UNIQUE ( user_name ASC )) ENGINE = INNODB DEFAULT
  15. CHARACTER SET = utf8mb4 COMMENT = '⽤⼾表';
  16. -- 博客表
  17. drop table if exists spring_blog.blog;
  18. CREATE TABLE spring_blog.blog (
  19. `id` INT NOT NULL AUTO_INCREMENT,
  20. `title` VARCHAR(200) NULL,
  21. `content` TEXT NULL,
  22. `user_id` INT(11) NULL,
  23. `delete_flag` TINYINT(4) NULL DEFAULT 0,
  24. `create_time` DATETIME DEFAULT now(),
  25. `update_time` DATETIME DEFAULT now(),
  26. PRIMARY KEY (id))
  27. ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '博客表';
  28. -- 新增⽤⼾信息
  29. insert into spring_blog.user (user_name, password,github_url)values('zhangsan','123456','https://gitee.com/Bwindmill');
  30. insert into spring_blog.user (user_name, password,github_url)values('lisi','123456','https://gitee.com/Bwindmill');
  31. insert into spring_blog.user (user_name, password,github_url)values('wangwu','123456','https://gitee.com/Bwindmill');
  32. insert into spring_blog.user (user_name, password,github_url)values('luliu','123456','https://gitee.com/Bwindmill');
  33. insert into spring_blog.blog (title,content,user_id) values('第⼀篇博客','1111111',1);
  34. insert into spring_blog.blog (title,content,user_id) values('第二篇博客','2222222',2);

四、测试

之后运行一下程序,看程序有没有问题。

并且写一个简单的程序测测运行正常不正常。

eg:

  1. @RestController
  2. public class UserController {
  3. @RequestMapping("/test")
  4. public String test(){
  5. return "Hello";
  6. }
  7. }

对于新手来说。我们就写一点测一点。慢慢来。

将前端代码cv到staric目录中。我们再测一测前端代码能不能正常访问。

五、书写项目公共模块代码

项目架构图

5.1实体类

UserInfo类

  1. @Data
  2. public class UserInfo {
  3. private Integer id;
  4. private String userName;
  5. private String password;
  6. private String githubUrl;
  7. private Integer deleteFlag;
  8. private Date createTime;
  9. private Date updateTime;
  10. }

BlogInfo类

  1. @Data
  2. public class BlogInfo {
  3. private Integer id;
  4. private String title;
  5. private String content;
  6. private Integer userId;
  7. private Integer deleteFlag;
  8. private Date createTime;
  9. private Date updateTime;
  10. }

5.2统一结果返回

Result类

  1. /**
  2. * 统一返回结果
  3. * 我们先设定返回的结果
  4. * 为了让其他地方方便调用。我们统一给方法加上static
  5. */
  6. @Data
  7. public class Result {
  8. private int code; //200成功, -1失败 -2未登录
  9. private String errMsg;
  10. private Object data;
  11. public static Result success(Object data){
  12. Result result = new Result();
  13. result.setCode(Constant.SUCCESS_CODE);
  14. result.setErrMsg("");
  15. result.setData(data);
  16. return result;
  17. }
  18. public static Result fail(String errMsg){
  19. Result result = new Result();
  20. result.setCode(Constant.FAIL_CODE);
  21. result.setErrMsg(errMsg);
  22. result.setData(null);
  23. return result;
  24. }
  25. public static Result fail(String errMsg,Object data){
  26. Result result = new Result();
  27. result.setCode(Constant.FAIL_CODE);
  28. result.setErrMsg(errMsg);
  29. result.setData(data);
  30. return result;
  31. }
  32. public static Result unLogin(String errMsg){
  33. Result result = new Result();
  34. result.setCode(Constant.UNLOGIN_CODE);
  35. result.setErrMsg("用户未登录");
  36. result.setData(null);
  37. return result;
  38. }
  39. }

ResponseAdvice类

  1. @ControllerAdvice //注意加上这个注解才有效。
  2. public class ResponseAdvice implements ResponseBodyAdvice {
  3. @Autowired
  4. private ObjectMapper objectMapper;
  5. @Override
  6. public boolean supports(MethodParameter returnType, Class converterType) {
  7. /**
  8. * 设定哪些方法统一返回结果
  9. * 哪个接口执行统一结果返回
  10. */
  11. return true;
  12. }
  13. @SneakyThrows
  14. //这个注解帮我们对
  15. // return objectMapper.writeValueAsString(Result.success(body));
  16. //进行try catch。异常处理
  17. @Override
  18. public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
  19. //统一结果返回的具体逻辑
  20. if(body instanceof Result){
  21. return body;
  22. }
  23. //对String 类型单独处理.否则会报错
  24. if (body instanceof String){
  25. return objectMapper.writeValueAsString(Result.success(body));
  26. }
  27. return Result.success(body);
  28. }
  29. }

5.3统一异常处理

第一种写法

ErrorHandler类

三个注解:@ResponseBody @ControllerAdvice @ExceptionHandler

  1. @ResponseBody
  2. @ControllerAdvice
  3. public class ErrorHandler {
  4. @ExceptionHandler
  5. public Result handler(Exception e){
  6. return Result.fail(e.getMessage());
  7. }
  8. }

第二种写法

eg:

/捕获空指针异常代码的两种写法

  1. //捕获空指针异常代码的两种写法
  2. @ExceptionHandler(NullPointerException.class)
  3. public Result handler(Exception e){
  4. return Result.fail(e.getMessage());
  5. }
  6. @ExceptionHandler
  7. public Result handler(NullPointerException e){
  8. return Result.fail(e.getMessage());
  9. }

如果注解里面没有写捕获什么异常。那么就会以参数中为准。

六、业务代码

MybatisGenerate插件

注:持久层的代码可以由MybatisGenerate插件一键生成。

直接根据我们的数据库表
生成实体类,mapper类,xml文件
不需要我们自己写mapper类,和基于标签的mapper.xml这些简单又繁琐的工作
但是值得注意的是生成的方法中的细微区别!!

接口分析

1.用户登录

根据用户名和密码、判断是否正确。

2.查询用户信息

根据用户Id.查询用户信息。

3.博客列表

查询所有博客

4.查询作者信息

①根据博客,拿到作者Id

②根据作者id,获取作者信息

5.查询博客详情

根据博客id,查询博客信息

6.修改博客

根据博客id,修改博客信息

7.添加博客

插入博客信息

8.删除博客

梳理一下

用户表:

1.根据用户名,查询用户信息。

2.根据用户id,查询用户信息

博客表

1.查询博客列表

2.根据博客id,查询博客信息

3.根据博客id,修改博客信息

4.插入博客

5.删除博客

6.1持久层代码

UserMapper类

  1. @Mapper
  2. public interface UserMapper {
  3. //根据用户名,查询用户信息\
  4. @Select("select * from user where user_name = #{userName} and delete_flag = 0")
  5. UserInfo selectByName(String userName);
  6. @Select("select *from user where id = #{userId} and delete_flag = 0")
  7. UserInfo selectById(Integer userId);
  8. }

BlogMapper类

注:由于update既是uptate功能的接口。也是delete功能的接口,因此我们要写动态SQL。

动态SQL我们使用XML的方式来书写。

  1. @Mapper
  2. public interface BlogMapper {
  3. //查询博客列表
  4. @Select("select * from blog where delete_flag =0 order by create_time desc ")
  5. List<BlogInfo> selectAllBlog();
  6. //根据博客Id,查询博客信息。
  7. @Select("select * from blog where id = #{blogId} and delete_flag = 0")
  8. BlogInfo selectById(Integer blogId);
  9. //根据博客Id,修改博客信息。
  10. //此修改包括修改和删除。根据参数决定修改什么。
  11. //我们用动态SQL来实现
  12. Integer updateById(BlogInfo blogInfo);
  13. //插入博客
  14. @Insert("insert into blog (title, content, user_id) values (#{title},#{content},#{userId})")
  15. Integer interBlog(BlogInfo blogInfo);
  16. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.qyy.springblog.mapper.BlogMapper">
  5. <update id="updateById">
  6. update blog
  7. <set>
  8. <if test="title != null">
  9. title = #{title},
  10. </if>
  11. <if test="content != null">
  12. content = #{content},
  13. </if>
  14. <if test="deleteFlag != null">
  15. delete_flag = #{deleteFlag},
  16. </if>
  17. </set>
  18. where id = #{id}
  19. </update>
  20. </mapper>

写完之后。我们测试一下持久层代码是否都正确执行。

6.2实现前后端接口

6.2.1实现博客列表显示的接口

后端

  1. @RequestMapping("/getList")
  2. public List<BlogInfo> queryBlogList(){
  3. return blogService.queryBlogList();
  4. }
  1. public List<BlogInfo> queryBlogList() {
  2. return blogMapper.selectAllBlog();
  3. }

前端

  1. <script>
  2. $.ajax({
  3. type: "get",
  4. url: "blog/getList",
  5. success:function(result){
  6. //逻辑不全,可以再完善
  7. //比如code == 200,但是data为空,页面可以提示,当前没有任何博客,快去写博客。然后进行跳转
  8. if(result.code == 200 && result.data!=null){
  9. var finalHtml = "";
  10. for(var blog of result.data){ //循环的时候每个数据叫blog
  11. finalHtml += '<div class="blog">';
  12. finalHtml += '<div class="title">'+blog.title+'</div>';
  13. finalHtml += '<div class="date">'+blog.createTime+'</div>';
  14. finalHtml += '<div class="desc">'+blog.content+'</div>';
  15. finalHtml += '<a class="detail" href="blog_detail.html?blogId='+blog.id+'">查看全文&gt;&gt;</a>';
  16. finalHtml += '</div>';
  17. }
  18. $(".right").html(finalHtml);
  19. }
  20. }
  21. });
  22. </script>

我们发现显示的时间很长。 返回的时间就如我们postman返回的时间一样。

如何修改呢。我们最好在后端统一修改了

修改时间显示

我们在blog实体类中修改。

1.创建utils包。

2.创建 DataUtils 类

3.创建formatDate方法

指定我们的时间返回格式的方法参考如下表。

  1. public class DateUtils {
  2. public static String formatDate(Date date){
  3. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
  4. return simpleDateFormat.format(date);
  5. }
  6. }

4.在blog实体类添加如下代码

  1. public String getCreateTime(){
  2. return DateUtils.formatDate(createTime);
  3. }

存的的问题

这是博客列表显示的

博客列表中我们发现存在####。

不但如此。我们还希望。在博客列表中只显示一部分博客。而不是将博客全部显示出来。这个又该怎么操作呢?

**这个如何修改呢 **

1.去掉特殊符号

2.对内容长度进行处理

①通过SQL截断

②通过Java截断

我选择通过java截断

  1. public List<BlogInfo> queryBlogList() {
  2. List<BlogInfo> blogInfos = blogMapper.selectAllBlog();
  3. for (BlogInfo blog: blogInfos){
  4. String result = blog.getContent();
  5. result = result.replace("#","");
  6. if(result.length() >= 66){
  7. result = result.substring(0,65)+"......";
  8. }
  9. blog.setContent(result);
  10. }
  11. return blogInfos;
  12. }

实现成功

6.2.2实现博客查看全文接口

后端

  1. @RequestMapping("getBlogDetail")
  2. public BlogInfo queryBlogById(Integer blogId){
  3. return blogService.queryBlogById(blogId);
  4. }
  1. @RequestMapping("getBlogDetail")
  2. public BlogInfo queryBlogById(Integer blogId){
  3. return blogService.queryBlogById(blogId);
  4. }

正确返回

前端

  1. <div class="right">
  2. <div class="content">
  3. <div class="title"></div>
  4. <div class="date"></div>
  5. <div class="detail"></div>
  6. <div class="operating">
  7. <button onclick="window.location.href='blog_update.html'">编辑</button>
  8. <button onclick="deleteBlog()">删除</button>
  9. </div>
  10. </div>
  11. </div>
  1. $.ajax({
  2. type: "get",
  3. url: "/blog/getBlogDetail"+location.search, //location.search拿到问号及后面的内容
  4. success:function(result){
  5. var blog = result.data;
  6. if(result.code == 200 && result.data!=null){
  7. $(".right .content .title").text(blog.title);
  8. $(".right .content .date").text(blog.createTime);
  9. $(".right .content .detail").text(blog.content);
  10. }
  11. }
  12. });

成功显示。

本篇博客暂时就写到这里啦。后续内容会在下一篇文章更新哦。

后面登录的接口才是本次项目的大Boss。

标签: java-ee spring java

本文转载自: https://blog.csdn.net/m0_73456341/article/details/143689975
版权归原作者 振兴祁门 所有, 如有侵权,请联系我们删除。

“24.<Spring博客系统①(数据库+公共代码+持久层+显示博客列表+博客详情)>”的评论:

还没有评论