CRM客户关系管理系统开发第十七讲——实现客户拜访记录管理模块中分页查询客户拜访记录列表的功能

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/yerenyuan_pku/article/details/102308589

在CRM客户关系管理系统中,客户的拜访是很重要的一个环节,由业务员面见客户并介绍公司的相关的业务,在业务员回到公司以后,需要对此次的拜访的整个过程记录下来,记录中需要包含拜访的客户的姓名,拜访的时间以及拜访的地点等信息。
在这里插入图片描述

准备工作

在正式编写代码实现客户拜访记录管理模块中分页查询客户拜访记录列表的功能之前,我们得做一些准备工作,因为这个功能实现起来还是比较难的,不能一蹴而就。

分析客户表和用户表它俩之间的关系

一个使用系统的用户其实就是一个公司的业务员,公司业务员需要对客户进行拜访,并对拜访的过程进行记录。现在出现了一个问题,那就是客户表和用户表它俩之间到底是啥子关系呢?正常情况下,需要根据具体业务具体分析,但一般都逃不过如下两种关系:

  • 一对多的关系:可能公司比较小,产品比较单一,只允许一个业务员对应多个客户,这就是一对多的关系;
  • 多对多的关系:一些大公司有不同的产品,不同产品下有不同业务员都可以接触到同一个客户,即一个客户对应了多个业务员,不仅如此,一个业务员也可以拜访多个客户,即一个业务员对应了多个客户,这就是多对多的关系。

大部分情况下,客户表和用户表它俩之间是多对多的关系,这里,我们也采用这种关系。既然是多对多的关系,那就需要创建中间表了,正常的中间表是只需要有两个字段的,而且这两个字段分别作为外键指向多对多双方各自的主键。但是我们现在的要求是需要记录拜访的时间,拜访地点等信息的,所以这些信息也需要存在于中间表中。
在这里插入图片描述

创建拜访记录表

在crm数据库下新建一张拜访记录表,也即中间表,其建表的sql语句如下:

