案例综合练习-博客系统

完整代码 gitee:优今夏/项目仓库

项目介绍

使用SSM框架实现一个简单的博客系统

共5个页面

  1. 用户登录
  2. 博客发表页
  3. 博客编辑页
  4. 博客列表页
  5. 博客详情页

功能描述

用户登录成功后,可以查看所有人的博客,点击<<查看全文>>可以查看该博客的正文内容,如果该博客作者为当前登录用户,可以完成博客的修改和删除操作,以及发表新博客

页面预览

用户登录

博客列表页

博客详情页

博客发表/修改页

1. 项目公共模块

项目分为控制层(Controller),服务层(Service),持久层(Mapper)各层调用关系如下

1.1 统一返回结果实体类

1.2 统一返回结果

1.3 定义项目异常

1.4 统一异常处理


数据准备

2. 业务代码

2.1 持久层

Mapper

2.2 实现博客列表

约定前后端接口

java 复制代码
[请求]
/blog/getList  GET

[响应]
{
   "code": 200,
   "errMsg": null,
   "data": [{
      "id": 1,
      "title": "第⼀篇博客",
      "content": "111我是博客正⽂我是博客正⽂我是博客正⽂",
      "userId": 1,
      "updateTime": "2024-08-22 11:27:03"
   },
   .....
   ]
}

实现服务器代码

1.定义接口返回实体

日期的返回格式有两种方法实现


2.实现Controller

  1. 实现Service

实现客户端代码

测试

2.3 实现博客详细

约定前后端接口

java 复制代码
[请求]
/blog/getBlogDetail?blogId=1

[响应]
{
   "code": 200,
   "errMsg": null,
   "data": {
      "id": 1,
      "title": "第⼀篇博客",
      "content": "111我是博客正⽂我是博客正⽂我是博客正⽂",
      "userId": 1,
      "updateTime": "2024-08-22 11:27:03"
   }
}

实现服务器代码

参数校验: jakarta。validation

这个接口中,blogId不能为空,可以借助校验. @NotNull , jakarta.validation 帮我们完成参数校验,免去繁琐的串 javax.validation 是JavaBeanValidationAPI的包名,这个API允许开发者通过注解 (如 @NotBlank , @Null 等)来声明对象的验证规则,然后在运行时自动验证这些对象.

java 复制代码
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
</dependency>


将 BlogInfo 转为 BlogInfoResponse 的操作封装起来


实现客户端代码

测试

2.4 实现登录

分析

传统思路:

  • 登录页面把用户名和密码提交给服务器
  • 服务器端验证用户密码是否正确,并返回校验结果给后端
  • 如果密码正确,则在服务器端创建 Session ,通过Cookie 把sessionId 返回给浏览器

问题:

  • 服务器重启,Session丢失
  • Session 存储在内存中(耗费服务器资源)
  • 集群环境下无法直接使用Session

原因分析:

开发项目,在企业中很少会部署在一台机器上,容易发生单点故障(单点故障:一旦这台服务器挂了,整个应用就无法访问了)所以通常情况下,一个Web应用会部署在多个服务器上,通过Nginx等进行负载均衡。此时,来自同一个用户的请求会被分发到不同的服务器上

此时需要另一种方案:令牌技术

令牌是一个用户身份的标识,本质是一个字符串

优点:

  • 解决了集群环境下的认证问题
  • 减轻了服务器的存储压力

JWT令牌

令牌本质就是一个字符串,他的实现方式有很多,我们采用一个JWT令牌来实现

官网:JSON Web Tokens - jwt.io

JWT令牌生成和校验

  1. 引入依赖
java 复制代码
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt-api</artifactId>
   <version>0.11.5</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt-impl</artifactId>
   <version>0.11.5</version>
   <scope>runtime</scope>
</dependency>

<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt-jackson</artifactId> 
   <!-- or jjwt-gson if Gson is preferred -->
   <version>0.11.5</version>
   <scope>runtime</scope>
</dependency>
  1. 使用Jar包中提供的API来完成JWT令牌的生成和校验

约定前后端接口

java 复制代码
[
请求]
/user/login

[参数]
{
   "userName": "test",
   "password": "123456"
}

[响应] 
{
   "code": 200,
   "errMsg": null,
   "data": {
      "userId": 1,
      "token": 
"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiemhhbmdzYW4iLCJpZCI6MSwiaWF0IjoxNzI0OTE5NjgyL
CJleHAiOjE3MjQ5MjE0ODJ9.5hwKlAh2jPPBNn3uPja4JTGguZNB3QrpRoPqCep7qME"
      }
}
//验证成功, 返回token, 验证失败返回 ""

实现服务器代码

创建JWT工具类:可以生成token和解析

创建请求和响应实体类

参数不合法会抛出异常:

可以单独获取想要的异常信息(原本的信息太长)


实现Controlled

实现Service

实现客户端代码

java 复制代码
//存储数据
localStorage.setItem("user_token","value");

//读取数据
localStorage.getItem("user_token");

//删除数据
localStorage.removeItem("user_token");

