1.个人博客系统项目

一、项目介绍

  个人博客系统

  • 相关技术:  SpringBoot+SpringMvc+Mybatis+Mysql+Redis
  • 项目简介:本项目为一个功能完善的个人博客系统,支持文章的编辑、修改、删除和发布,以及作者个人信息的展示等功能。
  • 项目描述:
  1. 采用前后端分离架构,基于SpringBoot和Mybatis等框架构建。
  2. 设计统一的前后端数据返回格式,提高系统可读性和可维护性。
  3. 使用拦截器实现用户登录校验,并采用MD5算法对密码进行加密存储。
  4. 利用Redis对内容数据进行缓存,减轻数据库压力,提高系统性能。
  5. 使用ThreadPoolExecutor线程池技术,并发执行查询文章详情和修改文章阅读量等任务,提升系统响应速度。

二、项目实现效果

  项目包含7个前端页面(注册,登录,个人博客,总博客,修改已有博客,增加新博客,显示博客详情),每个页面顶端有一个导航栏。其中编辑文章使用markdown编辑器,不过其中个人信息没有实现修改功能,其头像和博客地址固定了(显示为奶龙和我的gitee地址)。

注册页面:

登录页面:

个人博客页面:

总博客页面:

修改已有博客页面:

增加新博客页面:

显示博客详情页面(左边有作者个人信息):


三、项目具体实现

1.软件生命周期

  一个软件的生命周期可以划分为

  • 可行性研究
  • 需求分析
  • 概要设计
  • 详细设计
  • 编码实现
  • 测试
  • 使用及维护
  • 退役

2.项目需求分析

  1. 用户 注册、登录、退出登录 的功能。
  2. 显示个人博客列表:按发布时间倒序排列,各博客显示 标题、发布时间、简介。博客下方有 查看全文、修改、删除等功能。
  3. 显示总博客列表:分页显示(首页、末页、上一页、下一页功能),按发布时间倒序排列,各博客显示 标题、发布时间、简介。博客下方有 查看全文 功能。
  4. 查看全文:显示作者信息(头像,账号名,博客地址,所发布文章总数),博客信息(标题,发布时间,文章详情,文章阅读量)。
  5. 增加新文章功能。
  6. 修改已有文章功能(在修改界面,导入文章之前已有的内容)。
  7. 删除文章功能。
  8. 用户权限限制:进入总博客页面,查看全文,无需登录。进入个人博客页面(修改,删除博客),增加新博客,都需要登录(如果用户没有登录,则强制登录)。

3.设计

  主要是设计数据库存储用户和文章信息。

用户信息表结构:

表中的 昵称 未作具体使用,博客地址,头像 固定了不可修改。

文章信息表结构:

文章发布和修改时间自动为当前时间。

4.编码实现

4.1项目构建及相关配置

  基于SpringBoot和Mybatis等框架构建项目,及mysql,Mybatis,Redis等相关配置...

4.2创建实体类(依据数据库中表结构)

例如:

@Data
public class Userinfo implements Serializable {private int id;private String username;private String password;private String nickname;private String blogSite;private String photo;private boolean state;}

4.3数据库持久层(涉及到的增删查改)

例如:

