当前位置 : 主页 > 编程语言 > java >

Java项目:CRM客户关系管理系统(Spring+SpringMVC+MyBatis + maven)

来源:互联网 收集:自由互联 发布时间:2022-08-10
目录 ​​1. 项目概述​​ ​​2. 环境搭建​​ ​​2.1 创建项目​​ ​​2.2 导入jsp页面​​ ​​2.3 配置类​​ ​​2.3.1 MyBatis 配置​​ ​​2.3.2 Spring 配置​​ ​​2.3.3 Spring MVC 配置


目录

​​1. 项目概述​​

​​2. 环境搭建​​

​​2.1 创建项目​​

​​2.2 导入jsp页面​​

​​2.3 配置类​​

​​2.3.1 MyBatis 配置​​

​​2.3.2 Spring 配置​​

​​2.3.3 Spring MVC 配置​​

​​2.3.4 Web 配置​​

​​2.4 数据库初始化​​

​​2.4.1 建表语句​​

​​2.4.2 字典表​​

​​2.4.3 客户表与字典表的关系​​

​​2.5 JavaBean​​

​​2.5.1 BaseDict​​

​​2.5.2 Customer​​

​​2.5.3 LinkMan​​

​​2.6 Mapper​​

​​2.6.1 BaseDictMapper​​

​​2.6.2 CustomerMapper​​

​​2.6.3 LinkManMapper​​

​​3. 客户管理​​

​​3.1 查询所有客户​​

​​3.1.1 查询所有​​

​​3.1.2 条件查询​​

​​3.1.3 分页查询​​

​​3.2 添加客户​​

​​3.2.1 需求​​

​​3.2.2 显示表单​​

​​3.2.3 添加​​

​​3.3 修改客户​​

​​3.3.1 需求​​

​​3.3.2 显示表单,回显数据​​

​​3.3.3 修改​​

​​3.4 删除客户​​

​​4. 联系人管理​​

​​4.1 联系人与客户关系分析​​

​​4.2 查询所有联系人​​

​​4.2.1 查询所有​​

​​4.2.2 条件查询​​

​​4.2.3 分页查询​​

​​4.3 添加联系人​​

​​4.3.1 需求​​

​​4.3.2 显示表单​​

​​4.3.3 添加​​

​​4.4 修改联系人​​

​​4.4.1 需求​​

​​4.4.2 显示表单,回显数据​​

​​4.4.3 修改​​

​​4.5 删除联系人​​

​​4.6 完善:删除客户​​

​​4.6.1 问题:客户和联系人主外键约束​​

​​4.6.2 解决方案1:自动删除联系人​​

​​4.6.3 作业:完善删除提示​​

​​end​​


1. 项目概述

  • CRM:Customer Relationship Management,客户关系管理系统。
  • 客户关系管理的定义是:企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在​​销售​​、​​营销​​和服务上的交互,从而提升其​​管理方式​​,向客户提供创新式的个性化的客户交互和服务的过程。其最终目标是吸引新客户、保留老客户以及将已有客户转为忠实​​客户​​,增加市场。
  • 比如:汽车4S店、售楼中心、房产中介、保险行业
  • 本案例主要是完成两个模块:客户管理、联系人管理。

2. 环境搭建

2.1 创建项目

  • 项目名:maven-crm
  • 项目位置:
  • 导入坐标​ ​

<packaging>war</packaging>

<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>
<!--声明不需要web.xml文件-->
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- 事务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>


<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>

<!--整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

<!-- mvc json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>

<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>


<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

<!--jsp相关-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--整合日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.10</version>
</dependency>
<!--common工具-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>

</dependencies>
  • 创建webapp目录

2.2 导入jsp页面

2.3 配置类

  • 拷贝配置类

2.3.1 MyBatis 配置

  • 拷贝:MyBatisConfiguration3,修改mapper所在包,并创建对应的包

package com.czxy.crm.config;

import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import javax.sql.DataSource;
import java.util.Properties;

/**
* @author 桐叔
*/
public class MyBatisConfiguration3 {
/**
* 配置session工厂
* @param dataSource
* @return
* @throws Exception
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{
//1 创建 factoryBean
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//2 设置数据
// 2.1 数据源
factoryBean.setDataSource(dataSource);

// 2.2 驼峰命名
Configuration configuration = new Configuration();
configuration.setMapUnderscoreToCamelCase(true);
factoryBean.setConfiguration(configuration);

// 2.3 分页插件
Properties props = new Properties();
// 设置方言
props.setProperty("dialect", "mysql");
// 分页的同时进行count查询
props.setProperty("rowBoundsWithCount", "true");
// 分页合理化参数,pageNum<=0 时会查询第一页,pageNum>pages (超过总数时),会查询最后一页
props.setProperty("reasonable", "true");

// PageInterceptor pageInterceptor = new PageInterceptor();
// pageInterceptor.setProperties(props);
PageHelper pageHelper = new PageHelper();
pageHelper.setProperties(props);

factoryBean.setPlugins(new Interceptor[] {pageHelper});

//3 通过factorybean获得对应
return factoryBean.getObject();
}
/**
* 映射扫描器
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
//1 创建
MapperScannerConfigurer mapperScanner = new MapperScannerConfigurer();
//2设置包
mapperScanner.setBasePackage("com.czxy.crm.mapper");

return mapperScanner;
}

}


2.3.2 Spring 配置

  • 拷贝:SpringConfiguration3
  • 修改service所在包,并创建对应的包
  • 创建 db.propertiesjdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm_crm jdbc.username=root jdbc.password=1234

package com.czxy.crm.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@ComponentScan(basePackages="com.czxy.crm.service")
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
public class SpringConfiguration3 {
/**
* 获得properties文件中内容,并注入对应变量
*/
@Value("${jdbc.driver}")
private String driver;

@Value("${jdbc.url}")
private String url;

@Value("${jdbc.username}")
private String username;

@Value("${jdbc.password}")
private String password;
/**
* 配置数据源
* @return
*/
@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}

/**
* 事务管理器
* @param dataSource
* @return
*/
@Bean
public DataSourceTransactionManager txManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}

}


2.3.3 Spring MVC 配置

  • 拷贝:MvcConfiguration3
  • 修改controller所在包,并创建对应的包
  • 修改视图解析器的前后缀
