JavaWeb入门_模仿天猫整站Tmall_SSH实践项目
Tmall_SSH
技術(shù)棧 Struts2 + Hibernate + Spring + Jsp + Tomcat , 是 Java Web 入門非常好的練手項目
效果展示:
模仿天貓前臺
模仿天貓后臺
項目簡介
關(guān)聯(lián)項目
github - 天貓 JavaEE 項目
github - 天貓 SSH 項目
github - 天貓 SSM 項目
之前使用 JavaEE 整套技術(shù)來作為解決方案,實現(xiàn)模仿天貓網(wǎng)站的各種業(yè)務(wù)場景,現(xiàn)在開始使用框架技術(shù),畢竟工作中還是要用框架。
本項目技術(shù)相對老舊,現(xiàn)在很少用 Struts2 了,但如果接手老項目的話還是要懂的,學(xué)習(xí)過程我們也可以認識到它們當時優(yōu)秀的設(shè)計理念,
當時解決了哪些痛點,后面又是因為什么被新技術(shù)替代,這樣才能加深對 Java Web 整個平臺的理解,不虧。
項目用到的技術(shù)如下:
Java:Java SE基礎(chǔ)
前端:HTML,CSS, JavaScript,AJAX, JQuery, Bootstrap
J2EE:Tomcat, Servlet, JSP, Filter
框架: Hibernate,Struts,Spring,SSH整合
數(shù)據(jù)庫:MySQL
表結(jié)構(gòu)
建表sql 已經(jīng)放在 Github 項目的 /sql 文件夾下
| Category | 分類表 | 存放分類信息,如女裝,平板電視,沙發(fā)等 |
| Property | 屬性表 | 存放屬性信息,如顏色,重量,品牌,廠商,型號等 |
| Product | 產(chǎn)品表 | 存放產(chǎn)品信息,如LED40EC平板電視機,海爾EC6005熱水器 |
| PropertyValue | 屬性值表 | 存放屬性值信息,如重量是900g,顏色是粉紅色 |
| ProductImage | 產(chǎn)品圖片表 | 存放產(chǎn)品圖片信息,如產(chǎn)品頁顯示的5個圖片 |
| Review | 評論表 | 存放評論信息,如買回來的蠟燭很好用,么么噠 |
| User | 用戶表 | 存放用戶信息,如斬手狗,千手小粉紅 |
| Order | 訂單表 | 存放訂單信息,包括郵寄地址,電話號碼等信息 |
| OrderItem | 訂單項表 | 存放訂單項信息,包括購買產(chǎn)品種類,數(shù)量等 |
| Category-分類 | Product-產(chǎn)品 |
| Category-分類 | Property-屬性 |
| Property-屬性 | PropertyValue-屬性值 |
| Product-產(chǎn)品 | PropertyValue-屬性值 |
| Product-產(chǎn)品 | ProductImage-產(chǎn)品圖片 |
| Product-產(chǎn)品 | Review-評價 |
| User-用戶 | Order-訂單 |
| Product-產(chǎn)品 | OrderItem-訂單項 |
| User-用戶 | OrderItem-訂單項 |
| Order-訂單 | OrderItem-訂單項 |
| User-用戶 | User-評價 |
以上直接看可能暫時無法完全理解,結(jié)合后面具體到項目的業(yè)務(wù)流程就明白了。
開發(fā)流程
首先使用經(jīng)典的 SSH 模式進行由淺入深地開發(fā)出第一個分類管理模塊 ,
然后分析這種方式的弊端,對其進行項目重構(gòu),重構(gòu)這一塊可以學(xué)習(xí)到不少 Java 里的中高級處理手法,
使得框架更加緊湊,后續(xù)開發(fā)更加便利和高效率。
實體類設(shè)計
準備 Category 實體類,并用 Hibernate 注解標示其對應(yīng)的表,字段等信息。
舉個例子,對于 分類 / category 的 實體類 和 表結(jié)構(gòu) 設(shè)計如下:
DAOImpl 類設(shè)計
DAO 是 Data Access Object 的縮寫,專門用于進行數(shù)據(jù)庫訪問的操作。
DAOImpl 繼承了 HibernateTemplate,這是一個 Hibernate 框架提供的模板類,提供了各種各樣的 CRUD方法,滿足各種數(shù)據(jù)庫操作的需要。
重寫 HibernateTemplate 的 setSessionFactory() 方法, 以用于注入 SessionFactory ,
SessionFactory 是在 spring 的配置文件里面定義的 bean ,可以看到其配置了連接數(shù)據(jù)庫的數(shù)據(jù)源等信息,這樣 dao 操作的時候,就不必獲取對應(yīng)的數(shù)據(jù)庫連接進行操作,
Spring 將數(shù)據(jù)源 ds 對象注入 SessionFactory ,sf 又被注入到 HibernateTemplate ,dao 繼承 HibernateTemplate 就可以直接操作數(shù)據(jù)庫了,非常簡便。
對比不使用 Spring+Hibernate 的情況,我們需要利用數(shù)據(jù)管理類 DBUtil 獲取 Connectoion ,
并在 dao 里面獲取對應(yīng)的 Statement 分別實現(xiàn) CURD 等方法,利用 JDBC 從數(shù)據(jù)庫取出數(shù)據(jù),再構(gòu)造成 bean 對象返回。
Service 類
設(shè)計 CategoryService 接口,用于提供業(yè)務(wù)方法 list() ,即查詢所有的分類。
public interface CategoryService{public List list(); }CategoryServiceImpl 實現(xiàn)了 CategoryService 接口,提供list()方法的具體實現(xiàn),同時自動裝配(注入) 了 DAOImpl 的實例 dao ,
在 list() 方法中,通過 dao 獲取所有的分類對象。
Action 類
CategoryAction 類作為 MVC 設(shè)計模式中的控制層起作用。
配置文件
web.xml
這個web.xml做了3件事情
1.讓所有請求都進入 Struts2 的過濾器 StrutsPrepareAndExecuteFilter
2.對所有請求進行 UTF-8 編碼
3.指定Spring配置文件 applicationContext.xml 的位置
struts.xml
<struts><constant name="struts.i18n.encoding" value="UTF-8"></constant><constant name="struts.objectFactory" value="spring"/><package name="basicstruts" extends="struts-default"></package> </struts>applicationContext.xml
applicationContext 除了配置上述的 SessionFactory ,還要配置事務(wù)管理器
<!-- 配置事務(wù)管理器(聲明式的事務(wù)) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sf"></property> </bean>訪問 jsp 顯示數(shù)據(jù)
Action 攜帶數(shù)據(jù)跳轉(zhuǎn)到 jsp ,作為視圖,擔當?shù)慕巧秋@示數(shù)據(jù),借助 JSTL 的 c:forEach 標簽遍歷從CategoryAction 的 list() 的傳遞過來的集合。
完整版的 listCategory.jsp 還包含4個公共文件,分別是 頭部,導(dǎo)航,行業(yè),頁腳。
分類管理還有增加,編輯,修改,刪除,分頁,另外后臺其他管理頁面,前臺頁面。具體的需要瀏覽代碼,篇幅原因就不展開了。
思路流程圖
重構(gòu)(這里非常精彩)
分類管理的 CURD 功能全部做好之后,代碼層面的問題開始逐漸浮現(xiàn)出來了,問題主要表現(xiàn)在 Service 層,和 Action 層。
Service層的問題
Service 層代碼如下:
首先看接口:CategoryService。 其聲明的方法基本上就是 CURD 和分頁。可以預(yù)見的是,在后續(xù)做產(chǎn)品管理,用戶管理,訂單管理等等,
也會有這么一個非常近似的 CURD 的接口,換句話說,這里是有做抽象和代碼重構(gòu)的機會和價值的。
然后看實現(xiàn)類:CategoryServiceImpl。 CategoryServiceImpl本身其實就是個架子,真正起作用的是為其注入的DAO對象,
所以這個地方也是可以引入委派模式,使得代碼調(diào)用更加順暢。
Service 層的重構(gòu)
Service層 的重構(gòu)行為主要包括兩種角度
由于可以預(yù)見的在后續(xù)做產(chǎn)品管理,用戶管理,訂單管理等等,也會有這么一個非常近似的CURD的接口,
那么我們就做一個BaseService,里面就提供這些CRUD和分頁查詢的方法。
接著設(shè)計 BaseServiceImpl 類,其 CURD 關(guān)鍵方法都是調(diào)用的被注入的 dao 完成的,這樣就十分適合使用委派模式來重構(gòu)這塊代碼。
不使用委派模式訪問數(shù)據(jù)庫都需要通過dao.XXX()來進行。 而委派重構(gòu)之后,數(shù)據(jù)庫相關(guān)方法,不再需要通過dao,直接調(diào)用即可,代碼看上去更簡潔。
委派類 ServiceDelegateDAO
設(shè)計一個新的類,叫做 ServiceDelegateDAO ,在其中注入 dao ,然后讓對 dao 的每一個方法進行委派。
那么到底什么是委派呢? 如 ServiceDelegateDAO 類所示:
public void delete(Object entity) throws DataAccessException { dao.delete(entity); }
當調(diào)用 ServiceDelegateDAO 對象的 delete(Object entity) 的時候,其實就是委派給的 dao 的 delete(Object entity) 方法。
但是從調(diào)用者的角度來看,調(diào)用者只知道 ServiceDelegateDAO 這個類的 delete(Object entity) 方法,而意識不到 dao 的存在。
而 dao 繼承了 HibernateTemplate ,一共有一百多個方法,哈哈這么麻煩肯定有工具可以一鍵生成,
果然利用 idea 立馬就生成了所有委派方法,即快速又不會出錯,突然感覺好開心。
BaseServiceImpl
BaseServiceImpl 的構(gòu)造器非常騷氣,BaseServiceImpl 的 clazz 對象需要引用實體類對象,這樣 CURD 方法中的 DetachedCriteria dc = DetachedCriteria.forClass(clazz); 才能獲取到對應(yīng)的查詢對象。
所以這里利用反射,在構(gòu)造方法中,借助異常處理和反射得到 Category.class 或者 Product.class 。 即要做到哪個類繼承了 BaseServiceImpl ,clazz 就對應(yīng)哪個類對應(yīng)的實體類對象。
首先要獲取是哪個類繼承了 BaseServiceImpl ,因為實例化子類,父類的構(gòu)造方法一定會被調(diào)用,
所以在父類 BaseServiceImpl 里故意拋出一個異常,然后手動捕捉住它,
在其對應(yīng)的 StackTrace 里的第二個(下標是1) 棧跟蹤元素 StackTraceElement ,即對應(yīng)子類。
這樣我們就拿到了子類名稱 CategoryServiceImpl 或者 ProductServiceImpl,具體的在代碼注釋里了,寫的非常清楚。
這樣 CategoryService 就不需要自己聲明方法了,只需要繼承接口 BaseService 即可
CategoryServiceImpl 也不需要自己提供實現(xiàn)了,繼承 BaseServiceImpl 并實現(xiàn)接口 CategoryService 即可
這么做的好處主要在于:后續(xù)新功能開發(fā)的過程中,當需要新增加新的Service類的話,比如 PropertyService,無需從頭開發(fā),
只需要繼承 BaseServiceImpl 并實現(xiàn) PropertyService,那么其所需要CRUD一套方法都有了。
Action的問題
先看代碼
這樣的CategoryAction代碼完成功能是沒有問題的,但是問題恰恰在于,這樣一個本來是用于充當控制層(Controller)的類,需要集中應(yīng)付太多的需求:
把所有的這些代碼,都放在一個類里面,這個類就會顯得繁雜,不易閱讀,不易維護。 所以這個地方也是很有代碼重構(gòu)價值的。
Action 層的重構(gòu)
目前 CategoryAction 存在的問題是一個類需要做太多的事情,顯的繁雜,影響閱讀和維護。 那么重構(gòu)思路就是把不同的事情,放在專門的類進行處理,各司其職。
- 上傳專用 Action4Upload
這個類就專門用于處理圖片上傳,其他的事情一概不管 - 分頁專用 Action4Pagination
專門用于處理分頁,并且繼承上傳專用 Action4Upload - 對象和集合 Action4Pojo
用于提供實體對象以及實體對象集合的setter和getter.
setter用于接收注入
getter用于提供數(shù)據(jù)到JSP(VIEW)上 - 注入服務(wù)專用 Action4Service
Action4Service提供服務(wù)的注入
Action4Service 另外提供了一個方法 t2p() ,專門用于把對象指向?qū)?yīng)的持久對象。
方法調(diào)用的最后結(jié)果就導(dǎo)致父類 Action4Pojo 中聲明的 pojo 本身是指向瞬時對象的,現(xiàn)在指向了持久對象(從數(shù)據(jù)庫中取出的對象)。
再定義返回頁面的 Action4Result 繼承 Action4Service ,專門進行返回頁面的定義
這樣
CategoryAction 繼承Action4Result, 于是就間接地繼承了 Action4Service,Action4Pojo,Action4Pagination,Action4Upload,
于是就通過繼承提供了各種相關(guān)的功能,CategoryAction 本身只需要專注于扮演控制器(Controller)本身就行了。這些工作對后面其他 Action 同樣適用,大大簡化了后續(xù)開發(fā)。
此外,后續(xù)還有針對 Service 的關(guān)系查詢重構(gòu),和Service 多條件查詢重構(gòu),具體的由于篇幅原因,請移步github 項目的地址
頁面展示
本篇博客所講不足整個項目的 1/10 ,有興趣的朋友請移步 github 項目的地址 。
參考
天貓SSH整站學(xué)習(xí)教程 里面除了本項目,還有 Java 基礎(chǔ),前端,Tomcat 及其他中間件等教程, 可以注冊一個賬戶,能保存學(xué)習(xí)記錄。
轉(zhuǎn)載于:https://www.cnblogs.com/czwbig/p/9953893.html
總結(jié)
以上是生活随笔為你收集整理的JavaWeb入门_模仿天猫整站Tmall_SSH实践项目的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。