public interface ArticleMapper {//添加文章@Insert("insert into articleinfo(title,content,author_id,intro) values(#{title},#{content},#{author_id},#{intro})")public int addArticle(Articleinfo articleinfo);//以用户id获取用户文章列表@Select("select * from articleinfo where author_id=#{author_id} order by id desc")public List<Articleinfo> getUserArticleList(@Param("author_id") int author_id);//以用户id和文章id删除文章@Delete("delete from  articleinfo where author_id=#{author_id} and id=#{id}")public int deleteArticle(@Param("author_id")int author_id,@Param("id") int id);//根据用户id和文章id得到文章@Select("select * from articleinfo where author_id=#{author_id} and id=#{id}")public Articleinfo getArticleByUidAid(@Param("author_id")int author_id,@Param("id") int id);//修改文章@Update("update articleinfo set title=#{title},content=#{content},intro=#{intro} where id=#{id}")public int updateArticle(Articleinfo articleinfo);//根据文章id查询到文章@Select("select * from articleinfo where id=#{id}")public  Articleinfo getArticleByAid(@Param("id") int id);//统计用户发布文章数量@Select("select count(*) from articleinfo where author_id=#{author_id}")public int getArticleCountByUid(@Param("author_id")int author_id );//修改文章阅读量,+1.@Update("update articleinfo set read_count=read_count+1 where id=#{id}")public int updateArticleReadCount(@Param("id") int id);//查询所有文章,分页.@Select("select * from articleinfo order by id desc limit #{perPage} offset #{offsetPage}")public List<Articleinfo> getAllArticles(@Param("perPage") int perPage,@Param("offsetPage") int offsetPage);//计算一下总文章数@Select("select count(*) from articleinfo ")public int getAllArticleCount();

4.4统一前后端数据交互对象

public class ResultAjax {private int code;private String msg;private Object data;public static ResultAjax successful1(Object data){ResultAjax result=new ResultAjax();result.setCode(200);result.setData(data);result.setMsg("");return result;}public static ResultAjax successful2(int code,String msg,Object data){ResultAjax result=new ResultAjax();result.setCode(code);result.setData(data);result.setMsg(msg);return result;}public static ResultAjax fail1(int code,String msg){ResultAjax result=new ResultAjax();result.setCode(code);result.setMsg(msg);return result;}public static ResultAjax fail2(int code,String msg,Object data){ResultAjax result=new ResultAjax();result.setCode(code);result.setData(data);result.setMsg(msg);return result;}
}

4.5注册、登录、退出登录

  采用MD5算法对密码进行加密存储:

存储密码:利用uuid生成唯一的字符串作为盐值,与用户注册时输入的密码拼接后MD5加密生成最终密码,在数据库中存储盐值+最终密码。

验证密码:将数据库中盐值与最终密码分开,  将用户登录时输入的待验证密码与盐值进行MD5加密后,再与最终密码比较.

public class PasswordUtils {//加密public static String encrypt(String password){//1.用uuid作为盐值String salt= UUID.randomUUID().toString().replace("-","");//2.盐值加密码用md5加密String finalPassword= DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));//3.存储盐值和最终密码return salt+'$'+finalPassword;}//验证public static boolean verifyPassword(String password,String databasePassword){//1.将盐值与最终密码分开String[] saltPassword=databasePassword.split("\\$");//2.将待验证密码与盐值进行md5加密,再与最终密码比较.String salt=saltPassword[0];String finalPassword =saltPassword[1];String verifyPassword= DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));if(verifyPassword.equals(finalPassword)){return true;}else {return false;}}}

  登录后利用Session(会话)存储登录信息:

//得到当前登录用户对象
public class SessionUtils {public static Userinfo getLoginUser(HttpServletRequest request){HttpSession session=request.getSession(false);if(session!=null && session.getAttribute(SESSION_KEY)!=null){return (Userinfo) session.getAttribute(SESSION_KEY);}return null;}
}

4.6显示个人博客列表

  根据用户id查询该作者所有文章,按时间倒序(也可以按文章id倒序排列)显示。

4.7显示总博客列表

 要根据文章总数来计算总页数,和分页查询显示当前页面:利用ThreadPoolTaskExecutor线程池,并发执行分页查询数据库中文章和统计所有文章数(两个都是查询操作可以并发执行)每页显示文章数,由前端传入(默认每页显示两条文章)。

    //查询所有文章,分页.@RequestMapping("/getAllArticles")public ResultAjax getAllArticles(Integer currentPage,Integer perPage) throws ExecutionException, InterruptedException {//无需验证登录也可访问总博客页.//1.校验参数if(currentPage==null||currentPage<=0||perPage==null ||perPage<=0){return ResultAjax.fail1(-1,"参数错误");}//2.查询数据库.分页查询limit perPage offset (currentPage-1)*perPage,task1.int offsetPage=(currentPage-1)*perPage;//计算一下总文章数,再来计算总页数,task2.int  allArticleCount=0;//这两个都是查询,可以并发执行.FutureTask<List<Articleinfo>> task1 = new FutureTask(() -> {return articleService.getAllArticles(perPage,offsetPage);});taskExecutor.submit(task1);FutureTask<Integer> task2 = new FutureTask(() -> {return articleService.getAllArticleCount();});taskExecutor.submit(task2);List<Articleinfo> list=task1.get();allArticleCount= task2.get();int pageSzie=1;if(allArticleCount!=0){pageSzie=allArticleCount/perPage;if(allArticleCount%perPage!=0){pageSzie+=1;}}HashMap<String,Object> hashMap=new HashMap<>();hashMap.put("articleList",list);hashMap.put("pageSize",pageSzie);return ResultAjax.successful1(hashMap);}
}

4.8查看全文

