毕业设计实战:基于SSM的客户关系管理系统毕设全流程指南✨
去年做客户关系管理系统毕设时,我在客户积分和沟通记录的关联逻辑上卡了整整4天——一开始没处理"积分自动计算"问题,客户沟通后积分没实时更新,导师演示时直接发现了这个重大业务漏洞😫 经过反复修改优化,终于总结出了这套客户关系管理系统毕设实战经验!
一、需求分析:抓住客户管理核心业务
刚开始我想做一个"万能企业管理系统",包含了OA办公、财务管理、人力资源等模块,结果导师说"重点不突出,核心客户关系管理不清晰"。后来明白,客户关系管理系统要围绕线索-客户-沟通-积分这个核心业务链展开。
1. 核心用户角色与功能
系统主要面向两类用户,功能定位要精准:
-
管理员端(系统管理核心):
- 员工管理:管理员工信息、设置员工权限、禁用/启用账号
- 客户管理:审核客户信息、分配客户给员工、查看客户详情
- 线索管理:管理潜在客户线索、分配线索跟进、转化线索为客户
- 数据统计:客户数据分析、员工业绩统计、积分排名统计
-
员工端(业务执行核心):
- 客户跟进:管理分配到的客户、记录客户信息、更新客户状态
- 沟通记录:记录与客户的沟通内容、设置下次跟进时间、上传沟通附件
- 积分管理:为客户添加积分、查看积分明细、兑换积分奖励
- 线索转化:跟进潜在客户线索、将合格线索转化为正式客户
2. 需求分析实战技巧
- 企业调研很重要:我联系了几个销售团队,发现他们最需要"客户状态跟踪"功能,于是重点设计了客户生命周期管理
- 绘制业务流程图:用DrawIO画出"线索获取→员工跟进→转化为客户→持续沟通→积分管理"的完整流程,答辩时清晰展示业务逻辑
- 明确业务规则:如"沟通后自动记录积分""线索7天内必须跟进""客户分配给员工后不能重复分配"等约束条件
3. 可行性分析要点
- 技术可行性:SSM+MySQL技术成熟,企业应用广泛
- 经济可行性:全部使用开源工具,零开发成本
- 操作可行性:界面设计参考主流CRM系统,销售易上手
二、技术选型:企业级开发方案
曾经尝试用Spring Boot,但为了体现传统框架掌握程度,最终选择SSM框架,更显技术功底!
1. 技术栈选择理由
| 技术组件 | 选择理由 | 避坑提醒 |
|---|---|---|
| Spring 5.x | IOC和AOP支持完善 | 注意bean的配置管理 |
| Spring MVC | 请求处理流程清晰 | 注意拦截器配置 |
| MyBatis | SQL可控性强,方便优化 | 注意XML映射文件配置 |
| MySQL 8.0 | 事务支持完善,适合企业系统 | 配置连接池参数 |
| Maven | 依赖管理规范 | 注意依赖冲突解决 |
| Tomcat 9 | 稳定可靠 | 配置虚拟内存大小 |
2. 开发环境搭建
<!-- pom.xml 关键依赖 -->
<dependencies>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- MyBatis-Spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
三、数据库设计:客户关系业务数据建模
最初设计时把客户信息和沟通记录放在同一张表,导致查询性能低下。重新设计后按业务模块分表,系统响应速度大幅提升。
1. 核心数据表设计
客户表(kehu)
CREATE TABLE `kehu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`yuangong_id` int(11) NOT NULL COMMENT '负责员工ID',
`kehu_name` varchar(100) NOT NULL COMMENT '客户姓名',
`kehu_phone` varchar(20) NOT NULL COMMENT '客户手机号',
`kehu_id_number` varchar(20) DEFAULT NULL COMMENT '客户身份证号',
`kehu_photo` varchar(255) DEFAULT NULL COMMENT '客户照片',
`sex_types` int(11) DEFAULT NULL COMMENT '性别',
`kehu_email` varchar(100) DEFAULT NULL COMMENT '电子邮箱',
`kehu_jifen_number` decimal(10,2) DEFAULT '0.00' COMMENT '积分',
`kehu_level` int(11) DEFAULT '1' COMMENT '客户等级:1普通/2VIP/3SVIP',
`kehu_status` int(11) DEFAULT '1' COMMENT '客户状态:1潜在/2活跃/3沉默/4流失',
`kehu_content` text COMMENT '客户详细介绍',
`last_contact_time` datetime DEFAULT NULL COMMENT '最后联系时间',
`next_contact_time` datetime DEFAULT NULL COMMENT '下次联系时间',
`insert_time` datetime DEFAULT NULL COMMENT '添加时间',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_phone` (`kehu_phone`),
KEY `idx_yuangong` (`yuangong_id`),
KEY `idx_status` (`kehu_status`),
KEY `idx_level` (`kehu_level`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户表';
沟通记录表(goutongjilu)
CREATE TABLE `goutongjilu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`yuangong_id` int(11) NOT NULL COMMENT '员工ID',
`kehu_id` int(11) NOT NULL COMMENT '客户ID',
`goutong_name` varchar(200) NOT NULL COMMENT '沟通标题',
`goutong_types` int(11) DEFAULT NULL COMMENT '沟通类型',
`goutong_time` datetime NOT NULL COMMENT '沟通时间',
`goutong_content` text NOT NULL COMMENT '沟通详情',
`goutong_result` text COMMENT '沟通结果',
`next_plan` text COMMENT '下次计划',
`jifen_add` decimal(10,2) DEFAULT '0.00' COMMENT '本次增加积分',
`insert_time` datetime DEFAULT NULL COMMENT '添加时间',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_yuangong` (`yuangong_id`),
KEY `idx_kehu` (`kehu_id`),
KEY `idx_time` (`goutong_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='沟通记录表';
客户积分表(kehujifen)
CREATE TABLE `kehujifen` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`yuangong_id` int(11) NOT NULL COMMENT '员工ID',
`kehu_id` int(11) NOT NULL COMMENT '客户ID',
`kehujifen_types` int(11) NOT NULL COMMENT '增加类型',
`kehujifen_content` text COMMENT '备注',
`kehujifen_number` decimal(10,2) NOT NULL COMMENT '增加积分数量',
`related_id` int(11) DEFAULT NULL COMMENT '关联记录ID',
`related_type` varchar(50) DEFAULT NULL COMMENT '关联类型',
`insert_time` datetime DEFAULT NULL COMMENT '增加时间',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_kehu` (`kehu_id`),
KEY `idx_yuangong` (`yuangong_id`),
KEY `idx_time` (`insert_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户积分表';
2. 表关系设计要点
- 状态字段设计:客户状态(潜在/活跃/沉默/流失)、客户等级(普通/VIP/SVIP)
- 积分关联:沟通记录与积分变动关联,实现积分自动计算
- 时间跟踪:记录最后联系时间和下次联系时间,方便跟进
四、核心功能实现与代码详解
1. 客户管理模块(核心业务功能)
Service层实现:
@Service
public class KehuServiceImpl implements KehuService {
@Autowired
private KehuMapper kehuMapper;
@Autowired
private KehujifenMapper kehujifenMapper;
@Autowired
private GoutongjiluMapper goutongjiluMapper;
@Override
@Transactional
public void addKehu(KehuEntity kehu) {
// 1. 检查手机号是否重复
Integer count = kehuMapper.selectCount(
new EntityWrapper<KehuEntity>()
.eq("kehu_phone", kehu.getKehuPhone())
);
if (count > 0) {
throw new RuntimeException("客户手机号已存在");
}
// 2. 设置初始状态
kehu.setKehuStatus(1); // 潜在客户
kehu.setKehuLevel(1); // 普通客户
kehu.setKehuJifenNumber(new BigDecimal("0")); // 初始积分
kehu.setInsertTime(new Date());
kehuMapper.insert(kehu);
}
@Override
@Transactional
public void updateKehuStatus(Integer kehuId, Integer status) {
KehuEntity kehu = new KehuEntity();
kehu.setId(kehuId);
kehu.setKehuStatus(status);
kehuMapper.updateById(kehu);
// 记录状态变更日志
logKehuStatusChange(kehuId, status);
}
@Override
public PageUtils queryKehuPage(Map<String, Object> params, Integer yuangongId) {
Page<KehuEntity> page = new Page<>(
Integer.parseInt(params.get("page").toString()),
Integer.parseInt(params.get("limit").toString())
);
EntityWrapper<KehuEntity> ew = new EntityWrapper<>();
// 员工只能查看自己的客户
if (yuangongId != null) {
ew.eq("yuangong_id", yuangongId);
}
// 客户姓名模糊查询
if (params.get("kehuName") != null) {
ew.like("kehu_name", params.get("kehuName").toString());
}
// 客户状态筛选
if (params.get("kehuStatus") != null) {
ew.eq("kehu_status", params.get("kehuStatus"));
}
// 客户等级筛选
if (params.get("kehuLevel") != null) {
ew.eq("kehu_level", params.get("kehuLevel"));
}
ew.orderBy("insert_time", false);
IPage<KehuEntity> result = kehuMapper.selectPage(page, ew);
return new PageUtils(result);
}
}
Controller层:
@Controller
@RequestMapping("/kehu")
public class KehuController {
@Autowired
private KehuService kehuService;
@RequestMapping("/list")
public String list(@RequestParam Map<String, Object> params,
HttpServletRequest request, Model model) {
// 获取当前登录员工
YuangongEntity yuangong = (YuangongEntity) request.getSession().getAttribute("yuangong");
PageUtils page = kehuService.queryKehuPage(params, yuangong.getId());
model.addAttribute("page", page);
model.addAttribute("params", params);
return "kehu/list";
}
@PostMapping("/save")
@ResponseBody
public R save(@RequestBody KehuEntity kehu, HttpServletRequest request) {
try {
// 设置负责员工
YuangongEntity yuangong = (YuangongEntity) request.getSession().getAttribute("yuangong");
kehu.setYuangongId(yuangong.getId());
kehuService.addKehu(kehu);
return R.ok();
} catch (Exception e) {
return R.error(e.getMessage());
}
}
}
2. 沟通记录与积分管理模块
Service层实现:
@Service
public class GoutongjiluServiceImpl implements GoutongjiluService {
@Autowired
private GoutongjiluMapper goutongjiluMapper;
@Autowired
private KehuMapper kehuMapper;
@Autowired
private KehujifenMapper kehujifenMapper;
@Override
@Transactional
public void addGoutong(GoutongjiluEntity goutong) {
// 1. 保存沟通记录
goutong.setInsertTime(new Date());
goutongjiluMapper.insert(goutong);
// 2. 自动计算并添加积分
BigDecimal jifenAdd = calculateJifen(goutong);
if (jifenAdd.compareTo(BigDecimal.ZERO) > 0) {
addKehuJifen(goutong, jifenAdd);
}
// 3. 更新客户最后联系时间
updateKehuContactTime(goutong.getKehuId());
}
private BigDecimal calculateJifen(GoutongjiluEntity goutong) {
// 根据沟通类型计算积分
// 1-电话沟通:10分,2-面谈:20分,3-微信沟通:5分,4-邮件沟通:3分
switch (goutong.getGoutongTypes()) {
case 1: return new BigDecimal("10");
case 2: return new BigDecimal("20");
case 3: return new BigDecimal("5");
case 4: return new BigDecimal("3");
default: return BigDecimal.ZERO;
}
}
private void addKehuJifen(GoutongjiluEntity goutong, BigDecimal jifenAdd) {
// 添加积分记录
KehujifenEntity jifen = new KehujifenEntity();
jifen.setYuangongId(goutong.getYuangongId());
jifen.setKehuId(goutong.getKehuId());
jifen.setKehujifenTypes(1); // 沟通增加
jifen.setKehujifenContent("沟通记录积分:" + goutong.getGoutongName());
jifen.setKehujifenNumber(jifenAdd);
jifen.setRelatedId(goutong.getId());
jifen.setRelatedType("goutong");
jifen.setInsertTime(new Date());
kehujifenMapper.insert(jifen);
// 更新客户总积分
KehuEntity kehu = kehuMapper.selectById(goutong.getKehuId());
kehu.setKehuJifenNumber(kehu.getKehuJifenNumber().add(jifenAdd));
kehuMapper.updateById(kehu);
// 检查是否需要升级客户等级
checkKehuLevel(kehu);
}
private void checkKehuLevel(KehuEntity kehu) {
BigDecimal totalJifen = kehu.getKehuJifenNumber();
Integer newLevel = kehu.getKehuLevel();
if (totalJifen.compareTo(new BigDecimal("1000")) >= 0) {
newLevel = 3; // SVIP
} else if (totalJifen.compareTo(new BigDecimal("500")) >= 0) {
newLevel = 2; // VIP
} else {
newLevel = 1; // 普通
}
if (!newLevel.equals(kehu.getKehuLevel())) {
kehu.setKehuLevel(newLevel);
kehuMapper.updateById(kehu);
}
}
}
3. 客户线索转化模块
Service层实现:
@Service
public class KehuxiansuoServiceImpl implements KehuxiansuoService {
@Autowired
private KehuxiansuoMapper kehuxiansuoMapper;
@Autowired
private KehuMapper kehuMapper;
@Override
@Transactional
public void convertToKehu(Integer xiansuoId, Integer yuangongId) {
KehuxiansuoEntity xiansuo = kehuxiansuoMapper.selectById(xiansuoId);
if (xiansuo == null) {
throw new RuntimeException("客户线索不存在");
}
// 检查是否已转化
if (xiansuo.getConvertStatus() == 1) {
throw new RuntimeException("该线索已转化为客户");
}
// 创建客户
KehuEntity kehu = new KehuEntity();
kehu.setYuangongId(yuangongId);
kehu.setKehuName(xiansuo.getKehuxiansuoName());
kehu.setKehuPhone(xiansuo.getKehuxiansuoPhone());
kehu.setKehuIdNumber(xiansuo.getKehuxiansuoIdNumber());
kehu.setKehuPhoto(xiansuo.getKehuxiansuoPhoto());
kehu.setSexTypes(xiansuo.getSexTypes());
kehu.setKehuEmail(xiansuo.getKehuxiansuoEmail());
kehu.setKehuJifenNumber(BigDecimal.ZERO);
kehu.setKehuStatus(1); // 潜在客户
kehu.setKehuLevel(1); // 普通客户
kehu.setInsertTime(new Date());
kehuMapper.insert(kehu);
// 更新线索状态
xiansuo.setConvertStatus(1); // 已转化
xiansuo.setConvertTime(new Date());
xiansuo.setConvertKehuId(kehu.getId());
kehuxiansuoMapper.updateById(xiansuo);
}
}
五、系统测试:确保客户管理业务流程可靠
曾经以为功能实现就完成了,结果测试时发现沟通后积分没自动计算,紧急加了积分自动计算逻辑。
1. 功能测试用例
客户管理测试:
| 测试场景 | 操作步骤 | 预期结果 |
|---|---|---|
| 重复客户 | 添加手机号重复的客户 | 提示"客户手机号已存在" |
| 客户转化 | 将线索转化为客户 | 客户创建成功,线索状态更新 |
| 状态变更 | 修改客户状态 | 状态更新成功,记录变更日志 |
沟通积分测试:
| 测试场景 | 操作步骤 | 预期结果 |
|---|---|---|
| 电话沟通 | 记录电话沟通 | 自动增加10积分 |
| 面谈沟通 | 记录面谈沟通 | 自动增加20积分 |
| 等级提升 | 积分达到阈值 | 自动升级客户等级 |
2. 业务规则测试
- 积分自动计算:不同沟通类型对应不同积分值
- 等级自动调整:积分达到阈值自动调整客户等级
- 状态流转:线索转化为客户的状态同步
- 权限控制:员工只能操作自己的客户数据
六、部署与演示准备
1. 数据库初始化脚本
-- 插入测试数据
INSERT INTO `yuangong` VALUES
(1, '张三', '13800138000', '110101199001011234', '/images/emp1.jpg', 'zhangsan@qq.com', 1, NOW());
INSERT INTO `kehu` VALUES
(1, 1, '李客户', '13800138001', '110101199001011235', '/images/cus1.jpg', 1, 'likehu@qq.com', 0.00, 1, 1, '重要客户', NOW(), NULL, NOW(), NOW());
INSERT INTO `kehuxiansuo` VALUES
(1, 1, '王线索', '13800138002', '110101199001011236', '/images/lead1.jpg', 1, 'wangxiansuo@qq.com', 1, '潜在客户线索', 0, NULL, NULL, NOW(), NOW());
2. 演示流程设计
按照真实业务流程演示:
- 员工登录→查看客户列表→添加新客户
- 记录客户沟通→查看积分自动增加→确认等级变化
- 跟进客户线索→转化为正式客户→查看客户详情
- 管理员登录→查看员工业绩→统计数据报表
3. 答辩重点准备
- 业务逻辑亮点:积分自动计算、等级自动调整、状态流转管理
- 技术实现亮点:事务管理、MyBatis灵活使用、业务规则封装
- 系统特色:完整的客户生命周期管理、智能化积分体系
结语
基于SSM的客户关系管理系统毕设成功的关键在于:抓住客户管理核心业务,设计合理的积分体系,保证数据一致性。这套系统虽然业务逻辑相对复杂,但一旦掌握,无论是技术深度还是业务完整性都能得到导师认可。
记住:积分自动计算、客户等级管理、线索转化流程是三大得分点!需要完整源码、数据库脚本、部署文档的同学可以在评论区留言。
点赞收藏这篇,下次找流程不迷路~祝宝子们毕设顺利,轻松毕业!😘