CREATE TABLE `sale_visit` (
	`visit_id` varchar(32) NOT NULL,
	`visit_cust_id` bigint(32) DEFAULT NULL COMMENT '客户id',
	`visit_user_id` bigint(32) DEFAULT NULL COMMENT '负责人id',
	`visit_time` date DEFAULT NULL COMMENT '拜访时间',
	`visit_addr` varchar(128) DEFAULT NULL COMMENT '拜访地点',
	`visit_detail` varchar(256) DEFAULT NULL COMMENT '拜访详情',
	`visit_nexttime` date DEFAULT NULL COMMENT '下次拜访时间',
	PRIMARY KEY (`visit_id`),
	KEY `FK_sale_visit_cust_id` (`visit_cust_id`),
	KEY `FK_sale_visit_user_id` (`visit_user_id`),
	CONSTRAINT `FK_sale_visit_cust_id` FOREIGN KEY (`visit_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
	CONSTRAINT `FK_sale_visit_user_id` FOREIGN KEY (`visit_user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建SaleVisit实体类及其对应的映射配置文件

首先,在com.meimeixia.crm.domain包下创建一个SaleVisit实体类及其相对应的映射配置文件。

  • SaleVisit实体类:

    package com.meimeixia.crm.domain;
    
    import java.util.Date;
    
    /**
     * 客户拜访记录管理的实体
     * @author liayun
     *
     */
    public class SaleVisit {
    
    	private String visit_id;
    	private Date visit_time;
    	private String visit_addr;
    	private String visit_detail;
    	private Date visit_nexttime;
    	
    	//拜访记录所关联的客户对象
    	private Customer customer;
    	//拜访记录所关联的用户对象
    	private User user;
    	
    	public String getVisit_id() {
    		return visit_id;
    	}
    	public void setVisit_id(String visit_id) {
    		this.visit_id = visit_id;
    	}
    	public Date getVisit_time() {
    		return visit_time;
    	}
    	public void setVisit_time(Date visit_time) {
    		this.visit_time = visit_time;
    	}
    	public String getVisit_addr() {
    		return visit_addr;
    	}
    	public void setVisit_addr(String visit_addr) {
    		this.visit_addr = visit_addr;
    	}
    	public String getVisit_detail() {
    		return visit_detail;
    	}
    	public void setVisit_detail(String visit_detail) {
    		this.visit_detail = visit_detail;
    	}
    	public Date getVisit_nexttime() {
    		return visit_nexttime;
    	}
    	public void setVisit_nexttime(Date visit_nexttime) {
    		this.visit_nexttime = visit_nexttime;
    	}
    	public Customer getCustomer() {
    		return customer;
    	}
    	public void setCustomer(Customer customer) {
    		this.customer = customer;
    	}
    	public User getUser() {
    		return user;
    	}
    	public void setUser(User user) {
    		this.user = user;
    	}
    	
    }
    

    上面我讲过,如果中间表中有其他的字段参与到业务逻辑运算当中,那么就不能创建普通的多对多的映射关系了,需要创建两个一对多来实现多对多的关系。所以,肯定是要在创建SaleVisit实体类时,在这一端写上一的一方的对象的,需不需要在另外的一端放置多的一方的集合呢?这个得根据具体情况具体分析,就是说你自己要判断好在查询客户的时候,需不需要去关联查询客户所对应的拜访记录,如果不需要,那么配置单向的关联关系就行了。例如,在以上的SaleVisit实体类中,客户和拜访记录就是单向的关联关系(在客户实体类这边并没有放置拜访记录的集合),这意味着在查询拜访记录的时候,可以查看到所关联的客户信息(这个人拜访了哪个客户),在查询客户的时候,不会查看到他具体被哪个用户所拜访了。

  • SaleVisit.hbm.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
    <hibernate-mapping>
    	<!-- 建立类与表的映射 -->
    	<class name="com.meimeixia.crm.domain.SaleVisit" table="sale_visit">
    		<!-- 建立类中的属性与表中的主键相对应 -->
    		<id name="visit_id" column="visit_id">
    			<!-- 主键的生成策略 -->
    			<generator class="uuid" />
    		</id>
    		
    		<!-- 建立类中的普通属性和表中的字段相对应 -->
    		<property name="visit_time" column="visit_time" />
    		<property name="visit_addr" column="visit_addr" />
    		<property name="visit_detail" column="visit_detail" />
    		<property name="visit_nexttime" column="visit_nexttime" />
    		
    		<!-- 配置与客户的关联关系 -->
    		<many-to-one name="customer" class="com.meimeixia.crm.domain.Customer" column="visit_cust_id"></many-to-one>
    		<!-- 配置与用户的关联关系 -->
    		<many-to-one name="user" class="com.meimeixia.crm.domain.User" column="visit_user_id"></many-to-one>
    	</class>
    </hibernate-mapping>
    

然后,千万记得要把SaleVisit实体类相对应的映射配置文件交给Spring来管理!
在这里插入图片描述

创建相关的类(接口)

之前,我们一直是在使用Spring中IoC的XML开发方式进行开发,这儿,我会换一种开发方式,即使用XML文件和注解的整合开发,在这种整合开发中,我们会使用XML文件来管理Bean,使用注解完成属性注入。接下来,我便会创建客户拜访记录管理模块中相关的类和接口。
首先,创建web层相关的类,即在com.meimeixia.crm.web.action包下创建一个SaleVisitAction类,在该类中使用注解完成属性注入。

package com.meimeixia.crm.web.action;

import javax.annotation.Resource;

import com.meimeixia.crm.domain.SaleVisit;
import com.meimeixia.crm.service.SaleVisitService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

/**
 * 客户拜访记录的Action类
 * @author liayun
 *
 */
public class SaleVisitAction extends ActionSupport implements ModelDriven<SaleVisit> {
	
	//模型驱动使用的对象
	private SaleVisit saleVisit = new SaleVisit();

	@Override
	public SaleVisit getModel() {
		return saleVisit;
	}
	
	//在Action中注入service
	@Resource(name="saleVisitService")
	private SaleVisitService saleVisitService;
	
}

然后,创建service层相关的类。

  • 先在com.meimeixia.crm.service包下创建一个SaleVisitService接口,一开始该接口中并没有声明任何方法,如下:

    package com.meimeixia.crm.service;
    
    /**
     * 客户拜访记录的业务层的接口
     * @author liayun
     *
     */
    public interface SaleVisitService {
    
    }
    
  • 再在com.meimeixia.crm.service.impl包下编写以上接口的一个实现类——SaleVisitServiceImpl.java,在该类中同样使用注解完成属性注入。

    package com.meimeixia.crm.service.impl;
    
    import javax.annotation.Resource;
    
    import com.meimeixia.crm.dao.SaleVisitDao;
    import com.meimeixia.crm.service.SaleVisitService;
    
    /**
     * 客户拜访记录的业务层的实现类
     * @author liayun
     *
     */
    public class SaleVisitServiceImpl implements SaleVisitService {
    
    	//注入客户拜访记录的dao
    	@Resource(name="saleVisitDao")
    	private SaleVisitDao saleVisitDao;
    	
    }
    

接着,创建dao层相关的类。

  • 先在com.meimeixia.crm.dao包下创建一个SaleVisitDao接口,并让其继承通用的BaseDao<T>接口,因为父接口中已经定义了基本的CRUD的操作的相关方法,所以子接口中可以直接从父接口中继承过来,而不再需要自己编写了。

    package com.meimeixia.crm.dao;
    
    import com.meimeixia.crm.domain.SaleVisit;
    
    /**
     * 客户拜访记录的dao的接口
     * @author liayun
     *
     */
    public interface SaleVisitDao extends BaseDao<SaleVisit> {
    
    }
    
  • 再在com.meimeixia.crm.dao.impl包下编写以上接口的一个实现类——SaleVisitDaoImpl.java。在该实现类中,也不再需要那些任何有关CRUD的代码了,因为在通用的BaseDaoImpl<T>实现类中已经对这些方法实现过了,我们自己编写的SaleVisitDaoImpl实现类只需要继承该通用实现类就可以了。

    package com.meimeixia.crm.dao.impl;
    
    import com.meimeixia.crm.dao.SaleVisitDao;
    import com.meimeixia.crm.domain.SaleVisit;
    
    /**
     * 客户拜访记录的dao的实现类
     * @author liayun
     *
     */
    public class SaleVisitDaoImpl extends BaseDaoImpl<SaleVisit> implements SaleVisitDao {
    
    }
    

最后,我们还要在Spring配置文件里面开启属性注入的注解,一旦开启了这么一个玩意,那么就可以在没有组件扫描的情况下,来使用那些属性注入的注解了,也就是说可以直接使用@Resource、@Value、@Autowired、@Qualifier这些注解了。
在这里插入图片描述
还有不要忘了在Spring配置文件中对以上类进行配置,即将这些相关的类交给Spring来管理。
在这里插入图片描述

编写代码实现分页查询客户拜访记录列表的功能

在左侧的菜单页面(menu.jsp)中修改提交路径

在这里插入图片描述

编写web层

首先,我们要在SaleVisitAction类中编写一个分页查询客户拜访记录列表的方法。在该方法中,需要接收分页查询的参数,这里最好使用离线条件查询对象(即DetachedCriteria对象),因为用了它之后,在我们底层Hibernate模板调用的时候,直接就可以进行分页查询了,而且后期咱们进行条件查询(条件查询还能带分页),使用DetachedCriteria这个对象就会变得非常方便。

package com.meimeixia.crm.web.action;

import javax.annotation.Resource;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import com.meimeixia.crm.domain.PageBean;
import com.meimeixia.crm.domain.SaleVisit;
import com.meimeixia.crm.service.SaleVisitService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

/**
 * 客户拜访记录的Action类
 * @author liayun
 *
 */
public class SaleVisitAction extends ActionSupport implements ModelDriven<SaleVisit> {
	
	//模型驱动使用的对象
	private SaleVisit saleVisit = new SaleVisit();

	@Override
	public SaleVisit getModel() {
		return saleVisit;
	}
	
	//在Action中注入service
	@Resource(name="saleVisitService")
	private SaleVisitService saleVisitService;
	
	//接收分页查询的参数
	private Integer currentPage = 1;
	private Integer pageSize = 3;
	
	public void setCurrentPage(Integer currentPage) {
		if (currentPage == null) {
			currentPage = 1;
		}
		this.currentPage = currentPage;
	}

	public void setPageSize(Integer pageSize) {
		if (pageSize == null) {
			pageSize = 3;
		}
		this.pageSize = pageSize;
	}

	/*
	 * 查询拜访记录列表的方法
	 */
	public String findAll() {
		//创建离线条件查询对象
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(SaleVisit.class);
		//如果有条件,那么就设置条件
		//...
		//调用业务层
		PageBean<SaleVisit> pageBean = saleVisitService.findByPage(detachedCriteria, currentPage, pageSize);
		//把pageBean存入值栈
		ActionContext.getContext().getValueStack().push(pageBean);
		return "findAll";
	}
	
}

然后,我们还得在Struts2配置文件中(即struts.xml)对SaleVisitAction进行如下的配置,即配置页面的跳转。
在这里插入图片描述

编写service层

首先,在SaleVisitService接口中添加一个分页查询客户拜访记录列表的方法声明,如下:

package com.meimeixia.crm.service;

import org.hibernate.criterion.DetachedCriteria;

import com.meimeixia.crm.domain.PageBean;
import com.meimeixia.crm.domain.SaleVisit;

/**
 * 客户拜访记录的业务层的接口
 * @author liayun
 *
 */
public interface SaleVisitService {

	PageBean<SaleVisit> findByPage(DetachedCriteria detachedCriteria, Integer currentPage, Integer pageSize);

}

然后,在以上接口的一个实现类(SaleVisitServiceImpl.java)中去实现分页查询客户拜访记录列表的方法。

package com.meimeixia.crm.service.impl;

import java.util.List;

import javax.annotation.Resource;

import org.hibernate.criterion.DetachedCriteria;

import com.meimeixia.crm.dao.SaleVisitDao;
import com.meimeixia.crm.domain.PageBean;
import com.meimeixia.crm.domain.SaleVisit;
import com.meimeixia.crm.service.SaleVisitService;

/**
 * 客户拜访记录的业务层的实现类
 * @author liayun
 *
 */
//@Transactional
public class SaleVisitServiceImpl implements SaleVisitService {

	//注入客户拜访记录的dao
	@Resource(name="saleVisitDao")
	private SaleVisitDao saleVisitDao;

	//业务层分页显示拜访记录的方法
	@Override
	public PageBean<SaleVisit> findByPage(DetachedCriteria detachedCriteria, Integer currentPage, Integer pageSize) {
		PageBean<SaleVisit> pageBean = new PageBean<SaleVisit>();
		//设置当前页数
		pageBean.setCurrentPage(currentPage);
		//设置每页显示的记录数
		pageBean.setPageSize(pageSize);
		//设置总记录数
		Integer totalCount = saleVisitDao.findCount(detachedCriteria);
		pageBean.setTotalCount(totalCount);
		//设置总页数
		double tc = totalCount;
		Double num = Math.ceil(tc / pageSize);
		pageBean.setTotalPage(num.intValue());
		//设置每页显示的数据的集合
		Integer begin = (currentPage - 1) * pageSize;
		List<SaleVisit> list = saleVisitDao.findByPage(detachedCriteria, begin, pageSize);
		pageBean.setList(list);
		return pageBean;
	}
	
}

在客户拜访记录列表页面中显示数据

猛然发现没有这个客户拜访记录列表页面啊!那咋办?很简单,复制一份联系人列表页面(list.jsp),将其存放到WebContent/jsp/salevisit目录下,以此作为客户拜访记录列表页面,在该页面中,我们只需要做一点点修改,即将查询出来的客户拜访记录列表数据在页面中显示出来。
在这里插入图片描述
该页面底部的分页工具条的实现代码,我们就可以不用写了,复用之前的代码片段就行!此时,发布我们的项目到Tomcat服务器并启动,然后访问该项目的首页,点击客户拜访列表超链接之后,你就能看到客户拜访记录列表了。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yerenyuan_pku/article/details/102308589