1. 程式人生 > >crm經典總結

crm經典總結

crm-01

1、搭建開發環境
	* 配置eclipse工作區字符集:UTF-8
	* 新建一個web專案(生成web.xml檔案),我們這裡使用的是Servlet3.1版本。
	* 將原型拷貝到WebContent目錄下。
	* 部署專案,啟動伺服器,測試。
	* 引入jar包,配置檔案,工具類。

crm-02

1、設計資料庫表,工具:PowerDesigner(PDM建模:物理資料模型)
	tbl_dic_type
	tbl_dic_value
	
	資料庫表設計的時候注意事項:
	
		* 一般情況下為了開發方便,能用字串型別儘量用字串型別:Varchar/Char....(java:String)
		
		* 在實際開發中為了保證程式的執行效率,一般是不建議新增外來鍵約束的(FK一般不新增)。
		添加了外來鍵約束之後,會讓檢索效率降低。例如A表使用了B表的某個欄位作為外來鍵,在進行A
		表資料檢索的時候,不管是否取B表中的資料,總會關聯去B表中進行檢索,這樣效率很低,為了
		提高程式的執行效率,不新增外來鍵約束,不新增外來鍵約束,怎麼保證資料的有效性和完整性呢?
			在前端頁面設計的時候,使用下拉列表方式。
	
	執行sql指令碼:
		mysql> source D:\course\14-CRM\01-基礎資料\crm-1.sql
		
	在實際開發中,sql指令碼檔案可能很大,比如:64MB(sql指令碼檔案的大小)
	記事本以及普通的文字編輯器,包括navicat都是無法開啟的,這種檔案需要使用source命令來執行指令碼。
	
2、把字典型別和字典值模組的html修改為jsp,解決所有的404錯誤。
	* html修改為jsp的順序:
		先開啟html,新增<%@page contentType="text/html;charset=UTF-8"%>
		再重新命名。
		<base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
		base標籤設定了base路徑之後,當前頁面自動從專案的根路徑下開始查詢資源。
		
	* 新增base標籤
		<base>標籤屬於html的語法,不屬於JSP的語法。
		<base>標籤用來設定當前頁面的基礎路徑,當前頁面中凡是不以“/”開始的路徑都會自動新增base。
		當前頁面中以“/”開始的路徑和base沒有關係。
		
	* 將所有jsp中的../全部替換成空白。
	
	* 解決404

3、實現儲存字典型別。

	3.1、字典型別表單驗證。(以下描述你們將在“詳細設計文件”中看到。)
		編碼不能為空(前端驗證)
		編碼只能由數字和字母組成(前端驗證)
		編碼在資料庫表當中是主鍵,要求具有唯一性(後臺驗證:ajax)
		失去焦點則驗證
		驗證訊息顯示在控制元件的下方
		訊息要求紅色字型,12號。
		獲得焦點之後,自動清除錯誤資訊,並且文字框中的內容不合法的時候,文字框的內容自動清空。
		使用者最終儲存按鈕點選之後,必須保證所有的表單項都是合法的方可提交。
	

注意:使用javascript程式碼怎麼彈出modal,怎麼隱藏modal?
	// 顯示modal視窗
	$("#modalId").modal("show");
	// 隱藏modal視窗
	$("#modalId").modal("hide");

4、使用jquery傳送ajax請求:
	第一種方式:通用的方式,比較靈活 
		$.ajax({
			type : "get/post",			請求的方式
			url : "url",				url
			data : {}或者"",				請求傳送的資料(當請求傳送的資料是字串的時候,需要滿足什麼格式?name=value&name=value&name=value)
			beforeSend : function(){	ajax請求傳送之前的回撥函式
				// return true;  // 表示繼續傳送該ajax請求。 
				// return false; // 表示放棄傳送該ajax請求。
				
				if(表單在最後提交的時候,驗證所有的表單項,當所有的表單項都合法的時候){
					return  true;
				}
				return false;
			},
			success : function(json){
				// 響應正常結束之後的回撥函式。
				// 通常在這裡解析json,重新整理前端資料。
			},
			dataType : "",  // 用來指定響應的資料型別
			async : false,  // 設定ajax請求為同步方式(預設是非同步方式,非同步是併發,同步是排隊。)
			cache : false,  // 解決get請求的快取問題。自動在請求url後面新增時間戳。保證每一次請求路徑不一樣,這樣瀏覽器就不會走快取了。
			.....
		});
	第二種方式:專門傳送post,基於$.ajax()實現的
		$.post(url,data,function(json){},dataType);
	
	第三種方式:專門傳送get,基於$.ajax()實現的
		$.get(url,data+時間戳,function(json){},dataType);
	
	第四種方式:傳送get ajax請求,並且一定返回json
		$.getJSON(url,data,function(json){});
	
	....
	
