Java项目:CRM客户关系管理系统(Spring+SpringMVC+MyBatis + maven)
目录
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 桐叔 * @email liangtong@itcast.cn */ 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.properties
jdbc.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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ public interface LinkManMapper extends Mapper<LinkMan> { }
3. 客户管理
3.1 查询所有客户
3.1.1 查询所有
-
需求:查询所有客户
-
步骤:
-
步骤1:入口
-
步骤2:编写Controller
-
步骤3:编写Service 接口、实现类
-
步骤4:修改 list.jsp展示数据
-
-
步骤1:入口
-
步骤2:编写Controller
package 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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,用于封装查询条件
package com.czxy.crm.vo; /** * @author 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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:编写LinkManController
package 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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,用于封装查询条件
package com.czxy.crm.vo; /** * @author 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ @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 桐叔 * @email liangtong@itcast.cn */ 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个联系人,您确定一并删除吗?”
-