1. 项目概述:Vue-SpringBoot通讯录管理系统
通讯录管理系统作为企业信息化建设的基础组件,几乎存在于每个组织的数字化架构中。这个基于Vue+SpringBoot的前后端分离项目,完美融合了现代Web开发的两大主流技术栈。前端采用Vue.js构建响应式用户界面,后端基于SpringBoot提供RESTful API服务,通过Axios实现前后端数据交互。
我在实际开发中发现,这类系统虽然表面看起来简单,但要实现企业级应用的标准,需要考虑诸多技术细节:比如联系人数据的树形组织、多终端同步机制、权限精细控制等。本系统采用典型的MVC架构模式,前端使用Vue CLI脚手架初始化工程,Element UI组件库加速界面开发;后端SpringBoot整合MyBatis-Plus实现高效数据持久化,JWT保障接口安全。
提示:对于中小型企业,通讯录系统往往需要与OA、CRM等系统对接,因此在设计之初就要考虑API的扩展性
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈选型解析
2.1 前端技术栈深度配置
Vue 3.x的组合式API相比Options API更适合复杂业务逻辑组织。我在项目中采用了以下技术组合:
- 核心框架:Vue 3.2 + Vue Router 4 + Pinia状态管理
- UI库:Element Plus(适配Vue 3的版本)
- 辅助工具:Axios封装、Day.js日期处理、VeeValidate表单验证
javascript复制// 典型API请求封装示例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000,
withCredentials: true
})
// 请求拦截器
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
},
error => {
return Promise.reject(error)
}
)
2.2 后端技术栈架构设计
SpringBoot 2.7.x版本提供了更好的性能和新特性支持。后端主要模块包括:
- 安全控制:Spring Security + JWT
- 数据持久化:MyBatis-Plus 3.5 + Druid连接池
- 工具组件:Hutool工具包、Lombok
- 接口文档:Knife4j增强Swagger
java复制// 典型Controller层设计
@RestController
@RequestMapping("/contact")
@Api(tags = "联系人管理")
public class ContactController {
@Autowired
private ContactService contactService;
@GetMapping
@ApiOperation("分页查询联系人")
public Result<PageInfo<Contact>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
return Result.success(contactService.page(pageNum, pageSize));
}
}
3. 核心功能实现细节
3.1 联系人数据结构设计
通讯录系统的核心在于联系人数据模型的设计。我采用了分层结构设计:
sql复制CREATE TABLE `contact` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '姓名',
`mobile` varchar(20) COMMENT '手机号',
`email` varchar(100) COMMENT '邮箱',
`dept_id` bigint COMMENT '所属部门',
`position` varchar(100) COMMENT '职位',
`avatar` varchar(255) COMMENT '头像URL',
`tags` json DEFAULT NULL COMMENT '标签数组',
`is_star` tinyint DEFAULT 0 COMMENT '是否星标',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_dept` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 部门树形结构实现
企业通讯录通常需要展示组织架构树,这里使用MP的Lambda查询:
java复制public List<DeptTree> buildDeptTree() {
List<Dept> depts = baseMapper.selectList(
Wrappers.<Dept>lambdaQuery()
.orderByAsc(Dept::getSort)
);
return buildTree(depts, 0L);
}
private List<DeptTree> buildTree(List<Dept> depts, Long parentId) {
return depts.stream()
.filter(d -> parentId.equals(d.getParentId()))
.map(d -> {
DeptTree node = new DeptTree(d);
node.setChildren(buildTree(depts, d.getId()));
return node;
}).collect(Collectors.toList());
}
3.3 文件导入导出功能
使用EasyExcel处理大批量数据导入导出:
java复制// 导出Excel示例
@GetMapping("/export")
public void export(HttpServletResponse response) {
List<Contact> list = contactService.list();
String fileName = "通讯录_" + System.currentTimeMillis() + ".xlsx";
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition",
"attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
EasyExcel.write(response.getOutputStream(), Contact.class)
.sheet("联系人")
.doWrite(list);
}
4. 系统安全与性能优化
4.1 接口安全防护体系
采用分层安全策略:
- 传输层:HTTPS + 请求签名
- 认证层:JWT + Redis黑名单
- 权限层:RBAC模型控制
- 数据层:SQL注入防护、XSS过滤
java复制// JWT认证过滤器关键代码
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain) {
String token = resolveToken(request);
if (token != null && jwtProvider.validateToken(token)) {
Authentication auth = jwtProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
4.2 性能优化实践
- 前端优化:
- 路由懒加载
- 组件异步加载
- 列表虚拟滚动
- 后端优化:
yaml复制# MyBatis-Plus配置
mybatis-plus:
configuration:
cache-enabled: true
default-executor-type: reuse
global-config:
db-config:
logic-delete-field: deleted
logic-not-delete-value: 0
logic-delete-value: 1
- 缓存策略:
java复制@Cacheable(value = "contact", key = "#id")
public Contact getById(Long id) {
return getById(id);
}
@CacheEvict(value = "contact", key = "#contact.id")
public boolean update(Contact contact) {
return updateById(contact);
}
5. 典型问题排查实录
5.1 跨域问题解决方案
开发环境配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
生产环境推荐使用Nginx反向代理:
nginx复制location /api {
proxy_pass http://backend;
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Credentials' 'true';
# 其他CORS头...
}
5.2 大文件上传断点续传
前端实现:
vue复制<template>
<el-upload
:action="uploadUrl"
:before-upload="beforeUpload"
:on-progress="onProgress"
:http-request="customRequest">
</el-upload>
</template>
<script>
export default {
methods: {
async customRequest(options) {
const chunkSize = 2 * 1024 * 1024; // 2MB
const file = options.file;
const chunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < chunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
await this.uploadChunk(chunk, i, file.name);
}
}
}
}
</script>
后端分片处理:
java复制@PostMapping("/upload")
public Result upload(@RequestParam("file") MultipartFile file,
@RequestParam("chunkNumber") int chunkNumber,
@RequestParam("totalChunks") int totalChunks) {
String tempDir = "/tmp/upload/" + file.getOriginalFilename();
File chunkFile = new File(tempDir, chunkNumber + ".part");
file.transferTo(chunkFile);
if (chunkNumber == totalChunks - 1) {
mergeFiles(tempDir, file.getOriginalFilename());
}
return Result.success();
}
6. 项目部署方案
6.1 前端部署优化
生产环境构建配置:
javascript复制// vue.config.js
module.exports = {
productionSourceMap: false,
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial'
},
elementUI: {
name: 'chunk-elementUI',
priority: 20,
test: /[\\/]node_modules[\\/]_?element-ui(.*)/
}
}
}
}
}
}
6.2 后端Docker化部署
Dockerfile示例:
dockerfile复制FROM openjdk:11-jre-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
docker-compose集成:
yaml复制version: '3'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: contact_db
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
mysql_data:
在项目开发过程中,我特别推荐使用Git Submodule管理前后端代码仓库的分离与协同。对于企业级应用,可以考虑引入Spring Cloud Alibaba组件实现微服务化改造,将用户服务、部门服务等拆分为独立模块。前端方面,如果预计会有移动端需求,可以提前考虑采用Uniapp进行多端适配开发。