5、get請求和post請求如何選擇?

	post(郵寄,郵遞,傳送):
		- 請求傳送的資料當中有敏感資訊
		- 請求引數過大
		- 請求傳送的不是普通字串,例如:檔案、圖片、視訊等
		- 主要目的是為了向伺服器傳送資料,而不是獲取資料時採用post
		
	get(獲取):
		- get請求的最終響應結果會被瀏覽器自動cache。(怎麼避免get快取,時間戳)
		- get請求傳送的資料在請求行的url後面,所以最終會顯示到瀏覽器的位址列上。
		- get請求只能傳送普通字串。
		- get請求不能提交大量的資料。
		- get請求最終的目的是為了從伺服器端獲取資源,到瀏覽器上展示資料。
	
	增 刪 改一般都屬於post。
	查 屬於get。
	
	http協議中這樣規定:
		post請求適合於瀏覽器客戶端向伺服器傳送資料。專門負責傳送資料的。
		get請求適合於從伺服器端索取資料到瀏覽器上,並且顯示資料。所以get請求應該是設計為支援快取的。
6、包名:
	com.wkcto.crm.settings.web.controller
	公司域名倒序 + 專案名 + 模組名 + 功能名
	
	一個模組對應一個Controller
	一個業務對應一個service
	一張表對應一個dao

crm-03

1、儲存字典型別。
	* 儲存之前必須驗證所有的表單項是合法的。
	* 這裡的儲存只要提交form表單就行。可以不用ajax。

2、重點:什麼時候ajax使用同步方式?
	在表單驗證的時候,其中某個或者某些表單項需要ajax驗證,那麼要求這些ajax請求必須是同步請求。

crm-04

1、新增字符集過濾器,保證post請求不出現亂碼。

crm-05

1、儲存字典值:

	1.1、使用者點選“建立”按鈕,跳轉到save.jsp頁面,字典型別編碼動態顯示。
		c:forEach
		
	1.2、表單驗證:
		字典型別編碼不能為空
		字典值不能為空
		在“同一個字典型別編碼”下“字典值”具有唯一性。
		排序號可以為空,但不為空的時候必須是正整數。

		先把每一項的name和id全部加上。
		新增三個span。

crm-06

1、封裝一個響應json的工具類。

crm-07

1、對部門表進行設計。

2、將部門模組的html修改為jsp,解決404錯誤。

3、傳送ajax post請求,儲存部門。

注意:
	重置表單之後,再彈出modal視窗。

crm-08

1、將使用者維護模組相關的html修改為jsp,解決404錯誤。
2、彈出“儲存使用者”的modal視窗。
	當用戶點選“建立”按鈕的時候,傳送ajax get請求,取出所有的部門,解析json,拼接html。
	var html = "";
	$.each(array , function(i , n){
		html += "";
	});
	$("#").html(html);
3、設計資料庫表。
	tbl_user
		特殊欄位:
			部門編號(外來鍵)
			失效時間
			允許訪問的IP
			鎖定狀態
			登入密碼(MD5)
			建立人和修改人(登入賬號)
			
4、使用者點選儲存按鈕的時候,傳送ajax post請求,提交使用者資訊,儲存使用者。

5、“自學”了一個bootstrap datetimepicker外掛。(日曆控制元件)

crm-09

1、實現使用者登入功能:(使用ajax post方式,進行登入。)
	* 將login.html修改為jsp,解決404錯誤。
	* 登入頁面載入完畢之後,使用者名稱文字框自動獲得焦點。
	* 使用者點選登入按鈕登入,回車同樣可以登入。
	* 登入請求傳送之前,必須保證使用者名稱和密碼不能為空。

