智能云图库项目复盘

核心业务流程分析

画板

功能模块设计

  • 用户模块

用户登录、注册、注销、用户权限管理、管理用户(管理员权限)

  • 图片模块

上传图片、图片信息编辑(标签、分类,管理图片、查看(page和搜索图片、图片详情、图片下载、用户上传图片、管理员审核图片、通过Url导入图片、管理员批量抓取图片

图片模块扩展:

图片搜索:基础属性搜索,图片搜索,颜色搜索

图片分享:链接分享、扫码分享

图片批量管理:批量修改信息,批量重命名

图片编辑:基础图片编辑,ai图片编辑

  • 空间模块

管理空间(admin权限、用户开通私有空间、私有空间权限控制、空间级别和限额控制、空间图库分析

空间模块扩展:

创建团队空间

空间成员管理(CRUD,成员邀请、设置权限

空间成员权限控制

技术选型

Spring Boot

Mysql数据库

Mybatis-Plus

Mybatis-X

Redi分布式缓存、Caffeine本地缓存

Jsoup数据抓取

Sa-Token权限控制

AI大模型接入

JUC并发和异步编程

Vue3、Vite、Ant Design Vue组件库、Axios、Pinia


架构设计

功能开发

一些没有必要重复编写的代码

  1. 自定义异常(错误类枚举,见项目代码 enum ErrorCode

    1. 注意和主流的错误码保持一致,但是要有一定的区分度

    2. 不要完全连续,预留一些间隔

  2. 自定义业务异常,便于定制化输出异常信息,见项目代码 class BussinessException

  3. 封装一个ThrowUtils,类似断言,简化异常代码 见项目代码 ThrowUtils

  4. 统一响应包装类,便于前端获取结果信息 class BaseResponse<T>

  5. 统一响应包装类的工具类,简化相应类实例化 class ResultUtils

  6. 全局异常处理器 class GlobalExceptionHandler

  7. 请求包装类(对于分页,删除

    1. class PageResult

    2. class DeleteRequest

  8. 全局跨域配置

    1. CorsConfig

前端项目搭建

  1. 创建项目 npm create vue@latest

  1. 自动生成请求代码

npm i --save-dev @umijs/openapi

在根目录创建openapi.config.js

import { generateService } from '@umijs/openapi'
​
generateService({
  requestLibPath: "import request from '@/request'",
  schemaPath: 'http://localhost:8123/api/v2/api-docs',// 这里的路径改为后端Swagger接口文档的
  serversPath: './src',
})
​

在package.json 的 script 中添加:

 "openapi":"node openapi.config.js"

Java8的函数式编程语法

// map是一个中间操作,调用getPictureVO方法,将每一个picture转化为pictureVO
// collect是一个结束操作,将Stream中的元素收集到List中
List<PictureVO> pictureVOList = records.stream().map(picture -> getPictureVO(picture, request)).collect(Collectors.toList());
​
//从List收集userId到Set集中
Set<Long> userIdSet = records.stream().map(Picture::getUserId).collect(Collectors.toSet());
​
//批量查询userIds,将结果按照userId 将结果收集为Map
 Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream().collect(Collectors.groupingBy(User::getId));
​
 // 从Map中取出对应的 User
 if(userIdUserListMap.containsKey(userId)){
                List<User> userList = userIdUserListMap.get(userId);
                user = userList.get(0);
            }

项目中涉及到的设计模式

  1. 模板方法:针对同一个方法中写了两种不同的文件上传实现,这两种不同的实现包含了大部分相同的代码,考虑将不同的代码抽离出来,保留相同的代码。

    1. 实现: 新建一个上传模板抽象类,将不同的实现封装为抽象方法,需要实现实现不同抽象方法就去继承模板抽象类,然后具体实现

功能开发part-1-用户模块

  1. 需求分析

    1. 用户注册

      1. 提交账号、密码、确认密码进行注册

    2. 用户登录

      1. 输入账号、密码

    3. 获取当前登录用户

      1. 得到当前登录用户的信息(不用重复登录

    4. 用户注销

      1. 退出登录

    5. 管理员-管理用户

      1. 管理员权限,对整个系统的用户进行管理,例如:删除用户、搜索用户

  2. 方案设计

    1. 库表设计、用户登录流程、如何对用户进行权限控制

  3. 用户登录流程

画板

  1. 权限控制分类

    1. 未登录可用

    2. 登录可用

    3. 未登录限制可用(登录可以有更多的操作

    4. 仅管理员可用

传统的权限校验方法,是在每个接口内单独编写逻辑:先获取到当前登录用户的信息,然后判断用户的权限是否符合,虽然灵活但是繁琐,而且无法一眼看出接口所需要的权限。

使用Spring AOP + 自定义权限校验注解(流程如下

画板

功能模块part-2-图片模块

  1. 需求分析

    1. 管理员功能

      1. 图片上传和创建(支持本地上传,并填写相关信息,如名称、简介、便签、分类。系统自动解析图片基础信息

      2. 图片管理(CRUD

    2. 用户功能

      1. 查看与搜索图片(主页、按照关键词检索图片、并支持按照分类标签条件筛选分页查看的图片列表

      2. 查看图片详情

      3. 图片下载

  2. 图片上传(流程图-fileManager公共上传方法

画板

  1. 图片上传Service开发

画板

功能模块-part3-用户传图

  1. 需求分析

    1. 支持用户上传图片和审核功能

    2. 通过RUL导入图片

    3. 批量抓取和创建图片

  2. 审核流程

画板

  1. 通过URL上传图片(区别file文件校验、通过HttpUtil.downloadFile下载图片

画板

  1. 批量抓取和创建图片

画板

part4-传图优化

  1. 图片查询优化

    1. redis分布式缓存

      1. 缓存设计:key、value、过期时间

        1. key:针对不同的查询条件,对应的数据不同,所以要把查询条件作为key的一部分,(实现:将查询条件对象作为转换为JSON,利用MD5来压缩key,此外因为使用分布式缓存,需要在key前拼接项目名称前缀:

        2. value: 将Page对象转为JSON,或二进制,对应的Redis结构都是String

        3. 缓存过期时间:合适即可

        4. 接口: class listPictureVOByPageWithCache

      2. 流程设计

画板

2. Caffenine本地缓存

    1. 构造本地缓存,流程相同
    2. private final Cache<String, String> LOCAL_CACHE =
​
               Caffeine.newBuilder().initialCapacity(1024)
​
            .maximumSize(10000L)
​
            // 缓存 5 分钟移除
​
            .expireAfterWrite(5L, TimeUnit.MINUTES)
​
            .build();

​
3. 测试用例

@SpringBootTest
public class RedisStringTest {
​
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
​
    @Test
    public void testRedisStringOperations() {
        // 获取操作对象
        ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
​
        // Key 和 Value
        String key = "testKey";
        String value = "testValue";
​
        // 1. 测试新增或更新操作
        valueOps.set(key, value);
        String storedValue = valueOps.get(key);
        assertEquals(value, storedValue, "存储的值与预期不一致");
​
        // 2. 测试修改操作
        String updatedValue = "updatedValue";
        valueOps.set(key, updatedValue);
        storedValue = valueOps.get(key);
        assertEquals(updatedValue, storedValue, "更新后的值与预期不一致");
​
        // 3. 测试查询操作
        storedValue = valueOps.get(key);
        assertNotNull(storedValue, "查询的值为空");
        assertEquals(updatedValue, storedValue, "查询的值与预期不一致");
​
        // 4. 测试删除操作
        stringRedisTemplate.delete(key);
        storedValue = valueOps.get(key);
        assertNull(storedValue, "删除后的值不为空");
    }
}
  1. 构建多级缓存

画板

  1. 缓存常见问题

    1. 缓存击穿:某些热点信息在缓存过期后,大量请求直接打到数据库上(解决:设置超长过期时间,获取使用互斥锁控制缓存刷新

    2. 缓存穿透:用户请求频繁请求不存在的数据,导致大量请求直接触发数据库查询(解决:对无效查询结果也进行缓存,如火村空值,或者使用布隆过滤器

    3. 缓存雪崩:大量缓存同时过期,导致请求达到数据库(解决:设置不同的过期时间,使用多级缓存

  2. 扩展

    1. 缓存击穿(Cache Breakdown) 命名原因:“击穿”这个词形象地描述了当某个热点数据的缓存失效时,大量请求像“击穿”了缓存层一样,直接打到数据库上,导致数据库压力骤增。就像一层保护屏障被“击穿”了,失去了保护作用。

问题本质:热点数据缓存失效,导致请求直接访问数据库。

解决思路:通过设置超长过期时间或使用互斥锁(如分布式锁)来控制缓存刷新,避免大量请求同时打到数据库。

2. 缓存穿透(Cache Penetration)  

命名原因:“穿透”这个词形象地描述了请求直接“穿透”缓存层,到达数据库的场景。通常是因为请求的数据在缓存和数据库中都不存在,导致缓存无法发挥作用,请求每次都直接访问数据库。

问题本质:频繁请求不存在的数据,导致缓存失效,数据库压力增加。

解决思路:对无效查询结果也进行缓存(如缓存空值),或者使用布隆过滤器(Bloom Filter)来快速判断数据是否存在,避免无效查询。

3. 缓存雪崩(Cache Avalanche)  

命名原因:“雪崩”这个词形象地描述了大量缓存同时失效的场景,就像雪山上的积雪突然崩塌一样,导致大量请求直接打到数据库,造成数据库压力瞬间激增,甚至可能引发系统崩溃。

问题本质:大量缓存同时过期,导致请求直接访问数据库。

解决思路:通过设置不同的过期时间(如添加随机值),或者使用多级缓存(如本地缓存 + 分布式缓存)来分散缓存失效的压力。

part4-图片上传优化

主要就是阅读COS对象存储、万象存储文档

功能模块-part5-空间模块

  1. 用户创建私有空间

画板

  1. RBAC权限管理

    • 登录认证(设计思路

画板

- 权限设计(设计思路
    * 核心逻辑就是判断一个账号是否拥有指定的权限
        + 有:通过
        + 无:禁止访问

4.空间模块

- 从请求冲获取上下文参数
​
- 私人空间创建

画板

- 空间成员管理(CURD
- 空间成员权限控制

画板

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值