- javaWEB簡單商城項目(一)
-
項目中使用到了上一篇博文的分頁框架,還有mybatis,重點是學習mybatis.
現在有些小迷茫,不知道該干啥,唉,不想那么多了,學就對了
一.項目功能結構
1.功能

2.實體

3.對應sql語句
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960<codeclass="language-sql hljs ">CREATE DATABASE shop;use shop;create table user(idint(11) primary key auto_increment,username varchar(100),password varchar(100),nickname varchar(100),typeint(5));INSERT INTO user VALUES (null,'admin','7946521','管理員',1);CREATE TABLE address(id INT(10) PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255),phone VARCHAR(100),postcode VARCHAR(100),user_id INT(10),CONSTRAINT FOREIGN KEY (user_id) REFERENCES user(id));INSERT INTO address VALUES (NULL ,'安徽阜陽','1234567890','236000','1');SELECT t1.*,t2.* FROM address t1 LEFT JOIN user t2 ON t1.user_id = t2.id where t1.user_id =1;create table orders(idint(11) primary key auto_increment,buy_date datetime,pay_date datetime,confirm_date datetime,statusint(5),user_idint(11),address_idint(11),CONSTRAINT FOREIGN KEY(user_id) REFERENCES user(id),CONSTRAINT FOREIGN KEY(address_id) REFERENCES address(id));create table category(idint(11) primary key auto_increment,name varchar(100));create table goods(idint(11) primary key auto_increment,name varchar(100),pricedouble,intro text,img varchar(100),stockint(10),c_idint(10),CONSTRAINT FOREIGN KEY(c_id) REFERENCES category(id));create table goods_orders(idint(11) primary key auto_increment,goods_idint(10),orders_idint(10),CONSTRAINT FOREIGN KEY(goods_id) REFERENCES goods(id),CONSTRAINT FOREIGN KEY(orders_id) REFERENCES orders(id));</code>二.項目准備
1.實體類實現
分別建立dao,filter,model,util的包,並在model中實現實體類,這里以User.java為例.
注意對於數據庫中外鍵,比如adress表中有外鍵user_id,那么在Adress.java中就可以直接給個User對象,在取adress表的時候就把user一並取出來.
User.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465<codeclass="language-java hljs ">packagecom.model;importjava.util.List;/*** Created by nl101 on 2016/2/22.*/publicclassUser {privateintid;//idprivateString username;privateString password;privateString nickname;//昵稱privateinttype;//1表示管理員,2表示注冊用戶privateList</code><codeclass="language-java hljs "> addresses;publicList</code><codeclass="language-java hljs "> getAddresses() {returnaddresses;}publicvoidsetAddresses(List</code><codeclass="language-java hljs "> addresses) {this.addresses = addresses;}publicintgetId() {returnid;}publicvoidsetId(intid) {this.id = id;}publicString getUsername() {returnusername;}publicvoidsetUsername(String username) {this.username = username;}publicString getPassword() {returnpassword;}publicvoidsetPassword(String password) {this.password = password;}publicString getNickname() {returnnickname;}publicvoidsetNickname(String nickname) {this.nickname = nickname;}publicintgetType() {returntype;}publicvoidsetType(inttype) {this.type = type;}}</code>Adress.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354<codeclass="hljs java">packagecom.model;/*** Created by nl101 on 2016/2/22.*/publicclassAddress {privateintid;privateString name;privateString phone;privateString postcode;//直接給user對象,來代替user_idprivateUser user;publicintgetId() {returnid;}publicvoidsetId(intid) {this.id = id;}publicString getName() {returnname;}publicvoidsetName(String name) {this.name = name;}publicString getPhone() {returnphone;}publicvoidsetPhone(String phone) {this.phone = phone;}publicString getPostcode() {returnpostcode;}publicvoidsetPostcode(String postcode) {this.postcode = postcode;}publicUser getUser() {returnuser;}publicvoidsetUser(User user) {this.user = user;}}</code>2.分頁框架准備
分頁主要是寫pager.java和SystemContext.java以及SystemFilter.java三個類.可以參開前面的博文,jsp通用分頁框架
完整建立后如下

-
- javaWEB簡單商城項目(三)
-
一.通用的BaseDao.java
既然要大家都能用,所以使用了泛型.其中要注意的問題就是類似User.getClass().getName()這樣的代碼是需要修改的.修改方法就是使用參數Class tc傳遞過來,然后在使用tc.getName()即可.
完整代碼:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140<codeclass="hljs scala">packagecom.dao;importcom.model.Pager;importcom.util.SessionUtil;importcom.util.SystemContext;importorg.apache.ibatis.session.SqlSession;importjava.util.HashMap;importjava.util.List;importjava.util.Map;/*** Created by nl101 on 2016/2/23.*/publicclassBaseDao<t> {/*** 根據id取出一個T類型* @param id 要取出T類型的id* @return*/publicT load(Class<t> tc,intid){SqlSession session = SessionUtil.getSession();T t =null;try{t = session.selectOne(tc.getName()+".load",id);}finally{SessionUtil.closeSession(session);}returnt;}/*** 添加一個T類型* @param t 要添加的T類型* @return true成功*/publicbooleanadd(T t){intisAdd =0;SqlSession session = SessionUtil.getSession();try{isAdd = session.insert(t.getClass().getName()+".add",t);session.commit();//提交}catch(Exception e) {session.rollback();//提交失敗則回滾}finally{SessionUtil.closeSession(session);}returnisAdd>0;}/***根據id刪除T類型* @param id 要刪除T的id* @return true成功*/publicbooleandelete(Class<t> t,intid){intisDelete =0;SqlSession session = SessionUtil.getSession();try{isDelete = session.delete(t.getName()+".delete",id);session.commit();}catch(Exception e) {session.rollback();//失敗返回System.out.println("刪除用戶失敗");e.printStackTrace();}finally{SessionUtil.closeSession(session);}returnisDelete>0;}/***更新T類型* @param t 要更新的用戶* @return true成功*/publicbooleanupdate(T t){intisUpdate =0;SqlSession session = SessionUtil.getSession();try{isUpdate = session.delete(t.getClass().getName()+".update",t);session.commit();}catch(Exception e) {session.rollback();//失敗返回System.out.println("更新用戶失敗");e.printStackTrace();}finally{SessionUtil.closeSession(session);}returnisUpdate>0;}/*** 根據指定條件分頁查詢* @param maps 指定條件集合* @return*/publicPager<t> find(Class<t> t,Map<string,object> maps){intpageStart = SystemContext.getPageStart();//分頁起始intpageSize = SystemContext.getPageSize();//分頁大小Pager<t> pagers =newPager<>();maps.put("pageStart",pageStart);maps.put("pageSize",pageSize);SqlSession session = SessionUtil.getSession();List<t> datas =null;try{datas = session.selectList(t.getName()+".find",maps);//獲取記錄pagers.setDatas(datas);pagers.setPageSize(pageSize);pagers.setPageStart(pageStart);inttotalRecord = session.selectOne(t.getName()+".findcount",maps);//獲取記錄總數pagers.setTotalRecord(totalRecord);pagers.setPageIndex(pageStart/pageSize+1);}finally{SessionUtil.closeSession(session);}returnpagers;}/*** 根據指定條件取出部分數據* @param maps 指定條件集合* @return*/publicPager<t> list(Class<t> t,Map<string,object> maps){Pager<t> pagers =newPager<>();SqlSession session = SessionUtil.getSession();List<t> datas =null;try{datas = session.selectList(t.getName()+".list",maps);//獲取記錄pagers.setDatas(datas);pagers.setTotalRecord(datas.size());}finally{SessionUtil.closeSession(session);}returnpagers;}}</t></t></string,object></t></t></t></t></string,object></t></t></t></t></t></code>
同樣的UserDao.java也需要相應的修改
12345678910111213<codeclass="hljs scala">publicclassUserDaoextendsBaseDao<user>{/*** 根據id取出一個用戶* @param id 要取出用戶的id* @return*/publicUser load(intid){returnsuper.load(User.class,id);}/* 其他函數就不一一貼出來了,都是類似的寫法*/}</user></code>二.resultMap的映射
簡單來說當數據庫中的字段信息和對象的屬性不一致時需要通過resultMap來映射.
舉個例子:Address屬性中有一個User的實體類,如下123456789<codeclass="hljs cs">publicclassAddress {privateintid;privateString name;privateString phone;privateString postcode;//直接給user對象,來代替user_idprivateUser user;`````````}</code>那么我們想取出來一個Address的同時也取出其對應的user,然而這是兩個對象,且兩者都有id屬性,所以對於mybatis在調用set方法設置屬性時就會混亂而使用resultMap的目的就是消除這種混亂.
編寫load的sql
123456<codeclass="hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%E5%8A%A0%E8%BD%BD%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%2D%2D%3E--><!--{cke_protected}{C}%3C!%2D%2D%E8%BF%99%E9%87%8C%E9%9C%80%E8%A6%81%E8%A1%A8%E8%BF%9E%E6%8E%A5%2C%E5%8F%96%E5%87%BAUser%2C%E5%8F%88%E8%BF%9E%E6%8E%A5%E4%BF%9D%E8%AF%81%E5%8F%96%E5%87%BA%E7%9A%84%E5%9C%B0%E5%9D%80%E4%B8%8D%E4%B8%BA%E7%A9%BA%2C%E5%B9%B6%E4%B8%94%E4%B8%BA%E9%87%8D%E5%A4%8D%E5%B1%9E%E6%80%A7id%E5%8F%96%E5%88%AB%E5%90%8D%2D%2D%3E--><select id="load"parametertype="int"resultmap="addressMap">select *,t1.id AS'a_id'from address t1 RIGHT JOIN user t2 ON(t1.user_id = t2.id) WHERE t1.id=#{id};</select></code>這里就使用的resultMap來映射,這個resultMap的名字叫做addressMap.
addressMap
type 代表其類型,不包括關聯屬性 autoMapping true表示消除沖突后,剩下的屬性會自動匹配 id和result id 和 result 都映射一個單獨列的值到簡單數據類型,不同是 id 表示的結果將是當比較對象實例時用到的標識屬性,一般是主鍵 association 代表關聯屬性,這里設置的是User, 對於關聯映射,其里面想要顯示的屬性必須要手動指定property,不然會無法映射123456789101112<codeclass="hljs xml"><resultmap automapping="true"id="addressMap"type="Address"><!--{cke_protected}{C}%3C!%2D%2D%E6%8A%8A%E7%BB%93%E6%9E%9C%E4%B8%AD%E7%9A%84a_id%E6%98%A0%E5%B0%84%E4%B8%BAid%2C%E5%85%B6%E4%BB%96%E7%9A%84autoMapping%20%3D%20true%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%8C%B9%E9%85%8D%2D%2D%3E--><id column="a_id"property="id"><!--{cke_protected}{C}%3C!%2D%2D%E5%8F%96%E5%87%BA%E5%85%B3%E8%81%94%E5%B1%9E%E6%80%A7%2D%2D%3E--><association javatype="User"property="user"><!--{cke_protected}{C}%3C!%2D%2D%E6%8A%8Auser_id%E6%98%A0%E5%B0%84%E4%B8%BAuser%E7%9A%84id%2D%2D%3E--><id column="user_id"property="id"><result column="username"property="username"><result column="nickname"property="nickname"><result column="type"property="type"></result></result></result></id></association></id></resultmap></code>上面配置完,當搜索出來的時候,mybatis就會自動調用其相應的set方法,把屬性設置到實體類中.
測試
12345678910111213141516171819<codeclass="hljs scala">packagecom.dao;importcom.model.Address;publicclassAddressDaoextendsBaseDao</code><codeclass="hljs scala"> {publicstaticvoidmain(String[] args) {AddressDao addressDao =newAddressDao();Address address = addressDao.load(1);System.out.println(address.toString());}/*** 加載一個地址* @param id 要加載地址的id* @return 返回要加載的地址,null則加載失敗*/publicAddress load(intid){returnsuper.load(Address.class,id);}}</code>效果圖可以看出來,只要是映射的關聯屬性都取出來了,沒映射的都為null

按照這樣的想法把其他函數補全<喎�"/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPnhtbLT6wus6PC9wPg0KPHByZSBjbGFzcz0="brush:java;"> <code class="hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%2D%2D%3E--> <mapper namespace="com.model.Address"> <!--{cke_protected}{C}%3C!%2D%2D%E5%BD%93%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E7%9A%84%E5%AD%97%E6%AE%B5%E4%BF%A1%E6%81%AF%E5%92%8C%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7%E4%B8%8D%E4%B8%80%E8%87%B4%E6%97%B6%E9%9C%80%E8%A6%81%E9%80%9A%E8%BF%87resultMap%E6%9D%A5%E6%98%A0%E5%B0%84%20%2D%2D%3E--> <resultmap automapping="true" id="addressMap" type="Address"> <!--{cke_protected}{C}%3C!%2D%2D%E6%8A%8A%E7%BB%93%E6%9E%9C%E4%B8%AD%E7%9A%84a_id%E6%98%A0%E5%B0%84%E4%B8%BAid%2C%E5%85%B6%E4%BB%96%E7%9A%84autoMapping%20%3D%20true%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%8C%B9%E9%85%8D%2D%2D%3E--> <id column="a_id" property="id"> <!--{cke_protected}{C}%3C!%2D%2D%E5%8F%96%E5%87%BA%E5%85%B3%E8%81%94%E5%B1%9E%E6%80%A7%2D%2D%3E--> <association javatype="User" property="user"> <!--{cke_protected}{C}%3C!%2D%2D%E6%8A%8Auser_id%E6%98%A0%E5%B0%84%E4%B8%BAuser%E7%9A%84id%2D%2D%3E--> <id column="user_id" property="id"> <result column="username" property="username"> <result column="nickname" property="nickname"> <result column="type" property="type"> </result></result></result></id></association> </id></resultmap> <!--{cke_protected}{C}%3C!%2D%2D%E5%8A%A0%E8%BD%BD%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%2D%2D%3E--> <!--{cke_protected}{C}%3C!%2D%2D%E8%BF%99%E9%87%8C%E9%9C%80%E8%A6%81%E8%A1%A8%E8%BF%9E%E6%8E%A5%2C%E5%8F%96%E5%87%BAUser%2C%E5%8F%88%E8%BF%9E%E6%8E%A5%E4%BF%9D%E8%AF%81%E5%8F%96%E5%87%BA%E7%9A%84%E5%9C%B0%E5%9D%80%E4%B8%8D%E4%B8%BA%E7%A9%BA%2C%E5%B9%B6%E4%B8%94%E4%B8%BA%E9%87%8D%E5%A4%8D%E5%B1%9E%E6%80%A7id%E5%8F%96%E5%88%AB%E5%90%8D%2D%2D%3E--> <select id="load" parametertype="int" resultmap="addressMap"> select *,t1.id AS 'a_id' from address t1 RIGHT JOIN user t2 ON (t1.user_id = t2.id) WHERE t1.id=#{id}; </select> <!--{cke_protected}{C}%3C!%2D%2D%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%2D%2D%3E--> <insert id="add" parametertype="Address"> insert into address values (null,#{name},#{phone},#{postcode},${user_id}) </insert> <!--{cke_protected}{C}%3C!%2D%2D%E5%88%A0%E9%99%A4%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%2D%2D%3E--> <delete id="delete" parametertype="int"> DELETE FROM address WHERE id=#{id} </delete> <!--{cke_protected}{C}%3C!%2D%2D%E4%BF%AE%E6%94%B9%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%2D%2D%3E--> <update id="update" parametertype="Address"> UPDATE address SET name=#{name},phone=#{phone},postcode=#{postcode} where id=#{id} </update> <!--{cke_protected}{C}%3C!%2D%2D%E6%89%BE%E5%87%BA%E6%8C%87%E5%AE%9A%E7%94%A8%E6%88%B7%E6%89%80%E6%9C%89%E7%9A%84%E5%9C%B0%E5%9D%80%2D%2D%3E--> <select id="list" parametertype="Map" resultmap="addressMap"> SELECT *,t1.id AS 'a_id' FROM address t1 RIGHT JOIN user t2 ON (t1.user_id=t2.id) WHERE t1.user_id=#{user_id} </select> </mapper></code>
java代碼:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970<codeclass="hljs scala">packagecom.dao;importcom.model.Address;importcom.model.Pager;importjava.util.HashMap;importjava.util.Map;/*** Created by nl101 on 2016/2/23.*/publicclassAddressDaoextendsBaseDao</code><codeclass="hljs scala"> {publicstaticvoidmain(String[] args) {AddressDao addressDao =newAddressDao();Pager</code><codeclass="hljs scala"> pagers = addressDao.list(1);System.out.println(pagers.getDatas().size());}/*** 加載一個地址* @param id 要加載地址的id* @return 返回要加載的地址,null則加載失敗*/publicAddress load(intid){returnsuper.load(Address.class,id);}/*** 添加一個地址* @param address 要添加的地址* @param user_id 要添加的地址對應的user_id* @return true成功*/publicbooleanadd(Address address,intuser_id){UserDao userDao =newUserDao();if(userDao.load(user_id)==null){returnfalse;}returnsuper.add(address);}/*** 刪除一個地址* @param id 要刪除地址對應的id* @return true刪除成功*/publicbooleandelete(intid){returnsuper.delete(Address.class,id);}/*** 更新一個地址* @param address 要更新的地址* @return true更新成功*/publicbooleanupdate(Address address){returnsuper.update(address);}/*** 根據用戶id取出該用戶所有地址* @param user_id* @return*/publicPager</code><codeclass="hljs scala"> list(intuser_id){Map<string,object> maps =newHashMap<>();maps.put("user_id",user_id);returnsuper.list(Address.class,maps);}}</address></address></address></string,object></code>
ADO層按照這樣寫,就沒問題了,后面的實體DAO代碼就不貼上來了,下一篇工廠模式學習
-
- javaWEB簡單商城項目(四)
-
接着上一篇javaWEB簡單商城項目(三),這一篇學習基於反射的工廠模式和java依賴注入在項目中的使用
一.java反射
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
說的通俗點不像以前那樣通過new創建對象,現在通過類的限定名即可創建對象.1.通過反射獲取對象
程序通過類的完整限定名創建出了User的實例,這就是利用到了反射
123456789101112131415<codeclass="hljs cs">publicstaticvoidmain(String[] args) {String str ="com.model.User";//類的限定名try{Class clz = Class.forName(str);//獲取類的Class對象User user = (User) clz.newInstance();//通過Class對象獲取User的實例user.setUsername("Admin");System.out.println(user.getUsername());}catch(ClassNotFoundException e) {e.printStackTrace();}catch(InstantiationException e) {e.printStackTrace();}catch(IllegalAccessException e) {e.printStackTrace();}}</code>2.通過反射調用類方法
基於反射調用方法,主要通過Method這個類的invoke()方法,這樣做的好處是需要調用的信息,字符串等我們可以寫在配置文件中,然后修改就可以直接在配置文件中修改了,后期維護方便太多了
123456789101112131415161718192021222324252627<codeclass="hljs java">publicstaticvoidmain(String[] args) {String str ="com.model.User";//類的限定名String method ="setUsername";try{Class clz = Class.forName(str);//獲取類的Class對象User u = (User) clz.newInstance();/*** 通過getMethod可以獲取類方法,第一個參數是方法名,第二個參數是方法參數,可以無限加參數*/Method method1 = clz.getMethod(method,String.class);/*** 通過invoke()可以執行這個方法,參數1是執行該方法的對象,參數二是方法的參數*/method1.invoke(u,"admin");System.out.println(u.getUsername());}catch(ClassNotFoundException e) {e.printStackTrace();}catch(InstantiationException e) {e.printStackTrace();}catch(IllegalAccessException e) {e.printStackTrace();}catch(NoSuchMethodException e) {e.printStackTrace();}catch(InvocationTargetException e) {e.printStackTrace();}}</code>
二.基於配置文件的工廠模式
說工廠模式之前,先說下OCP(open closed Principle)原則,翻譯過來就是開閉原則,意思是項目應該對擴展開放,對修改關閉,也就是做到最少的修改而完成所想要的變動.
1.簡單工廠模式
在com.dao這個包中,每一個實體都有一個對應的DAO,假如實體很多的話,對於DAO管理就需要一個來創建DAO的工廠來管理,如下面例子
12345678910111213141516<codeclass="hljs java">importcom.dao.AddressDao;importcom.dao.UserDao;/*** Created by nl101 on 2016/2/26.*/publicclassDAOFactory {//獲取UserDaopublicstaticUserDao getUserDao(){returnnewUserDao();}//獲取AddressDaopublicstaticAddressDao getAddressDao(){returnnewAddressDao();}}</code>唯一的用處就是把Dao統一了起來,用的時候世界DAOFactory.getUserDao()即可
缺點:假如更換數據庫,或者更換Dao的時候,就需要在這里面修改其相應的方法
2.工廠方法模式
工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣做的目的是將類的實例化操作延遲到子類中完成。
首先定義抽象父類接口
12345678910<codeclass="hljs java">importcom.dao.AddressDao;importcom.dao.UserDao;/*** Created by nl101 on 2016/2/26.*/publicinterfaceAbstractFactory {publicUserDao createUserDao();publicAddressDao createAddressDao();}</code>接着定義實現具體方法的子類
123456789101112131415161718192021222324252627282930<codeclass="hljs java">importcom.dao.AddressDao;importcom.dao.UserDao;/*** Created by nl101 on 2016/2/26.*/publicclassMysqlDAOFactoryimplementsAbstractFactory{/*** 單例設計具體工廠*/privatestaticAbstractFactory factory =newMysqlDAOFactory ();privateDAOFactory() {}publicstaticAbstractFactory getInstance(){returnfactory;}//獲取UserDao@OverridepublicUserDao createUserDao(){returnnewUserDao();}//獲取AddressDao@OverridepublicAddressDao createAddressDao(){returnnewAddressDao();}}</code>同樣的還可以有OracleDAOFactory,而他們的方法統一由父類接口來定義,自己只負責實現具體方法.
缺點:修改起來還是麻煩,而且調用需要MysqlDAOFactory.getInstance().createUserDao(),太長了
3.基於配置文件的工廠
基於配置文件的意思就是我們把一些參數寫到配置文件中,由一個類通過讀取配置文件信息,創建我們需要的DAO.
1.首先我們要創建properties文件,里面存儲着dao對應的限定名
dao.properties
12<codeclass="hljs avrasm">userdao = com.dao.UserDaoaddressdao = com.dao.AddressDao</code>2.創建抽象工廠 ,工廠里面有一個通用的創建DAO方法
123<codeclass="hljs cs">publicinterfaceAbstractFactory {publicObject createDao(String name);}</code>3.創建peopertiesUtil,用來方便的讀取配置文件
12345678910111213141516171819202122232425262728<codeclass="hljs java">importjava.io.IOException;importjava.util.Properties;/*** Created by nl101 on 2016/2/26.*/publicclassPropertiesUtil {publicstaticProperties daoProperties =null;/*** 獲取dao配置文件* @return*/publicstaticProperties getDaoPro(){//如果已經創建,則直接返回if(daoProperties!=null){returndaoProperties;}daoProperties =newProperties();try{daoProperties.load(PropertiesUtil.class.getClassLoader().getResourceAsStream("dao.properties"));//加載配置文件}catch(IOException e) {System.out.println("未找到dao配置文件");e.printStackTrace();}returndaoProperties;}}</code>4.創建具體工廠,通過傳入的name值,利用反射就可以獲取到對應的DAO實體類
123456789101112131415161718192021222324252627282930313233343536<codeclass="hljs java">publicclassPropertiesFactoryimplementsAbstractFactory{/*** 首先為工廠實現單例模式* @return*/privatestaticAbstractFactory factory =newPropertiesFactory();privatePropertiesFactory() {}publicstaticAbstractFactory getInstance(){returnfactory;}/*** 實現父類接口的方法* @param name 需要創建的dao名字* @return 創建的dao*/@OverridepublicObject createDao(String name) {Properties properties = PropertiesUtil.getDaoPro();String daoName = properties.getProperty(name);//獲取要創建dao對應的限定名Object obj =null;//承載創建對象的容器try{Class clz = Class.forName(daoName);obj = clz.newInstance();}catch(ClassNotFoundException e) {e.printStackTrace();}catch(InstantiationException e) {e.printStackTrace();}catch(IllegalAccessException e) {e.printStackTrace();}returnobj;}}</code>5.具體工廠優化,對於dao實體我們可以把創建好的存起來,調用的時候先判斷是否已經創建,已經創建則返回.所以自然想到了鍵值對的Map集合.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152<codeclass="hljs java">importcom.util.PropertiesUtil;importjava.util.HashMap;importjava.util.Map;importjava.util.Properties;/*** Created by nl101 on 2016/2/26.*/publicclassPropertiesFactoryimplementsAbstractFactory{/*** 首先為工廠實現單例模式* @return*/privatestaticAbstractFactory factory =newPropertiesFactory();privatePropertiesFactory() {}publicstaticAbstractFactory getInstance(){returnfactory;}privateMap<string,object> maps =newHashMap<>();/*** 實現父類接口的方法* @param name 需要創建的dao名字* @return 創建的dao*/@OverridepublicObject createDao(String name) {//判斷map中是否已經創建,是則直接返回if(maps.containsKey(name)){returnmaps.get(name);}Properties properties = PropertiesUtil.getDaoPro();String daoName = properties.getProperty(name);//獲取要創建dao對應的限定名Object obj =null;//承載創建對象的容器try{Class clz = Class.forName(daoName);//加載classobj = clz.newInstance();//獲取實例maps.put(name,obj);//存入map中}catch(ClassNotFoundException e) {e.printStackTrace();}catch(InstantiationException e) {e.printStackTrace();}catch(IllegalAccessException e) {e.printStackTrace();}returnobj;}}</string,object></code>調用就可以按照下面方法
1<codeclass="hljs avrasm">UserDao userDao = (UserDao) PropertiesFactory.getInstance().createDao("userdao");</code>是不是感覺調用還是很麻煩,要寫這么長,別急,下面依賴注入就是來解決這個問題的
這樣基於配置為工廠模式就比較完美了,如果想換DAO則只要在配置文件中修改下限定名即可,很方便
三.java依賴注入
為什么叫“依賴注入”:縱觀所有的Java應用,它們都是由一些互相協作的對象構成的。我們稱這種互相協作的關系為依賴關系。假如A組件調用了B組件的方法,我們可稱A組件依賴於B組件。系統創建的實例供調用者調用,也可以看作是系統將創建的實例注入調用者。
1.依賴注入setXXX()方法
前面我們在AddressDao中使用了UserDao這個類,我們采用的是
UserDao userDao = (UserDao) PropertiesFactory.getInstance().createDao("userdao");這樣的復雜方法,現在通過依賴注入,我們就可以在創建這個類的時候把這個對象初始化好1.首先我們需要對需要依賴注入的類寫上set和get方法,這里我們需要在AddressDao對userDao設置.
所謂的依賴注入就是在初始化類的時候,調用set方法,對userDao進行賦值123456789101112<codeclass="hljs java">/*** 通過依賴注入進行賦值*/privateUserDao userDao;publicUserDao getUserDao() {returnuserDao;}publicvoidsetUserDao(UserDao userDao) {this.userDao = userDao;}</code>2.為了方便,寫一個DaoUtil用來存放依賴注入的代碼
123456789101112131415161718192021222324252627282930313233343536<codeclass="hljs java">importcom.dao.PropertiesFactory;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;/*** Created by nl101 on 2016/2/26.*/publicclassDaoUtil {/*** dao依賴注入方法* @param obj*/publicstaticvoiddaoInject(Object obj){//獲取當前類的不包括繼承下來的方法Method[] methods = obj.getClass().getDeclaredMethods();try{//對方法篩選出setXXX方法for(Method method : methods){//判斷是否以set開始if(method.getName().startsWith("set")){//截取set之后的字串和properties相對應String mm = method.getName().substring(3);//獲取實例Object o = PropertiesFactory.getInstance().createDao(mm);//調用set方法進行設置method.invoke(obj,o);}}}catch(IllegalAccessException e) {e.printStackTrace();}catch(InvocationTargetException e) {e.printStackTrace();}}}</code>3.我們知道所有的Dao都有一個父類,BaseDao,當我們創建某個Dao的時候就會先執行父類的構造方法,所以我們可以在父類的方法中調用依賴注入這個方法
123456<codeclass="hljs java">/*** 調用依賴注入方法*/publicBaseDao() {DaoUtil.daoInject(this);}</code>這樣做是可以實現創建AddressDao的時候就初始化userDao變量,但是如果AddressDao還有其他set方法的話,那么程序因為在配置文件中找不到相應的數據,就會報錯
2.使用Annotation優化注入
什么是Annotation?就是在方法前面@符號引出的代碼,如下圖
當@Dao(“UserDao”)的時候注入UserDao 當@Dao不帶參數的時候使用setXXX()注入
因此我們可以創建自己的Annotation:Dao,想要實現的效果如下1.創建自己的Annotation,從代碼可以看到Annotation標識是@interface
12345678910<codeclass="hljs java">importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;/*** 加這個聲明,說明當前Annotation在運行的時候執行*/@Retention(RetentionPolicy.RUNTIME)public@interfaceDao {String value()default"";}</code>其中value()代表他的值,默認是空,當然也可以自定義其他值,比如
String abc() default ""2.使用Annotation,使用很簡單,在需要注入的代碼上面添加標識就好了
1234<codeclass="hljs java">@Dao("UserDao")publicvoidsetUserDao(UserDao userDao) {this.userDao = userDao;}</code>3.修改注入代碼,實現上面所說的邏輯
12345678910111213141516171819202122232425262728293031323334353637383940414243444546<codeclass="hljs java">packagecom.util;importcom.dao.PropertiesFactory;importcom.model.Dao;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;/*** Created by nl101 on 2016/2/26.*/publicclassDaoUtil {/*** dao依賴注入方法* @param obj*/publicstaticvoiddaoInject(Object obj){//獲取當前類的不包括繼承下來的方法Method[] methods = obj.getClass().getDeclaredMethods();try{//對方法篩選出setXXX方法for(Method method : methods){//如果有Dao這個Annotation,則處理if(method.isAnnotationPresent(Dao.class)){//獲取當前這個AnonotationDao dao = method.getDeclaredAnnotation(Dao.class);//獲取其值String name = dao.value();//如果值為空,則截取set之后的字符作為值if(name==null|| name.equals("")){name = method.getName().substring(3);}//獲取實例Object o = PropertiesFactory.getInstance().createDao(name);//調用set方法進行設置method.invoke(obj,o);}}}catch(IllegalAccessException e) {e.printStackTrace();}catch(InvocationTargetException e) {e.printStackTrace();}}}</code>通過運行發現成功存入數據,這樣就解決了setXXX()時候的缺點