crm-10

1、十天內免登入

	* 使用者登入的時候選擇了“十天內免登入”,登入成功之後,關閉瀏覽器,在十天之內,使用該版本的瀏覽器開啟crm專案,出現在
	使用者瀏覽器頁面上的是“工作臺”。
	
	* 怎麼實現十天內免登入?
		使用Cookie機制。
		登入成功之後,假設使用者選擇了十天內免登入,那麼應該建立十天有效的Cookie,將使用者的登入資訊儲存到Cookie當中,將
		Cookie傳送給瀏覽器,瀏覽器將Cookie儲存在硬碟檔案當中,只要不清除Cookie,只要還是當前版本的瀏覽器,下一次再
		訪問該web站點的時候,瀏覽器自動提交Cookie給伺服器,伺服器從Cookie中獲取使用者的登入資訊,驗證資訊通過之後,直接
		跳轉到“工作臺”。
	
	* 回顧Cookie:
		- Cookie只有在javaweb中有嗎,其他語言的web開發中有Cookie嗎?
			有,並且Cookie不屬於java,屬於HTTP協議的一部分。只要是web專案,只要是B/S架構,一定離不開:cookie 和 session。
		- Cookie和Session存在的目的是什麼?
			是為了補充http協議的不足,HTTP協議的不足是什麼?
				http協議是無連線的無狀態的協議。
			我們可以使用Cookie和Session來儲存會話的狀態。
			其中Cookie可以將會話的狀態儲存在瀏覽器客戶端上。
			其中Session可以將會話的狀態儲存在伺服器端上。
		- Session實現機制中是依賴Cookie的:
			伺服器端的session列表當中的每一個session物件都有sessionId,而SessionId是儲存在Cookie當中的。
			sessionId最後儲存在Cookie中,Cookie放在瀏覽器的快取當中,只要不關閉瀏覽器,下一次訪問會自動提交
			帶有SessionId的Cookie給伺服器,伺服器接收該sessionId用來查詢對應的Session物件。
		- HTTP為什麼是無連線無狀態協議?
			這是為了降低伺服器的壓力。只有使用者請求的過程中是連線的,響應結束之後,瀏覽器與伺服器之間的連線就斷開了。
		- 由於HTTP協議是一種無連線無狀態協議,所以關閉瀏覽器的時候,伺服器是不知道的,那麼Session物件也不能直接
		給“客戶”保留著,畢竟Session物件也會佔用JVM的記憶體空間,所以在Servlet規範中,使用Session超時機制來銷燬
		Session物件。預設的配置是:30分鐘,常見的MIS系統一般設定為120分鐘,安全級別較高的系統,時間會很短,例如,
		網銀系統一般是使用者在3分鐘之內沒有再次操作網銀頁面,網銀系統會自動銷燬Session物件。
		
		- Cookie是怎麼儲存會話狀態的,經典的案例有哪些?
		
			* 購物車的實現:
				沒登入的情況下,向購物車新增商品,實際上是將商品的編號放到了Cookie當中,Cookie被儲存在瀏覽器客戶端
				硬碟檔案中,下一次訪問該購物網站的時候,自動讀取關聯的Cookie,獲取商品編號,初始化購物車。這種會話
				狀態的儲存是不穩定的,當清除Cookie之後,會話狀態丟失。
				
				在登入的情況下呢:向購物車當中新增商品,實際上這個商品資訊關聯客戶的資訊,一併儲存到資料庫表當中。這種
				會話狀態的保留是穩定的。不會因為更換瀏覽器版本而丟失。
				
			* 十天內免登入。
		
		- Cookie禁用之後,一些web站點的功能就無法使用了。
		
		- 當Cookie禁用之後,怎麼實現session機制呢?
			URL重寫機制。
			可以在URL後面新增:jsessionid..
				url;jsessionid=32位長度的字串?name=value&name=value&name=value....
			但這種方式會大大提高程式設計複雜度,每一個URL後面都需要動態的新增jsessionid
			所以99%的web站點都會提示你開啟瀏覽器Cookie功能。
		
		- 在servlet中Cookie的API?
			
			* 建立Cookie
				Cookie cookie = new Cookie(String name,String value);
			* 設定有效時長
				cookie.setMaxAge(秒);
				秒 > 0	儲存到硬碟檔案
				秒 = 0	刪除該Cookie
				秒 < 0	不被儲存
				不設定有效時長,預設是:儲存到瀏覽器快取當中,直到瀏覽器關閉之後銷燬Cookie。
			* 設定Cookie的關聯路徑
				cookie.setPath("/crm");
				以上程式碼的含義表示:以後瀏覽器只有傳送/crm請求的時候,該Cookie就會被自動傳送給伺服器。
			* 獲取Cookie的name和value
				String name = cookie.getName();
				String value = cookie.getValue();
			* 將Cookie傳送到瀏覽器客戶端
				response.addCookie(cookie);
			* 伺服器獲取瀏覽器客戶端提交的Cookie 
				Cookie[] cookies = request.getCookies();