  显示文章和用户信息:根据文章id查询到文章,再拿到用户id,从而查询到用户信息。其中(查询用户对象和统计该用户发布文章数量 并且修改当前文章阅读量+1,以上三个操作利用ThreadPoolTaskExecutor线程池并发执行):

//查看全文//返回文章和用户对象.@RequestMapping("/fullText")public ResultAjax fullText(Integer id) throws ExecutionException, InterruptedException {//1.校验参数if(id==null || id<=0){return ResultAjax.fail1(-1,"参数错误");}//2.根据文章id查询到文章,再从中拿到用户id.Articleinfo articleinfo=articleService.getArticleByAid(id);if(articleinfo==null){return ResultAjax.fail1(-2,"查看全文失败");}int uid=articleinfo.getAuthor_id();if(uid<=0){return ResultAjax.fail1(-2,"查看全文失败");}// 得到相应用户对象和统计发布文章数量// 并且修改文章阅读量,+1.//3.以上三个操作并发执行,利用线程池.//根据uid查询用户对象FutureTask<UserinfoVO> userTask = new FutureTask(() -> {return userService.getUserByUserId(uid);});taskExecutor.submit(userTask);//统计用户发布文章数量FutureTask<Integer> articleCountTask = new FutureTask(() -> {return articleService.getArticleCountByUid(uid);});taskExecutor.submit(articleCountTask);//修改文章阅读量,+1.FutureTask <Integer> articleReadCountTask = new FutureTask(() -> {return articleService.updateArticleReadCount(id);});taskExecutor.submit(articleReadCountTask );UserinfoVO userinfovo=userTask.get();int articleCount=articleCountTask.get();int articleReadCount=articleReadCountTask.get();//返回更新操作影响的行数//校验一下参数if(userinfovo==null || articleCount<=0 || articleReadCount !=1){return ResultAjax.fail1(-2,"查看全文失败");}//4.组装好数据userinfovo.setArticleCount(articleCount);//设好文章发布数量articleinfo.setRead_count(articleinfo.getRead_count()+1);//文章阅读量+1.//5.用一个哈希表返回HashMap<String,Object> hashMap=new HashMap<>();hashMap.put("user",userinfovo);hashMap.put("article",articleinfo);return ResultAjax.successful1(hashMap);}

4.9增加新文章

增加文章操作...

4.10修改文章

修改文章操作:先查询导入原有文章内容,还要验证该文章是否为当前作者的文章后才能修改(通过比较当前登录用户id与文章用户id)。

4.12删除文章

此处删除文章操作是真的删除数据库中文章...

4.13用户权限限制

  使用拦截器实现用户登录校验:

  进入总博客页面,查看全文,无需登录。进入个人博客页面(修改,删除博客),增加新博客,需要登录(如果用户没有登录,则强制登录)

/*** 登录拦截器*/
public class LoginIntercept implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session=request.getSession(false);if(session!=null && session.getAttribute(SESSION_KEY)!=null){return true;}//没登录就跳转到登录页面response.sendRedirect("/login.html");return false;}
}/*** 系统配置*/
@Configuration
public class MyConfig implements WebMvcConfigurer {// 添加拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginIntercept()).addPathPatterns("/**") // 拦截所有接⼝.excludePathPatterns("/editor.md/*")//放行.excludePathPatterns("/img/*").excludePathPatterns("/js/*").excludePathPatterns("/css/*").excludePathPatterns("/blog_list.html").excludePathPatterns("/article/getAllArticles").excludePathPatterns("/blog_content.html").excludePathPatterns("/article//fullText").excludePathPatterns("/reg.html").excludePathPatterns("/user/reg").excludePathPatterns("/login.html").excludePathPatterns("/user/login");}
}

