软件项目实践之CRM系统

圈内存在这么一句话:“世上本来没有CRM,大家的生意越来越难做了,才有了CRM。"在同质化竞争时代,顾客资产尤为重要,新时代在呼唤 CRM。

CRM 系统概念

CRM 基本概念

CRM系统即客户关系管理系统,顾名思义就是管理公司与客户之间的关系。是一种以"客户关系一对一理论"为 基础,旨在改善企业与客户之间关系的新型管理机制。客户关系管理的定义是:企业为提高核心竞争力,利用相应的信息技术以及互联网技术来协调企业与顾客间在销售、营销和服务上的交互, 从而提升其管理方式,向客户提供创新式的个性化的客户交互和服务的过程。其最终目标是吸引新客户、保留老客户以及将已有客户转为忠实客户,增加公司市场份额。

CRM的实施目标就是通过全面提升企业业务流程的管理来降低企业成本, 通过提供更快速和周到的优质服务来吸引和保持更多的客户。作为一种新型管理机制, CRM 极大地改善了企业与客户之间的关系,应用于企业的市场营销、销售、服务与技术支持等与客户相关的领域。

CRM 分类

根据客户的类型不同, CRM 可以分为 B to B CRM 及 B to C CRM 。B to B CRM 中管理的客户是企业客户,而 B to C CRM 管理的客户则是个人客户。提供企业产品销售和服务的企业需要的 B to B 的 CRM, 也就是市面上大部分 CRM 的内容。而提供个人及家庭消费的企业需要的是 B to C 的 CRM。

根据 CRM 管理侧重点不同又分为操作性和分析型 CRM 。 大部分 CRM 为操作型 CRM, 支持 CRM 的日常作业流程的每个环节, 而分析型 CRM 则偏重于数据分析。

CRM 系统模块划分

CRM系统模块图

模块功能描述

基础模块

包含系统基本的用户登录,退出,记住我,密码修改等基本操作。

营销管理

营销机会管理:企业客户的质询需求所建立的信息录入功能,方便销售人员进行后续的客户需求跟踪。

营销开发计划:开发计划是根据营销机会而来,对于企业质询的客户,会有相应的销售人员对于该客户进行具体的沟通交流,此时对于整个CRM 系统而言,通过营销开发计划来进行相应的信息管理,提高客户的购买企业产品的可能性。

客户管理

客户信息管理:CRM 系统中完整记录客户信息来源的数据、企业与客户交往、客户订单查询等信息录入功能,方便企业与客户进行相应的信息交流与后续合作。

客户流失管理:CRM 通过一定规则机制所定义的流失客户(无效客户),通过该规则可以有效管理客户信息资源,提高营销开发效率。

服务管理

服务管理是针对客户而开发的功能,针对客户要求,CRM 提供客户相应的信息质询,反馈与投诉功能,提高企业对于客户的服务质量。

数据报表

CRM 提供的数据报表功能能够帮助企业了解客户整体分布,了解客户开发结果整体信息,从而帮助企业整体调整客户开发计划,提高企业的在市场中的竞争力度。

系统管理

系统管理包含常量字典维护工作,以及权限管理模块,CRM 权限管理是基于角色的一种权限控制,基于RBAC实现基于角色的权限控制,通过不同角色的用户登录该系统后展示系统不同的操作功能,从而达到对不同角色完成不同操作功能。

CRM 系统数据库设计

CRM系统根据产品的原型搞以及UI组的设计稿, 接下来就要设计数据库, 一般在大公司通常会有专门的DBA, 这时我们可以不要考虑数据库表设计, 但是也要能够读懂或者了解DBA的设计思路方便在程序开发阶段不会出现问题, 一般关系型数据库表设计满足三范式的设计即可, 表名设计做到见名知意最好。

E-R图表简介

营销管理模块

客户管理模块

客户信息管理

客户流失管理

服务管理

系统管理

权限模块 E-R 模型

字典&日记管理

表结构详情

