1. 项目背景与核心需求
小型企业客户关系管理系统(CRM)是当前数字化转型浪潮中的刚需产品。根据我过去为3家小微企业实施CRM系统的经验,传统Excel管理客户的方式存在数据分散、跟进记录缺失、商机转化率低等痛点。而市面上的成熟CRM产品如Salesforce、Dynamics 365往往功能冗余且价格高昂,这正是SpringBoot技术栈在毕业设计选题中的价值所在。
这个毕业设计项目的核心要解决四个业务痛点:
- 客户信息碎片化:名片、微信联系人、Excel表格等多渠道数据无法统一管理
- 销售过程不透明:业务员外出拜访记录难以追踪,历史沟通记录缺失
- 商机转化率低:缺乏销售漏斗分析,无法识别关键转化节点
- 移动办公需求:小微企业员工常需在外访问系统
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 为什么选择SpringBoot
在比对了PHP Laravel、Python Django等框架后,SpringBoot的三大优势使其成为首选:
- 内嵌Tomcat:无需单独部署Web服务器,
java -jar即可启动,这对毕业设计演示特别友好 - 自动配置:通过
spring-boot-starter-data-jpa等starter依赖快速集成持久层 - 监控端点:
/actuator端点天然适合展示系统运行状态(内存、线程等指标)
实际开发中我推荐使用2.7.x版本(当前最新2.7.18),避免直接使用3.x系列可能遇到的Jakarta EE兼容性问题。
2.2 分层架构设计
系统采用经典三层架构,但针对CRM特性做了调整:
code复制com.crm
├── config # 安全/JPA等配置类
├── controller # 前后端分离接口层
├── service # 业务逻辑层
│ ├── impl # 实现类
│ └── task # 定时任务
├── repository # JPA数据访问层
├── model # 实体类
│ ├── dto # 数据传输对象
│ └── vo # 视图对象
└── exception # 全局异常处理
特别要注意的是Customer实体的设计,需要包含动态字段扩展能力:
java复制@Entity
public class Customer {
@Id @GeneratedValue
private Long id;
private String name;
private String phone;
@ElementCollection
@CollectionTable(name="customer_extra_fields")
private Map<String,String> customFields; // 动态扩展字段
}
3. 核心功能实现细节
3.1 客户信息管理模块
这是系统的核心模块,开发时容易踩三个坑:
- 数据去重:通过
@Query实现手机号/邮箱模糊匹配
java复制@Repository
public interface CustomerRepo extends JpaRepository<Customer, Long> {
@Query("SELECT c FROM Customer c WHERE c.phone LIKE %:keyword% OR c.email LIKE %:keyword%")
List<Customer> search(@Param("keyword") String keyword);
}
- 联系人时间轴:使用Hibernate的
@OneToMany级联操作
java复制public class Customer {
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
private List<ContactRecord> records; // 沟通记录
}
- Excel导入导出:推荐使用EasyExcel避免OOM
java复制// 导出示例
public void export(HttpServletResponse response) {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
EasyExcel.write(response.getOutputStream(), Customer.class)
.sheet("客户列表").doWrite(dataList);
}
3.2 销售漏斗分析
这是毕业设计的亮点功能,实现要点:
- 使用枚举定义销售阶段:
java复制public enum SalesStage {
INITIAL_CONTACT(1),
NEEDS_ANALYSIS(2),
PROPOSAL(3),
NEGOTIATION(4),
CLOSED(5);
private int order;
// getter/setter...
}
- 漏斗统计SQL(MySQL语法):
sql复制SELECT
stage,
COUNT(*) as count,
CONCAT(ROUND(COUNT(*)/MAX(total)*100,2),'%') as ratio
FROM (
SELECT
o.stage,
(SELECT COUNT(*) FROM opportunity) as total
FROM opportunity o
WHERE o.deleted = false
) t GROUP BY stage ORDER BY stage;
4. 关键问题解决方案
4.1 权限控制设计
小微企业CRM的权限系统不宜过于复杂,推荐RBAC模型实现:
- 数据库设计:
sql复制CREATE TABLE `sys_user` (
`id` BIGINT PRIMARY KEY,
`username` VARCHAR(50) UNIQUE,
`password` VARCHAR(100) -- BCrypt加密
);
CREATE TABLE `sys_role` (
`id` INT PRIMARY KEY,
`name` VARCHAR(20) -- SALES/MANAGER/ADMIN
);
CREATE TABLE `sys_user_role` (
`user_id` BIGINT,
`role_id` INT,
PRIMARY KEY (`user_id`, `role_id`)
);
- Spring Security配置要点:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/sales/**").hasAnyRole("SALES","MANAGER")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthFilter(authenticationManager()));
return http.build();
}
}
4.2 移动端适配方案
考虑到毕业设计展示需要,推荐两种方案:
- 响应式前端:使用Vue+Element Plus的Layout组件
vue复制<template>
<el-container>
<el-header>CRM系统</el-header>
<el-container>
<el-aside width="200px">...</el-aside>
<el-main>
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8">...</el-col>
</el-row>
</el-main>
</el-container>
</el-container>
</template>
- 微信小程序对接(加分项):
java复制@RestController
@RequestMapping("/wechat")
public class WechatController {
@GetMapping("/login")
public ResponseEntity<String> wechatLogin(
@RequestParam String code) {
// 调用微信API获取openid
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?"
+ "appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code";
// 使用RestTemplate调用
Map<String,String> result = restTemplate.getForObject(
apiUrl, Map.class, appId, appSecret, code);
return ResponseEntity.ok(result.get("openid"));
}
}
5. 毕业设计特别注意事项
5.1 文档编写要点
根据指导老师反馈的常见问题,文档要特别注意:
- ER图规范:使用PowerDesigner或Draw.io绘制,包含所有字段类型和关系
- 接口文档:推荐使用Swagger UI自动生成
java复制@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.crm.controller"))
.paths(PathSelectors.any())
.build();
}
}
- 答辩演示脚本:准备3个典型用户场景
- 销售员小王录入新客户
- 销售经理查看团队漏斗报表
- 管理员配置自定义字段
5.2 性能优化技巧
避免毕业答辩时系统卡顿的实用方法:
- N+1查询问题:在Repository方法上加
@EntityGraph
java复制@EntityGraph(attributePaths = {"records"})
List<Customer> findAllWithRecordsBy();
- 缓存策略:对静态字典数据使用Spring Cache
java复制@Service
public class DictService {
@Cacheable(value = "regionCache")
public List<Region> getAllRegions() {
return regionRepo.findAll();
}
}
- 批量插入:使用JPA的
saveAll()而非循环save
java复制List<Customer> batch = new ArrayList<>(1000);
// 填充数据...
customerRepo.saveAll(batch);
6. 项目扩展方向
如果想在基础功能上增加亮点,可以考虑:
- 客户画像分析:集成HanLP分词实现沟通记录关键词提取
java复制public class HanLPService {
public List<String> extractKeywords(String text) {
return HanLP.extractKeyword(text, 5);
}
}
- 自动化邮件跟进:结合Quartz定时任务
java复制public class FollowUpJob implements Job {
@Autowired
private EmailService emailService;
@Override
public void execute(JobExecutionContext context) {
List<Customer> targets = findCustomersNeedFollowUp();
targets.forEach(c -> emailService.send(
c.getEmail(),
"跟进提醒",
buildEmailContent(c)));
}
}
- 数据可视化大屏:通过ECharts展示
javascript复制// 在Vue中示例
import * as echarts from 'echarts';
export default {
mounted() {
const chart = echarts.init(this.$refs.chart);
chart.setOption({
tooltip: {...},
series: [{
type: 'funnel',
data: [...]
}]
});
}
}
在系统部署阶段,建议使用Docker-compose一键部署:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