四、项目代码(gitee地址)

blog_system · new林/项目 - 码云 - 开源中国 (gitee.com)

(服务器过期了,没部署...,redis没用到...)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/28048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用钉钉机器人和PHP开发一款免费的网站可用性检测工具,单节点版

前言 手里有几套系统正在运维&#xff0c;需要保障正常运行&#xff0c;所以可用性检测就必不可少啦&#xff0c; 以前本来是用的阿里官方的云监控&#xff0c;但现在价格感觉太贵了&#xff0c;不划算 那就自己手搓一个简易版的监控吧。 成品效果展示 代码展示 <?php …

微信小程序毕业设计-实验室管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

centos环境上:k8s 简单安装教程

本次演示安装3节点k8s环境&#xff0c;无需多言&#xff0c;直接上操作步骤&#xff1a; 1、环境准备 k8s部署前&#xff0c;首先需要准备好环境&#xff0c;除了1.4 步骤&#xff0c;其他步骤在所有&#xff08;3个&#xff09;节点上都要执行&#xff1a; 1.1 关闭防火墙 s…

【工具】新手如何正确使用Pycharm?

1. 什么是JetBrains Toolbox JetBrains Toolbox是一个管理工具&#xff0c;用于安装、更新和管理JetBrains开发工具的所有版本。它可以简化多个IDE的管理&#xff0c;并确保你总是使用最新版本的软件。 2. 安装JetBrains Toolbox 步骤1&#xff1a;下载Toolbox 访问JetBrai…

非关系型数据库NoSQL数据层解决方案 之 redis springboot整合与读写操作 2024详解以及window版redis5.0.14下载百度网盘

redis下载安装以及基本使用 下载地址 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;0410 一个名对应一个数值 内存级 在内存里进行操作 准备启动 我们现在就有一个redis客户端的服务器了 我们再启动一个cmd 操作redis数据库 redis里面的基本数据类型有五种 …

PythonSQL应用随笔4——PySpark创建SQL临时表

零、前言 Python中直接跑SQL&#xff0c;可以很好的解决数据导过来导过去的问题&#xff0c;本文方法主要针对大运算量时&#xff0c;如何更好地让Python和SQL打好配合。 工具&#xff1a;Zeppelin 语法&#xff1a;PySpark&#xff08;Apache Spark的Python API&#xff09;…

改进YOLO系列 | Microsoft 团队 | Dynamic Convolution :自适应地调整卷积参数

改进YOLO系列&#xff1a;Microsoft团队的Dynamic Convolution——自适应调整卷积参数的计算机视觉方法&#xff08;中文综述&#xff09; 简介 YOLO&#xff08;You Only Look Once&#xff09;是一种目标检测算法&#xff0c;以其速度和精度著称。 本文将介绍YOLO系列的改进…

HTML5的未来:掌握最新技术,打造炫酷网页体验

引言 随着互联网技术的飞速发展&#xff0c;HTML5已经成为构建现代网页和应用的核心技术之一。HTML5不仅提供了丰富的语义化标签&#xff0c;还引入了多项前沿技术&#xff0c;使得网页体验更加丰富多彩。本文将探讨HTML5的最新技术&#xff0c;并结合行业实践&#xff0c;提供…

Linux操作系统学习:day02

内容来自&#xff1a;Linux介绍 视频推荐&#xff1a;[Linux基础入门教程-linux命令-vim-gcc/g -动态库/静态库 -makefile-gdb调试]( 目录 day025、Linux目录结构6、相对路径7、绝对路径8、命令提示行9、命令解析器10、命令行快捷键11、cd 命令—目录切换12、ls 命令13、文件…

在Ubuntu 20.04上安装和配置MySQL 8:详细指南和远程访问设置

目录 一、MySQL 8的特点和优势 二、在Ubuntu 20.04上安装MySQL 8 三、初始化MySQL 四、配置MySQL远程访问 五、 创建远程访问用户 六. 配置防火墙 七、 测试远程访问 总结 MySQL是一种开源的关系型数据库管理系统&#xff0c;被广泛应用于各种应用程序和网站中。MySQL …

