使用SpringBoot+SpringMVC+Mybatis+Redis实现个人博客管理平台

文章目录

  • 前言
    • 1. 项目概述
    • 2. 项目需求
      • 2.1功能需求
      • 2.2 其他需求
      • 2.3 系统功能模块图
    • 3. 开发环境
    • 4. 项目结构
    • 5. 部分功能介绍
      • 5.1 数据库密码密文存储
      • 5.2 统一数据格式返回
      • 5.3 登录拦截器
    • 6. 项目展示

前言

在几个月前实现了一个servlet版本的博客系统,本项目则是在原有基础上进行升级。使用SSM框架、数据库密码使用加盐算法加密、使用Redis对session进行持久化存储从而支持分部式部署、通过拦截器实现用户登录校验、对于数据格式返回以及异常处理进行统一功能处理、增加分页以及点击量统计等功能。

1. 项目概述

用户进入主页可以看到他人发布的博客,同时也可以注册账号通过本平台编写发布博客,平台支持markdown编辑;用户也可以在个人中心修改个人信息,同时对博客可以随写随存以草稿形式,之后也可以发布修改草稿。用户可以通过博客的点击量,判断博客质量等等。

2. 项目需求

2.1功能需求

  • 登录与注册功能
  • 个人中心(查看、修改个人信息)
  • 查看博客详情
  • 编写个人博客
  • 修改个人博客
  • 删除个人博客
  • 草稿箱(保存博客为草稿,修改博客为草稿,发布草稿为博客,草稿增删改查)
  • 博客列表分页查询功能
  • 博客阅读量统计
  • 注销功能

2.2 其他需求

  • 系统界面有良好的视觉体验,营造美观舒适的界面;
  • 操作简单流畅,无可视卡顿;
  • 有良好的引导提示,增强用户体验;

2.3 系统功能模块图

在这里插入图片描述

3. 开发环境

1.前端开发:
技术:HTML、CSS、JavaScript
工具:IntelliJ IDEA 2021.3.1
2.后端开发:
服务器:tomcat-8.5.50
数据库:MySQL5.7
开发语言:Java
技术框架:SpringBoot、SpringMVC、Mybatis、Redis
管理工具:Maven
开发工具:Intellij IDEA 2020.1.4
操作系统:Windows10

4. 项目结构

Java源代码位于com.example.blog_system中;

  1. common包:设置统一数据格式返回代码(AjaxResult)、全局变量用于session存储(AppVariable)、密码加盐已经密码验证(PasswordUtils)、获取当前用户(UserSessionUtils)。
  2. config包:系统配置文件(Appconfig)用于设置登录拦截器规则、登录拦截器的实现(LoginIntercept)、数据返回增强,校验是否是统一格式返回不是则封装为统一格式(ResponseAdvice)
  3. controller包:控制层;连接页面请求和服务层,获取页面请求的参数,通过自动装配,映射不同的URL到相应的处理函数,并获取参数,对参数进行处理,之后传给服务层。关于博客文章的控制器(ArticleController),实现博客以及草稿的增删改查以及列表分页点击量统计等功能、关于用户的控制器(UserController)实现增删改查功能。
  4. entity包:实体类,定义文章以及用户属性,同时定义视图UserVo的属性。
  5. service包:服务层;为控制层提供服务,接受控制层的参数,完成相应的功能,并返回给控制层;
  6. mapper包:持久层;根据service相关功能定义与数据库相关的增删改查方法。

在这里插入图片描述

在resources包中保存着系统资源,其中:

  1. mapper:根据 com.example.blog_system.mapper中的方法实现sql语句的增删改查。
  2. static:存储系统的前端页面HTML,CSS样式,markdown编辑器,jquery等相关资源。

5. 部分功能介绍

5.1 数据库密码密文存储

基于spring框架提供的md5加密的基础上通过UUID生成随机盐值,对用户密码进行加密;

加密过程如下:

