CRM客户关系管理系统开发第十七讲——实现客户拜访记录管理模块中分页查询客户拜访记录列表的功能
在CRM客戶(hù)關(guān)系管理系統(tǒng)中,客戶(hù)的拜訪是很重要的一個(gè)環(huán)節(jié),由業(yè)務(wù)員面見(jiàn)客戶(hù)并介紹公司的相關(guān)的業(yè)務(wù),在業(yè)務(wù)員回到公司以后,需要對(duì)此次的拜訪的整個(gè)過(guò)程記錄下來(lái),記錄中需要包含拜訪的客戶(hù)的姓名,拜訪的時(shí)間以及拜訪的地點(diǎn)等信息。
準(zhǔn)備工作
在正式編寫(xiě)代碼實(shí)現(xiàn)客戶(hù)拜訪記錄管理模塊中分頁(yè)查詢(xún)客戶(hù)拜訪記錄列表的功能之前,我們得做一些準(zhǔn)備工作,因?yàn)檫@個(gè)功能實(shí)現(xiàn)起來(lái)還是比較難的,不能一蹴而就。
分析客戶(hù)表和用戶(hù)表它倆之間的關(guān)系
一個(gè)使用系統(tǒng)的用戶(hù)其實(shí)就是一個(gè)公司的業(yè)務(wù)員,公司業(yè)務(wù)員需要對(duì)客戶(hù)進(jìn)行拜訪,并對(duì)拜訪的過(guò)程進(jìn)行記錄。現(xiàn)在出現(xiàn)了一個(gè)問(wèn)題,那就是客戶(hù)表和用戶(hù)表它倆之間到底是啥子關(guān)系呢?正常情況下,需要根據(jù)具體業(yè)務(wù)具體分析,但一般都逃不過(guò)如下兩種關(guān)系:
- 一對(duì)多的關(guān)系:可能公司比較小,產(chǎn)品比較單一,只允許一個(gè)業(yè)務(wù)員對(duì)應(yīng)多個(gè)客戶(hù),這就是一對(duì)多的關(guān)系;
- 多對(duì)多的關(guān)系:一些大公司有不同的產(chǎn)品,不同產(chǎn)品下有不同業(yè)務(wù)員都可以接觸到同一個(gè)客戶(hù),即一個(gè)客戶(hù)對(duì)應(yīng)了多個(gè)業(yè)務(wù)員,不僅如此,一個(gè)業(yè)務(wù)員也可以拜訪多個(gè)客戶(hù),即一個(gè)業(yè)務(wù)員對(duì)應(yīng)了多個(gè)客戶(hù),這就是多對(duì)多的關(guān)系。
大部分情況下,客戶(hù)表和用戶(hù)表它倆之間是多對(duì)多的關(guān)系,這里,我們也采用這種關(guān)系。既然是多對(duì)多的關(guān)系,那就需要?jiǎng)?chuàng)建中間表了,正常的中間表是只需要有兩個(gè)字段的,而且這兩個(gè)字段分別作為外鍵指向多對(duì)多雙方各自的主鍵。但是我們現(xiàn)在的要求是需要記錄拜訪的時(shí)間,拜訪地點(diǎn)等信息的,所以這些信息也需要存在于中間表中。
創(chuàng)建拜訪記錄表
在crm數(shù)據(jù)庫(kù)下新建一張拜訪記錄表,也即中間表,其建表的sql語(yǔ)句如下:
CREATE TABLE `sale_visit` (`visit_id` varchar(32) NOT NULL,`visit_cust_id` bigint(32) DEFAULT NULL COMMENT '客戶(hù)id',`visit_user_id` bigint(32) DEFAULT NULL COMMENT '負(fù)責(zé)人id',`visit_time` date DEFAULT NULL COMMENT '拜訪時(shí)間',`visit_addr` varchar(128) DEFAULT NULL COMMENT '拜訪地點(diǎn)',`visit_detail` varchar(256) DEFAULT NULL COMMENT '拜訪詳情',`visit_nexttime` date DEFAULT NULL COMMENT '下次拜訪時(shí)間',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;創(chuàng)建SaleVisit實(shí)體類(lèi)及其對(duì)應(yīng)的映射配置文件
首先,在com.meimeixia.crm.domain包下創(chuàng)建一個(gè)SaleVisit實(shí)體類(lèi)及其相對(duì)應(yīng)的映射配置文件。
-
SaleVisit實(shí)體類(lèi):
package com.meimeixia.crm.domain;import java.util.Date;/*** 客戶(hù)拜訪記錄管理的實(shí)體* @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;//拜訪記錄所關(guān)聯(lián)的客戶(hù)對(duì)象private Customer customer;//拜訪記錄所關(guān)聯(lián)的用戶(hù)對(duì)象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;}}上面我講過(guò),如果中間表中有其他的字段參與到業(yè)務(wù)邏輯運(yùn)算當(dāng)中,那么就不能創(chuàng)建普通的多對(duì)多的映射關(guān)系了,需要?jiǎng)?chuàng)建兩個(gè)一對(duì)多來(lái)實(shí)現(xiàn)多對(duì)多的關(guān)系。所以,肯定是要在創(chuàng)建SaleVisit實(shí)體類(lèi)時(shí),在這一端寫(xiě)上一的一方的對(duì)象的,需不需要在另外的一端放置多的一方的集合呢?這個(gè)得根據(jù)具體情況具體分析,就是說(shuō)你自己要判斷好在查詢(xún)客戶(hù)的時(shí)候,需不需要去關(guān)聯(lián)查詢(xún)客戶(hù)所對(duì)應(yīng)的拜訪記錄,如果不需要,那么配置單向的關(guān)聯(lián)關(guān)系就行了。例如,在以上的SaleVisit實(shí)體類(lèi)中,客戶(hù)和拜訪記錄就是單向的關(guān)聯(lián)關(guān)系(在客戶(hù)實(shí)體類(lèi)這邊并沒(méi)有放置拜訪記錄的集合),這意味著在查詢(xún)拜訪記錄的時(shí)候,可以查看到所關(guān)聯(lián)的客戶(hù)信息(這個(gè)人拜訪了哪個(gè)客戶(hù)),在查詢(xún)客戶(hù)的時(shí)候,不會(huì)查看到他具體被哪個(gè)用戶(hù)所拜訪了。
-
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><!-- 建立類(lèi)與表的映射 --><class name="com.meimeixia.crm.domain.SaleVisit" table="sale_visit"><!-- 建立類(lèi)中的屬性與表中的主鍵相對(duì)應(yīng) --><id name="visit_id" column="visit_id"><!-- 主鍵的生成策略 --><generator class="uuid" /></id><!-- 建立類(lèi)中的普通屬性和表中的字段相對(duì)應(yīng) --><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" /><!-- 配置與客戶(hù)的關(guān)聯(lián)關(guān)系 --><many-to-one name="customer" class="com.meimeixia.crm.domain.Customer" column="visit_cust_id"></many-to-one><!-- 配置與用戶(hù)的關(guān)聯(lián)關(guān)系 --><many-to-one name="user" class="com.meimeixia.crm.domain.User" column="visit_user_id"></many-to-one></class> </hibernate-mapping>
然后,千萬(wàn)記得要把SaleVisit實(shí)體類(lèi)相對(duì)應(yīng)的映射配置文件交給Spring來(lái)管理!
創(chuàng)建相關(guān)的類(lèi)(接口)
之前,我們一直是在使用Spring中IoC的XML開(kāi)發(fā)方式進(jìn)行開(kāi)發(fā),這兒,我會(huì)換一種開(kāi)發(fā)方式,即使用XML文件和注解的整合開(kāi)發(fā),在這種整合開(kāi)發(fā)中,我們會(huì)使用XML文件來(lái)管理Bean,使用注解完成屬性注入。接下來(lái),我便會(huì)創(chuàng)建客戶(hù)拜訪記錄管理模塊中相關(guān)的類(lèi)和接口。
首先,創(chuàng)建web層相關(guān)的類(lèi),即在com.meimeixia.crm.web.action包下創(chuàng)建一個(gè)SaleVisitAction類(lèi),在該類(lèi)中使用注解完成屬性注入。
然后,創(chuàng)建service層相關(guān)的類(lèi)。
-
先在com.meimeixia.crm.service包下創(chuàng)建一個(gè)SaleVisitService接口,一開(kāi)始該接口中并沒(méi)有聲明任何方法,如下:
package com.meimeixia.crm.service;/*** 客戶(hù)拜訪記錄的業(yè)務(wù)層的接口* @author liayun**/ public interface SaleVisitService {} -
再在com.meimeixia.crm.service.impl包下編寫(xiě)以上接口的一個(gè)實(shí)現(xiàn)類(lèi)——SaleVisitServiceImpl.java,在該類(lèi)中同樣使用注解完成屬性注入。
package com.meimeixia.crm.service.impl;import javax.annotation.Resource;import com.meimeixia.crm.dao.SaleVisitDao; import com.meimeixia.crm.service.SaleVisitService;/*** 客戶(hù)拜訪記錄的業(yè)務(wù)層的實(shí)現(xiàn)類(lèi)* @author liayun**/ public class SaleVisitServiceImpl implements SaleVisitService {//注入客戶(hù)拜訪記錄的dao@Resource(name="saleVisitDao")private SaleVisitDao saleVisitDao;}
接著,創(chuàng)建dao層相關(guān)的類(lèi)。
-
先在com.meimeixia.crm.dao包下創(chuàng)建一個(gè)SaleVisitDao接口,并讓其繼承通用的BaseDao<T>接口,因?yàn)楦附涌谥幸呀?jīng)定義了基本的CRUD的操作的相關(guān)方法,所以子接口中可以直接從父接口中繼承過(guò)來(lái),而不再需要自己編寫(xiě)了。
package com.meimeixia.crm.dao;import com.meimeixia.crm.domain.SaleVisit;/*** 客戶(hù)拜訪記錄的dao的接口* @author liayun**/ public interface SaleVisitDao extends BaseDao<SaleVisit> {} -
再在com.meimeixia.crm.dao.impl包下編寫(xiě)以上接口的一個(gè)實(shí)現(xiàn)類(lèi)——SaleVisitDaoImpl.java。在該實(shí)現(xiàn)類(lèi)中,也不再需要那些任何有關(guān)CRUD的代碼了,因?yàn)樵谕ㄓ玫腂aseDaoImpl<T>實(shí)現(xiàn)類(lèi)中已經(jīng)對(duì)這些方法實(shí)現(xiàn)過(guò)了,我們自己編寫(xiě)的SaleVisitDaoImpl實(shí)現(xiàn)類(lèi)只需要繼承該通用實(shí)現(xiàn)類(lèi)就可以了。
package com.meimeixia.crm.dao.impl;import com.meimeixia.crm.dao.SaleVisitDao; import com.meimeixia.crm.domain.SaleVisit;/*** 客戶(hù)拜訪記錄的dao的實(shí)現(xiàn)類(lèi)* @author liayun**/ public class SaleVisitDaoImpl extends BaseDaoImpl<SaleVisit> implements SaleVisitDao {}
最后,我們還要在Spring配置文件里面開(kāi)啟屬性注入的注解,一旦開(kāi)啟了這么一個(gè)玩意,那么就可以在沒(méi)有組件掃描的情況下,來(lái)使用那些屬性注入的注解了,也就是說(shuō)可以直接使用@Resource、@Value、@Autowired、@Qualifier這些注解了。
還有不要忘了在Spring配置文件中對(duì)以上類(lèi)進(jìn)行配置,即將這些相關(guān)的類(lèi)交給Spring來(lái)管理。
編寫(xiě)代碼實(shí)現(xiàn)分頁(yè)查詢(xún)客戶(hù)拜訪記錄列表的功能
在左側(cè)的菜單頁(yè)面(menu.jsp)中修改提交路徑
編寫(xiě)web層
首先,我們要在SaleVisitAction類(lèi)中編寫(xiě)一個(gè)分頁(yè)查詢(xún)客戶(hù)拜訪記錄列表的方法。在該方法中,需要接收分頁(yè)查詢(xún)的參數(shù),這里最好使用離線(xiàn)條件查詢(xún)對(duì)象(即DetachedCriteria對(duì)象),因?yàn)橛昧怂?#xff0c;在我們底層Hibernate模板調(diào)用的時(shí)候,直接就可以進(jìn)行分頁(yè)查詢(xún)了,而且后期咱們進(jìn)行條件查詢(xún)(條件查詢(xún)還能帶分頁(yè)),使用DetachedCriteria這個(gè)對(duì)象就會(huì)變得非常方便。
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;/*** 客戶(hù)拜訪記錄的Action類(lèi)* @author liayun**/ public class SaleVisitAction extends ActionSupport implements ModelDriven<SaleVisit> {//模型驅(qū)動(dòng)使用的對(duì)象private SaleVisit saleVisit = new SaleVisit();@Overridepublic SaleVisit getModel() {return saleVisit;}//在Action中注入service@Resource(name="saleVisitService")private SaleVisitService saleVisitService;//接收分頁(yè)查詢(xún)的參數(shù)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;}/** 查詢(xún)拜訪記錄列表的方法*/public String findAll() {//創(chuàng)建離線(xiàn)條件查詢(xún)對(duì)象DetachedCriteria detachedCriteria = DetachedCriteria.forClass(SaleVisit.class);//如果有條件,那么就設(shè)置條件//...//調(diào)用業(yè)務(wù)層PageBean<SaleVisit> pageBean = saleVisitService.findByPage(detachedCriteria, currentPage, pageSize);//把pageBean存入值棧ActionContext.getContext().getValueStack().push(pageBean);return "findAll";}}然后,我們還得在Struts2配置文件中(即struts.xml)對(duì)SaleVisitAction進(jìn)行如下的配置,即配置頁(yè)面的跳轉(zhuǎn)。
編寫(xiě)service層
首先,在SaleVisitService接口中添加一個(gè)分頁(yè)查詢(xún)客戶(hù)拜訪記錄列表的方法聲明,如下:
package com.meimeixia.crm.service;import org.hibernate.criterion.DetachedCriteria;import com.meimeixia.crm.domain.PageBean; import com.meimeixia.crm.domain.SaleVisit;/*** 客戶(hù)拜訪記錄的業(yè)務(wù)層的接口* @author liayun**/ public interface SaleVisitService {PageBean<SaleVisit> findByPage(DetachedCriteria detachedCriteria, Integer currentPage, Integer pageSize);}然后,在以上接口的一個(gè)實(shí)現(xiàn)類(lèi)(SaleVisitServiceImpl.java)中去實(shí)現(xiàn)分頁(yè)查詢(xún)客戶(hù)拜訪記錄列表的方法。
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;/*** 客戶(hù)拜訪記錄的業(yè)務(wù)層的實(shí)現(xiàn)類(lèi)* @author liayun**/ //@Transactional public class SaleVisitServiceImpl implements SaleVisitService {//注入客戶(hù)拜訪記錄的dao@Resource(name="saleVisitDao")private SaleVisitDao saleVisitDao;//業(yè)務(wù)層分頁(yè)顯示拜訪記錄的方法@Overridepublic PageBean<SaleVisit> findByPage(DetachedCriteria detachedCriteria, Integer currentPage, Integer pageSize) {PageBean<SaleVisit> pageBean = new PageBean<SaleVisit>();//設(shè)置當(dāng)前頁(yè)數(shù)pageBean.setCurrentPage(currentPage);//設(shè)置每頁(yè)顯示的記錄數(shù)pageBean.setPageSize(pageSize);//設(shè)置總記錄數(shù)Integer totalCount = saleVisitDao.findCount(detachedCriteria);pageBean.setTotalCount(totalCount);//設(shè)置總頁(yè)數(shù)double tc = totalCount;Double num = Math.ceil(tc / pageSize);pageBean.setTotalPage(num.intValue());//設(shè)置每頁(yè)顯示的數(shù)據(jù)的集合Integer begin = (currentPage - 1) * pageSize;List<SaleVisit> list = saleVisitDao.findByPage(detachedCriteria, begin, pageSize);pageBean.setList(list);return pageBean;}}在客戶(hù)拜訪記錄列表頁(yè)面中顯示數(shù)據(jù)
猛然發(fā)現(xiàn)沒(méi)有這個(gè)客戶(hù)拜訪記錄列表頁(yè)面啊!那咋辦?很簡(jiǎn)單,復(fù)制一份聯(lián)系人列表頁(yè)面(list.jsp),將其存放到WebContent/jsp/salevisit目錄下,以此作為客戶(hù)拜訪記錄列表頁(yè)面,在該頁(yè)面中,我們只需要做一點(diǎn)點(diǎn)修改,即將查詢(xún)出來(lái)的客戶(hù)拜訪記錄列表數(shù)據(jù)在頁(yè)面中顯示出來(lái)。
該頁(yè)面底部的分頁(yè)工具條的實(shí)現(xiàn)代碼,我們就可以不用寫(xiě)了,復(fù)用之前的代碼片段就行!此時(shí),發(fā)布我們的項(xiàng)目到Tomcat服務(wù)器并啟動(dòng),然后訪問(wèn)該項(xiàng)目的首頁(yè),點(diǎn)擊客戶(hù)拜訪列表超鏈接之后,你就能看到客戶(hù)拜訪記錄列表了。
總結(jié)
以上是生活随笔為你收集整理的CRM客户关系管理系统开发第十七讲——实现客户拜访记录管理模块中分页查询客户拜访记录列表的功能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: spss24 中文版 2.数据清洗与处理
- 下一篇: 【idea2018调节字体大小】