1. 项目概述
古风诗词交流平台是一个基于SpringBoot+Vue技术栈构建的B/S架构Web应用,旨在为传统文化爱好者提供诗词鉴赏、创作交流的线上空间。作为全栈开发者,我在项目中负责了从技术选型到核心功能实现的全流程开发工作。系统采用前后端分离架构,后端基于SpringBoot 2.7提供RESTful API,前端使用Vue 3组合式API开发响应式界面,数据库选用MySQL 8.0存储结构化数据。
技术选型考量:SpringBoot的自动配置特性大幅减少了XML配置工作量,内置Tomcat服务器简化了部署流程;Vue的响应式数据绑定和组件化开发模式非常适合构建动态交互界面;MyBatis-Plus的ActiveRecord模式使数据库操作更加直观。
2. 系统架构设计
2.1 技术栈全景图
后端技术矩阵:
- 核心框架:SpringBoot 2.7.12
- ORM工具:MyBatis-Plus 3.5.3
- 安全认证:JWT + Spring Security
- 缓存机制:Redis 6.2
- 文档生成:Swagger 3.0
- 构建工具:Maven 3.8
前端技术体系:
- 基础框架:Vue 3.2 + Vue Router 4.1
- UI组件库:Element Plus 2.3
- 状态管理:Pinia 2.0
- HTTP客户端:Axios 1.3
- 构建工具:Vite 4.1
2.2 分层架构设计
系统采用经典的三层架构,各层职责明确:
- 表现层:Vue SPA处理用户交互,通过Axios与后端通信
- 业务逻辑层:SpringBoot服务处理核心业务,包含:
- 诗词服务(PoetryService)
- 用户服务(UserService)
- 评论服务(CommentService)
- 数据访问层:MyBatis-Plus实现CRUD操作
- 基础设施层:MySQL存储、Redis缓存、OSS文件存储
java复制// 典型服务层代码结构示例
@Service
public class PoetryServiceImpl extends ServiceImpl<PoetryMapper, Poetry>
implements PoetryService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Page<PoetryVO> searchPoetry(SearchDTO dto) {
// 实现带缓存的诗词搜索逻辑
}
}
3. 核心功能实现
3.1 诗词模块设计
数据结构设计:
sql复制CREATE TABLE `poetry` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL COMMENT '诗词标题',
`author` varchar(50) NOT NULL COMMENT '作者',
`dynasty` varchar(20) NOT NULL COMMENT '朝代',
`content` text NOT NULL COMMENT '正文',
`translation` text COMMENT '译文',
`notes` text COMMENT '注释',
`cover_img` varchar(255) DEFAULT NULL COMMENT '封面图',
`view_count` int DEFAULT '0' COMMENT '浏览数',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FULLTEXT KEY `ft_idx` (`title`,`author`,`content`) WITH PARSER `ngram`
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
关键功能实现:
- 全文检索功能:
java复制public interface PoetryMapper extends BaseMapper<Poetry> {
@Select("SELECT * FROM poetry WHERE MATCH(title,author,content) AGAINST(#{keyword})")
List<Poetry> fullTextSearch(@Param("keyword") String keyword);
}
- 热门推荐算法:
java复制public List<Poetry> getHotPoetries(int limit) {
String cacheKey = "hot:poetries";
List<Poetry> cached = (List<Poetry>)redisTemplate.opsForValue().get(cacheKey);
if (cached != null) return cached;
List<Poetry> result = this.lambdaQuery()
.orderByDesc(Poetry::getViewCount)
.last("LIMIT " + limit)
.list();
redisTemplate.opsForValue().set(cacheKey, result, 1, TimeUnit.HOURS);
return result;
}
3.2 用户认证系统
采用JWT实现无状态认证,关键流程包括:
- 登录流程:
java复制@PostMapping("/login")
public Result<String> login(@RequestBody LoginDTO dto) {
Users user = userService.lambdaQuery()
.eq(Users::getUsername, dto.getUsername())
.one();
if (user == null || !passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
return Result.error("用户名或密码错误");
}
String token = JwtUtil.generateToken(user.getId(), user.getRole());
return Result.success(token);
}
- 权限控制:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/poetry/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
}
4. 前端工程实践
4.1 组件化开发
采用基于功能的组件划分:
PoetryCard.vue:诗词卡片展示组件CommentEditor.vue:评论编辑器组件DynamicNavbar.vue:响应式导航栏
vue复制<script setup>
// PoetryCard组件示例
const props = defineProps({
poetry: {
type: Object,
required: true
}
})
const emit = defineEmits(['view-detail'])
const handleClick = () => {
emit('view-detail', props.poetry.id)
}
</script>
<template>
<el-card @click="handleClick" class="poetry-card">
<template #header>
<h3>{{ poetry.title }}</h3>
<span class="author">{{ poetry.author }} · {{ poetry.dynasty }}</span>
</template>
<div class="content-preview">
{{ poetry.content.substring(0, 50) }}...
</div>
</el-card>
</template>
4.2 状态管理方案
使用Pinia管理全局状态:
javascript复制// stores/poetry.js
export const usePoetryStore = defineStore('poetry', {
state: () => ({
hotPoetries: [],
recentComments: []
}),
actions: {
async fetchHotPoetries() {
const res = await api.getHotPoetries()
this.hotPoetries = res.data
}
}
})
5. 系统测试与优化
5.1 性能测试指标
使用JMeter进行压力测试,关键指标:
- 单节点QPS:诗词列表接口达到1200+
- 平均响应时间:<200ms(无缓存情况下)
- 缓存命中率:热门接口达到95%+
5.2 典型优化案例
诗词详情页优化:
- 原始方案:每次请求查询数据库
- 优化方案:多级缓存策略
- 一级缓存:Redis缓存热门诗词
- 二级缓存:本地Caffeine缓存
- 回源策略:缓存穿透防护
java复制@Cacheable(value = "poetry", key = "#id")
public Poetry getByIdWithCache(Long id) {
Poetry poetry = getById(id);
if (poetry == null) {
throw new BusinessException("诗词不存在");
}
return poetry;
}
6. 部署实施方案
6.1 CI/CD流程
采用GitHub Actions实现自动化部署:
yaml复制name: Backend Deployment
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
- name: Build with Maven
run: mvn clean package -DskipTests
- name: Deploy to Server
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /opt/poetry-platform
./deploy.sh
6.2 容器化部署
Docker Compose编排方案:
dockerfile复制version: '3.8'
services:
backend:
image: poetry-backend:1.0
build: ./backend
ports:
- "8080:8080"
depends_on:
- redis
- mysql
frontend:
image: poetry-frontend:1.0
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: $DB_ROOT_PASS
MYSQL_DATABASE: poetry_db
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
volumes:
mysql_data:
7. 开发经验总结
在实际开发过程中,有几个关键点值得特别注意:
- MyBatis-Plus的Lambda查询:在复杂查询场景下,推荐使用Lambda表达式构建查询条件,既能保证类型安全,又提高代码可读性:
java复制// 不推荐
QueryWrapper<Poetry> wrapper = new QueryWrapper<>();
wrapper.like("title", keyword).or().like("author", keyword);
// 推荐使用Lambda写法
LambdaQueryWrapper<Poetry> wrapper = Wrappers.lambdaQuery();
wrapper.like(Poetry::getTitle, keyword)
.or()
.like(Poetry::getAuthor, keyword);
- Vue组合式API组织逻辑:对于复杂组件,建议按功能而非选项类型组织代码:
javascript复制// 传统选项式API
export default {
data() { /*...*/ },
methods: { /*...*/ },
computed: { /*...*/ }
}
// 推荐组合式API写法
const usePoetryLogic = () => {
const searchKeyword = ref('')
const searchResults = ref([])
const search = async () => {
// 搜索逻辑
}
return { searchKeyword, searchResults, search }
}
- 接口版本控制实践:从项目初期就应该规划API版本,避免后期兼容性问题:
java复制@RestController
@RequestMapping("/api/v1/poetry")
public class PoetryControllerV1 {
// v1版本接口
}
@RestController
@RequestMapping("/api/v2/poetry")
public class PoetryControllerV2 {
// 不兼容的v2版本接口
}
这个项目让我深刻体会到,传统文化与现代技术的结合可以产生独特的价值。在开发过程中,既要保证技术方案的先进性,又要考虑最终用户的使用体验。比如在诗词展示模块,我们特别注重排版的美观性,实现了自动断行和标点压缩算法,确保古典诗词的呈现效果符合传统阅读习惯。