1. 项目概述与设计思路
作为一个热爱传统文化的开发者,我一直想打造一个现代化的古诗文鉴赏平台。这个基于Vue.js和Spring Boot的前后端分离项目,旨在为用户提供流畅的古诗文浏览、收藏和互动体验。与传统文学网站不同,我们采用了响应式设计和RESTful架构,让用户在手机和电脑上都能舒适地品味经典。
技术选型上,前端采用Vue 3组合式API开发,配合Element Plus组件库实现优雅的UI交互。后端使用Spring Boot 2.7构建微服务,数据持久层采用MyBatis-Plus提升开发效率。这种技术组合既保证了系统性能,又具有良好的可维护性。
2. 核心功能模块设计
2.1 用户认证系统实现
JWT认证是系统的安全基石。我们在Spring Security基础上进行了二次封装,实现了以下关键功能:
java复制// JWT过滤器核心逻辑
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) {
String token = parseToken(request);
if (token != null && jwtProvider.validateToken(token)) {
Authentication auth = jwtProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
}
密码存储采用BCrypt强哈希算法,即使数据库泄露也能保证用户密码安全:
java复制// 密码加密处理
public class PasswordEncoderImpl implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return BCrypt.hashpw(rawPassword.toString(), BCrypt.gensalt());
}
}
2.2 诗文数据建模与检索
数据库设计考虑了古诗文的特点,建立了多维度关联模型:
sql复制CREATE TABLE `poem` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`author_id` bigint NOT NULL,
`dynasty_id` bigint NOT NULL,
`rhythm` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FULLTEXT KEY `ft_content` (`content`) /* 全文检索支持 */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
后端采用Elasticsearch实现高级搜索功能,支持按平仄、韵脚等专业维度查询:
java复制// 诗文高级搜索接口
@GetMapping("/search")
public Result searchPoems(
@RequestParam String keyword,
@RequestParam(required = false) String dynasty,
@RequestParam(required = false) String rhythm) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
if (StringUtils.hasText(keyword)) {
queryBuilder.withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"));
}
if (StringUtils.hasText(dynasty)) {
queryBuilder.withFilter(QueryBuilders.termQuery("dynasty", dynasty));
}
// 其他搜索条件处理...
return Result.success(poemRepository.search(queryBuilder.build()));
}
3. 前端交互实现细节
3.1 响应式布局方案
使用Element Plus的布局组件结合自定义CSS实现多端适配:
vue复制<template>
<el-container class="app-container">
<el-header>
<nav-bar :user="userStore.user" />
</el-header>
<el-main>
<el-row :gutter="20">
<el-col :xs="24" :sm="18" :md="16" :lg="14">
<poem-list :poems="poems" />
</el-col>
<el-col :xs="0" :sm="6" :md="8" :lg="10">
<side-panel />
</el-col>
</el-row>
</el-main>
</el-container>
</template>
3.2 诗文展示优化技巧
针对长诗文展示做了特殊处理:
vue复制<script setup>
const MAX_PREVIEW_LINES = 10;
const truncatedContent = computed(() => {
const lines = props.poem.content.split('\n');
return lines.length > MAX_PREVIEW_LINES
? lines.slice(0, MAX_PREVIEW_LINES).join('\n') + '...'
: props.poem.content;
});
const showFull = ref(false);
</script>
4. 性能优化实践
4.1 前端性能提升
- 使用Vue的
<script setup>语法减少代码量 - 实现路由懒加载减小首屏体积
- 对诗文图片使用WebP格式并设置懒加载
vue复制<template>
<img
:src="placeholder"
:data-src="realSrc"
class="lazy-image"
@load="handleImageLoad"
/>
</template>
<script setup>
const placeholder = ref('/placeholder.webp');
const realSrc = ref('');
onMounted(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
realSrc.value = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
});
observer.observe(document.querySelector('.lazy-image'));
});
</script>
4.2 后端缓存策略
采用多级缓存方案提升响应速度:
- 使用Redis缓存热门诗文数据
- 对静态资源配置CDN加速
- 实现HTTP缓存头控制
java复制@Cacheable(value = "poems", key = "#id")
@GetMapping("/poems/{id}")
public Result getPoemById(@PathVariable Long id) {
return Result.success(poemService.getById(id));
}
@CacheEvict(value = "poems", key = "#poem.id")
@PostMapping("/poems")
public Result updatePoem(@RequestBody Poem poem) {
return Result.success(poemService.updateById(poem));
}
5. 部署与运维方案
5.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
5.2 监控与日志
集成Prometheus和Grafana监控系统健康状态:
java复制// Spring Boot Actuator配置
management:
endpoints:
web:
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
6. 开发中的经验教训
- 跨域问题:开发初期没处理好OPTIONS请求,导致前端请求失败。最终在后端添加了专门的CORS配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
- 状态管理混乱:初期在多个组件直接修改Pinia状态导致难以追踪变更。后来统一采用Action处理状态修改:
js复制// store/poem.js
export const usePoemStore = defineStore('poem', {
actions: {
async fetchPoems(params) {
const res = await api.getPoems(params);
this.poems = res.data;
return res;
}
}
})
- Nginx配置陷阱:部署时遇到前端路由刷新404问题,通过以下配置解决:
nginx复制location / {
try_files $uri $uri/ /index.html;
}
这个项目从技术选型到最终部署历时两个月,期间遇到了各种预料之外的挑战。最大的收获是认识到良好的架构设计对后期维护的重要性。比如早期没有规划好缓存策略,导致后期重构花费了大量时间。如果重新开始,我会在项目初期就建立完整的监控体系,而不是等到性能出现问题才补救