目录
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所在包,并创建对应的包
- 修改视图解析器的前后缀
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
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.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 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>
<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,用于封装查询条件
/**
* @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
- 接口
- 实现类
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>]条 ,每页显示
<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)
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 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>
<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,用于封装查询条件
/**
* @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 页面
- 查询所有客户
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方法
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个联系人,您确定一并删除吗?”