package com.czxy.crm.config;


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan(basePackages="com.czxy.crm.controller")
@EnableWebMvc
public class MvcConfiguration3 implements WebMvcConfigurer {
/**
* 视图解析器
* @return
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/",".jsp");
}

}


2.3.4 Web 配置

  • 拷贝:WebInitializer3
package com.czxy.crm.config;


import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class WebInitializer3 implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//1 配置spring工厂
AnnotationConfigWebApplicationContext application = new AnnotationConfigWebApplicationContext();
// 注册所有的配置类
application.register(MyBatisConfiguration3.class);
application.register(SpringConfiguration3.class);
application.register(MvcConfiguration3.class);

//2 post中文乱码
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encoding", new CharacterEncodingFilter("UTF-8"));
encodingFilter.addMappingForUrlPatterns(null, true, "/*");

//3 核心控制器
ServletRegistration.Dynamic mvcServlet = servletContext.addServlet("springmvc", new DispatcherServlet(application));
mvcServlet.addMapping("*.action"); //普通项目
//mvcServlet.addMapping("/"); //RESTFul项目
mvcServlet.setLoadOnStartup(2); //tomcat启动时,执行servlet的初始化方法

}

}


2.4 数据库初始化

2.4.1 建表语句


CREATE DATABASE ssm_crm;
USE ssm_crm;

/*创建客户表*/
CREATE TABLE cst_customer (
cust_id BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
cust_name VARCHAR(32) NOT NULL COMMENT '客户名称(公司名称)',
cust_source VARCHAR(32) DEFAULT NULL COMMENT '客户信息来源(外键字典表)',
cust_industry VARCHAR(32) DEFAULT NULL COMMENT '客户所属行业',
cust_level VARCHAR(32) DEFAULT NULL COMMENT '客户级别(外键字典表)',
cust_address VARCHAR(128) DEFAULT NULL COMMENT '客户联系地址',
cust_phone VARCHAR(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (cust_id)
) ENGINE=INNODB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8;


/*创建联系人表*/
CREATE TABLE cst_linkman (
lkm_id BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
lkm_name VARCHAR(16) DEFAULT NULL COMMENT '联系人姓名',
lkm_gender VARCHAR(10) DEFAULT NULL COMMENT '联系人性别',
lkm_phone VARCHAR(16) DEFAULT NULL COMMENT '联系人办公电话',
lkm_mobile VARCHAR(16) DEFAULT NULL COMMENT '联系人手机',
lkm_email VARCHAR(64) DEFAULT NULL COMMENT '联系人邮箱',
lkm_position VARCHAR(16) DEFAULT NULL COMMENT '联系人职位',
lkm_memo VARCHAR(512) DEFAULT NULL COMMENT '联系人备注',
lkm_cust_id BIGINT(32) NOT NULL COMMENT '客户id(外键)',
PRIMARY KEY (lkm_id),
KEY FK_cst_linkman_lkm_cust_id (lkm_cust_id),
CONSTRAINT FK_cst_linkman_lkm_cust_id FOREIGN KEY (lkm_cust_id) REFERENCES cst_customer (cust_id) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


/*创建数据字典表*/
CREATE TABLE base_dict (
dict_id VARCHAR(32) NOT NULL COMMENT '数据字典id(主键)',
dict_type_code VARCHAR(10) NOT NULL COMMENT '数据字典类别代码',
dict_type_name VARCHAR(64) NOT NULL COMMENT '数据字典类别名称',
dict_item_name VARCHAR(64) NOT NULL COMMENT '数据字典项目名称',
dict_item_code VARCHAR(10) DEFAULT NULL COMMENT '数据字典项目(可为空)',
dict_sort INT(10) DEFAULT NULL COMMENT '排序字段',
dict_enable CHAR(1) NOT NULL COMMENT '1:使用 0:停用',
dict_memo VARCHAR(64) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (dict_id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


/*为字典表插入数据 */
INSERT INTO base_dict(dict_id,dict_type_code,dict_type_name,dict_item_name,dict_item_code,dict_sort,dict_enable,dict_memo)
VALUES ('1','001','客户行业','教育',NULL,1,'1',NULL),
('2','001','客户行业','电子商务',NULL,2,'1',NULL),
('3','001','客户行业','医药',NULL,3,'1',NULL),
('4','001','客户行业','酒店旅游',NULL,4,'1',NULL),
('5','001','客户行业','房地产',NULL,5,'1',NULL),
('6','002','客户信息来源','电话营销',NULL,1,'1',NULL),
('7','002','客户信息来源','网络营销',NULL,2,'1',NULL),
('8','003','公司性质','合资',NULL,1,'1',NULL),
('9','003','公司性质','国企',NULL,2,'1',NULL),
('10','003','公司性质','民企',NULL,3,'1',NULL),
('12','004','年营业额','1-10万',NULL,1,'1',NULL),
('13','004','年营业额','10-20万',NULL,2,'1',NULL),
('14','004','年营业额','20-50万',NULL,3,'1',NULL),
('15','004','年营业额','50-100万',NULL,4,'1',NULL),
('16','004','年营业额','100-500万',NULL,5,'1',NULL),
('17','004','年营业额','500-1000万',NULL,6,'1',NULL),
('18','005','客户状态','基础客户',NULL,1,'1',NULL),
('19','005','客户状态','潜在客户',NULL,2,'1',NULL),

('20','005','客户状态','成功客户',NULL,3,'1',NULL),
('21','005','客户状态','无效客户',NULL,4,'1',NULL),
('22','006','客户级别','普通客户',NULL,1,'1',NULL),
('23','006','客户级别','VIP客户',NULL,2,'1',NULL),
('24','007','商机状态','意向客户',NULL,1,'1',NULL),
('25','007','商机状态','初步沟通',NULL,2,'1',NULL),
('26','007','商机状态','深度沟通',NULL,3,'1',NULL),
('27','007','商机状态','签订合同',NULL,4,'1',NULL),

('30','008','商机类型','新业务',NULL,1,'1',NULL),
('31','008','商机类型','现有业务',NULL,2,'1',NULL),
('32','009','商机来源','电话营销',NULL,1,'1',NULL),
('33','009','商机来源','网络营销',NULL,2,'1',NULL),
('34','009','商机来源','推广活动',NULL,3,'1',NULL);

/*客户表数据*/
INSERT INTO cst_customer VALUES ('1', '传智教育', '6', '1', '23', '北京市昌平区建材城西路金燕龙办公楼一层', '010-66668888');
INSERT INTO cst_customer VALUES ('2', '传智专修学院', '6', '1', '23', '江苏省宿迁市沭阳县北京南路999号', '0527-80961111');
INSERT INTO cst_customer VALUES ('3', '京西集团', '7', '2', '23', '京西玉泉山', '010-65085588');
INSERT INTO cst_customer VALUES ('4', '修正药业', '7', '3', '22', '北京市昌平区北七家镇', '010-68909090');


/*联系人表数据*/
INSERT INTO cst_linkman VALUES ('1', '梁老师', 'male', '0527-82930000', '1388888888', 'zzz@czxy.com', '宣传部负责人', '很负责', '1');
INSERT INTO cst_linkman VALUES ('2', '汪老师', 'female', '0527-8290000', '1377777777', 'lll@czxy.com', '全国统一咨询中心', '很负责', '1');
INSERT INTO cst_linkman VALUES ('3', '高工', 'male', '010-82930000', '1399999999', 'bggg@163.com', '传智专修学院宣传中心', '宣传责任人', '2');
INSERT INTO cst_linkman VALUES ('4', '刘管', 'female', '0527-82935100', '1366666666', 'gg@czxy.com', '管理专员', '管理', '2');
INSERT INTO cst_linkman VALUES ('5', '李总', 'male', '021-89986886', '1355555555', 'lz@zongli.com', '总经理', '企划负责人', '3');
INSERT INTO cst_linkman VALUES ('6', '王董', 'male', '021-80980990', '1333333333', 'wd@zongli.com', '董事长', '企业老大', '3');
INSERT INTO cst_linkman VALUES ('7', '孙老板', 'male', '010-80980990', '1322222222', 'slb@xunta.com', '老板', '一把手', '4');
INSERT INTO cst_linkman VALUES ('8', '陈秘书', 'female', '010-80980990', '1311111111', 'cms@xunta.com', '秘书', '二把手', '4');


2.4.2 字典表

  • 开发过程中,页面中会出现​​固定值​​。例如:客户来源、客户所属行业、客户级别 等。
  • 存在的问题?随着项目的不断壮大,此类数据的维护难度,将几何倍的增长。
  • 解决方案:项目开发中,我们一般采用字典表进行处理。
  • 什么是字典表?
  • 用于存放系统基本参数的表。也就是将​​客户来源​​等信息抽取到表中。
  • 例如:客户来源、客户所属行业、客户级别 等。
  • 问题:独立的表越多,维护成本也将大大提升。
  • 优化:创建数据字典表base_dict,用于存放此类所有数据。

2.4.3 客户表与字典表的关系

  • 根据图片分析,字典表和客户表之间关系是​​一对多​​关系。

2.5 JavaBean

2.5.1 BaseDict

@Table(name="base_dict")
public class BaseDict {
// 编号
@Id
private String dictId;
//数据字典类别代码
private String dictTypeCode;
//数据字典类别名称
private String dictTypeName;
//数据字典项目名称
private String dictItemName;
//数据字典项目
private String dictItemCode;
//排序字段
private String dictSort;
//状态 0 停用 1 启用
private String dictEnable;
// 备注
private String dictMemo;

//getter和setter
}


2.5.2 Customer

@Table(name="cst_customer")
public class Customer {

// 主键
@Id
private Long custId;
// 客户名称
private String custName;
// 客户来源
private String custSource;
// 客户行业
private String custIndustry;
// 客户级别
private String custLevel;

// 客户地址
private String custAddress;
// 客户电话
private String custPhone;

// 客户来源数据字典对象(typeCode=002)
private BaseDict custSourceBaseDict;
// 客户行业数据字典对象(typeCode=001)
private BaseDict custIndustryBaseDict;
// 客户级别数据字典对象(typeCode=006)
private BaseDict custLevelBaseDict;

 //getter 和 setter }


2.5.3 LinkMan

@Table(name="cst_linkman")
public class LinkMan {

// 主键
@Id
private Long lkmId;
// 名称
private String lkmName;
// 性别
private String lkmGender;
// 电话
private String lkmPhone;
// 移动电话
private String lkmMobile;
// 邮箱
private String lkmEmail;
// 职位
private String lkmPosition;
// 备注
private String lkmMemo;
// 客户的对象
private Customer customer;

@Column(name="lkm_cust_id")
private Long custId; //所属客户主键信息(及联系人的外键)

//getter 和 setter
}


2.6 Mapper

2.6.1 BaseDictMapper

package com.czxy.crm.mapper;

import com.czxy.crm.domain.BaseDict;
import tk.mybatis.mapper.common.Mapper;

/**
* @author 桐叔
*/
public interface BaseDictMapper extends Mapper<BaseDict> {
}


2.6.2 CustomerMapper

package com.czxy.crm.mapper;

import com.czxy.crm.domain.Customer;
import tk.mybatis.mapper.common.Mapper;

/**
* @author 桐叔
*/
public interface CustomerMapper extends Mapper<Customer> {
}


2.6.3 LinkManMapper

package com.czxy.crm.mapper;

import com.czxy.crm.domain.LinkMan;
import tk.mybatis.mapper.common.Mapper;

/**
* @author 桐叔
*/
public interface LinkManMapper extends Mapper<LinkMan> {
}


3. 客户管理

3.1 查询所有客户

3.1.1 查询所有

  • 需求:查询所有客户
  • 步骤:
  • 步骤1:入口
  • 步骤2:编写Controller
  • 步骤3:编写Service 接口、实现类
  • 步骤4:修改 list.jsp展示数据
  • 步骤1:入口
  • 步骤2:编写Controllerpackage com.czxy.crm.controller; ​
import com.czxy.crm.domain.Customer;
import com.czxy.crm.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Controller
@RequestMapping("/customer")
public class CustomerController {

@Resource
private CustomerService customerService;

@RequestMapping("/findAll")
public String findAll( Model model){

List<Customer> allCustomer = customerService.findAll();
model.addAttribute("allCustomer", allCustomer);

return "customer/list";
}

}
  • ​ ​
  • 步骤3:编写Service 接口、实现类
  • 接口package com.czxy.crm.service; ​
import com.czxy.crm.domain.Customer;

import java.util.List;

/**
* @author 桐叔
*/
public interface CustomerService {
/**
* 查询所有
* @return
*/
List<Customer> findAll();
}

实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.BaseDict;
import com.czxy.crm.domain.Customer;
import com.czxy.crm.mapper.BaseDictMapper;
import com.czxy.crm.mapper.CustomerMapper;
import com.czxy.crm.service.CustomerService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {

@Resource
private CustomerMapper customerMapper;
@Resource
private BaseDictMapper baseDictMapper;

@Override
public List<Customer> findAll() {

// 查询所有
List<Customer> list = customerMapper.selectAll();

// 关联查询
list.forEach(customer -> {
// 客户来源
BaseDict custSourceBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustSource());
customer.setCustSourceBaseDict(custSourceBaseDict);

//客户行业
BaseDict custIndustryBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustIndustry());
customer.setCustIndustryBaseDict(custIndustryBaseDict);

//客户级别
BaseDict custLevelBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustLevel());
customer.setCustLevelBaseDict(custLevelBaseDict);
});

return list;
}
}

步骤4:修改 list.jsp展示数据<c:forEach items="${allCustomer}" var="customer">
<TR style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
<TD>${customer.custName }</TD>
<TD>${customer.custLevelBaseDict.dictItemName }</TD>
<TD>${customer.custSourceBaseDict.dictItemName }</TD>
<TD>${customer.custIndustryBaseDict.dictItemName }</TD>
<TD>${customer.custAddress }</TD>
<TD>${customer.custPhone }</TD>
<TD>
<a href="${pageContext.request.contextPath }/customer/editUI.action?custId=${customer.custId}">修改</a>
&nbsp;&nbsp;
<a href="${pageContext.request.contextPath }/customer/delete.action?custId=${customer.custId}" οnclick="return confirm('您确定要删除【${customer.custName }】吗?')">删除</a>
</TD>
</TR>
</c:forEach>

3.1.2 条件查询

  • 需求:
  • 步骤
  • 步骤1:入口,确定查询表单
  • 步骤2:创建CustomerVo,用于封装查询条件
  • 步骤3:修改controller,获得查询条件
  • 步骤4:修改service,使用查询条件
  • 步骤1:入口,确定查询表单
  • 步骤2:创建CustomerVo,用于封装查询条件
package com.czxy.crm.vo;

/**
* @author 桐叔
*/
public class CustomerVo {
private String custName;

public String getCustName() {
return custName;
}

public void setCustName(String custName) {
this.custName = custName;
}
}

步骤3:修改controller,获得查询条件
package com.czxy.crm.controller;

import com.czxy.crm.domain.Customer;
import com.czxy.crm.service.CustomerService;
import com.czxy.crm.vo.CustomerVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Controller
@RequestMapping("/customer")
public class CustomerController {

@Resource
private CustomerService customerService;

@RequestMapping("/findAll")
public String findAll(CustomerVo customerVo, Model model){

List<Customer> allCustomer = customerService.findAll(customerVo);
model.addAttribute("allCustomer", allCustomer);

return "customer/list";
}

}

​• 步骤4:修改service,使用查询条件
接口
实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.BaseDict;
import com.czxy.crm.domain.Customer;
import com.czxy.crm.mapper.BaseDictMapper;
import com.czxy.crm.mapper.CustomerMapper;
import com.czxy.crm.service.CustomerService;
import com.czxy.crm.vo.CustomerVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {

@Resource
private CustomerMapper customerMapper;
@Resource
private BaseDictMapper baseDictMapper;

@Override
public List<Customer> findAll(CustomerVo customerVo) {

// 1 条件查询
Example example = new Example(Customer.class);
Example.Criteria criteria = example.createCriteria();
if(StringUtils.isNotBlank(customerVo.getCustName())) {
criteria.andLike("custName", "%"+customerVo.getCustName()+"%");
}

// 2 分页查询

// 3 查询所有
List<Customer> list = customerMapper.selectByExample(example);

// 4 关联查询
list.forEach(customer -> {
// 客户来源
BaseDict custSourceBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustSource());
customer.setCustSourceBaseDict(custSourceBaseDict);

//客户行业
BaseDict custIndustryBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustIndustry());
customer.setCustIndustryBaseDict(custIndustryBaseDict);

//客户级别
BaseDict custLevelBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustLevel());
customer.setCustLevelBaseDict(custLevelBaseDict);
});

// 5 封装分页

return list;
}
}