服务器硬件基础知识:服务器硬件组成和选择

服务器是网络世界的核心,支撑着各种应用程序和服务的运行。了解服务器的硬件基础知识,不仅能帮助我们选择和配置适合的服务器,还能确保其高效稳定地运行。本文将详细介绍服务器硬件的各个关键组成部分,并探讨如何根据不同需求选择合适的硬件配置。 一、服务器硬件的主要组…

Agilent 安捷伦 N9342C 手持式频谱分析仪

Agilent 安捷伦 N9342C 手持式频谱分析仪 N9342C 手持式7GHz频谱分析仪专为现场测试而设计&#xff0c;无论是安装和维护射频系统&#xff0c;现场进行故障诊断&#xff0c;监测射频环境还是分析干扰&#xff0c;都可以为您提供快速、精确的测量。它具有同类最佳的显示平均噪声…

Vscode中使用make命令

前言 需要注意&#xff0c;如下操作需要进行网络代理&#xff0c;否则会出现安装失败的情况 安装 第一步 — 安装MingGW &#xff08;1&#xff09;进入官网下载 &#xff08;2&#xff09;下载完成之后&#xff0c;双击exe文件 &#xff08;3&#xff09;点击Install &#x…

iOS18新增通话录音和应用锁!附升级教程及内置壁纸

一觉睡醒&#xff0c;iOS18终于是揭开面纱了&#xff0c;而且已经有测试版给开发者使用了。 不过还是建议咱们普通用户不要轻易尝试&#xff0c;而且在升级之前一定要用iMazing做个备份&#xff0c;以免测试系统出现问题&#xff0c;丢失数据。 这次WWDC2024与之前爆料完全一样…

【云岚到家】-day04-2-索引同步-搜索接口

【云岚到家】-day04-2-索引同步-搜索接口 1 索引同步1.1 编写同步程序1.1.1 创建索引结构1.1.2 编写同步程序1.1.2.1 添加依赖1.1.2.2 配置连接ES1.1.2.3 编写同步程序 1.1.3 测试1.1.4 小结1.1.4.1 如何保证CanalMQ同步消息的顺序性&#xff1f;1.1.4.2 如何保证只有一个消费者…

Maven 核心插件 maven-clean-plugin 使用详解

在软件开发中&#xff0c;构建和管理项目的复杂性随着代码量和依赖的增加而不断提升。Maven作为一个强大的构建工具&#xff0c;简化了这一过程&#xff0c;并通过其插件机制提供了丰富的功能。其中&#xff0c;maven-clean-plugin 是Maven的核心插件之一&#xff0c;它在项目的…

java课设

项目简介:射击生存类小游戏 项目采用技术: 游戏引擎: Unity编程语言: Java图形处理: NVIDIA PhysX (物理引擎), HDRP (High Definition Render Pipeline)音效与音乐: FMOD, Wwise版本控制: Git 功能需求分析: 角色控制&#xff1a;玩家能够使用键盘和鼠标控制角色移动、瞄准…

前端面试题——React篇

文章目录 前言1.useEffect是异步还是同步为何是异步如何拿到最新的数据 2.微任务和宏任务概念优点 3.事件循环&#xff08;Event Loop&#xff09;概念执行机制 4.React性能优化手段 前言 准备了一些高频面试题&#xff0c;有需要的小伙伴可以收藏&#xff0c;需要的时候看看&…

基于RandLA-Net深度学习模型的激光点云语义分割

一、场景要素语义分割部分的文献阅读笔记 RandLA-Net是一种高效、轻量级的神经网络&#xff0c;其可直接逐点推理大规模点云的语义标签。RandLA-Net基于随机点采样获得了显著的计算和内存效率&#xff0c;并采用新的局部特征聚合模块有效地保留了几何细节&#xff0c;弥补了随机…

SpringBoot之自动装配原理DataSourceAutoConfiguration注解剖析

自动装配候选类满足候选bean流程如下&#xff1a; 解析Conditional & Conditional 引申出的相关注解【ConditionalOnClass、ConditionalOnMissingBean】判断当前自动装配类是否需要跳过skip作为候选bean的流程。候选类存在Component注解则加载其全部的内部类&#xff0c;当…