crm-11

1、常量類:

	專案中多次出現:request.getSession().setAttribute("user", user);
	其中"user"這個字串多次編寫,每一次程式設計師編寫這個"user"字串的時候都需要很謹慎的編寫。
	因為在編寫過程中,當錯誤的時候,編譯器也不會提示錯誤資訊。
	
	其實,我們開發有一個原則:錯誤越早發現越好,儘可能讓所有的錯誤發生在編譯階段。
	編譯器能夠檢測出來的錯誤儘可能交給編譯器來完成。

2、登入成功之後,在工作臺右上角顯示當前登入的使用者。
	workbench/index.html修改為jsp,然後在jsp中使用EL表示式。
	${sessionScope.user.name}
	${user.name}

3、登入攔截過濾器:
	攔截什麼?
		*.jsp
		*.do
	什麼不能攔截?
		/login.jsp
		/login.do	
		/welcome.do
		
		使用者已經登入則不需要攔截(登入的標誌:session中有user)	

crm-12

1、將市場活動相關html修改為jsp,解決404錯誤。
2、設計資料庫表:市場活動模組相關的表。
	tbl_activity
	tbl_activity_remark
3、彈出建立市場活動的modal視窗。
	- 所有者動態(動態的下拉列表)
		* select * from tbl_user where loginAct != 'admin' (系統賬號超級管理員admin一般是內建賬號,前端顯示的所有者不應該顯示該賬號。)
		* 關於下拉列表定位的問題:使用者要求,張三登入,則所有者預設選擇張三。
			想讓下拉列表的某個選項選中,可以通過設定下拉列表的“value”即可。
			設定下拉列表的value是zhangsan,則zhangsan會被自動選中。
	- 開始日期和結束日期新增日曆控制元件。
4、儲存市場活動。
	使用者點選儲存按鈕,傳送ajax post,儲存市場活動資訊。

crm-13

1、實現分頁查詢的後臺功能。(先不實現前端的)

crm-14

1、市場活動列表頁面載入完畢之後,顯示第一頁資料。

crm-15

1、給分頁查詢新增翻頁功能:
	翻頁使用bootstrap pagination外掛來完成。
	
2、使用者點選查詢按鈕,分頁查詢。

3、翻頁的時候條件是怎麼處理的?
	隱藏域 hidden
	點選“查詢”的時候,將四個條件放到隱藏域當中。
	每一次分頁查詢的時候,條件都從隱藏域當中取。
	每一次翻頁的時候,再將隱藏域當中的條件更新到頁面的文字框中。

4、分頁查詢面試官都會問哪些問題呢?
	* 分頁查詢你是怎麼實現的,說一下?
		重點要說的是:
			- mybatis的動態sql(where if)
			- sql語句的limit
			- 封裝了一個分頁查詢專用的VO物件(PaginationVO)
			- 最後捎帶著說一下,前端使用了一個分頁的元件:pagination
	* 翻頁的時候查詢條件是如何處理的?
		隱藏域。

crm-16