3.1.3 分页查询

  • 需求
  • 步骤:
  • 步骤1:修改CustomerVo,获得分页参数
  • 步骤2:修改controller,返回pageInfo
  • 步骤3:修改service,封装PageInfo
  • 步骤4:修改jsp,展示列表数据
  • 步骤5:修改jsp,展示分页条
  • 步骤1:修改CustomerVo,获得分页参数package com.czxy.crm.vo; ​
/**
* @author 桐叔
*/
public class CustomerVo {
private String custName;
private Integer pageNum = 1;
private Integer pageSize = 2;

// getter和setter
}
  • 步骤2:修改controller,返回pageInfo
  • 步骤3:修改service,封装PageInfo
  • 接口
  • 实现类
package com.czxy.crm.service.impl;

import com.czxy.crm.domain.BaseDict;
import com.czxy.crm.domain.Customer;
import com.czxy.crm.mapper.BaseDictMapper;
import com.czxy.crm.mapper.CustomerMapper;
import com.czxy.crm.service.CustomerService;
import com.czxy.crm.vo.CustomerVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {

@Resource
private CustomerMapper customerMapper;
@Resource
private BaseDictMapper baseDictMapper;

@Override
public PageInfo<Customer> findAll(CustomerVo customerVo) {
// 1 条件查询
Example example = new Example(Customer.class);
Example.Criteria criteria = example.createCriteria();
if(StringUtils.isNotBlank(customerVo.getCustName())) {
criteria.andLike("custName", "%"+customerVo.getCustName()+"%");
}
// 2 分页查询
PageHelper.startPage(customerVo.getPageNum(),customerVo.getPageSize());
// 3 查询所有
List<Customer> list = customerMapper.selectByExample(example);
// 4 关联查询
list.forEach(customer -> {
// 客户来源
BaseDict custSourceBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustSource());
customer.setCustSourceBaseDict(custSourceBaseDict);
//客户行业
BaseDict custIndustryBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustIndustry());
customer.setCustIndustryBaseDict(custIndustryBaseDict);
//客户级别
BaseDict custLevelBaseDict = baseDictMapper.selectByPrimaryKey(customer.getCustLevel());
customer.setCustLevelBaseDict(custLevelBaseDict);
});
// 5 封装分页
return new PageInfo<>(list);
}
}
  • 步骤4:修改jsp,展示列表数据
  • 步骤5:修改jsp,展示分页条
  • 查询表单
  • 分页条当前第[<B>${pageInfo.pageNum}</B>]页,共[<B>${pageInfo.total}</B>]条 ,每页显示
