24.<Spring博客系统①(数据库+公共代码+持久层+显示博客列表+博客详情)>
项目整体预览
登录页面
主页
查看全文
编辑
写博客
PS:Service.impl(现在流行写法)
推荐写法。后续完成项目。会尝试这样写。
接口可以有多个实现。每个实现都可以不同。
这也算一种设计模式。叫做(策略模式)。
我们博客项目较为简单。Service层我们还是只写一层。如果后续有更复杂的项目。我们就会使用多层。
而。
Mapper.impl
Mapper里放的接口。
impl里面放的是接口的实现。(早期写法)
1.分析需求
2.技术方案设计
①画UML图、流程图、ER图
②数据库的设计、
数据库的表通常分两类。实体表、关系表。
实体表:可以认为就是一个对象。一个对象包含什么属性。比如人员表、员工表、部门表、图书表、博客表、这些都是实体表
关系表:表示实体之间的关系,比如员工属于什么部门。用户表、权限表、用户和权限相关关系。实体之间都是有关系的。对于简单的关系。该表可以省略。可以放在实体表之中。
比如一个用户可以有多个权限。
③接口设计、、
3.开发
4.测试
5.测试(QA)
6.联调
7.验收
8.上线
数据库的设计
用户表:用户名、密码、照片、昵称、github地址
博客表:标题、日期、内容、作者、分类。
这两者有很多关系。那么我们可以单独建立一个表
接口的设计
后端人员是主动地
登录接口
一、创建项目
创建细节就不一一演示了。这是是我们使用的IDEA中主要的依赖的版本。
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency>
二、配置文件处理
将
修改为
三、建立数据库
--创建数据库
create database if not exists spring_blog charset utf8mb4;
-- ⽤⼾表
DROP TABLE IF EXISTS spring_blog.user;
CREATE TABLE spring_blog.user(`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR ( 128 ) NOT NULL,`password` VARCHAR ( 128 ) NOT NULL,`github_url` VARCHAR ( 128 ) NULL,`delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id ),
UNIQUE INDEX user_name_UNIQUE ( user_name ASC )) ENGINE = INNODB DEFAULT
CHARACTER SET = utf8mb4 COMMENT = '⽤⼾表';
-- 博客表
drop table if exists spring_blog.blog;
CREATE TABLE spring_blog.blog (`id` INT NOT NULL AUTO_INCREMENT,`title` VARCHAR(200) NULL,`content` TEXT NULL,`user_id` INT(11) NULL,`delete_flag` TINYINT(4) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),PRIMARY KEY (id))ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '博客表';-- 新增⽤⼾信息
insert into spring_blog.user (user_name, password,github_url)values('zhangsan','123456','https://gitee.com/Bwindmill');
insert into spring_blog.user (user_name, password,github_url)values('lisi','123456','https://gitee.com/Bwindmill');
insert into spring_blog.user (user_name, password,github_url)values('wangwu','123456','https://gitee.com/Bwindmill');
insert into spring_blog.user (user_name, password,github_url)values('luliu','123456','https://gitee.com/Bwindmill');insert into spring_blog.blog (title,content,user_id) values('第⼀篇博客','1111111',1);
insert into spring_blog.blog (title,content,user_id) values('第二篇博客','2222222',2);
四、测试
之后运行一下程序,看程序有没有问题。
并且写一个简单的程序测测运行正常不正常。
eg:
@RestController public class UserController {@RequestMapping("/test")public String test(){return "Hello";} }
对于新手来说。我们就写一点测一点。慢慢来。
将前端代码cv到staric目录中。我们再测一测前端代码能不能正常访问。
五、书写项目公共模块代码
项目架构图
5.1实体类
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;
}
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;
}
5.2统一结果返回
Result类
/*** 统一返回结果* 我们先设定返回的结果* 为了让其他地方方便调用。我们统一给方法加上static*/
@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(String errMsg){Result result = new Result();result.setCode(Constant.UNLOGIN_CODE);result.setErrMsg("用户未登录");result.setData(null);return result;}}
ResponseAdvice类
@ControllerAdvice //注意加上这个注解才有效。
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {/*** 设定哪些方法统一返回结果* 哪个接口执行统一结果返回*/return true;}@SneakyThrows//这个注解帮我们对// return objectMapper.writeValueAsString(Result.success(body));//进行try catch。异常处理@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//统一结果返回的具体逻辑if(body instanceof Result){return body;}//对String 类型单独处理.否则会报错if (body instanceof String){return objectMapper.writeValueAsString(Result.success(body));}return Result.success(body);}
}
5.3统一异常处理
第一种写法
ErrorHandler类
三个注解:@ResponseBody @ControllerAdvice @ExceptionHandler
@ResponseBody
@ControllerAdvice
public class ErrorHandler {@ExceptionHandlerpublic Result handler(Exception e){return Result.fail(e.getMessage());}
}
第二种写法
eg:
/捕获空指针异常代码的两种写法
//捕获空指针异常代码的两种写法@ExceptionHandler(NullPointerException.class)public Result handler(Exception e){return Result.fail(e.getMessage());}@ExceptionHandlerpublic Result handler(NullPointerException e){return Result.fail(e.getMessage());}
如果注解里面没有写捕获什么异常。那么就会以参数中为准。
六、业务代码
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类
@Mapper
public interface UserMapper {//根据用户名,查询用户信息\@Select("select * from user where user_name = #{userName} and delete_flag = 0")UserInfo selectByName(String userName);@Select("select *from user where id = #{userId} and delete_flag = 0")UserInfo selectById(Integer userId);
}
BlogMapper类
注:由于update既是uptate功能的接口。也是delete功能的接口,因此我们要写动态SQL。
动态SQL我们使用XML的方式来书写。
@Mapper
public interface BlogMapper {//查询博客列表@Select("select * from blog where delete_flag =0 order by create_time desc ")List<BlogInfo> selectAllBlog();//根据博客Id,查询博客信息。@Select("select * from blog where id = #{blogId} and delete_flag = 0")BlogInfo selectById(Integer blogId);//根据博客Id,修改博客信息。//此修改包括修改和删除。根据参数决定修改什么。//我们用动态SQL来实现Integer updateById(BlogInfo blogInfo);//插入博客@Insert("insert into blog (title, content, user_id) values (#{title},#{content},#{userId})")Integer interBlog(BlogInfo blogInfo);}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qyy.springblog.mapper.BlogMapper"><update id="updateById">update blog<set><if test="title != null">title = #{title},</if><if test="content != null">content = #{content},</if><if test="deleteFlag != null">delete_flag = #{deleteFlag},</if></set>where id = #{id}</update>
</mapper>
写完之后。我们测试一下持久层代码是否都正确执行。
6.2实现前后端接口
6.2.1实现博客列表显示的接口
后端
@RequestMapping("/getList")public List<BlogInfo> queryBlogList(){return blogService.queryBlogList();}
public List<BlogInfo> queryBlogList() {return blogMapper.selectAllBlog();}
前端
<script>$.ajax({type: "get",url: "blog/getList",success:function(result){//逻辑不全,可以再完善//比如code == 200,但是data为空,页面可以提示,当前没有任何博客,快去写博客。然后进行跳转if(result.code == 200 && result.data!=null){var finalHtml = "";for(var blog of result.data){ //循环的时候每个数据叫blogfinalHtml += '<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+'">查看全文>></a>';finalHtml += '</div>';}$(".right").html(finalHtml);}}});</script>
我们发现显示的时间很长。 返回的时间就如我们postman返回的时间一样。
如何修改呢。我们最好在后端统一修改了
修改时间显示
我们在blog实体类中修改。
1.创建utils包。
2.创建 DataUtils 类
3.创建formatDate方法
指定我们的时间返回格式的方法参考如下表。
public class DateUtils {public static String formatDate(Date date){SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");return simpleDateFormat.format(date);} }
4.在blog实体类添加如下代码
public String getCreateTime(){return DateUtils.formatDate(createTime);}
存的的问题
这是博客列表显示的
在博客列表中我们发现存在####。
不但如此。我们还希望。在博客列表中只显示一部分博客。而不是将博客全部显示出来。这个又该怎么操作呢?
这个如何修改呢
1.去掉特殊符号
2.对内容长度进行处理
①通过SQL截断
②通过Java截断
我选择通过java截断
public List<BlogInfo> queryBlogList() {List<BlogInfo> blogInfos = blogMapper.selectAllBlog();for (BlogInfo blog: blogInfos){String result = blog.getContent();result = result.replace("#","");if(result.length() >= 66){result = result.substring(0,65)+"......";}blog.setContent(result);}return blogInfos;}
实现成功
6.2.2实现博客查看全文接口
后端
@RequestMapping("getBlogDetail")public BlogInfo queryBlogById(Integer blogId){return blogService.queryBlogById(blogId);}
@RequestMapping("getBlogDetail")public BlogInfo queryBlogById(Integer blogId){return blogService.queryBlogById(blogId);}
正确返回
前端
<div class="right"><div class="content"><div class="title"></div><div class="date"></div><div class="detail"></div><div class="operating"><button onclick="window.location.href='blog_update.html'">编辑</button><button onclick="deleteBlog()">删除</button></div></div></div>
$.ajax({type: "get",url: "/blog/getBlogDetail"+location.search, //location.search拿到问号及后面的内容success:function(result){var blog = result.data;if(result.code == 200 && result.data!=null){$(".right .content .title").text(blog.title);$(".right .content .date").text(blog.createTime);$(".right .content .detail").text(blog.content);}}});
成功显示。
本篇博客暂时就写到这里啦。后续内容会在下一篇文章更新哦。
后面登录的接口才是本次项目的大Boss。
相关文章:

24.<Spring博客系统①(数据库+公共代码+持久层+显示博客列表+博客详情)>
项目整体预览 登录页面 主页 查看全文 编辑 写博客 PS:Service.impl(现在流行写法) 推荐写法。后续完成项目。会尝试这样写。 接口可以有多个实现。每个实现都可以不同。 这也算一种设计模式。叫做(策略模式)。 我们…...

webp 网页如何录屏?
工作中正好研究到了一点:记录下这里: 先看下效果: 具体实现代码:  <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

丹摩征文活动|实现Llama3.1大模型的本地部署
文章目录 1.前言2.丹摩的配置3.Llama3.1的本地配置4. 最终界面 丹摩 1.前言 Llama3.1是Meta 公司发布的最新开源大型语言模型,相较于之前的版本,它在规模和功能上实现了显著提升,尤其是最大的 4050亿参数版本,成为开源社区中非常…...

Spring Boot 2 和 Spring Boot 3 中使用 Spring Security 的区别
文章目录 Spring Boot 2 和 Spring Boot 3 中使用 Spring Security 的区别1. Jakarta EE 迁移2. Spring Security 配置方式的变化3. PasswordEncoder 加密方式的变化4. permitAll() 和 authenticated() 的变化5. 更强的默认安全设置6. Java 17 支持与语法提升7. PreAuthorize、…...

【数据结构与算法】 LeetCode:回溯
文章目录 回溯算法组合组合总和(Hot 100)组合总和 II电话号码的字母组合(Hot 100)括号生成(Hot 100)分割回文串(Hot 100)复原IP地址子集(Hot 100)全排列&…...

SpringBoot线程池的使用
SpringBoot线程池的使用 在现代Web应用开发中,特别是在使用Spring Boot框架时,合理使用线程池可以显著提高应用的性能和响应速度。线程池不仅能够减少线程创建和销毁的开销,还能有效地控制并发任务的数量,避免因线程过多而导致的…...

Neural Magic 发布 LLM Compressor:提升大模型推理效率的新工具
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

HttpServletRequest req和前端的关系,req.getParameter详细解释,req.getParameter和前端的关系
HttpServletRequest 对象在后端和前端之间起到了桥梁的作用,它包含了来自客户端的所有请求信息。通过 HttpServletRequest 对象,后端可以获取前端发送的请求参数、请求头、请求方法等信息,并根据这些信息进行相应的处理。以下是对 HttpServle…...

React-useEffect的使用
useEffect react提供的一个常用hook,用于在函数组件中执行副作用操作,比如数据获取、订阅或手动更改DOM。 基本用法: 接受2个参数: 一个包含命令式代码的函数(副作用函数)。一个依赖项数组,用…...

MySQL数据库与Informix:能否创建同名表?
MySQL数据库与Informix:能否创建同名表? 一、MySQL数据库中的同名表创建1. 使用CREATE TABLE ... SELECT语句2. 使用CREATE TABLE LIKE语句3. 复制表结构并选择性复制数据4. 使用同义词(Synonym)二、Informix数据库中的同名表创建1. 使用不同所有者2. 使用不同模式3. 复制表…...

爬虫实战:采集知乎XXX话题数据
目录 反爬虫的本意和其带来的挑战目标实战开发准备代码开发发现问题1. 发现问题[01]2. 发现问题[02] 解决问题1. 解决问题[01]2. 解决问题[02] 最终结果 结语 反爬虫的本意和其带来的挑战 在这个数字化时代社交媒体已经成为人们表达观点的重要渠道,对企业来说&…...

大数据新视界 -- Hive 数据桶原理:均匀分布数据的智慧(上)(9/ 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

【小白学机器学习33】 大数定律python的 pandas.Dataframe 和 pandas.Series基础内容
目录 0 总结 0.1pd.Dataframe有一个比较麻烦琐碎的地方,就是引号 和括号 0.2 pd.Dataframe关于括号的原则 0.3 分清楚几个数据类型和对应的方法的范围 0.4 几个数据结构的构造关系 list → np.array(list) → pd.Series(np.array)/pd.Dataframe 1 python 里…...

【shodan】(五)网段利用
shodan基础(五) 声明:该笔记为up主 泷羽的课程笔记,本节链接指路。 警告:本教程仅作学习用途,若有用于非法行为的,概不负责。 nsa ip address range www.nsa.gov需科学上网 搜索网段 shodan s…...

LeetCode739. 每日温度(2024冬季每日一题 15)
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。 示例 1: 输入: temperatu…...

Node.js的http模块:创建HTTP服务器、客户端示例
新书速览|Vue.jsNode.js全栈开发实战-CSDN博客 《Vue.jsNode.js全栈开发实战(第2版)(Web前端技术丛书)》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 要使用http模块,只需要在文件中通过require(http)引入即可。…...

加菲工具 - 好用免费的在线工具集合
加菲工具 https://orcc.online AI 工具 加菲工具 集合了目前主流的,免费可用的ai工具 文档处理 加菲工具 pdf转word、office与pdf互转等等工具都有链接 图片图标 加菲工具 统计了好用免费的在线工具 编码解码 加菲工具 base64编码解码、url编码解码、md5计算…...

.NET9 - 新功能体验(二)
书接上回,我们继续来聊聊.NET9和C#13带来的新变化。 01、新的泛型约束 allows ref struct 这是在 C# 13 中,引入的一项新的泛型约束功能,允许对泛型类型参数应用 ref struct 约束。 可能这样说不够直观,简单来说就是Span、ReadO…...

map和redis关系
Map 和 Redis 都是用于存储和管理数据的工具,但它们在用途、实现和应用场景上有所不同。下面详细解释 Map 和 Redis 之间的关系和区别。 1. Map 数据结构 定义 Map 是一种数据结构,用于存储键值对(key-value pairs)。每个键都是…...

《数据结构》学习系列——图(中)
系列文章目录 目录 图的遍历深度优先遍历递归算法堆栈算法 广度优先搜索 拓扑排序定义定理算法思想伪代码 关键路径基本概念关键活动有关量数学公式伪代码时间复杂性 图的遍历 从给定连通图的某一顶点出发,沿着一些边访问遍图中所有的顶点,且使每个顶点…...

探索Python的HTTP之旅:揭秘Requests库的神秘面纱
文章目录 **探索Python的HTTP之旅:揭秘Requests库的神秘面纱**第一部分:背景介绍第二部分:Requests库是什么?第三部分:如何安装Requests库?第四部分:Requests库的五个简单函数使用方法第五部分&…...

Python 爬虫从入门到(不)入狱学习笔记
爬虫的流程:从入门到入狱 1 获取网页内容1.1 发送 HTTP 请求1.2 Python 的 Requests 库1.2 实战:豆瓣电影 scrape_douban.py 2 解析网页内容2.1 HTML 网页结构2.2 Python 的 Beautiful Soup 库 3 存储或分析数据(略) 一般爬虫的基…...

IDEA优雅debug
目录 引言一、断点分类🎄1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧🎉3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…...

wp the_posts_pagination 与分类页面搭配使用
<ul> <?php while( have_posts() ) : the_post(); <li > <a href"<?php the_permalink(); ?>"> <?php xizhitbu_get_thumbnail(thumb-pro); ?> </a> <p > <a href&q…...

大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
点一下关注吧!!!非常感谢!!持续更新!!! Java篇开始了! 目前开始更新 MyBatis,一起深入浅出! 目前已经更新到了: Hadoop࿰…...

【Python】分割秘籍!掌握split()方法,让你的字符串处理轻松无敌!
在Python开发中,字符串处理是最常见也是最基础的任务之一。而在众多字符串操作方法中,split()函数无疑是最为重要和常用的一个。无论你是Python新手,还是经验丰富的开发者,深入理解并熟练运用split()方法,都将大大提升…...

免费实用在线AI工具集合 - 加菲工具
免费在线工具-加菲工具 https://orcc.online/ 在线录屏 https://orcc.online/recorder 时间戳转换 https://orcc.online/timestamp Base64 编码解码 https://orcc.online/base64 URL 编码解码 https://orcc.online/url Hash(MD5/SHA1/SHA256…) 计算 https://orcc.online/h…...

正则表达式灾难:重新认识“KISS原则”的意义
RSS Feed 文章标题整理 微积分在生活中的应用与思维启发 捕鹿到瞬时速度的趣味探索 微积分是一扇通往更广阔世界的门,从生活中学习思维的工具。 数据库才是最强架构 你还在被“复杂架构”误导吗? 把业务逻辑写入数据库,重新定义简单与效率。…...

eNSP-缺省路由配置
缺省路由是一种特殊的静态路由,其目的地址为0.0.0.0,子网掩码为0.0.0.0。 1.拓扑图搭建 2.配置路由器 AR2 <Huawei>sys #进入系统视图 [Huawei]ip route-static 0.0.0.0 0.0.0.0 192.168.3.2 #设置缺省路由 [Huawei]q #返回上一层 <Huawe…...

solr 远程命令执行 (CVE-2019-17558)
漏洞描述 Apache Velocity是一个基于Java的模板引擎,它提供了一个模板语言去引用由Java代码定义的对象。Velocity是Apache基金会旗下的一个开源软件项目,旨在确保Web应用程序在表示层和业务逻辑层之间的隔离(即MVC设计模式)。 Apa…...