//1.加盐并生成密码
    public static String encrypt(String password){
        //1.生成盐值
        String salt = UUID.randomUUID().toString().replace("-","");
        //2.生成加盐之后的密码
        String saltpassword = DigestUtils.md5DigestAsHex((salt+password).getBytes());
        //3。生成最终密码,32位盐值+"$"+加盐密码
        String finalpassword = salt+"$"+saltpassword;
        retur

在进行用户登录密码校验中,密码解密过程,从数据库取出密码,得到盐值,根据盐值以及用户输入密码进行加密,校验与数据库存储密码是否相同。

具体实现如下:

//2.生成最终密码(数据库中的,便于密码验证)
    public static String encrypt(String password,String salt){
          //2.通过盐值和原始密码生成加盐之后的密码
        String saltpassword = DigestUtils.md5DigestAsHex((salt+password).getBytes());
//        最终密码
        String finalPassword = salt+"$"+saltpassword;
        return finalPassword;
    }

    //3.验证密码

    /**
     *
     * @param inputPassword 用户输入密码
     * @param finalPassword 数据库存储密码
     * @return
     */
    public static boolean check(String inputPassword,String finalPassword){
        //先进性非空校验和长度校验
        if (StringUtils.hasLength(inputPassword)&&StringUtils.hasLength(finalPassword)
        &&finalPassword.length()==65){
            //1.得到盐值,从finalPassword,对$加上\\进行转义,它是关键字
            String salt = finalPassword.split("\\$")[0];
            //2.使用之前加密步骤将明文加密并生成最终密码
           String confinmrPassword =  PasswordUtils.encrypt(inputPassword,salt);
           //3,进行比较
            return confinmrPassword.equals(finalPassword);
        }
        return false;
    }

5.2 统一数据格式返回

定义数据格式为状态码+状态码描述信息+返回数据,实现成功以及失败的返回。

具体实现如下:

package com.example.blog_system.common;

import lombok.Data;

import java.io.Serializable;

/**
 * 统一数据格式返回
 */
@Data
public class AjaxResult implements Serializable {
    // 状态码
    private Integer code;
    // 状态码描述信息
    private String msg;
    // 返回的数据
    private Object data;

    /**
     * 操作成功返回的结果
     */
    public static AjaxResult succecc(Object data) {
        AjaxResult result = new AjaxResult();
        result.setCode(200);
        result.setMsg("");
        result.setData(data);
        return result;
    }

    public static AjaxResult succecc(int code, Object data) {
        AjaxResult result = new AjaxResult();
        result.setCode(code);
        result.setMsg("");
        result.setData(data);
        return result;
    }

    public static AjaxResult succecc(int code, String msg, Object data) {
        AjaxResult result = new AjaxResult();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

    /**
     * 返回失败结果
     */
    public static AjaxResult fail(int code, String msg) {
        AjaxResult result = new AjaxResult();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(null);
        return result;
    }

    public static AjaxResult fail(int code, String msg, Object data) {
        AjaxResult result = new AjaxResult();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

}

5.3 登录拦截器

继承HandlerInterceptor实现一个登录拦截器,判断在用户进入主页、登录页、注册页、以外的页面进行相关操作时判断是否登录,未登录则自动跳转到登录页面。

具体实现如下:

/**登录拦截器
 * @author zq
 * @date 2023-07-22 22:33
 */

public class LoginIntercept implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if(session!=null&&session.getAttribute(AppVariable.USER_SESSION_KEY)!=null){
            //用户已登录
            return true;
        }
        //跳转到登录页面
        response.sendRedirect("/login.html");
        return false;
    }
}

6. 项目展示

主页:
在这里插入图片描述

我的博客列表页:
在这里插入图片描述

博客编辑页:
在这里插入图片描述

草稿列表页:
在这里插入图片描述

草稿编辑页:
在这里插入图片描述

个人中心:
在这里插入图片描述

修改个人信息:
在这里插入图片描述

登录页面:
在这里插入图片描述
注册页面:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

左神算法之中级提升班(8)

目录 【案例1】 【题目描述】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【案例5】 【题目描述】 【子序列概念】 【思路解析1 经典…

【C++】STL中list的模拟实现(增删查改,迭代器封装,运算符重载)

文章目录 前言大体框架: 一、节点的封装(list_node)二、迭代器的封装(_list_iterator)1.类模板的定义:2.构造函数3.前置,后置4.前置--,后置--5.解引用(operator*())6. ->重载(operator- >…

关于提示词 Prompt

Prompt原则 原则1 提供清晰明确的指示 注意在提示词中添加正确的分割符号 prompt """ 请给出下面文本的摘要&#xff1a; <你的文本> """可以指定输出格式&#xff0c;如&#xff1a;Json、HTML提示词中可以提供少量实例&#xff0c;…

Android 面试题 ANR 五

&#x1f525; 什么是 ANR &#x1f525; ANR(Application Not Responding )应用无响应的简称&#xff0c;是为了在 APP卡死时&#xff0c;用户 可以强制退出APP的选择&#xff0c;从而避免卡机无响应问题&#xff0c;这是Android系统的一种自我保护机制。 在Android中&#xf…

【无标题】使用Debate Dynamics在知识图谱上进行推理(2020)7.31

使用Debate Dynamics在知识图谱上进行推理 摘要介绍背景与相关工作我们的方法 摘要 我们提出了一种新的基于 Debate Dynamics 的知识图谱自动推理方法。 其主要思想是将三重分类任务定义为两个强化学习主体之间的辩论游戏&#xff0c;这两个主体提取论点&#xff08;知识图中…

fixed-视频倍速

首先fn12打开开发者模式 然后进入console控制台 document.getElementsByTagName(“video”)[0].playbackRate 3 数字3 就是多少倍速 可以替换想要的倍速 直接快进到 最后 let video document.getElementsByTagName(‘video’) for (let i0; i<video.length; i) { video[…

音频编辑必备技能:怎么将音频转换mp3

丽萨&#xff1a;嘿&#xff0c;听说你最近在研究音频格式转换的方法&#xff0c;有眉目了吗&#xff1f; 凯瑞&#xff1a;没错&#xff0c;我下载了很多高清音乐&#xff0c;发现有些格式的音频文件在我的播放器上打不开&#xff0c;所以想一个转换工具。但是网上软件太多&a…

树莓派通过天线+gps获取经纬度并调用高德地图api在地图上标点

完整项目为《基于机器视觉的行人和路面缺陷检测及其边缘设备部署》 完整功能视频演示地址&#xff1a;本科最后的课设&#xff1a;“车载系统的辅助系统——基于机器视觉的行人和路面缺陷检测”完结撒花*罒▽罒*_哔哩哔哩_bilibili 该博客介绍的功能为&#xff1a; 1&#xff1…

学会这13个问题,轻松拿捏Java容器面试

java 容器都有哪些&#xff1f; 常用容器的图录&#xff1a; Collection 和 Collections 有什么区别&#xff1f; java.util.Collection 是一个集合接口&#xff08;集合类的一个顶级接口&#xff09;。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java …

【SpringBoot】| SpringBoot 和 web组件

目录 一&#xff1a;SpringBoot 和 web组件 1. SpringBoot中使用拦截器&#xff08;重点&#xff09; 2. SpringBoot中使用Servlet 3. SpringBoot中使用过滤器&#xff08;重点&#xff09; 4. 字符集过滤器的应用 一&#xff1a;SpringBoot 和 web组件 1. SpringBoot中使…

基于双层优化的微电网系统规划设计方法(Matlab代码实现)

目录 &#x1f4a5;1 概述 1.1 微电网系统结构 1.2 微电网系统双层规划设计结构 1.3 双层优化模型 1.4 上层容量优化模型 1.5 下层调度优化模型 &#x1f4da;2 运行结果 &#x1f389;3 文献来源 &#x1f308;4 Matlab代码、数据、文章讲解 &#x1f4a5;1 概述 文献来源&…

MySQL:MHA高可用集群部署及故障切换

目录 一、MHA概述 1、什么是MHA 2、MHA 的组成 3、MHA 的特点 4、MHA的工作原理 二、搭建MHA环境 主 从 manager 一、MHA概述 1、什么是MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现…

消息中间件ActiveMQ介绍

一、消息中间件的介绍 介绍 ​ 消息队列 是指利用 高效可靠 的 消息传递机制 进行与平台无关的 数据交流&#xff0c;并基于 数据通信 来进行分布式系统的集成。 特点(作用) 应用解耦 异步通信 流量削峰 (海量)日志处理 消息通讯 …... 应用场景 根据消息队列的特点&a…

Android adb shell 查看App内存(java堆内存/vss虚拟内存/详细的内存状况/内存快照hprof)和系统可用内存

1.adb shell 获取app 进程的pid adb shell "ps|grep com.xxx包名"根据某个渠道包&#xff0c;去查询对应的pid&#xff0c;如下所示&#xff1a; 2.通过adb shell 查看设备的java dalvik 堆内存的最大值 执行命令行&#xff1a; adb shell getprop dalvik.vm.h…

【RabbitMQ】之消息的可靠性方案

目录 一、数据丢失场景二、数据可靠性方案 1、生产者丢失消息解决方案2、MQ 队列丢失消息解决方案3、消费者丢失消息解决方案 一、数据丢失场景 MQ 消息数据完整的链路为&#xff1a;从 Producer 发送消息到 RabbitMQ 服务器中&#xff0c;再由 Broker 服务的 Exchange 根据…

微服务项目,maven无法加载其他服务依赖

微服务项目&#xff0c;导入了工具类工程&#xff0c;但是一直报错&#xff0c;没有该类&#xff0c; 检查maven 这里的Maven的版本与idea版本不匹配可能是导致依赖加载失败的最重要原因 检查maven配置&#xff0c;我这是原来的maven&#xff0c;home 修改之后,就不报错了

python文件处理方式

python文件处理方式 file open(D:\pythonText.txt, r, encodingUTF-8) print(file) # <_io.TextIOWrapper nameD:\\pythonText.txt moder encodingUTF-8> print(type(file)) # <class _io.TextIOWrapper>读取文件 file open(D:\pythonText.txt, r, encodingU…

C#文件操作从入门到精通(2)——查看某个dll中有哪些函数

kernel32.dll中含有ini文件操作使用的函数,我们可以通过VisualStudio自带的dumpbin.exe查看dll所包含的函数,操作步骤如下: 1、找到dumpbin.exe所在的文件夹 我的电脑中安装了VisualStudio2019社区版以及VisualStudio2017Professional,但是我发现VisualStudio2019社区版中…

【Linux下6818开发板(ARM)】在液晶屏上显示RGB颜色和BMP图片

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…

使用 CSS 自定义属性

我们常见的网站日夜间模式的变化&#xff0c;其实用到了 css 自定义属性。 CSS 自定义属性&#xff08;也称为 CSS 变量&#xff09;是一种在 CSS 中预定义和使用的变量。它们提供了一种简洁和灵活的方式来通过多个 CSS 规则共享相同的值&#xff0c;使得样式更易于维护和修改。…