1、當前CRM專案當中有很多位置都需要分頁查詢,目前service類當中的Map集合用來儲存展示的資料:
	Map<String, Object> pageMap = new HashMap<>();
	pageMap.put("total", activityDao.getTotalByCondition(conditionMap));
	pageMap.put("dataList", activityDao.getDataListByCondition(conditionMap));

	以上由於功能不止一個,建議使用一個專門的類進行封裝,所有的分頁查詢功能都使用這個封裝的類,
	該類由於儲存了前端展示的資料,所以這個類我們成為VO(View Object:檢視物件)
	VO 、 DAO等都屬於JavaEE設計模式。
	
	VO物件中的資料將來最終是負責向前端瀏覽器展示資料的。
	
	DTO
	PO
	POJO
	BO
	.....

crm-17

1、複選框的全選和取消全選

	$("#firstChk").click(function(){
		$(":checkbox[name='id']").prop("checked" , this.checked);
	});
	
	$("#activityTbody").on("click" , ":checkbox[name='id']" , function(){
		$("#firstChk").prop("checked" , $(":checkbox[name='id']").size() == $(":checkbox[name='id']:checked").size());
	});

2、刪除市場活動。
	* 刪除之前要提示使用者是否確認刪除。
	* 一次可以刪除多個市場活動。

crm-18

1、修改市場活動。
	* 第一步:彈出修改市場活動的modal視窗。
	* 第二步:使用者點選修改按鈕,傳送ajax post請求。在哪一頁修改還回到那一頁。

crm-19

1、展示市場活動的明細。
	detail.jsp

crm-20

1、備註列表先修改一下樣式。
	滑鼠移動到div當中,備註的修改和刪除按鈕顯示為紅色。

2、市場活動的明細頁面載入完畢之後,展示該市場活動的備註列表。
	頁面載入完畢之後傳送ajax get請求,根據市場活動id獲取備註列表。

crm-21

1、儲存市場活動備註。
	* 儲存市場活動的時候備註資訊不能為空。
	* 儲存成功之後,清除文字域中的“備註資訊”。

crm-22

1、刪除備註。

crm-23

1、修改備註。
	* 彈出修改備註的modal視窗。

注意目的:設定id,id重複了新增字首。

crm-24

1、關於市場活動的匯入和匯出。

	* 這裡所描述的匯入和匯出指的是excel。	
		匯出:將資料庫表當中的資料匯出到excel檔案當中。
		匯入:將excel檔案中的資料匯入到資料庫表當中。
		
	* 我們這裡先來看一下匯出市場活動。
		在java開發中要實現excel的匯出,可以使用java當中的一個開源元件:apache POI
	
	* 在使用POI元件之前,我們最好要對excel檔案結構有一定的認識。
	
		一個excel檔案的組成是怎樣的呢?
			excel檔案:WorkBook 工作簿
			一個WorkBook工作簿當中可以容納多個:Sheet 表格
			一個Sheet表格當中有多個行:Row 行
			一個Row行上面有多個單元格:Cell 單元格
			
			WorkBook --> Sheet --> Row --> Cell
			apache POI對excel檔案的操作主要使用的是以上的幾個物件(因為java語言本身就是完全面向物件的。)
	
	* 我們這裡先實現excel的匯出功能,匯出excel:使用POI寫excel檔案。
		我們這裡採用網路搜尋的方式,搜尋相關的資料或者部落格,找到簡單的示例,先執行起來,然後在簡單程式的基礎之上
		進一步學習,然後改造程式,最終達到效果。(這個過程不容易的。)
			
2、市場活動的匯出:
	提供兩個操作:一個是匯出選中,另一個是匯出全部。

crm-25

1、匯入市場活動。(先不使用非同步的方式,使用傳統方式匯入:提交form表單的方式。)
	第一步:檔案上傳。(apache commons fileupload)
	第二步:讀excel。(POI)

crm-26

1、匯入市場活動。(採用非同步ajax方式先完成檔案上傳,然後再匯入資料。)
	$.ajax({
		...
		contentType : false,   // 設定encType為multipart/form-data
		processData : false,   // 設定以物件的形式提交資料(提交檔案)
		data : new FormData().append("myfile" , $("#activityFile")[0].files[0]),
		...
	});

crm-27

1、將剩下的所有頁面修改為jsp,解決404錯誤。

2、將tbl_dic_type和tbl_dic_value資料通過執行sql指令碼的方式初始化資料。