<select οnchange="change(this)">
<option value="1" ${pageInfo.pageSize == 1 ? 'selected' : ''}>1</option>
<option value="2" ${pageInfo.pageSize == 2 ? 'selected' : ''}>2</option>
<option value="3" ${pageInfo.pageSize == 3 ? 'selected' : ''}>3</option>
<option value="5" ${pageInfo.pageSize == 5 ? 'selected' : ''}>5</option>
<option value="10" ${pageInfo.pageSize == 10 ? 'selected' : ''}>10</option>
</select>

<c:if test="${pageInfo.pageNum > 1}">
[<a href="javascript:void(0)" οnclick="page(1)">首页</a>]
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pageNum - 1})">上一页</a>]
</c:if>

<c:forEach begin="1" end="${pageInfo.pages}" var="num">
<b><a href="javascript:void(0)" οnclick="page(${num})">${num}</a></b>
</c:forEach>

<c:if test="${pageInfo.pageNum < pageInfo.pages}">
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pageNum + 1})">下一页</a>]
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pages})">尾页</a>]
</c:if>

<input type="number" style="width: 35px;" value="${customerVo.pageNum}" id="goId"/>


<input type="button" value="Go" οnclick="page(goId.value)"/>
js函数function change(obj) {
// 重置,如果修改了pageSize,从1开始
pageNumId.value = 1
// 修改隐藏字段 pageSize
pageSizeId.value = obj.value
// 提交表单
customerFormId.submit()
}

function page(pageNum) {
// 修改pageNum的值
pageNumId.value = pageNum
// 提交表单
customerFormId.submit()
}

3.2 添加客户

3.2.1 需求

3.2.2 显示表单

  • 步骤:
  • 步骤1:入口
  • 步骤2:修改CustomerController,用于显示​​customer/add.jsp​​ 页面
  • 查询数据字典:客户来源(typeCode=002)
  • 查询数据字典:客户行业(typeCode=001)
  • 查询数据字典:客户级别(typeCode=006)
  • 步骤3:编写BaseDictService,通过typeCode查询所有数据字典信息。
  • 步骤4:修改add.jsp,显示字典相关信息
  • 步骤1:入口
  • 步骤2:修改CustomerController,用于显示​​customer/add.jsp​​ 页面
  • 查询数据字典:客户来源(typeCode=002)
  • 查询数据字典:客户行业(typeCode=001)
  • 查询数据字典:客户级别(typeCode=006)
