訂單系統服務端和客戶端工程搭建、利用攔截器實現登錄功能及訂單確認頁面展示、生成訂單

訂單系統服務端和客戶端工程搭建

首先我們還是先看一眼淘淘商城的系統架構,如下圖所示,可以看到訂單模塊是單獨的模塊,有服務端還有客戶端,服務端負責存儲訂單,客戶端負責展示訂單。

下面我們便來搭建訂單服務,點擊File---->New----->Other…如下圖所示。

選擇"Maven Project",然後點擊"Next",如下圖所示。

勾選最上面的那個複選框,然後點擊"Next",如下圖所示。

我們要先創建聚合工程taoao-order,後面再創建屬於該聚合工程的兩個模塊taotao-order-interface和taotao-order-service,之所以不建dao模塊是因爲我們逆向生成的代碼便可以直接使用,因此不用單獨創建dao模塊。

下面我們配置taotao-order的pom.xml文件,我們可以參考taotao-content工程的pom.xml文件,如下圖所示。

下面我們再來新建taotao-order聚合工程的兩個模塊,首先創建taotao-order-interface模塊,在taotao-order工程上右鍵,在右鍵菜單中點擊"New",在子菜單中點擊"Other…",如下圖所示。

選擇"Maven Module",然後點擊"Next",如下圖所示。

勾選最上面的複選框,在Module Name一欄輸入"taotao-order-interface",然後點擊"Next"。

打包方式默認就是jar,我們不用動,直接點擊“Finish”,如下圖所示。

下面我們便配置taotao-order-interface的pom.xml文件,我們可以參考taotao-content-interface工程的pom.xml文件,如下圖所示。

下面我們再創建taotao-order-service模塊,還是在taotao-order工程上右鍵---->New----->Other…,如下圖所示。

選擇"Maven Module",然後點擊"Next",如下圖所示。

勾選最上方的複選框,在Module Name一欄輸入"taotao-order-service",然後點擊"Next",如下圖所示。

打包方式選擇war,然後點擊"Finish"。

下面我們配置taotao-order-service的pom.xml文件,我們可以參考taotao-content-service工程的pom.xml文件,將原來依賴的taotao-content-interface修改爲taotao-order-interface,另外將後面的redis的依賴去掉。

配好後,taotao-order-service工程的pom.xml文件的內容如下:

下面我們將taotao-content-service工程src/main/resources目錄下的文件夾拷貝過來mybatis目錄下配置文件不用動,properties目錄下的db.properties文件不用動,將resource.properties文件清空,並且設置該文件的編碼格式爲utf-8。

下面我們修改spring目錄下的文件,applicationContext-dao.xml文件我們不用動,刪掉applicationContext-jedis.xml文件,然後修改applicationContext-service.xml文件,掃描包修改爲com.taotao.order.service,然後我們在taotao-order-interface工程的src/main/java目錄下新建包com.taotao.order.service,然後在taotao-order-service工程的src/main/java目錄下新建一個com.taotao.order.service.impl包。dubbo服務的名稱修改爲"taotao-order",修改dubbo暴露的服務端口,前面已經用到8083了,因此這裏改爲8084,聲明要暴露的接口這塊,由於我們還沒有寫接口,暫且保留原來的一個配置,並註釋掉,這樣後面我們暴露服務的時候只需要稍微修改下就好了。

下面我們再修改下applicationContext-trans.xml文件,訂單模塊對事務要求非常高,將切面修改爲"com.taotao.order.service"。

下面我們再把taotao-content-service工程下的WEB-INF目錄直接拷貝到taotao-order-service工程的webapp目錄下,修改下的值爲"taotao-order"。這樣我們的服務端工程便搭建完了。

下面我們來搭建訂單表現層工程taotao-order-web,第一步還是File----->New------>Other…,如下圖所示。

第二步還是選擇"Maven Project",然後點擊"Next"。