3、思考:系統當中有很多位置需要下拉列表,每一次需要下拉列表都要從資料庫中查詢嗎?有沒有什麼好的方案?
	下拉列表中的資料有這樣的幾個特點:
		第一:資料量較小
		第二:所有使用者共享
		第三:一般不會輕易的修改
	當滿足以上的三個條件的時候,可以考慮將其儲存到application域當中。
	application域可以看做是一個快取:cache。
	使用快取機制,減少IO操作,是提高程式執行效率的重要手段。
	在實際開發中,遇到優化瓶頸的時候,首先要想到快取機制。
	
	將字典值查詢出來,儲存到一個什麼樣資料結構當中,application域當中儲存什麼?
		application.setAttribute("appellationList" , appellationList);
		application.setAttribute("clueStateList" , clueStateList);
		.....
		
		<c:forEach items="${appellationList}" var="字典值物件">
			<option value="${字典值物件.value}">${字典值物件.text}</option>
		</c:forEach>
		
	寫一個監聽器,在伺服器啟動階段,呼叫service返回一個Map集合,然後遍歷Map集合,將資料儲存到application域當中。
		Map<String,List<DicValue>>
		key					value
		----------------------------------------
		"appellationList"	appellationList
		"clueStateList"		clueStateList
		....
4、將“線索、客戶、聯絡人、交易”模組的所有表設計出來。
	線索模組
		tbl_clue		線索表(pk)
		tbl_clue_remark	線索備註表(pk + fk[clueId])
		tbl_clue_activity_relation 線索和市場活動關係表(pk + fk[clueId] + fk[activityId])
	客戶模組
		tbl_customer	客戶表(pk)
		tbl_customer_remark 客戶備註表(pk + fk[customerId])
	聯絡人模組
		tbl_contacts	聯絡人表(pk + fk[customerId])
		tbl_contacts_remark 聯絡人備註表(pk + fk[contactsId])
		tbl_contacts_activity_relation 聯絡人和市場活動關係表(pk + fk[contactsId] + fk[activityId])
	交易模組
		tbl_tran		交易表(pk + fk[customerId] + fk[activityId] + fk[contactsId])
		tbl_tran_remark	交易備註表(pk + fk[tranId])
		tbl_tran_history 交易歷史表(pk + fk[tranId])

crm-28

1、彈出建立線索的modal視窗:
	* 所有者動態(下拉列表定位)
	* 線索來源和線索狀態下拉列表從application域當中取出forEach
	* 下次聯絡時間日曆控制元件。 (設定控制元件的顯示位置:pickerPosition : "top-right")
	
2、傳送ajax post請求儲存線索。

crm-29

1、檢視線索的明細。

crm-30

1、展示該線索關聯的市場活動列表。
	前提是知道:線索id(clueId=77544dcfc4774e70a95ac1ba32912a92)
	tbl_clue_activity_relation car
	tbl_activity a
	tbl_user u
	
	select
		a.name, a.startDate, a.endDate, u.name as owner, car.id as relationId
	from
		tbl_activity a
	join
		tbl_clue_activity_relation car
	on
		car.activityId = a.id
	join
		tbl_user u
	on
		a.owner = u.id
	where
		car.clueId = #{clueId}

crm-31

1、解除關聯。
	* 傳送ajax post請求,提交關係id,刪除資料庫中的資料,前端刪除一個tr。

crm-32

