作为一名有10年全栈开发经验的工程师,我最近完成了一个基于SpringBoot的非遗文化宣传平台项目。这个系统采用B/S架构,前后端分离设计,旨在为非物质文化遗产的数字化保护和传播提供技术支撑。平台包含用户管理、非遗项目展示、在线互动、数据统计等核心模块,目前已通过完整测试并投入实际使用。
非遗文化作为中华民族的瑰宝,其数字化保护工作迫在眉睫。传统的手工记录和线下展示方式存在传播范围有限、互动性差等问题。我们这个平台通过现代Web技术,实现了非遗文化的在线展示、互动交流和系统化管理,解决了以下核心痛点:
平台主要面向三类用户:普通访客可以浏览非遗内容;注册用户能参与互动;管理员负责内容审核和系统维护。技术选型上,后端采用SpringBoot+MyBatisPlus,前端使用Vue.js,数据库选用MySQL,确保了系统的性能、稳定性和可扩展性。
系统采用经典的MVC设计模式,各层职责明确:
视图层(View):基于Vue.js构建响应式前端界面,使用Element UI组件库保证UI一致性。考虑到非遗内容的丰富性,我们特别优化了图片和视频的展示效果,支持高清大图和全屏播放。
控制层(Controller):SpringBoot的RestController处理HTTP请求,采用统一响应格式:
java复制{
"code": 200,
"message": "success",
"data": {...}
}
服务层(Service):业务逻辑的核心实现,包含:
数据访问层(DAO):MyBatisPlus实现,通过BaseMapper简化CRUD操作。我们自定义了通用查询封装,例如:
java复制public PageResult<Heritage> queryHeritage(HeritageQuery query) {
QueryWrapper<Heritage> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(query.getName())) {
wrapper.like("name", query.getName());
}
if (query.getCategoryId() != null) {
wrapper.eq("category_id", query.getCategoryId());
}
Page<Heritage> page = heritageMapper.selectPage(
new Page<>(query.getPageNum(), query.getPageSize()),
wrapper
);
return new PageResult<>(page.getRecords(), page.getTotal());
}
SpringBoot优势实践:
Vue.js前端优化:
MySQL设计要点:
sql复制CREATE TABLE `heritage` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '非遗名称',
`category_id` int NOT NULL COMMENT '分类ID',
`cover_url` varchar(255) COMMENT '封面图URL',
`video_url` varchar(255) COMMENT '视频URL',
`description` text COMMENT '详细描述',
`status` tinyint DEFAULT 1 COMMENT '状态:0-下架 1-上架',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
安全措施:
性能优化:
采用JWT+Shiro的混合认证方案,既保证无状态又实现细粒度权限控制。关键实现步骤:
java复制public String register(User user) {
if (userMapper.existsByUsername(user.getUsername())) {
throw new BusinessException("用户名已存在");
}
user.setPassword(passwordEncoder.encode(user.getPassword()));
userMapper.insert(user);
return "注册成功";
}
java复制public String login(String username, String password) {
User user = userMapper.selectByUsername(username);
if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
throw new BusinessException("用户名或密码错误");
}
return JwtUtil.generateToken(user.getId(), user.getUsername());
}
java复制public class CustomRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Long userId = (Long) principals.getPrimaryPrincipal();
// 查询用户角色和权限
Set<String> roles = roleService.getRolesByUserId(userId);
Set<String> permissions = permissionService.getPermissionsByUserId(userId);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(permissions);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
String jwt = (String) token.getPrincipal();
Long userId = JwtUtil.getUserId(jwt);
if (userId == null || !JwtUtil.verify(jwt)) {
throw new AuthenticationException("token无效");
}
return new SimpleAuthenticationInfo(userId, jwt, getName());
}
}
内容管理采用审核发布机制,支持富文本编辑和多媒体上传:
mermaid复制graph TD
A[用户提交] --> B[自动敏感词过滤]
B --> C{是否包含敏感词?}
C -->|是| D[打回修改]
C -->|否| E[进入审核队列]
E --> F[管理员审核]
F --> G{审核通过?}
G -->|是| H[正式发布]
G -->|否| I[退回并说明原因]
java复制@PostMapping("/upload")
public Result upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.fail("请选择文件");
}
try {
String originalName = file.getOriginalFilename();
String fileType = FileUtil.getFileType(originalName);
if (!Arrays.asList("jpg", "png", "mp4").contains(fileType)) {
return Result.fail("不支持的文件类型");
}
String newName = UUID.randomUUID() + "." + fileType;
String path = uploadPath + "/" + newName;
File dest = new File(path);
FileUtil.ensureDirExists(dest.getParentFile());
file.transferTo(dest);
String url = domain + "/uploads/" + newName;
return Result.success(url);
} catch (IOException e) {
log.error("文件上传失败", e);
return Result.fail("上传失败");
}
}
包括评论、收藏和分享三大互动功能:
java复制@Entity
@Table(name = "comment")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long heritageId;
@Column(nullable = false)
private Long userId;
@Column(nullable = false, length = 500)
private String content;
@Column
private Long parentId; // 回复的评论ID
@Column(updatable = false)
private LocalDateTime createTime;
// getters & setters
}
java复制@Transactional
public Result toggleFavorite(Long userId, Long heritageId) {
Favorite favorite = favoriteMapper.selectByUserAndHeritage(userId, heritageId);
if (favorite == null) {
// 添加收藏
favorite = new Favorite();
favorite.setUserId(userId);
favorite.setHeritageId(heritageId);
favoriteMapper.insert(favorite);
heritageMapper.incrementFavoriteCount(heritageId);
return Result.success(true);
} else {
// 取消收藏
favoriteMapper.deleteById(favorite.getId());
heritageMapper.decrementFavoriteCount(heritageId);
return Result.success(false);
}
}
采用分层测试策略,确保系统质量:
java复制@ExtendWith(MockitoExtension.class)
class HeritageServiceTest {
@Mock
private HeritageMapper heritageMapper;
@InjectMocks
private HeritageService heritageService;
@Test
void testGetHeritageDetail() {
Heritage mockHeritage = new Heritage();
mockHeritage.setId(1L);
mockHeritage.setName("测试非遗");
when(heritageMapper.selectById(1L)).thenReturn(mockHeritage);
Heritage result = heritageService.getHeritageDetail(1L);
assertEquals("测试非遗", result.getName());
}
}
java复制@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class HeritageControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testGetHeritageList() {
ResponseEntity<PageResult> response = restTemplate.getForEntity(
"/api/heritage/list?page=1&size=10",
PageResult.class
);
assertEquals(200, response.getStatusCodeValue());
assertNotNull(response.getBody());
}
}
采用Docker容器化部署,保证环境一致性:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: heritage
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_PROFILES_ACTIVE: prod
volumes:
mysql_data:
完善的监控体系保障系统稳定运行:
java复制@RestController
public class HeritageController {
private final Counter heritageViewCounter;
public HeritageController(MeterRegistry registry) {
this.heritageViewCounter = registry.counter("heritage.view.count");
}
@GetMapping("/heritage/{id}")
public Result getHeritage(@PathVariable Long id) {
heritageViewCounter.increment();
// ...
}
}
promql复制# JVM内存使用超过90%
sum(jvm_memory_used_bytes{area="heap"}) by (instance) / sum(jvm_memory_max_bytes{area="heap"}) by (instance) > 0.9
# 接口错误率超过1%
sum(rate(http_server_requests_seconds_count{status=~"5.."}[1m])) by (uri) / sum(rate(http_server_requests_seconds_count[1m])) by (uri) > 0.01
在实际开发过程中,有几个关键点值得特别注意:
文化敏感性处理:非遗内容常涉及民族、地域等敏感信息,我们建立了三级审核机制(自动过滤→人工审核→专家复核)确保内容合规。
多媒体处理优化:
性能调优经验:
未来可扩展的方向包括:
这个项目的完整源码和配套文档(包括数据库设计文档、API文档、部署手册等)已经整理成完整的资源包。对于想要学习SpringBoot全栈开发的同学,这个项目涵盖了从需求分析到部署上线的完整流程,具有很高的参考价值。特别是在处理文化类内容的特殊要求和性能优化方面,积累了不少实战经验。