第三步還是勾選最上面的那個複選框,然後點擊"Next"。

第四步如下圖,打包方式選擇"war",然後點擊"Finish"。

下面我們修改taotao-order-web工程的pom.xml文件,我們可以參考taotao-port-web工程的pom.xml文件,將原來依賴的taotao-content-interface修改爲taotao-order-interface,然後將最下面tomcat插件的端口號修改爲8091。

修改後taotao-order-web工程的pom.xml文件內容如下:

然後我們將taotao-portal-web工程src/main/resources目錄下的文件夾拷貝過來,接着我們將resource目錄下的resource.properties文件內容清空,並將該文件的編碼格式設置爲utf-8。

下面我們修改springmvc.xml文件,掃描包修改爲com.taotao.order.controller,並且在taotao-order-web工程的src/main/java目錄下新建這個包,引用的dubbo服務名稱修改爲taotao-order-web,將原來引用的服務先註釋掉,後面需要用的時候可以稍微修改下即可。

最後我們把taotao-portal-web工程的web.xml文件複製過來,但前提是先在taotao-order-web工程的webapp目錄下新建一個WEB-INF目錄,把web.xml文件複製到WEB-INF目錄下。將所有taotao-portal-web都替換爲taotao-order-web即可。

這樣,我們的服務端和客戶端工程便都搭建好了。

利用攔截器實現登錄功能及訂單確認頁面展示

我們上節課一起搭建了訂單的服務工程和web工程,我們參考京東可以知道,京東在沒有登錄時就可以使用購物車,但是當要真正付款的時候,一定是要求登錄的。也就是說由購物車列表頁面直接跳轉到登錄頁面去登錄。這顯然用到了攔截器的功能,這節課我們便一起實現登錄功能。

下圖便是購物車列表頁面,我們點擊"去結算",如果當前用戶還沒登錄,是必須要先登錄的。

下面我們便來寫攔截器,攔截器是要實現HandlerInterceptor的,我們在taotao-order-web工程的src/main/java目錄下新建一個包com.taotao.order.interceptor並在該包下新建LoginInterceptor攔截器(實現HandlerInterceptor)

可以看到,我們在代碼中用到了兩個常量,常量我們要定義在配置文件當中
preHandle方法的第3步通過token取用戶信息,顯然用到了SSO服務的接口,因此我們需要在taotao-order-web工程依賴taotao-sso-interface工程,如下圖所示。

光依賴taotao-sso-interface還不行,我們還得在springmvc.xml文件中引用taotao-sso-service發佈的dubbo服務,另外我們寫的攔截器Spring是不知道的,我們得告訴Spring我們寫了這個攔截器,於是需要在springmvc.xml文件中配置下攔截器。

我們是要由購物車列表頁面訪問訂單頁面時觸發攔截器的,因此我們要先處理購物車列表頁面,如下圖所示,我給大家提供的靜態頁面這裏已經改過了,不用修改。

由於要訪問訂單頁面,因此我們需要把訂單的靜態資源放到taotao-order-web工程下,

我們要訪問的訂單頁面是order-cart.jsp頁面,如下圖所示,這個頁面中"cartList"是Controller返回的購物車列表,cart的屬性一定要正確,我給大家的靜態資源文件已經修改好了,可以直接使用。

我們需要在taotao-order-web寫一個Controller來響應購物車列表請求訪問訂單頁面的請求

上面代碼中用到了常量CART_KEY,因此我們需要在配置文件中配置下這個常量

下面我們先來測試下攔截器是否好使,我們要啓動taotao-order-web工程,但是要先將taotao-order聚合工程打包到本地maven倉庫,方法是在taotao-order工程上右鍵----->Run As------>Maven install

我們啓動taotao-order-web工程,在taotao-order-web工程上右鍵------>Run As----->Maven build在彈出的對話框中的Goals一欄輸入"clean tomcat7:run