package com.czxy.crm.controller;

import com.czxy.crm.domain.BaseDict;
import com.czxy.crm.domain.Customer;
import com.czxy.crm.service.BaseDictService;
import com.czxy.crm.service.CustomerService;
import com.czxy.crm.vo.CustomerVo;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Controller
@RequestMapping("/customer")
public class CustomerController {

@Resource
private CustomerService customerService;

@Resource
private BaseDictService baseDictService;

/**
* 添加页面
* @return
*/
@RequestMapping("/addUI")
public String addUI(Model model) {

// 客户行业 (typeCode=001)
List<BaseDict> custIndustryBaseDictList = baseDictService.selectAllByTypeCode("001");
model.addAttribute("custIndustryBaseDictList",custIndustryBaseDictList);

// 客户来源(typeCode=002)
List<BaseDict> custSourceBaseDictList = baseDictService.selectAllByTypeCode("002");
model.addAttribute("custSourceBaseDictList",custSourceBaseDictList);


// 客户级别(typeCode=006)
List<BaseDict> custLevelBaseDictList = baseDictService.selectAllByTypeCode("006");
model.addAttribute("custLevelBaseDictList",custLevelBaseDictList);


return "customer/add";
}

}

  • 步骤3:编写BaseDictService,通过typeCode查询所有数据字典信息。
  • 接口package com.czxy.crm.service; ​
import com.czxy.crm.domain.BaseDict;

import java.util.List;

/**
* @author 桐叔
*/
public interface BaseDictService {
/**
* 通过类别代码查询数据字典信息
* @param dictTypeCode
* @return
*/
List<BaseDict> selectAllByTypeCode(String dictTypeCode);
}

实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.BaseDict;
import com.czxy.crm.mapper.BaseDictMapper;
import com.czxy.crm.service.BaseDictService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class BaseDictServiceImpl implements BaseDictService {
@Resource
private BaseDictMapper baseDictMapper;

@Override
public List<BaseDict> selectAllByTypeCode(String dictTypeCode) {
// 条件
Example example = Example.builder(BaseDict.class).build();
example.createCriteria().andEqualTo("dictTypeCode",dictTypeCode);
// 查询
return baseDictMapper.selectByExample(example);
}
}

步骤4:修改add.jsp,显示字典相关信息<td>所属行业 </td>
<td>
<select name="custIndustry" class=textbox style="WIDTH: 180px">
<option value="">---请选择---</option>
<c:forEach items="${custIndustryBaseDictList}" var="industry">
<option value="${industry.dictId}">${industry.dictItemName}</option>
</c:forEach>
</select>
</td><td>信息来源 :</td>
<td>
<select name="custSource" class=textbox style="WIDTH: 180px">
<option value="non">---请选择---</option>
<c:forEach items="${custSourceBaseDictList}" var="source">
<option value="${source.dictId}">${source.dictItemName}</option>
</c:forEach>
</select>
</td>
<td>客户级别:</td>
<td>
<select name="custLevel" class=textbox style="WIDTH: 180px">
<option value="non">---请选择---</option>
<c:forEach items="${custLevelBaseDictList}" var="level">
<option value="${level.dictId}">${level.dictItemName}</option>
</c:forEach>
</select>
</td>

3.2.3 添加

  • 步骤:
  • 步骤1:修改add.jsp页面,确定表单提交路径​​/customer/add.action​​
  • 步骤2:修改CustomerController,添加add方法,并处理成功和失败。
  • 步骤3:修改CustomerService,添加add方法
  • 步骤4:修改add.jsp,显示错误信息
  • 步骤1:修改add.jsp页面,确定表单提交路径​​/customer/add.action​​
  • 步骤2:修改CustomerController,添加add方法,并处理成功和失败。
/**
* 添加
* @param customer
* @return
*/
@RequestMapping("/add")
public String add(Customer customer, Model model) {
try {
// 添加
boolean result = customerService.add(customer);
if(result) {
// 成功
return "redirect:/customer/findAll.action";
} else {
// 失败
model.addAttribute("error","添加客户失败");
return "customer/add";
}
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("error",e.getMessage());
return "customer/add";
}
}
步骤3:修改CustomerService,添加add方法
接口
/**
* 添加客户
* @param customer
* @return
*/
boolean add(Customer customer); 实现类
@Override
public boolean add(Customer customer) {
int insert = customerMapper.insertSelective(customer);
return insert == 1;
} 步骤4:修改add.jsp,显示错误信息
<%-- 显示错误信息--%>
<span style="color:red">${error}</span>

3.3 修改客户

3.3.1 需求

3.3.2 显示表单,回显数据

  • 步骤:
  • 步骤1:入口​​/customer/editUI.action?custId=1​​
  • 步骤2:修改CustomerController,用于显示​​customer/edit.jsp​​ 页面
  • 查询数据字典:客户来源(typeCode=002)
  • 查询数据字典:客户行业(typeCode=001)
  • 查询数据字典:客户级别(typeCode=006)
  • 通过custId查询客户详情
  • 步骤3:编写CustomerService,查询客户详情。
  • 步骤4:修改edit.jsp,显示字典相关信息,回显客户信息。
  • 步骤1:入口​​/customer/editUI.action?custId=1​​
  • 步骤2:修改CustomerController,用于显示​​customer/edit.jsp​​ 页面
  • 查询数据字典:客户来源(typeCode=002)
  • 查询数据字典:客户行业(typeCode=001)
  • 查询数据字典:客户级别(typeCode=006)
  • 通过custId查询客户详情
/**
* 修改页面
* @return
*/
@RequestMapping("/editUI")
public String editUI(Long custId, Model model) {

// 客户行业 (typeCode=001)
List<BaseDict> custIndustryBaseDictList = baseDictService.selectAllByTypeCode("001");
model.addAttribute("custIndustryBaseDictList",custIndustryBaseDictList);

// 客户来源(typeCode=002)
List<BaseDict> custSourceBaseDictList = baseDictService.selectAllByTypeCode("002");
model.addAttribute("custSourceBaseDictList",custSourceBaseDictList);


// 客户级别(typeCode=006)
List<BaseDict> custLevelBaseDictList = baseDictService.selectAllByTypeCode("006");
model.addAttribute("custLevelBaseDictList",custLevelBaseDictList);

// 查询客户项
Customer customer = customerService.selectById(custId);
model.addAttribute("customer",customer);

return "customer/edit";
}
  • 步骤3:编写CustomerService,查询客户详情。
  • 接口
