1. 项目概述
这个作家信息管理系统采用了当前主流的前后端分离架构,后端基于SpringBoot框架,前端使用Vue3,数据持久层采用MyBatis,数据库选用MySQL。系统主要功能包括作家信息管理、作品管理、获奖记录管理等模块,适用于文学研究机构、出版社等需要对作家信息进行系统化管理的场景。
我在实际开发过程中发现,这种技术组合特别适合中小型信息管理系统的快速开发。SpringBoot提供了便捷的后端开发体验,Vue3的响应式特性让前端开发更加高效,而MyBatis则很好地平衡了SQL灵活性和开发效率。
2. 技术架构解析
2.1 后端技术选型
SpringBoot 2.7.x版本是这个项目的核心框架选择。这个版本在稳定性和功能完整性上达到了很好的平衡。我特别推荐使用Spring Security进行权限控制,它能够很好地与JWT配合实现前后端分离的认证方案。
数据库连接池选择了HikariCP,这是目前性能最好的Java连接池实现。在配置时需要注意:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/writer_db
username: root
password: yourpassword
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
2.2 前端技术栈
Vue3的组合式API让代码组织更加灵活。我建议使用以下核心依赖:
bash复制npm install vue@next vue-router@4 pinia axios element-plus
在实际开发中,Pinia作为状态管理库比Vuex更轻量易用。Element Plus提供了丰富的UI组件,可以显著提升开发效率。
3. 数据库设计
3.1 核心表结构
作家信息表的设计需要考虑多种情况:
sql复制CREATE TABLE `writer` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`gender` tinyint DEFAULT NULL,
`birth_date` date DEFAULT NULL,
`native_place` varchar(100) DEFAULT NULL,
`biography` text,
`photo_url` varchar(255) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
获奖记录表需要与作家表建立外键关联:
sql复制CREATE TABLE `award` (
`id` int NOT NULL AUTO_INCREMENT,
`writer_id` int NOT NULL,
`award_name` varchar(100) NOT NULL,
`award_time` date NOT NULL,
`award_work` varchar(100) DEFAULT NULL,
`award_level` varchar(50) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_writer_id` (`writer_id`),
CONSTRAINT `fk_award_writer` FOREIGN KEY (`writer_id`) REFERENCES `writer` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4. 核心功能实现
4.1 作家信息管理模块
后端Controller示例:
java复制@RestController
@RequestMapping("/api/writer")
public class WriterController {
@Autowired
private WriterService writerService;
@GetMapping("/{id}")
public Result<Writer> getById(@PathVariable Integer id) {
return Result.success(writerService.getById(id));
}
@PostMapping
public Result<Integer> create(@RequestBody Writer writer) {
return Result.success(writerService.create(writer));
}
@PutMapping("/{id}")
public Result<Boolean> update(@PathVariable Integer id, @RequestBody Writer writer) {
writer.setId(id);
return Result.success(writerService.update(writer));
}
@DeleteMapping("/{id}")
public Result<Boolean> delete(@PathVariable Integer id) {
return Result.success(writerService.delete(id));
}
@GetMapping("/page")
public Result<PageInfo<Writer>> pageQuery(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String name) {
return Result.success(writerService.pageQuery(pageNum, pageSize, name));
}
}
4.2 前端页面交互
Vue3组件示例:
vue复制<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="gender" label="性别" width="180">
<template #default="scope">
{{ scope.row.gender === 1 ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="birthDate" label="出生日期" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getWriterList } from '@/api/writer'
const tableData = ref([])
const fetchData = async () => {
const res = await getWriterList()
tableData.value = res.data
}
onMounted(() => {
fetchData()
})
const handleEdit = (row) => {
// 编辑逻辑
}
const handleDelete = (row) => {
// 删除逻辑
}
</script>
5. 系统部署方案
5.1 后端部署
推荐使用Docker部署SpringBoot应用:
dockerfile复制FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
构建并运行容器:
bash复制docker build -t writer-manager .
docker run -d -p 8080:8080 --name writer-manager writer-manager
5.2 前端部署
使用Nginx部署Vue3应用:
nginx复制server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
6. 开发经验分享
6.1 前后端联调技巧
在实际开发中,我总结了几个提高联调效率的方法:
- 使用Swagger生成API文档,后端开发完成后立即生成文档供前端参考
- 约定统一的响应格式,例如:
json复制{
"code": 200,
"message": "success",
"data": {}
}
- 使用Mock.js在前端开发阶段模拟接口数据
6.2 性能优化建议
- 数据库查询优化:
- 为常用查询字段添加索引
- 使用MyBatis的二级缓存
- 避免N+1查询问题
- 前端性能优化:
- 使用Vue3的异步组件
- 合理使用keep-alive缓存组件
- 对大型表格使用虚拟滚动
7. 常见问题解决
7.1 跨域问题
在SpringBoot中配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
7.2 MyBatis映射问题
当实体类属性与数据库字段命名不一致时,可以使用@ResultMap或直接在mapper.xml中配置:
xml复制<resultMap id="writerMap" type="com.example.model.Writer">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="birthDate" column="birth_date"/>
<!-- 其他字段映射 -->
</resultMap>
7.3 Vue3响应式问题
对于复杂对象的响应式更新,需要使用特殊处理:
javascript复制// 正确的方式
const updateWriter = (writer) => {
state.writer = {...state.writer, ...writer}
}
// 或者使用Vue3的reactive
import { reactive } from 'vue'
const state = reactive({
writer: {}
})
在实际开发中,这类技术组合的项目需要注意版本兼容性问题。建议锁定主要依赖的版本号,避免因自动升级导致的不兼容问题。同时,良好的项目结构和规范的代码风格对团队协作开发至关重要。