啓動成功後,我們再點擊本篇博客第一張圖的"去結算",就可以看到,頁面跳轉到了登錄頁面,如下圖所示。說明我們的攔截器沒問題

我們輸入用戶名和密碼進行登錄,發現登錄到淘淘商城首頁了,這不是我們想要去的頁面,應該到訂單確認頁面頁面纔對。

登錄有沒有成功在login.jsp當中有判斷,如下圖所示,可以看到,js首先會去嘗試獲取從Controller端傳過來的回調地址,如果取到了回調地址,那麼登錄成功後會跳轉到回調地址,如果沒有取到回調地址,那麼登錄成功後直接訪問的便是淘淘商城首頁,在上圖中之所以我登錄成功後訪問到的是淘淘商城首頁就是因爲我們沒有在PageController 當中添加回調地址。

下面我們到taotao-sso-web工程的PageController中簡單做下修改,如下圖所示,我們在showLogin方法中添加了兩個參數,一個是回調地址url,另一個是用來給jsp頁面添加屬性的Model,回調地址url也不是憑空來的,它是由攔截器重定向時就指定好的。

既然我們修改了taotao–sso-web工程,下面我們便重啓taotao-sso-web工程,重啓後,我們重新來測試一下,如果你是剛登錄的話,cookie中已經有你的登錄信息而且token還沒過期,要想達到用戶未登錄的情況,有兩種方法,一是刪除cookie中的TT_TOKEN,如下圖所示,另一種方法就是等,等30分鐘,30分鐘後token過期。顯然,我們刪除cookie中的TT_TOKEN比較靠譜。

刪除了cookie中的token或token過期後,我們還是從購物車列表頁面(本篇博客第一張圖)點擊"去結算",還是會讓我們登錄,登錄後會提示登錄成功,點擊"確定"後,我們看到的是下圖所示頁面,而不再是淘淘商城首頁了。下圖便是訂單確認頁面。

但是當前這個頁面頭部還是顯示的是未登錄狀態,我們參考單點登錄系統的代碼,在taotao-order-web工程的js目錄下找到base-v1.js,打開它修改最上面的兩個方法。

修改的代碼如下,這樣從訂單確認頁面便可以點擊"登錄"或"註冊"跳轉到相應的頁面。

我們再修改下js目錄下的taotao.js文件,其實這個文件我們只需要將端口修改爲8088就可以了。

下面我們重啓taotao-order-web工程,重啓後,我們刷新訂單確認頁面,便可以看到頭部有用戶信息了。

生成訂單

第一部分:訂單數據庫分析

我們先來看下tb_order表,如下圖所示,可以看到,

主鍵order_id是字符串類型,不是自增長的,因此我們需要自己生成訂單編號,我們平時使用京東、天貓等購物網站,發現人家的訂單號都是用數字組成的,我們也使用數字作爲訂單號,但是怎樣才能使訂單號不重複呢?用時間加隨機數的方案生成的訂單其實還是可能會重複的,當同一時刻生成的訂單越多越有可能出現訂單號一樣的情況,因此我們不能使用這種方案。比較好的方案是什麼呢?是用redis的incr方法,由於redis是單線程的,因此無論多少個線程共同訪問也不會出現訂單編號一樣的情況。

payment字段是實付金額,需要從前臺傳過來,保留小數點後2位,
payment_type是支付類型,分爲在線支付和貨到付款,也需要從前臺頁面傳過來,
post_free字段是郵費,郵費得由前臺傳過來,因爲很多電商都搞活動,買夠多少錢的東西就免郵費,因此郵費是動態變化的。
status字段是訂單狀態,訂單狀態我們暫且定義了6種狀態,未付款、已付款、未發貨、已發貨、交易成功、交易關閉。create_time字段是訂單創建時間,這沒什麼可說的,
update_time字段是訂單更新時間,這個通常是訂單狀態發生了變化,
payment_time字段是付款時間,
consign_time字段是發貨時間,
end_time字段是交易完成時間,這個通常是用戶點確認收貨的時間,交易關閉時間則是該訂單的所有流程都走完後的時間。
shipping_name字段是物流名稱,即用的誰家的快遞。
shipping_code字段是物流單號,這個不用廢話。
user_id字段當然是指購買者ID。
buyer_message字段是指買家留言,
buyer_nick字段指買家暱稱。
buyer_rate字段記錄買家是否已經評價。
表中還可以看到create_time、buyer_nick、status、payment_type四個字段由key修飾,說明爲這四個字段建立了索引。