/**
* 通过id查询详情
* @param custId
* @return
*/
Customer selectById(Long custId);
实现类@Override
public Customer selectById(Long custId) {
return customerMapper.selectByPrimaryKey(custId);
}
步骤4:修改edit.jsp,显示字典相关信息,回显客户信息。
<select name="custIndustry" class=textbox style="WIDTH: 180px">
<option value="">---请选择---</option>
<c:forEach items="${custIndustryBaseDictList}" var="industry">
<option value="${industry.dictId}" ${customer.custIndustry== industry.dictId?"selected":""}>${industry.dictItemName}</option>
</c:forEach>
</select><td>信息来源 :</td>
<td>
<select name="custSource" class=textbox style="WIDTH: 180px">
<option value="non">---请选择---</option>
<c:forEach items="${custSourceBaseDictList}" var="source">
<option value="${source.dictId}" ${customer.custSource== source.dictId?"selected":""}>${source.dictItemName}</option>
</c:forEach>
</select>
</td>
<td>客户级别:</td>
<td>
<select name="custLevel" class=textbox style="WIDTH: 180px">
<option value="non">---请选择---</option>
<c:forEach items="${custLevelBaseDictList}" var="level">
<option value="${level.dictId}" ${customer.custLevel==level.dictId?"selected":""}>${level.dictItemName}</option>
</c:forEach>
</select>
</td>

3.3.3 修改

  • 步骤:
  • 步骤1:修改edit.jsp页面,确定表单提交路径​​/customer/edit.action​​
  • 步骤2:修改CustomerController,添加edit方法,并处理成功和失败。
  • 步骤3:修改CustomerService,添加edit方法
  • 步骤4:修改edit.jsp,显示错误信息
  • 步骤1:修改edit.jsp页面,确定表单提交路径​​/customer/edit.action​​
  • 步骤2:修改CustomerController,添加edit方法,并处理成功和失败。
/**
* 修改
* @param customer
* @return
*/
@RequestMapping("/edit")
public String edit(Customer customer, Model model) {
try {
// 修改
boolean result = customerService.update(customer);
if(result) {
// 成功
return "redirect:/customer/findAll.action";
} else {
// 失败
model.addAttribute("error","修改客户失败");
return "customer/edit";
}
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("error",e.getMessage());
return "customer/edit";
}
步骤3:修改CustomerService,添加edit方法
接口
/**
* 修改
* @param customer
* @return
*/
boolean update(Customer customer); 实现类
@Override
public boolean update(Customer customer) {
int update = customerMapper.updateByPrimaryKeySelective(customer);
return update == 1;
} 步骤4:修改edit.jsp,显示错误信息

3.4 删除客户

  • 步骤:
  • 步骤1:入口​​customer/delete.action?custId=1​​
  • 步骤2:修改CustomerController,添加delete方法,删除成功重定向到列表页。
  • 步骤3:修改CustomerService,添加delete方法
  • 步骤1:入口​​customer/delete.action?custId=1​​<a href="${pageContext.request.contextPath }/customer/delete.action?custId=${customer.custId}" οnclick="return confirm('您确定要删除【${customer.custName }】吗?')">删除</a>
  • 步骤2:修改CustomerController,添加delete方法,删除成功重定向到列表页。
/**
* 通过id删除客户
* @param custId
* @return
*/
@RequestMapping("/delete")
public String delete(Long custId) {
// 删除
customerService.deleteById(custId);

// 重定向列表页
return "redirect:/customer/findAll.action";
}
步骤3:修改CustomerService,添加delete方法
接口
/**
* 通过id删除
* @param custId
*/
void deleteById(Long custId); 实现类
@Override
public void deleteById(Long custId) {
customerMapper.deleteByPrimaryKey(custId);
}

4. 联系人管理

4.1 联系人与客户关系分析

  • 客户:指的是有很多员工的公司、组织、企业或类似机构。
  • 例如:传智学院
  • 联系人:与某公司(客户)进行对接时,所需要找该公司具体的员工。
  • 例如:教学-梁老师、就业-刘老师、后勤-唐老师
  • 根据分析,在CRM系统中,客户和联系人的关系是​​一对多​​,一个公司有多个对接人。

4.2 查询所有联系人

4.2.1 查询所有

  • 需求:
  • 步骤:
  • 步骤1:入口
  • 步骤2:编写LinkManController
  • 步骤3:编写LinkManService 接口、实现类
  • 步骤4:修改 linkman/list.jsp 展示数据
  • 步骤1:入口
  • 步骤2:编写LinkManControllerpackage com.czxy.crm.controller;

import com.czxy.crm.domain.LinkMan;
import com.czxy.crm.service.LinkManService;
import com.czxy.crm.vo.LinkManVo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Controller
@RequestMapping("/linkman")
public class LinkManController {

@Resource
private LinkManService linkManService;

@RequestMapping("/findAll")
public String findAll(Model model){
// 查询所有
List<LinkMan> linkManList = linkManService.findAll();
model.addAttribute("linkManList", linkManList);

return "linkman/list";
}
}

步骤3:编写LinkManService 接口、实现类
接口package com.czxy.crm.service;

import com.czxy.crm.domain.LinkMan;

import java.util.List;

/**
* @author 桐叔
*/
public interface LinkManService {
/**
* 查询所有
* @param linkManVo
* @return
*/
List<LinkMan> findAll();
}
实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.LinkMan;
import com.czxy.crm.mapper.LinkManMapper;
import com.czxy.crm.service.LinkManService;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class LinkManServiceImpl implements LinkManService {

@Resource
private LinkManMapper linkManMapper;

@Override
public List<LinkMan> findAll() {
//1 条件查询
Example example = new Example(LinkMan.class);

//2 分页查询

//3 查询
List<LinkMan> linkManList = linkManMapper.selectByExample(example);

//4 关联
linkManList.forEach(linkMan -> {
Customer customer = customerMapper.selectByPrimaryKey(linkMan.getCustId());
linkMan.setCustomer(customer);
});

//5 封装
return linkManList;
//return new PageInfo<>(linkManList);
}
}
步骤4:修改 linkman/list.jsp 展示数据<c:forEach items="${linkManList}" var="linkman">
<TR
style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
<TD>${linkman.lkmName }</TD>
<TD>${linkman.lkmGender }</TD>
<TD>${linkman.lkmPhone }</TD>
<TD>${linkman.lkmMobile }</TD>
<TD>${linkman.lkmEmail }</TD>
<TD>${linkman.lkmPosition }</TD>
<TD>${linkman.lkmMemo }</TD>
<TD>${linkman.customer.custName}</TD>
<TD>
<a href="${pageContext.request.contextPath }/linkman/editUI.action?lkmId=${linkman.lkmId}">修改</a>
&nbsp;&nbsp;
<a href="javascript:void(0)" οnclick="deleteLinkMan('${linkman.lkmId}','${linkman.lkmName}')">删除</a>
</TD>
</TR>
</c:forEach>

4.2.2 条件查询

  • 需求:
  • 步骤:
  • 步骤1:入口,确定查询表单
  • 步骤2:创建LinkManVo,用于封装查询条件
  • 步骤3:修改LinkManController,获得查询条件
  • 步骤4:修改LinkManService,使用查询条件
  • 步骤1:入口,确定查询表单
  • 步骤2:创建LinkManVo,用于封装查询条件
package com.czxy.crm.vo;

/**
* @author 桐叔
*/
public class LinkManVo {
private String lkmName;

public String getLkmName() {
return lkmName;
}

public void setLkmName(String lkmName) {
this.lkmName = lkmName;
}
}

步骤3:修改LinkManController,获得查询条件
步骤4:修改LinkManService,使用查询条件
接口
实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.LinkMan;
import com.czxy.crm.mapper.LinkManMapper;
import com.czxy.crm.service.LinkManService;
import com.czxy.crm.vo.LinkManVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class LinkManServiceImpl implements LinkManService {

@Resource
private LinkManMapper linkManMapper;

@Override
public List<LinkMan> findAll(LinkManVo linkManVo) {
//1 条件查询
Example example = new Example(LinkMan.class);
Example.Criteria criteria = example.createCriteria();
if(StringUtils.isNotBlank(linkManVo.getLkmName())) {
criteria.andLike("lkmName", "%"+linkManVo.getLkmName()+"%");
}

//2 分页查询

//3 查询
List<LinkMan> linkManList = linkManMapper.selectByExample(example);

//4 关联
linkManList.forEach(linkMan -> {
Customer customer = customerMapper.selectByPrimaryKey(linkMan.getCustId());
linkMan.setCustomer(customer);
});

//5 封装
return linkManList;
}
}

4.2.3 分页查询

  • 需求:
  • 步骤
  • 步骤1:修改LinkManVo,获得分页参数
  • 步骤2:修改LinkManController,返回pageInfo
  • 步骤3:修改LinkManService,封装PageInfo
  • 步骤4:修改jsp,展示列表数据
  • 步骤5:修改jsp,展示分页条
  • 步骤1:修改LinkManVo,获得分页参数package com.czxy.crm.vo;

/**
* @author 桐叔
*/
public class LinkManVo {
private String lkmName;
private Integer pageNum = 1;
private Integer pageSize = 2;

//getter和setter
}
步骤2:修改LinkManController,返回pageInfo
步骤3:修改LinkManService,封装PageInfo
接口
实现类package com.czxy.crm.service.impl;

import com.czxy.crm.domain.Customer;
import com.czxy.crm.domain.LinkMan;
import com.czxy.crm.mapper.CustomerMapper;
import com.czxy.crm.mapper.LinkManMapper;
import com.czxy.crm.service.LinkManService;
import com.czxy.crm.vo.LinkManVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Service
@Transactional
public class LinkManServiceImpl implements LinkManService {

@Resource
private LinkManMapper linkManMapper;

@Resource
private CustomerMapper customerMapper;

@Override
public PageInfo<LinkMan> findAll(LinkManVo linkManVo) {
//1 条件查询
Example example = new Example(LinkMan.class);
Example.Criteria criteria = example.createCriteria();
if(StringUtils.isNotBlank(linkManVo.getLkmName())) {
criteria.andLike("lkmName", "%"+linkManVo.getLkmName()+"%");
}

//2 分页查询
PageHelper.startPage(linkManVo.getPageNum() ,linkManVo.getPageSize());

//3 查询
List<LinkMan> linkManList = linkManMapper.selectByExample(example);

//4 关联
linkManList.forEach(linkMan -> {
Customer customer = customerMapper.selectByPrimaryKey(linkMan.getCustId());
linkMan.setCustomer(customer);
});

//5 封装
return new PageInfo<>(linkManList);
}
}

步骤4:修改jsp,展示列表数据
步骤5:修改jsp,展示分页条
查询表单
分页条当前第[<B>${pageInfo.pageNum}</B>]页,共[<B>${pageInfo.total}</B>]条
,每页显示
<select οnchange="change(this)">
<option value="1" ${pageInfo.pageSize == 1 ? 'selected' : ''}>1</option>
<option value="2" ${pageInfo.pageSize == 2 ? 'selected' : ''}>2</option>
<option value="3" ${pageInfo.pageSize == 3 ? 'selected' : ''}>3</option>
<option value="5" ${pageInfo.pageSize == 5 ? 'selected' : ''}>5</option>
<option value="10" ${pageInfo.pageSize == 10 ? 'selected' : ''}>10</option>
</select>

<c:if test="${pageInfo.pageNum > 1}">
[<a href="javascript:void(0)" οnclick="page(1)">首页</a>]
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pageNum - 1})">上一页</a>]
</c:if>