t_sale_chance 营销机会表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
chance_source varchar(300) 可空 机会来源
customer_name varchar(100) 可空 客户名称
cgjl int(11) 可空 成功几率
overview varchar(300) 可空 概要
link_man varchar(100) 可空 联系人
link_phone varchar(100) 可空 手机号
description varchar(1000) 可空 描述
create_man varchar(100) 可空 创建人
assign_man varchar(100) 可空 分配人
assign_time datetime 可空 分配时间
state int(11) 可空 分配状态
dev_result int(11) 可空 开发结果
is_valid int(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_cus_dev_plan 客户开发计划表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id
sale_chance_id int(11) 可空 营销机会id
plan_item varchar(100) 可空 计划内容
plan_date datetime 可空 计划日期
exe_affect varchar(100) 可空 执行效果
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
is_valid int(4) 可空 有效状态
t_customer 客户信息表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
khno varchar(20) 可空 客户编号
name varchar(20) 可空 客户姓名
area varchar(20) 可空 客户所属地区
cus_manager varchar(20) 可空 客户经理
level varchar(30) 可空 客户级别
myd varchar(30) 可空 客户满意度
xyd varchar(30) 可空 客户信用度
address varchar(500) 可空 客户地址
post_code varchar(50) 可空 邮编
phone varchar(20) 可空 联系电话
fax varchar(20) 可空 传真
web_site varchar(20) 可空 网址
yyzzzch varchar(50) 可空 营业执照注册号
fr varchar(20) 可空 法人代表
zczj varchar(20) 可空 注册资金
nyye varchar(20) 可空 年营业额
khyh varchar(50) 可空 开户银行
khzh varchar(50) 可空 开户账号
dsdjh varchar(50) 可空 地税登记号
gsdjh varchar(50) 可空 国税登记号
state int(11) 可空 流失状态
is_valid int(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_customer_contact 客户交往记录表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
cus_id int(11) 可空 客户id
contact_time datetime 可空 交往时间
address varchar(500) 可空 交往地址
overview varchar(100) 可空 概要
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
is_valid int(4) 可空 有效状态
t_customer_linkman 客户联系人表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
cus_id int(11) 可空 客户id
link_name varchar(20) 可空 联系人姓名
sex varchar(20) 可空 性别
zhiwei varchar(50) 可空 职位
office_phone varchar(50) 可空 办公电话
phone varchar(20) 可空 手机号
is_valid int(4) 可空 有效状态
ceate_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_customer_loss 客户流失表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
cus_no varchar(40) 可空 客户编号
cus_name varchar(20) 可空 客户姓名
cus_manager varchar(20) 可空 客户经理
last_order_time date 可空 最后下单时间
confirm_loss_time date 可空 确认流失时间
state int(11) 可空 流失状态
loss_reason varchar(1000) 可空 流失原因
is_valid tinyint(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_customer_order 客户订单
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
cus_id int(11) 可空 客户id
order_no varchar(40) 可空 订单编号
order_date datetime 可空 下单时间
address varchar(200) 可空 地址
state int(11) 可空 状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
is_valid int(4) 可空 有效状态
t_order_details 订单详情表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
order_id int(11) 可空 订单id
goods_name varchar(100) 可空 商品名称
goods_num int(11) 可空 商品数量
unit varchar(20) 可空 商品单位
price float 可空 单价
sum float 可空 总金额
is_valid int(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_customer_reprieve 客户流失暂缓表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
loss_id int(11) 可空 流失id
measure varchar(500) 可空 措施
is_valid tinyint(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_customer_serve 客户服务
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
serve_type varchar(30) 可空 服务类型
overview varchar(500) 可空 概要
customer varchar(30) 可空 客户
state varchar(20) 可空 服务状态
service_request varchar(500) 可空 服务请求
create_people varchar(100) 可空 服务创建人
assigner varchar(100) 可空 服务分配人
assign_time datetime 可空 分配时间
service_proce varchar(500) 可空 服务处理
service_proce_people varchar(20) 可空 服务处理人
service_proce_time datetime 可空 服务处理时间
service_proce_result varchar(500) 可空 处理结果
myd varchar(50) 可空 满意度
is_valid int(4) 可空 是否有效
update_date datetime 可空 更新时间
create_date datetime 可空 创建时间
t_datadic 字典表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 id主键
data_dic_name varchar(50) 可空 字典名
data_dic_value varchar(50) 可空 字典值
is_valid tinyint(4) 可空 是否有效
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_user 用户表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 字段描述
user_name varchar(20) 可空 用户名
user_pwd varchar(100) 可空 用户密码
true_name varchar(20) 可空 真实姓名
email varchar(30) 可空 邮箱
phone varchar(20) 可空 电话
is_valid int(4) 可空 有效状态
create_date datetime 可空 创建时间
update_date datetime 可空 更新时间
t_role 角色表
字段 字段类型 字段限制 字段描述
主键 id int(11) 自增 字段描述
role_name varchar(255) 可空 角色名
role_remarker varchar(255) 可空 角色备注
create_date datetime 可空 创建时间
update_date datetime 更新时间
is_valid int(11) 非空 是否有效

项目环境搭建与测试

项目技术栈

环境搭建与测试

在 IDEA 中新建 SpringBoot 项目 - CRM

在pom.xml引入坐标&插件

<properties>

​    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

​    <maven.compiler.source>1.8</maven.compiler.source>

​    <maven.compiler.target>1.8</maven.compiler.target>

</properties>



<parent>

​    <groupId>org.springframework.boot</groupId>

​    <artifactId>spring-boot-starter-parent</artifactId>

​    <version>2.2.2.RELEASE</version>

  </parent>


  <dependencies>


​    <dependency>

​      <groupId>org.springframework.boot</groupId>

​      <artifactId>spring-boot-starter-web</artifactId>

​    </dependency>

​    <dependency>

​      <groupId>org.springframework.boot</groupId>

​      <artifactId>spring-boot-starter-aop</artifactId>

​    </dependency>

​    <dependency>

​      <groupId>org.springframework.boot</groupId>

​      <artifactId>spring-boot-starter-freemarker</artifactId>

​    </dependency>

​      <dependency>

​          <groupId>org.springframework.boot</groupId>

​          <artifactId>spring-boot-starter-test</artifactId>

​          <scope>test</scope>

​      </dependency>



​    <!--

​      mybatis 集成

​    -->

​    <dependency>

​      <groupId>org.mybatis.spring.boot</groupId>

​      <artifactId>mybatis-spring-boot-starter</artifactId>

​      <version>2.1.1</version>

​    </dependency>

​    <!-- 分页插件 -->

​    <dependency>

​      <groupId>com.github.pagehelper</groupId>

​      <artifactId>pagehelper-spring-boot-starter</artifactId>

​      <version>1.2.13</version>

​    </dependency>



​    <!--mysql 驱动-->

​    <dependency>

​      <groupId>mysql</groupId>

​      <artifactId>mysql-connector-java</artifactId>

​      <scope>runtime</scope>

​    </dependency>


    
​    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->

​    <dependency>

​      <groupId>com.mchange</groupId>

​      <artifactId>c3p0</artifactId>

​      <version>0.9.5.5</version>

​    </dependency>

​    <dependency>

​      <groupId>org.apache.commons</groupId>

​      <artifactId>commons-lang3</artifactId>

​      <version>3.5</version>

​    </dependency>

​    <dependency>

​      <groupId>com.alibaba</groupId>

​      <artifactId>fastjson</artifactId>

​      <version>1.2.47</version>

​    </dependency>



    
​    <!-- DevTools 的坐标 热部署 -->

​    <dependency>

​      <groupId>org.springframework.boot</groupId>

​      <artifactId>spring-boot-devtools</artifactId>

​      <optional>true</optional>

​    </dependency>

  </dependencies>



  <build>

​    <plugins>

​      <plugin>

​        <groupId>org.apache.maven.plugins</groupId>

​        <artifactId>maven-compiler-plugin</artifactId>

​        <version>2.3.2</version>

​        <configuration>

​          <source>1.8</source>

​          <target>1.8</target>

​          <encoding>UTF-8</encoding>

​        </configuration>

​      </plugin>

​        <plugin>

​            <groupId>org.mybatis.generator</groupId>

​            <artifactId>mybatis-generator-maven-plugin</artifactId>

​            <version>1.3.2</version>

​            <configuration>

​            <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>

​                <verbose>true</verbose>

​                <overwrite>true</overwrite>

​            </configuration>

​        </plugin>  

​      <plugin>

​        <groupId>org.springframework.boot</groupId>

​        <artifactId>spring-boot-maven-plugin</artifactId>

​        <configuration>

​          <!-- 如果没有该配置,热部署的devtools不生效 -->

​          <fork>true</fork>

​        </configuration>

​      </plugin>

​    </plugins>

  </build>

添加配置文件application.yml

src/main/resources 目录下新建application.yml配置文件,内容如下:

\## 端口号  上下文路径

server:

  port: 9898

  servlet:

​    context-path: /crm



\## 数据源配置

spring:

  datasource:

​    type: com.mchange.v2.c3p0.ComboPooledDataSource

​    driver-class-name: com.mysql.cj.jdbc.Driver

​    url: jdbc:mysql://127.0.0.1:3306/crm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8

​    username: root

​    password: root



  \## freemarker

  freemarker:

​    suffix: .ftl

​    content-type: text/html

​    charset: UTF-8

​    template-loader-path: classpath:/views/



  \## 启用热部署

  devtools:

​    restart:

​      enabled: true

​      additional-paths: src/main/java



\## mybatis 配置

mybatis:

  mapper-locations: classpath:/mappers/*.xml

  type-aliases-package: com.xxxx.crm.vo;com.xxxx.crm.query;com.xxxx.crm.dto

  configuration:

​    map-underscore-to-camel-case: true



\## pageHelper 分页

pagehelper:

  helper-dialect: mysql

  

\## 设置 dao 日志打印级别

logging:

  level:

​    com:

​      xxxx:

​        crm:

​          dao: debug

添加视图转发源代码

新建com.xxxx.crm.controller包,添加系统登录,主页面转发代码(这里继承BaseController,具体文件见相关目录)。

package com.xxxx.crm.controller;

import com.xxxx.crm.base.BaseController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController extends BaseController {

    /**
     * 系统登录页
     * @return
     */
    @RequestMapping("index")
    public String index(){
        return "index";
    }

    
    // 系统界面欢迎页
    @RequestMapping("welcome")
    public String welcome(){
        return "welcome";
    }

    /**
     * 后端管理主页面
     * @return
     */
    @RequestMapping("main")
    public String main(){
        return "main";
    }
}

静态资源文件目录添加

在src/main/resources目录下新建public 目录存放系统相关静态资源文件,copy静态文件内容到public 目录。

添加系统登录,主页面视图模板页

在src/main/resources 目录下新建views目录,添加index.ftl,main.ftl 等文件(具体视图文件详见相关目录)

添加SpringBoot应用启动类Starter

在com.xxxx.crm 包下新建Starter.java ,添加启动项目相关代码如下:

package com.xxxx.crm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Starter {

    public static void main(String[] args) {
        SpringApplication.run(Starter.class);
    }
}

项目目录结构

浏览器访问登录页、主页面

Chrome浏览器访问登录页地址:http://localhost:9898/crm/index

Chrome浏览器访问登录页地址:http://localhost:9898/crm/main

用户登录功能实现

用户登录功能核心思路

# 用户登录
## 后端实现
### 整体思路:
1. 参数判断 
   - 用户姓名 非空判断
   - 用户密码 非空判断
2. 通过用户名查询用户记录,返回用户对象
3. 判断用户对象是否为空
4. 如果用户对象不为空,则将前台传递的用户密码与数据库中的密码作比较
5. 判断密码是否正确
6. 如果密码正确,则登录成功,返回结果

**Controller层(控制层:接受请求,响应结果)**
1. 通过形参接收客户端传递的参数
2. 调用业务逻辑层的登录方法,得到登录结果
3. 响应数据给客户端

**Service层(业务逻辑层:非空判断、条件判断等业务逻辑处理)**
1. 参数判断,判断用户名、密码是否非空
   - 如果参数为空,抛出异常(异常被控制层捕获并处理)
2. 调用数据访问层,通过用户名查询用户记录,返回用户对象
3. 判断用户对象是否为空
   - 如果对象为空,抛出异常(异常被控制层捕获并处理)
   - 否则继续
4. 判断用户密码是否正确,比较客户端传递的用户密码与数据库中查询的用户对象中的密码
   - 如果密码不相等,抛出异常(异常被控制层捕获并处理)
   - 如果密码相等,登录成功,返回结果

**Dao层(数据访问层:数据库中增删改查操作)**

通过用户名查询用户记录,返回用户对象
赞赏