可以看到訂單表中並沒有購買商品詳情信息,那麼商品詳情信息在哪兒存放呢?它被存放到了tb_order_item表中,主鍵id字段也是個字符串,我們也需要爲其生成主鍵,不過我倒是覺得,如果id用Long類型並且主鍵自增長會更好點。

接着我們看tb_order_shipping,這張表存放的是用戶的收貨信息,包括收貨人姓名、固定電話、移動電話、省、市、區/縣、街道門牌號、郵政編碼,而且收貨人信息與訂單是一對一的,因此收貨地址表的主鍵是order_id。

第二部分:訂單生成頁面分析
生成訂單是在訂單確認頁面進行的,如下圖所示,可以看到"提交訂單"按鈕。

我們找到這個頁面對應的jsp文件,那就是order-cart.jsp,搜索"提交訂單",可以看到如下圖所示搜索結果,可以看到這是個button按鈕,該按鈕的onclick事件中使用id選擇器來得到表單,並且將該表單提交。

那麼,表單在哪兒呢?我們搜索"orderForm",如下圖所示,可以看到這個表單所有的標籤都是隱藏的,是不會被用戶看到的,用戶看到的只是表單下面展示的信息(這些信息只是做展示用,不會被提交,真正提交的是被隱藏的表單)。表單要提交的話,我們一般用pojo來接收比較合適,那麼這個表單我們應該用什麼樣的pojo來接收呢?

我們分析下上圖的表單,這個表單中包含了三張表的信息,其中便是tb_order表中的付款類型字段,這裏默認是1了,<c:forEach>遍歷的是購物車列表,var="cart"表示單個購物車對象,varStatus="status"的用法如下所示

varStatus屬性可以方便我們實現一些與行數相關的功能,如:奇數行、偶數行差異;最後一行特殊處理等等。先就varStatus屬性常用參數總結下:
${status.index} 輸出行號,從0開始。
${status.count} 輸出行號,從1開始。
${status.current} 當前這次迭代的(集合中的)項
${status.first} 判斷當前項是否爲集合中的第一項,返回值爲true或false
${status.last} 判斷當前項是否爲集合中的最後一項,返回值爲true或false
begin、end、step分別表示:起始序號,結束序號,跳躍步伐。

可以看到我們這裏用到的便是其行號功能,而且是從0開始,orderItems是個集合,該集合通過索引號獲取它的對象,然後將購物車對象的對應屬性賦給orderItems集合中當前索引號下的對象的這個屬性,totalPrice是將購物車裏每款商品的總價格相加,就是整個訂單的總金額。forEach裏面的屬性值都是tb_order_item表中的字段。forEach之後就是payment字段,該字段也是tb_order表裏面的字段,表示付款金額,我們看到了給payment賦的值是value="${totalPrice/100 },這裏之所以要除100是由於我們的tb_order_item表中定義的商品單價便是整數,這個整數是以分爲單位乘以100的,這樣兩位小數的金額比如11.11元便在數據庫中存成了1111,當然了,數據庫中存儲的金額單位便是分了,不再是元了。數據庫中雖然存儲的是以分爲單位的價格,但是我們展示在頁面的價格肯定是以元爲單位的,因此我們需要讓totalPrice/100,這纔是以元爲單位的金額。接着,下面這幾句代碼意思比較明顯,顯然存放的是收貨人地址信息,用到的類是逆向生成的TbOrderShipping類。