<c:forEach begin="1" end="${pageInfo.pages}" var="num">
<b><a href="javascript:void(0)" οnclick="page(${num})">${num}</a></b>
</c:forEach>

<c:if test="${pageInfo.pageNum < pageInfo.pages}">
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pageNum + 1})">下一页</a>]
[<a href="javascript:void(0)" οnclick="page(${pageInfo.pages})">尾页</a>]
</c:if>

<input type="number" style="width: 35px;" value="${customerVo.pageNum}" id="goId"/>


<input type="button" value="Go" οnclick="page(goId.value)"/>
JS函数<SCRIPT language=javascript>
function change(obj) {
// 重置,如果修改了pageSize,从1开始
pageNumId.value = 1
// 修改隐藏字段 pageSize
pageSizeId.value = obj.value
// 提交表单
linkmanFormId.submit()
}

function page(pageNum) {
// 修改pageNum的值
pageNumId.value = pageNum
// 提交表单
linkmanFormId.submit()
}
</SCRIPT>

4.3 添加联系人

4.3.1 需求

4.3.2 显示表单

  • 步骤:
  • 步骤1:入口
  • 步骤2:修改LinkManController,用于显示​​linkman/add.jsp​​ 页面
  • 查询所有客户
  • 步骤3:编写CustomerService,查询所有客户。
  • 步骤4:修改add.jsp,显示客户列表。
  • 步骤1:入口
  • 步骤2:修改LinkManController,用于显示​​linkman/add.jsp​​ 页面
  • 查询所有客户
package com.czxy.crm.controller;

import com.czxy.crm.domain.Customer;
import com.czxy.crm.domain.LinkMan;
import com.czxy.crm.service.CustomerService;
import com.czxy.crm.service.LinkManService;
import com.czxy.crm.vo.CustomerVo;
import com.czxy.crm.vo.LinkManVo;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
* @author 桐叔
*/
@Controller
@RequestMapping("/linkman")
public class LinkManController {

@Resource
private LinkManService linkManService;

@Resource
private CustomerService customerService;

/**
* 显示添加页面
* @param model
* @return
*/
@RequestMapping("/addUI")
public String addUI(Model model) {

// 查询所有客户
List<Customer> allCustomer = customerService.selectAll();
model.addAttribute("allCustomer", allCustomer);

return "linkman/add";
}
}

步骤3:编写CustomerService,查询所有客户。
接口
/**
* 查询所有
* @return
*/
List<Customer> selectAll(); 实现类
@Override
public List<Customer> selectAll() {
return customerMapper.selectAll();
} 步骤4:修改add.jsp,显示客户列表。
<select name="custId">
<option value="">--请选择--</option>
<c:forEach items="${allCustomer}" var="customer">
<option value="${customer.custId}">${customer.custName}</option>
</c:forEach>
</select>