1、當前線索關聯市場活動:

	1.1、彈出關聯市場活動的modal視窗:
		* 清空查詢條件
		* 第一個複選框取消選中
		* 清空tbody
	
	1.2、根據市場活動名稱查詢市場活動。支援模糊查詢!
		回車鍵的時候查。(keyCode==13)
		bootstrap當中的modal視窗只要接收到回車鍵,則modal視窗自動關閉。
		JS中的事件會冒泡,作用到子物件上的事件,會繼續傳遞給父物件,沒有阻止會一直傳遞下去。
		
		怎麼防止js的事件冒泡?
		
			方式一:event.stopPropagation();
			$("#div1").mousedown(function(event){
				event.stopPropagation();
			});
			
			方式二:return false;
			$("#div1").mousedown(function(event){
				return false;
			});
		
		這裡防止業務上出現漏洞?已關聯過的市場活動不能查出來。(sql語句子查詢。)
			<select id="getByName" resultType="Activity">
				select
					a.id, a.name, a.startDate, a.endDate, u.name as owner
				from
					tbl_activity a
				join
					tbl_user u
				on
					a.owner = u.id
				where
					a.name like '%' #{arg0} '%'
				and
					a.id not in (select activityId from tbl_clue_activity_relation where clueId = #{arg1})
			</select>
			
	1.3、刪除市場活動的時候應該級聯刪除對應的備註資訊。

crm-33

1、關聯市場活動:
	* 全選和取消全選。
	* 使用者點選關聯按鈕的時候:
		至少關聯一個。可以一次關聯多個。
		關聯實際上就是往關係表插入資料:
			tbl_clue_activity_relation
			id			clueId			activityId
			----------------------------------------------
			UUID		前端提交			前端提交

crm-34

1、在detail.jsp頁面上點選"轉換"按鈕跳轉到convert.jsp頁面:

	兩個jsp直接傳送資料?
	
		detail.jsp?name=value&name=value&name=value....
		
		convert.jsp中怎麼取資料{
			${param.name}
			${param.name}
			${param.name}
			${param.name}
			${param.name}
			${param.name}
			${param.name}
			${param.name}
			${param.name}
		}			
		
		重點:EL表示式當中有一個隱含物件,叫做:param
		用來代替:
			<%=request.getParameter("name")%>
			
2、分析:轉換涉及到哪些表?
	tbl_clue
	tbl_clue_activity_relation
	tbl_clue_remark
	
	tbl_customer
	tbl_customer_remark
	
	tbl_contacts
	tbl_contacts_activity_relation
	tbl_contacts_remark
	
	
	tbl_tran
	tbl_tran_history
	tbl_tran_remark

3、分析:轉換的實現步驟(共11張表)?(線索id已知)-----> 目前我們先不考慮交易。
	1、根據線索id查詢線索資訊。
	2、從線索物件中提取客戶資訊,儲存客戶資訊(判斷該客戶的資訊是否已經存在:根據公司名稱查詢,精確匹配)。
	3、從線索物件中提取聯絡人資訊,儲存聯絡人資訊。(這裡不考慮去除重複記錄,直接儲存)
	4、將“線索和市場活動的關係”轉換到“聯絡人和市場活動的關係”
	5、將“線索備註”轉換到“客戶備註”、“聯絡人備註”
	6、刪除線索對應的備註
	7、刪除線索和市場活動的關係
	8、刪除線索

4、注意事務,必須同時成功或者同時失敗,也就是說必須只能呼叫一次service方法。

crm-35

1、線索轉換的時候使用者選擇了建立交易:
	* 儲存交易
	* 儲存交易歷史
	* 儲存交易備註(線索備註有的話,可以轉換成交易備註。)

crm-36

1、展示建立交易的頁面:
	* 預計成交日期和下次聯絡時間(日曆控制元件)
	* “階段”動態顯示
	* “型別”動態顯示
	* “來源”動態顯示
	* “市場活動源”和“聯絡人名稱”固定(不再實現動態效果)
	* 所有者動態顯示,並且定位下拉列表選項。
	
2、下拉列表定位:
	第一種方式:頁面載入完畢之後定位。
		$(function(){
			$("#owner").val("${user.id}");
		});
	第二種方式:EL表示式當中使用三目運算子。
		${userObj.id eq user.id ? "selected" : ""}
	
	注意:
		第一:EL表示式是支援三目運算子的。
		第二:eq是EL表示式當中的運算子,底層實際上呼叫了java語言中的equals方法。
	另外:
		${"user"}和${user}有什麼區別?
			${"user"} 表示把"user"當做一個普通的字串直接列印輸出到瀏覽器。
			${user} 表示從四個域當中檢索資料,找到資料之後輸出到瀏覽器。
			
3、選擇不同的階段,生成不同的可能性。

	* change事件。
	
	* “階段”對應的“可能性”,他們之間的對應關係應該在配置檔案中體現出來:
		這裡選擇屬性配置檔案。
		Stage2Possibility.properties 
			Stage To Possibility:階段對應的可能性。
		log4j : logger for Java
		dom4j : dom for Java
		
		注意:屬性資原始檔中不能直接儲存中文,高版本的eclipse自動將中文轉換成unicode碼。
		那麼低版本的eclipse怎麼辦?程式設計師可以手動轉換:native2ascii.exe
	
	* 在伺服器啟動階段:SystemInitListener:
		讀取Stage2Possibility.properties,將讀取到資料放到Map集合當中,將Map集合放到application域當中。

crm-37

1、客戶名稱支援自動補全。
	bootstrap typeahead

crm-38

1、儲存交易。
	提交form表單。

crm-39

1、檢視交易的明細:
	五張表連線。

crm-40

1、檢視交易的歷史列表。
	頁面載入完畢之後傳送ajax get請求,根據交易id獲取交易歷史列表。

crm-41

1、展示階段圖示。

	* 修改頁面:失敗的圖示都以“叉號”顯示。
	
	* 實現什麼樣的效果?
	
		第一種情況:當前階段處於“正常期”:
			當前階段的圖示則:glyphicon glyphicon-map-marker (顏色:綠色)
			當前階段之前的圖示則:glyphicon glyphicon-ok-circle(顏色:綠色)
			當前階段之後的圖示則:glyphicon glyphicon-record(顏色:黑色)
			失敗的圖示則:glyphicon glyphicon-remove-circle(顏色:黑色)
			
		第二種情況:當前階段處於“失敗期”:
			當前失敗的階段圖示則:glyphicon glyphicon-remove-circle(顏色:紅色)
			其它失敗的階段圖示則:glyphicon glyphicon-remove-circle(顏色:黑色)
			其它正常的圖示則:glyphicon glyphicon-record(顏色:黑色)
		
		怎麼判定當前階段是失敗期還是正常期?
			主要依據是可能性是否為0

crm-42

1、點選圖示,更新當前交易的階段。(這個版本不實現圖示的更新。)
	* 提交什麼?
		tranId
		stage
		money
		expectedDate
	* 返回什麼?
		{"stage":"","possibility":"","editTime":"","editBy":""}

crm-43

1、更新圖示。
	竅門:使用下標i作為每一個圖示的id。

crm-44

1、統計圖表:

	實現交易的統計。(使用百度的ECharts完成統計圖表的展示。)
	
	對什麼進行統計呢?
		對“每個階段”的“交易數量”進行統計。
		共100筆交易:
			50筆成交
			10筆因競爭丟失而關閉
			20筆01資質審查
			10筆02需求分析
			.....
			
	客戶可能會按照月進行統計,也可能是按照季度進行統計,還可能按照年統計。
	也可能統計所有資料(自公司成立以來!)
	
	這個統計圖表我們準備使用:漏斗圖。
	
	統計圖表非常多:
		柱狀圖
		餅狀圖
		漏斗圖
		曲線圖
		....
			
2、掃尾:

	* 自己實現傳送郵件功能。(javamail)
	
	* 系統當中有很多位置都有“下次聯絡時間”:
		當“下次聯絡時間”到了之後,伺服器端應該自動推送訊息給瀏覽器,提示業務員。
		推送技術可以使用:pushlets
		反向AJAX。
		CRM專案中有沒有實時性效果的技術呢?
			有,下次聯絡時間到了之後,伺服器自動推送資訊,推送資訊使用的是:pushlets
		
	* CRM專案中還有許可權管理模組:
		許可權管理模組使用的是:apache shiro框架實現的(shiro框架底層是基於RBAC:Role Based Access Control:基於角色的訪問控制。)
		面試官問:CRM中有許可權嗎?
			有,當時我們好像使用的是apache shiro。但這塊不是我負責的。
		除了shiro之外還有其它的,例如spring框架下的子框架:spring security
	
	* 面試官可能還會問,CRM專案中有沒有“流程管理的功能”/“工作流”相關的內容?
		有,我們使用的是Activiti框架實現的工作流。
		
		jBPM5與Activiti5都是工作流框架:
			jBPM5老
			Activiti5新(使用這個比較多)
		
		流程管理是一個非常通用獨立的模組。例如:學生請假、報銷差旅費....
	
3、面試之前一定要將CRM專案的核心業務記憶一下。

4、使用單元測試工具junit4進行單元測試。