1. 项目概述
最近在做一个基于SpringBoot的资源分享系统,这个项目源于实际工作中遇到的文件共享需求。传统方式下,同事之间分享文档经常通过邮件、U盘或者即时通讯工具来回传递,不仅效率低下,还容易出现版本混乱的问题。于是决定开发一个集中化的资源管理平台,让团队成员可以方便地上传、查找和下载各类工作文档。
这个系统采用Java 8作为开发语言,SpringBoot 2.7作为基础框架,配合MySQL 8.0数据库。前端使用Vue.js + ElementUI构建用户界面,后端采用RESTful API设计风格。整个项目使用Maven进行依赖管理,开发工具选择了IntelliJ IDEA。
提示:SpringBoot的版本选择很关键,2.7.x是目前企业级应用中最稳定的LTS版本之一,相比3.x版本对JDK的要求更低,兼容性更好。
2. 技术架构设计
2.1 后端技术栈选型
选择SpringBoot作为基础框架主要基于以下几个考虑:
- 自动配置特性大幅减少了XML配置的工作量
- 内嵌Tomcat服务器简化了部署流程
- 丰富的Starter依赖可以快速集成常用组件
- Actuator提供了完善的应用监控能力
数据库方面,MySQL 8.0相比5.7版本在JSON支持、窗口函数等方面有显著提升,特别是对资源元数据的存储更加灵活。我们使用了InnoDB引擎,并针对资源表做了如下优化:
sql复制CREATE TABLE `resource` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`type` enum('DOC','IMG','VIDEO','AUDIO','OTHER') NOT NULL,
`size` bigint NOT NULL COMMENT '字节数',
`md5` char(32) NOT NULL COMMENT '文件指纹',
`download_count` int DEFAULT '0',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_md5` (`md5`),
KEY `idx_type` (`type`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2.2 前端技术方案
前端采用Vue 3 + Element Plus的组合,主要考虑到:
- 组件化开发模式适合构建复杂的后台管理系统
- TypeScript支持提供了更好的类型安全
- Axios处理HTTP请求与后端API对接
- Vue Router实现前端路由管理
- Pinia作为状态管理工具
特别在文件上传组件上,我们做了以下增强:
- 分片上传:大文件切割为2MB的块并行上传
- 断点续传:记录已上传分片信息
- MD5校验:前端预计算文件指纹避免重复上传
- 进度显示:实时展示上传进度和速度
3. 核心功能实现
3.1 资源上传与存储方案
文件上传是系统的核心功能,我们设计了多层次的存储方案:
-
本地存储模式(开发环境)
yaml复制# application-dev.yml file: storage: type: local location: ./uploads max-size: 1GB allowed-types: - application/pdf - image/* - video/* -
阿里云OSS存储(生产环境)
java复制@Service @ConditionalOnProperty(name = "file.storage.type", havingValue = "oss") public class OssStorageService implements StorageService { @Value("${aliyun.oss.endpoint}") private String endpoint; @Override public String upload(MultipartFile file, String path) { OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey); try { ossClient.putObject(bucketName, path, file.getInputStream()); return generateUrl(path); } finally { ossClient.shutdown(); } } }
注意事项:文件存储一定要考虑权限控制,特别是使用云存储时,建议通过临时URL的方式提供下载,避免直接暴露存储桶地址。
3.2 权限控制系统设计
系统采用RBAC(基于角色的访问控制)模型,主要包含以下实体:
- 用户:系统的使用者
- 角色:定义一组权限集合(如管理员、普通用户、访客)
- 权限:具体的操作权限(如resource:upload、resource:delete)
权限校验通过Spring Security实现:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/resources/download/**").permitAll()
.antMatchers("/api/resources/upload").hasAuthority("resource:upload")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
}
}
4. 性能优化实践
4.1 数据库查询优化
针对资源列表查询,我们做了以下优化:
- 添加适当的索引(如类型、创建时间)
- 使用MyBatis的二级缓存
- 复杂查询使用@Query注解优化SQL
- 分页查询使用PageHelper插件
典型的分页查询实现:
java复制@RestController
@RequestMapping("/api/resources")
public class ResourceController {
@GetMapping
public PageInfo<ResourceVO> listResources(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String keyword) {
PageHelper.startPage(pageNum, pageSize);
List<Resource> resources = resourceService.search(keyword);
return new PageInfo<>(resources.stream()
.map(this::convertToVO)
.collect(Collectors.toList()));
}
}
4.2 缓存策略设计
使用Redis作为缓存中间件,主要缓存以下数据:
- 热门资源列表(ZSET结构,按下载量排序)
- 用户权限信息(Hash结构)
- 资源元数据(String结构,JSON格式)
缓存更新策略采用Cache Aside Pattern:
java复制@Service
public class ResourceServiceImpl implements ResourceService {
@Cacheable(value = "resource", key = "#id")
public Resource getById(Long id) {
return resourceRepository.findById(id).orElse(null);
}
@CachePut(value = "resource", key = "#resource.id")
public Resource update(Resource resource) {
return resourceRepository.save(resource);
}
@CacheEvict(value = "resource", key = "#id")
public void delete(Long id) {
resourceRepository.deleteById(id);
}
}
5. 部署与监控方案
5.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3.8'
services:
app:
image: resource-share:1.0.0
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: resource_share
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
mysql_data:
5.2 监控与告警
集成Spring Boot Actuator和Prometheus:
yaml复制# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
endpoint:
health:
show-details: always
配置的监控指标包括:
- JVM内存使用情况
- 数据库连接池状态
- HTTP请求统计
- 系统CPU/内存负载
- 自定义业务指标(如上传下载次数)
6. 踩坑经验分享
在实际开发中遇到几个典型问题值得记录:
-
文件上传大小限制问题
- 现象:上传大文件时报413错误
- 原因:Spring Boot默认文件大小限制为1MB
- 解决:需要同时配置以下两个参数
yaml复制spring: servlet: multipart: max-file-size: 100MB max-request-size: 100MB
-
MySQL时区问题
- 现象:数据库中的时间比实际时间少8小时
- 解决:JDBC连接串添加时区参数
yaml复制spring: datasource: url: jdbc:mysql://localhost:3306/resource_share?serverTimezone=Asia/Shanghai
-
Redis缓存序列化问题
- 现象:缓存对象出现ClassCastException
- 解决:配置统一的序列化方式
java复制@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }
这个项目从技术选型到最终上线历时两个月,期间遇到了不少挑战,但也收获了很多宝贵的经验。特别在文件存储方案上,建议根据实际业务规模选择合适的策略,小型应用可以从本地存储开始,随着业务增长再迁移到云存储方案。