4.3.3 添加

  • 步骤:
  • 步骤1:修改add.jsp页面,确定表单提交路径​​/linkman/add.action​​
  • 步骤2:修改LinkManController,添加add方法,并处理成功和失败。
  • 步骤3:修改LinkManService,添加add方法
  • 步骤4:修改add.jsp,显示错误信息
  • 步骤1:修改add.jsp页面,确定表单提交路径​​/linkman/add.action​​
  • 步骤2:修改LinkManController,添加add方法,并处理成功和失败。
/**
* 添加联系人
* @param linkMan
* @param model
* @return
*/
@RequestMapping("/add")
public String add(LinkMan linkMan , Model model) {

try {
// 查询所有客户
boolean result = linkManService.add(linkMan);
if(result) {
return "redirect:/linkman/findAll.action";
} else {
model.addAttribute("error", "添加联系人失败");
return "linkman/add";
}
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("error", e.getMessage());
return "linkman/add";
}
}
步骤3:修改LinkManService,添加add方法
接口
实现类
@Override
public boolean add(LinkMan linkMan) {
int insert = linkManMapper.insertSelective(linkMan);
return insert == 1;
}
  • 步骤4:修改add.jsp,显示错误信息

4.4 修改联系人

4.4.1 需求

4.4.2 显示表单,回显数据

  • 步骤:
  • 步骤1:入口​​/linkman/editUI.action?lkmId=1​​
  • 步骤2:修改LinkManController,用于显示​​linkman/edit.jsp​​ 页面
  • 查询所有客户
  • 查询当前联系人
  • 步骤3:编写LinkManService,查询联系人详情。
  • 步骤4:修改edit.jsp,显示客户列表,回显联系人信息。
  • 步骤1:入口​​/linkman/editUI.action?lkmId=1​​
  • 步骤2:修改LinkManController,用于显示​​linkman/edit.jsp​​ 页面
  • 查询所有客户
  • 查询当前联系人
/**
* 编辑前操作
* @param lkmId
* @param model
* @return
*/
@RequestMapping("/editUI")
public String editUI(Long lkmId, Model model) {

// 查询所有客户
List<Customer> allCustomer = customerService.selectAll();
model.addAttribute("allCustomer", allCustomer);

// 查询详情
LinkMan linkMan = linkManService.selectById(lkmId);
model.addAttribute("linkMan", linkMan);

return "linkman/edit";
}
  • 步骤3:编写LinkManService,查询联系人详情。
  • 接口
/**
* 查询详情
* @param lkmId
* @return
*/
LinkMan selectById(Long lkmId);
实现类
@Override
public LinkMan selectById(Long lkmId) {
return linkManMapper.selectByPrimaryKey(lkmId);
}
  • 步骤4:修改edit.jsp,显示客户列表,回显联系人信息。


4.4.3 修改

  • 步骤:
  • 步骤1:修改edit.jsp页面,确定表单提交路径​​/linkman/edit.action​​
  • 步骤2:修改LinkManController,添加edit方法,并处理成功和失败。
  • 步骤3:修改LinkManService,添加edit方法
  • 步骤4:修改edit.jsp,显示错误信息
  • 步骤1:修改edit.jsp页面,确定表单提交路径​​/linkman/edit.action​​
  • 步骤2:修改LinkManController,添加edit方法,并处理成功和失败。
/**
* 修改联系人
* @param linkMan
* @param model
* @return
*/
@RequestMapping("/edit")
public String edit(LinkMan linkMan , Model model) {

try {
// 查询所有客户
boolean result = linkManService.update(linkMan);
if(result) {
return "redirect:/linkman/findAll.action";
} else {
model.addAttribute("error", "修改联系人失败");
return "linkman/edit";
}
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("error", e.getMessage());
return "linkman/edit";
}
}
步骤3:修改LinkManService,添加edit方法
接口
实现类
@Override
public boolean update(LinkMan linkMan) {
int update = linkManMapper.updateByPrimaryKeySelective(linkMan);
return update == 1;
} 步骤4:修改edit.jsp,显示错误信息

4.5 删除联系人

  • 步骤:
  • 步骤1:入口​​linkman/delete.action?lkmId=1​​
  • 步骤2:修改LinkManController,添加delete方法,删除成功重定向到列表页。
  • 步骤3:修改LinkManService,添加delete方法
  • 步骤1:入口​​linkman/delete.action?lkmId=1​​<a href="${pageContext.request.contextPath }/linkman/delete.action?lkmId=${linkman.lkmId}" οnclick="return confirm('您确定要删除【${linkman.lkmName}】吗?')">删除</a>
  • 步骤2:修改LinkManController,添加delete方法,删除成功重定向到列表页。
/**
* 通过id删除联系人
* @param lkmId
* @return
*/
@RequestMapping("/delete")
public String delete(Long lkmId) {
// 删除
linkManService.deleteById(lkmId);

// 重定向列表页
return "redirect:/linkman/findAll.action";
}
步骤3:修改LinkManService,添加delete方法
接口
/**
* 删除
* @param lkmId
*/
void deleteById(Long lkmId); 实现类
@Override
public void deleteById(Long lkmId) {
linkManMapper.deleteByPrimaryKey(lkmId);
}

4.6 完善:删除客户

4.6.1 问题:客户和联系人主外键约束

  • 当联系人使用了客户后,此时如果删除客户,默认出现:

4.6.2 解决方案1:自动删除联系人

  • 需求:删除客户前,先删除联系人
  • 步骤:
  • 步骤1:修改 LinkManMapper ,添加 deleteAllByCustId方法
  • 步骤2:修改 CustomerServiceImpl,修改 deleteById 方法
  • 步骤1:修改 LinkManMapper ,添加 deleteAllByCustId方法
package com.czxy.crm.mapper;

import com.czxy.crm.domain.LinkMan;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;

/**
* @author 桐叔
*/
public interface LinkManMapper extends Mapper<LinkMan> {
/**
* 删除指定客户的联系人
* @param custId
*/
@Delete("DELETE FROM cst_linkman WHERE lkm_cust_id = #{custId}")
void deleteAllByCustId(@Param("custId") Long custId);
}

步骤2:修改 CustomerServiceImpl,修改 deleteById 方法
@Override
public void deleteById(Long custId) {
// 依次删除联系人
linkManMapper.deleteAllByCustId(custId);

// 删除客户
customerMapper.deleteByPrimaryKey(custId);
}

4.6.3 作业:完善删除提示

  • 在删除客户时,完成如下2个需求:
  • 需求1:如果客户==没有==关联的联系人,删除时提示“您确定要删除【xxx】吗?”
  • 需求2:如果客户==有==关联的联系人,删除时提示“【xxx】客户关联3个联系人,您确定一并删除吗?”

end

上一篇:ServerReactor 和 ServerReceiver
下一篇:没有了
网友评论