1. 项目概述:基于SpringBoot2+Vue3的客户关系管理系统
这套客户关系管理系统(CRM)源码采用前后端分离架构,后端基于SpringBoot2框架构建,前端使用Vue3实现响应式界面,数据持久层采用MyBatis-Plus操作MySQL8.0数据库。系统包含完整的权限管理、客户信息管理、销售机会跟踪、合同管理等功能模块,配套的开发文档详细说明了系统架构设计、API接口规范以及部署流程。
提示:本系统适合作为企业级CRM基础框架进行二次开发,也可用于学习现代Java Web全栈技术栈的整合实践。源码经过生产环境验证,采用MIT开源协议发布。
2. 技术栈深度解析
2.1 后端技术选型
SpringBoot2作为基础框架提供了以下核心优势:
- 自动配置机制简化了SSM框架的整合流程
- 内嵌Tomcat服务器实现开箱即用
- Actuator端点提供完善的系统监控能力
- 与MyBatis-Plus的深度整合(通过
mybatis-spring-boot-starter依赖)
MyBatis-Plus在项目中主要解决了:
- 通用CRUD操作的自动化生成(BaseMapper)
- 动态SQL的优雅实现(Wrapper条件构造器)
- 分页插件的零配置整合(PaginationInterceptor)
- 逻辑删除的声明式支持(@TableLogic)
数据库设计特点:
sql复制CREATE TABLE `crm_customer` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(50) NOT NULL COMMENT '客户名称',
`level` tinyint DEFAULT '1' COMMENT '客户等级(1-5)',
`source` varchar(20) DEFAULT NULL COMMENT '客户来源',
`industry` varchar(30) DEFAULT NULL COMMENT '所属行业',
`credit_rating` varchar(10) DEFAULT NULL COMMENT '信用评级',
`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 COLLATE=utf8mb4_0900_ai_ci;
2.2 前端架构设计
Vue3的组合式API带来显著改进:
javascript复制// 客户列表查询逻辑
const queryParams = reactive({
name: '',
level: null,
pageNum: 1,
pageSize: 10
})
const { loading, data, total } = useAxiosGet('/api/customer/list', {
params: queryParams
})
// 分页处理
const handlePageChange = (val) => {
queryParams.pageNum = val
}
Element Plus组件库的典型应用:
vue复制<el-table :data="data.list" v-loading="loading">
<el-table-column prop="name" label="客户名称" />
<el-table-column prop="level" label="等级">
<template #default="{row}">
<el-tag :type="['','success','warning','danger','info'][row.level-1]">
{{ ['普通','重要','VIP','战略','合作伙伴'][row.level-1] }}
</el-tag>
</template>
</el-table-column>
</el-table>
3. 核心功能实现细节
3.1 权限控制系统
RBAC模型实现方案:
java复制@RestController
@RequestMapping("/api/customer")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerService customerService;
@GetMapping("/list")
@PreAuthorize("hasRole('sales') or hasRole('admin')")
public R list(CustomerQuery query) {
return R.ok(customerService.page(query));
}
}
前端路由守卫配置:
javascript复制router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !store.getters.token) {
next('/login?redirect=' + encodeURIComponent(to.fullPath))
} else {
next()
}
})
3.2 数据可视化看板
ECharts集成示例:
javascript复制const initChart = () => {
const chart = echarts.init(document.getElementById('chart'))
chart.setOption({
tooltip: { trigger: 'item' },
series: [{
type: 'pie',
data: [
{ value: 35, name: '互联网' },
{ value: 28, name: '金融' }
]
}]
})
window.addEventListener('resize', chart.resize)
}
4. 系统部署指南
4.1 后端部署要点
- 数据库初始化:
bash复制mysql -u root -p < schema.sql
mysql -u root -p < data.sql
- 应用打包配置:
xml复制<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
4.2 前端部署流程
生产环境构建优化:
javascript复制// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
Nginx配置示例:
nginx复制server {
listen 80;
server_name crm.example.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
}
5. 开发常见问题排查
5.1 跨域问题解决方案
SpringBoot配置类:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.maxAge(3600);
}
}
5.2 MyBatis-Plus分页失效处理
检查配置类是否缺失:
java复制@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
5.3 Vue3路由缓存问题
组件级解决方案:
vue复制<router-view v-slot="{ Component }">
<keep-alive :include="['CustomerList']">
<component :is="Component" />
</keep-alive>
</router-view>
6. 性能优化实践
6.1 数据库查询优化
慢SQL监控配置:
properties复制# application.properties
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=1000
索引优化示例:
sql复制ALTER TABLE crm_contract
ADD INDEX idx_customer_status (customer_id, contract_status);
6.2 前端性能提升
组件异步加载:
javascript复制const CustomerDetail = defineAsyncComponent(() =>
import('./views/customer/Detail.vue')
)
API请求节流:
javascript复制import { throttle } from 'lodash-es'
const search = throttle(() => {
getList()
}, 1000)
7. 扩展开发建议
7.1 微信集成方案
公众号消息处理:
java复制@RestController
@RequestMapping("/wechat")
public class WechatController {
@PostMapping
public String handleMessage(@RequestBody String xml) {
// 解析XML消息
Map<String,String> map = XmlUtil.parseXml(xml);
if ("event".equals(map.get("MsgType"))) {
return TextMessage.create(map.get("FromUserName"), "欢迎关注");
}
return "success";
}
}
7.2 工作流引擎集成
Activiti整合步骤:
xml复制<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
审批流程示例BPMN:
xml复制<process id="contract-approval" name="合同审批流程">
<startEvent id="start"/>
<userTask id="dept-approve" name="部门审批"/>
<sequenceFlow sourceRef="start" targetRef="dept-approve"/>
</process>
8. 安全防护措施
8.1 SQL注入防护
MyBatis-Plus安全写法:
java复制QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(User::getName, name)
.apply("date(create_time) = {0}", date);
8.2 XSS防御方案
前端过滤器:
javascript复制const xssFilter = (str) => {
return str.replace(/</g, '<').replace(/>/g, '>')
}
后端统一处理:
java复制@ControllerAdvice
public class XssAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
// 使用Jackson进行XSS过滤
}
}
9. 监控与日志系统
9.1 SpringBoot Actuator配置
安全端点暴露:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=when_authorized
自定义指标:
java复制@RestController
public class MetricsController {
private final Counter counter;
public MetricsController(MeterRegistry registry) {
this.counter = registry.counter("api.call.count");
}
@GetMapping("/api")
public String api() {
counter.increment();
return "OK";
}
}
9.2 前端埋点方案
用户行为跟踪:
javascript复制const track = (event, payload) => {
navigator.sendBeacon('/log', JSON.stringify({
event,
payload,
timestamp: Date.now(),
path: location.pathname
}))
}
10. 测试策略实施
10.1 后端测试方案
JUnit5集成测试:
java复制@SpringBootTest
class CustomerServiceTest {
@Autowired
private CustomerService service;
@Test
@Transactional
@Rollback
void testCreateCustomer() {
Customer customer = new Customer();
customer.setName("测试客户");
assertNotNull(service.save(customer));
}
}
10.2 前端测试方案
Vitest组件测试:
javascript复制import { mount } from '@vue/test-utils'
import CustomerForm from './CustomerForm.vue'
test('form validation', async () => {
const wrapper = mount(CustomerForm)
await wrapper.find('form').trigger('submit')
expect(wrapper.text()).toContain('名称不能为空')
})
11. 容器化部署方案
11.1 Docker镜像构建
后端Dockerfile:
dockerfile复制FROM openjdk:17-jdk-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
前端Dockerfile:
dockerfile复制FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
11.2 Kubernetes部署
Deployment示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: crm-backend
spec:
replicas: 3
selector:
matchLabels:
app: crm-backend
template:
metadata:
labels:
app: crm-backend
spec:
containers:
- name: app
image: registry.example.com/crm-backend:v1.2.0
ports:
- containerPort: 8080
12. 文档体系说明
12.1 API文档生成
Swagger配置类:
java复制@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.crm"))
.build();
}
}
12.2 数据库文档
Screw自动生成配置:
xml复制<plugin>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-maven-plugin</artifactId>
<version>1.0.5</version>
<configuration>
<databaseType>MYSQL</databaseType>
<title>CRM系统数据库文档</title>
</configuration>
</plugin>
13. 二次开发指南
13.1 模块扩展建议
- 客户画像分析模块
- 移动端适配方案
- 第三方系统对接(ERP、OA等)
- 数据大屏可视化
- 智能客服集成
13.2 代码规范检查
Git预提交钩子配置:
bash复制#!/bin/sh
mvn checkstyle:check
if [ $? -ne 0 ]; then
echo "代码规范检查未通过!"
exit 1
fi
14. 项目升级路径
14.1 SpringBoot3升级要点
- Jakarta EE 9命名空间变更
- Hibernate6兼容性调整
- 废弃配置属性处理
- 测试框架JUnit5全面支持
14.2 Vue3组合式API重构
选项式到组合式改造示例:
javascript复制// 改造前
export default {
data() {
return { count: 0 }
},
methods: {
increment() { this.count++ }
}
}
// 改造后
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
15. 商业应用建议
15.1 SaaS化改造方案
- 多租户数据库设计
- 订阅计费系统集成
- 自定义字段功能
- 白标品牌定制
15.2 私有化部署包
一键安装脚本示例:
bash复制#!/bin/bash
# 检查Docker环境
if ! command -v docker &> /dev/null; then
curl -fsSL https://get.docker.com | sh
fi
# 启动MySQL容器
docker run -d --name crm-mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
mysql:8.0
# 导入初始数据
docker exec -i crm-mysql mysql -uroot -p123456 < init.sql