綜合以上情況,我們來寫個pojo類包含這些表單信息,那麼我們這個pojo應該放到哪兒比較合適呢?我們不能把它放到taotao-common當中,因爲我們的taotao-order工程已經依賴了taotao-common工程了,如果taotao-common工程現在再依賴taotao-order,那麼便成了相互依賴了,這是斷不可行的。我們還想讓它儘可能的共用,把它放到taotao-order-interface工程比較合適,因爲taotao-order工程及taotao-order-web工程都依賴taotao-order-interface,因此把pojo寫到taotao-order-interface工程比較合適。

pojo類如下圖所示,這裏用到了一個技巧,那就是繼承了TbOrder類,這樣OrderInfo便直接擁有了TbOrder的屬性。爲了讓該pojo在網絡中傳輸,我們需要讓它實現序列化接口。

第三部分:生成訂單
首先我們需要在taotao-order-interface工程新建一個接口類並在該接口類中添加一個接口,如下圖所示。

下面我們在taotao-order-service工程的com.taotao.order.service.impl包下新建OrderService接口的實現類

既然用到了redis,我們便要添加對redis的依賴、redis的配置文件以及redis的接口和實現類,首先我們在taotao-order-service工程添加對redis的依賴

下面我們還需要redis的配置文件,我們可以從taotao-manager-service工程的spring目錄下複製一份過來,如下圖所示,由於初始化Spring容器時以applicationContext-*.xml爲條件了,因此凡是以"applicationContext-“”開頭的都會被裝入容器中。

下面我們從taotao-content-interface工程中複製com.taotao.jedis.service目錄到taotao-order-interface工程的src/main/java目錄下,然後把taotao-content-service工程的com.taotao.jedisservice.impl包複製到taotao-order-service工程的src/main/java目錄下

代碼中還用到了常量,我們把常量放到配置文件中

配置文件有了,但是我們要確認Spring加載了該配置文件,我們查看applicationContext-dao.xml文件,發現加載了properties目錄下所有以.properties文件結尾的配置文件。所以自然而然resource.properties文件也被加載了。

第四部分:訂單生成表現層
既然服務端寫好了,我們便要發佈服務,我們在applicationContext-service.xml文件中發佈,如下圖所示

下面便是在taotao-order-web工程引用dubbo服務

接着我們在taotao-order-web工程的OrderController中添加一個接口,如下圖所示,其中用到了3天以後的時間,以前我們用Calandar來計算日期,但太麻煩,這裏介紹一個簡單的方法,那就是使用joda-time-2.5.jar這個包,實例化DateTime,然後直接使用plusDays(3)便可以得到3 天后的日期,是不是非常方便。訂單生成成功後,我們要跳轉到訂單生成成功頁面,這個頁面是success.jsp,這個頁面有三個變量需要從Controller傳過來,因此我們便在Controller方法中使用Model帶回這三個參數。

@RequestMapping("/order/create")這個請求來自於taotao-order-web工程的order-cart.jsp中的隱藏表單,如下圖所示。

第五部分:測試
代碼寫完了,下面我們來測試,我們先將taotao-order工程打包到本地maven倉庫,然後用tomcat插件啓動taotao-order工程(這個我已經寫過太多遍了,就不再寫了),然後再重啓taotao-order-web工程。

今天看了下工程沒法啓動的原因,原來是由於發佈服務的時候,把ref="orderServiceImpl"寫成了ref=“orderService”,導致taotao-order工程啓動老是報找不到orderService的錯誤,細節決定成敗,大家寫代碼的時候一定要細心了。

我們到訂單確認頁面,點擊"提交訂單"。

我們會看到如下圖所示頁面,提示訂單提交成功了。

我們再來看看數據庫中的數據,可以看到三張表都有數據了。說明我們的訂單功能沒問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章