2.5 实现强制要求登录

当用户访问博客列表页和博客详情页时,如果用户当前尚未登录,就自动跳转到登录页面

可以采用拦截器来完成,token通常有前端放在header中,从header中获取token,并校验token是否合法

添加拦截器

ERROR com.example.springblog.common.util.JwtUtils -- token解析失败,token:eyJhbGciOiJIUzI1NiJ9.ehyJuYW1lIjoiemhhbmdzYW4iLCJpZCI6MX0.8GHwbRNe44MuWq-UteQFqZ_-oIc_649gBovAn56XSeE null

解析失败会返回null

实现客户端代码

浏览器不会自动把 localStorage 中的 token 放到请求头里,必须由前端代码显式实现

前端请求时,header中统一添加token,后端返回异常时,跳转登录页面,代码逻辑卸载common。js中

2.6 实现显示用户信息

用户信息可以随着用户登录而发生改变

  1. 如果当前页面是博客列表页,则显示当前登录用户的信息

2.如果当前页面是博客详细页,则显示该博客的作者用户的信息


由于前端代码能力有限,改为在后端处理

约定前后端交互接口

在博客列表页,获取当前登录用户的用户信息

java 复制代码
[请求]
/user/getUserInfo?userId=1

[响应]
{
   "id": 1,
   "username": "test",
   "githubUrl":"bite.gitee.com"
}

在博客详情页,获取当前文章作者的用户信息

java 复制代码
[请求]
/user/getAuthorInfo?blogId=1

[响应]
{
   "id": 1,
   "username": "test",
   "githubUrl":"bite.gitee.com"
}

实现服务器代码

定义返回接口实体类

服务层可以相互调用

实现客户端代码

2.7 实现用户退出

前端直接清楚token即可

实现客户端代码

2.8 实现发布博客

约定前后端交互

java 复制代码
[请求]
/blog/add

[参数]
{
   "userId":1,
   "title":"标题",
   "content":"正⽂"
}

[响应]
{
   "code": 200,
   "msg": "",
   "data": true
}
//true 成功
//false 失败

实现服务器代码

客户端代码

editor.md简单介绍 Editor.md - 开源在线 Markdown 编辑器

是一个开源的页面,markdown编辑组件

配置使得html生效

设置背景等细节

2.9 实现删除/编辑博客

进入用户详情页,如果当前登录用户正式文章作者,则在导航栏中显示【编辑】【删除】按钮,用户点击时则进行相应的处理

需要实现两件事:

  1. 判定当前博客详情页是否要显示【删除】【编辑】按钮

2.实现编辑/删除逻辑(采用逻辑删除)

约定前后端接口

  1. 修改博客
java 复制代码
[请求]
/blog/update

[参数]
Content-Type: application/json
{
   "id": "4",
   "title": "测试修改⽂章",
   "content": "在这⾥写下⼀篇博客"
}

[响应]
{
   "code": 200,
   "msg": "",
   "data": true
}
  1. 删除博客
java 复制代码
[请求]
/blog/delete?blogId=1

[响应]
{
   "code": 200,
   "msg": "",
   "data": true
}

实现服务器代码

定义修改接口实体类

实现客户端代码

blog_detail.html

blog_update.html

测试

以zhangsan的身份登录

3.10 加密/加盐

加密介绍

在MySQL数据库中,需要对密码,身份证号,手机号等敏感信息进行加密,以保证数据的安全性,如果使用明文储存,当黑客入侵数据库时,就可以轻松获取到用户的相关信息,从而对用户或者企业造成信息泄露或者财产损失

目前我们用户的密码还是明文设置,为了保护用户的密码信息,我们需要对密码进行加密

密码算法分类

密码算法主要分为三类:对称密码算法,非对称密码算法,摘要算法

加密思路

博客系统中我们采用MD5算法来进行加密


测试:

实现服务器代码

由于该博客系统没有注册功能,只介绍登录场景

修改接口

修改数据库中的密码

相关推荐
其实防守也摸鱼1 小时前
告别单个变量,用列表和字典批量管理你的 Python 数据
开发语言·网络·软件测试·python·web安全·数据结构,编程教程
瑞雪兆丰年兮1 小时前
[从0开始学Java|第十八、十九天]API(常见API&对象克隆&正则表达式)
java·开发语言
KobeSacre1 小时前
JVM G1 垃圾回收器
java·开发语言·jvm
右耳朵猫AI1 小时前
JavaScript技术周刊 2026年第20周
开发语言·javascript·ecmascript
摇滚侠2 小时前
浏览器调试工具 检查元素 谷歌模拟器 控制台 断点调试
java·html
心之伊始2 小时前
Spring Boot 接入 MCP 实战:用 Spring AI 调用本地工具的最小闭环
java·spring boot·agent·spring ai·mcp
basketball6162 小时前
Go 语言从入门到进阶:5. 玩转Go函数
开发语言·后端·golang
Refrain_zc2 小时前
无触摸屏场景下的蓝牙交互:Android 纯按键蓝牙扫描配对与 A2DP/Headset 连接
java·蓝牙