javaWEB簡單商城項目

javaWEB簡單商城項目(一)

項目中使用到了上一篇博文的分頁框架,還有mybatis,重點是學習mybatis.
如今有些小迷茫,不知道該幹啥,唉,不想那麼多了,學就對了php


一.項目功能結構

1.功能

這裏寫圖片描述

 

2.實體

這裏寫圖片描述

 

3.對應sql語句

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<code class = "language-sql hljs " >CREATE DATABASE shop;
use shop;
 
create table user(
   id int ( 11 ) primary key auto_increment,
   username varchar( 100 ),
   password varchar( 100 ),
   nickname varchar( 100 ),
   type int ( 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(
   id int ( 11 ) primary key auto_increment,
   buy_date datetime,
   pay_date datetime,
   confirm_date datetime,
   status int ( 5 ),
   user_id int ( 11 ),
   address_id int ( 11 ),
   CONSTRAINT FOREIGN KEY(user_id) REFERENCES user(id),
   CONSTRAINT FOREIGN KEY(address_id) REFERENCES address(id)
);
 
create table category(
   id int ( 11 ) primary key auto_increment,
   name varchar( 100 )
);
 
create table goods(
   id int ( 11 ) primary key auto_increment,
   name varchar( 100 ),
   price double ,
   intro text,
   img varchar( 100 ),
   stock int ( 10 ),
   c_id int ( 10 ),
   CONSTRAINT FOREIGN KEY(c_id) REFERENCES category(id)
);
 
create table goods_orders(
   id int ( 11 ) primary key auto_increment,
   goods_id int ( 10 ),
   orders_id int ( 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爲例.html

注意對於數據庫中外鍵,好比adress表中有外鍵user_id,那麼在Adress.java中就能夠直接給個User對象,在取adress表的時候就把user一併取出來.java

User.javasql

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<code class = "language-java hljs " > package com.model;
 
import java.util.List;
 
/**
  * Created by nl101 on 2016/2/22.
  */
public class User {
     private int id; //id
     private String username;
     private String password;
     private String nickname; //暱稱
     private int type; //1表示管理員,2表示註冊用戶
 
     private List</code><code class = "language-java hljs " > addresses;
 
     public List</code><code class = "language-java hljs " > getAddresses() {
         return addresses;
     }
 
     public void setAddresses(List</code><code class = "language-java hljs " > addresses) {
         this .addresses = addresses;
     }
 
     public int getId() {
         return id;
     }
 
     public void setId( int id) {
         this .id = id;
     }
 
     public String getUsername() {
         return username;
     }
 
     public void setUsername(String username) {
         this .username = username;
     }
 
     public String getPassword() {
         return password;
     }
 
     public void setPassword(String password) {
         this .password = password;
     }
 
     public String getNickname() {
         return nickname;
     }
 
     public void setNickname(String nickname) {
         this .nickname = nickname;
     }
 
     public int getType() {
         return type;
     }
 
     public void setType( int type) {
         this .type = type;
     }
}
</code>

Adress.java數據庫

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<code class = "hljs java" > package com.model;
 
/**
  * Created by nl101 on 2016/2/22.
  */
public class Address {
     private int id;
     private String name;
     private String phone;
     private String postcode;
     //直接給user對象,來代替user_id
     private User user;
 
     public int getId() {
         return id;
     }
 
     public void setId( int id) {
         this .id = id;
     }
 
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this .name = name;
     }
 
     public String getPhone() {
         return phone;
     }
 
     public void setPhone(String phone) {
         this .phone = phone;
     }
 
     public String getPostcode() {
         return postcode;
     }
 
     public void setPostcode(String postcode) {
         this .postcode = postcode;
     }
 
     public User getUser() {
         return user;
     }
 
     public void setUser(User user) {
         this .user = user;
     }
}
</code>

2.分頁框架準備

分頁主要是寫pager.java和SystemContext.java以及SystemFilter.java三個類.能夠參開前面的博文,jsp通用分頁框架apache


完整創建後以下canvas

這裏寫圖片描述

javaWEB簡單商城項目(三)

一.通用的BaseDao.java

既然要你們都能用,因此使用了泛型.其中要注意的問題就是相似User.getClass().getName()這樣的代碼是須要修改的.修改方法就是使用參數Class tc傳遞過來,而後在使用tc.getName()便可.session

完整代碼:mybatis

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<code class = "hljs scala" > package com.dao;
 
import com.model.Pager;
import com.util.SessionUtil;
import com.util.SystemContext;
import org.apache.ibatis.session.SqlSession;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
  * Created by nl101 on 2016/2/23.
  */
public class BaseDao<t> {
     /**
      * 根據id取出一個T類型
      * @param id 要取出T類型的id
      * @return
      */
     public T load(Class<t> tc, int id){
         SqlSession session = SessionUtil.getSession();
         T t = null ;
         try {
             t = session.selectOne(tc.getName()+ ".load" ,id);
         } finally {
             SessionUtil.closeSession(session);
         }
         return t;
     }
     /**
      * 添加一個T類型
      * @param t 要添加的T類型
      * @return true成功
      */
     public boolean add(T t){
         int isAdd = 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);
         }
         return isAdd> 0 ;
     }
     /**
      *根據id刪除T類型
      * @param id 要刪除T的id
      * @return true成功
      */
     public boolean delete(Class<t> t, int id){
         int isDelete = 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);
         }
         return isDelete> 0 ;
     }
     /**
      *更新T類型
      * @param t 要更新的用戶
      * @return true成功
      */
     public boolean update(T t){
         int isUpdate = 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);
         }
         return isUpdate> 0 ;
     }
 
     /**
      * 根據指定條件分頁查詢
      * @param maps 指定條件集合
      * @return
      */
     public Pager<t> find(Class<t> t,Map<string,object> maps){
         int pageStart = SystemContext.getPageStart(); //分頁起始
         int pageSize = SystemContext.getPageSize(); //分頁大小
         Pager<t> pagers = new Pager<>();
         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);
             int totalRecord = session.selectOne(t.getName()+ ".findcount" ,maps); //獲取記錄總數
             pagers.setTotalRecord(totalRecord);
             pagers.setPageIndex(pageStart/pageSize+ 1 );
 
         } finally {
             SessionUtil.closeSession(session);
         }
 
         return pagers;
     }
     /**
      * 根據指定條件取出部分數據
      * @param maps 指定條件集合
      * @return
      */
     public Pager<t> list(Class<t> t,Map<string,object> maps){
         Pager<t> pagers = new Pager<>();
         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);
         }
 
         return pagers;
     }
}
</t></t></string,object></t></t></t></t></string,object></t></t></t></t></t></code>

一樣的UserDao.java也須要相應的修改app

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<code class = "hljs scala" > public class UserDao extends BaseDao<user>{
 
     /**
      * 根據id取出一個用戶
      * @param id 要取出用戶的id
      * @return
      */
     public User load( int id){
         return super .load(User. class ,id);
     }
/* 其餘函數就不一一貼出來了,都是相似的寫法*/
}
</user></code>

二.resultMap的映射

簡單來講當數據庫中的字段信息和對象的屬性不一致時須要經過resultMap來映射.
舉個例子:Address屬性中有一個User的實體類,以下

?
1
2
3
4
5
6
7
8
9
<code class = "hljs cs" >    public class Address {
     private int id;
     private String name;
     private String phone;
     private String postcode;
     //直接給user對象,來代替user_id
     private User user;
         `````````
}</code>

那麼咱們想取出來一個Address的同時也取出其對應的user,然而這是兩個對象,且二者都有id屬性,因此對於mybatis在調用set方法設置屬性時就會混亂而使用resultMap的目的就是消除這種混亂.

編寫load的sql

?
1
2
3
4
5
6
<code class = "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

?
1
2
3
4
5
6
7
8
9
10
11
12
<code class = "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>
type 表明其類型,不包括關聯屬性 autoMapping true表示消除衝突後,剩下的屬性會自動匹配 id和result id 和 result 都映射一個單獨列的值到簡單數據類型,不一樣是 id 表示的結果將是當比較對象實例時用到的標識屬性,通常是主鍵 association 表明關聯屬性,這裏設置的是User, 對於關聯映射,其裏面想要顯示的屬性必需要手動指定property,否則會沒法映射

上面配置完,當搜索出來的時候,mybatis就會自動調用其相應的set方法,把屬性設置到實體類中.

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<code class = "hljs scala" > package com.dao;
 
import com.model.Address;
public class AddressDao extends BaseDao</code><code class = "hljs scala" > {
     public static void main(String[] args) {
         AddressDao addressDao = new AddressDao();
         Address address = addressDao.load( 1 );
         System.out.println(address.toString());
     }
 
     /**
      * 加載一個地址
      * @param id 要加載地址的id
      * @return 返回要加載的地址,null則加載失敗
      */
     public Address load( int id){
         return super .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代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<code class = "hljs scala" > package com.dao;
 
import com.model.Address;
import com.model.Pager;
 
import java.util.HashMap;
import java.util.Map;
 
/**
  * Created by nl101 on 2016/2/23.
  */
public class AddressDao extends BaseDao</code><code class = "hljs scala" > {
     public static void main(String[] args) {
         AddressDao addressDao = new AddressDao();
         Pager</code><code class = "hljs scala" > pagers = addressDao.list( 1 );
         System.out.println(pagers.getDatas().size());
     }
 
     /**
      * 加載一個地址
      * @param id 要加載地址的id
      * @return 返回要加載的地址,null則加載失敗
      */
     public Address load( int id){
         return super .load(Address. class ,id);
     }
 
     /**
      * 添加一個地址
      * @param address 要添加的地址
      * @param user_id 要添加的地址對應的user_id
      * @return true成功
      */
     public boolean add(Address address, int user_id){
         UserDao userDao = new UserDao();
         if (userDao.load(user_id)== null ){
             return false ;
         }
         return super .add(address);
     }
 
     /**
      * 刪除一個地址
      * @param id 要刪除地址對應的id
      * @return true刪除成功
      */
     public boolean delete( int id){
         return super .delete(Address. class ,id);
     }
 
     /**
      * 更新一個地址
      * @param address 要更新的地址
      * @return true更新成功
      */
     public boolean update(Address address){
         return super .update(address);
     }
 
     /**
      * 根據用戶id取出該用戶全部地址
      * @param user_id
      * @return
      */
     public Pager</code><code class = "hljs scala" > list( int user_id){
         Map<string,object> maps = new HashMap<>();
         maps.put( "user_id" ,user_id);
         return super .list(Address. class ,maps);
     }
}</address></address></address></string,object></code>

ADO層按照這樣寫,就沒問題了,後面的實體DAO代碼就不貼上來了,下一篇工廠模式學習

javaWEB簡單商城項目(四)

接着上一篇javaWEB簡單商城項目(三),這一篇學習基於反射的工廠模式和java依賴注入在項目中的使用


一.java反射

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
說的通俗點不像之前那樣經過new建立對象,如今經過類的限定名便可建立對象.

1.經過反射獲取對象

程序經過類的完整限定名建立出了User的實例,這就是利用到了反射

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class = "hljs cs" > public static void main(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()方法,這樣作的好處是須要調用的信息,字符串等咱們能夠寫在配置文件中,而後修改就能夠直接在配置文件中修改了,後期維護方便太多了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<code class = "hljs java" > public static void main(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的工廠來管理,以下面例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<code class = "hljs java" > import com.dao.AddressDao;
import com.dao.UserDao;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class DAOFactory {
     //獲取UserDao
     public static UserDao getUserDao(){
         return new UserDao();
     }
     //獲取AddressDao
     public static AddressDao getAddressDao(){
         return new AddressDao();
     }
}</code>

惟一的用處就是把Dao統一了起來,用的時候世界DAOFactory.getUserDao()便可
缺點:假如更換數據庫,或者更換Dao的時候,就須要在這裏面修改其相應的方法


2.工廠方法模式

工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣作的目的是將類的實例化操做延遲到子類中完成。

首先定義抽象父類接口

?
1
2
3
4
5
6
7
8
9
10
<code class = "hljs java" > import com.dao.AddressDao;
import com.dao.UserDao;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public interface AbstractFactory {
     public UserDao createUserDao();
     public AddressDao createAddressDao();
}</code>

接着定義實現具體方法的子類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<code class = "hljs java" > import com.dao.AddressDao;
import com.dao.UserDao;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class MysqlDAOFactory implements AbstractFactory{
     /**
      * 單例設計具體工廠
      */
     private static AbstractFactory factory = new MysqlDAOFactory ();
 
     private DAOFactory() {
     }
     public static AbstractFactory getInstance(){
         return factory;
     }
     //獲取UserDao
     @Override
     public UserDao createUserDao(){
         return new UserDao();
     }
     //獲取AddressDao
     @Override
     public AddressDao createAddressDao(){
         return new AddressDao();
     }
 
}
</code>

一樣的還能夠有OracleDAOFactory,而他們的方法統一由父類接口來定義,本身只負責實現具體方法.
缺點:修改起來仍是麻煩,並且調用須要MysqlDAOFactory.getInstance().createUserDao(),太長了


3.基於配置文件的工廠

基於配置文件的意思就是咱們把一些參數寫到配置文件中,由一個類經過讀取配置文件信息,建立咱們須要的DAO.

1.首先咱們要建立properties文件,裏面存儲着dao對應的限定名

 

dao.properties

?
1
2
<code class = "hljs avrasm" >userdao = com.dao.UserDao
addressdao = com.dao.AddressDao</code>

2.建立抽象工廠 ,工廠裏面有一個通用的建立DAO方法

?
1
2
3
<code class = "hljs cs" > public interface AbstractFactory {
     public Object createDao(String name);
}</code>

3.建立peopertiesUtil,用來方便的讀取配置文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<code class = "hljs java" > import java.io.IOException;
import java.util.Properties;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class PropertiesUtil {
     public static Properties daoProperties = null ;
 
     /**
      * 獲取dao配置文件
      * @return
      */
     public static Properties getDaoPro(){
         //若是已經建立,則直接返回
         if (daoProperties!= null ){
             return daoProperties;
         }
         daoProperties = new Properties();
         try {
             daoProperties.load(PropertiesUtil. class .getClassLoader().getResourceAsStream( "dao.properties" )); //加載配置文件
         } catch (IOException e) {
             System.out.println( "未找到dao配置文件" );
             e.printStackTrace();
         }
         return daoProperties;
     }
}</code>

4.建立具體工廠,經過傳入的name值,利用反射就能夠獲取到對應的DAO實體類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<code class = "hljs java" > public class PropertiesFactory implements AbstractFactory{
     /**
      * 首先爲工廠實現單例模式
      * @return
      */
     private static AbstractFactory factory = new PropertiesFactory();
 
     private PropertiesFactory() {
     }
     public static AbstractFactory getInstance(){
         return factory;
     }
 
     /**
      * 實現父類接口的方法
      * @param name 須要建立的dao名字
      * @return 建立的dao
      */
     @Override
     public Object 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();
         }
         return obj;
     }
}</code>

5.具體工廠優化,對於dao實體咱們能夠把建立好的存起來,調用的時候先判斷是否已經建立,已經建立則返回.因此天然想到了鍵值對的Map集合.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<code class = "hljs java" > import com.util.PropertiesUtil;
 
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class PropertiesFactory implements AbstractFactory{
     /**
      * 首先爲工廠實現單例模式
      * @return
      */
     private static AbstractFactory factory = new PropertiesFactory();
 
     private PropertiesFactory() {
     }
     public static AbstractFactory getInstance(){
         return factory;
     }
     private Map<string,object> maps = new HashMap<>();
     /**
      * 實現父類接口的方法
      * @param name 須要建立的dao名字
      * @return 建立的dao
      */
     @Override
     public Object createDao(String name) {
         //判斷map中是否已經建立,是則直接返回
         if (maps.containsKey(name)){
             return maps.get(name);
         }
         Properties properties = PropertiesUtil.getDaoPro();
         String daoName = properties.getProperty(name); //獲取要建立dao對應的限定名
         Object obj = null ; //承載建立對象的容器
         try {
             Class clz = Class.forName(daoName); //加載class
             obj = clz.newInstance(); //獲取實例
             maps.put(name,obj); //存入map中
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (InstantiationException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         }
 
         return obj;
     }
}
</string,object></code>

調用就能夠按照下面方法

?
1
<code class = "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進行賦值

?
1
2
3
4
5
6
7
8
9
10
11
12
<code class = "hljs java" > /**
      * 經過依賴注入進行賦值
      */
     private UserDao userDao;
 
     public UserDao getUserDao() {
         return userDao;
     }
 
     public void setUserDao(UserDao userDao) {
         this .userDao = userDao;
     }</code>

2.爲了方便,寫一個DaoUtil用來存放依賴注入的代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<code class = "hljs java" > import com.dao.PropertiesFactory;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class DaoUtil {
     /**
      * dao依賴注入方法
      * @param obj
      */
     public static void daoInject(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的時候就會先執行父類的構造方法,因此咱們能夠在父類的方法中調用依賴注入這個方法

?
1
2
3
4
5
6
<code class = "hljs java" > /**
      * 調用依賴注入方法
      */
     public BaseDao() {
         DaoUtil.daoInject( this );
     }</code>

這樣作是能夠實現建立AddressDao的時候就初始化userDao變量,可是若是AddressDao還有其餘set方法的話,那麼程序由於在配置文件中找不到相應的數據,就會報錯

2.使用Annotation優化注入

什麼是Annotation?就是在方法前面@符號引出的代碼,以下圖
這裏寫圖片描述
所以咱們能夠建立本身的Annotation:Dao,想要實現的效果以下

當@Dao(「UserDao」)的時候注入UserDao 當@Dao不帶參數的時候使用setXXX()注入

1.建立本身的Annotation,從代碼能夠看到Annotation標識是@interface

?
1
2
3
4
5
6
7
8
9
10
<code class = "hljs java" > import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
 
/**
  * 加這個聲明,說明當前Annotation在運行的時候執行
  */
@Retention (RetentionPolicy.RUNTIME)
public @interface Dao {
     String value() default "" ;
}</code>

其中value()表明他的值,默認是空,固然也能夠自定義其餘值,好比String abc() default ""

2.使用Annotation,使用很簡單,在須要注入的代碼上面添加標識就行了

?
1
2
3
4
<code class = "hljs java" >    @Dao ( "UserDao" )
     public void setUserDao(UserDao userDao) {
         this .userDao = userDao;
     }</code>

3.修改注入代碼,實現上面所說的邏輯

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<code class = "hljs java" > package com.util;
 
import com.dao.PropertiesFactory;
import com.model.Dao;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
/**
  * Created by nl101 on 2016/2/26.
  */
public class DaoUtil {
     /**
      * dao依賴注入方法
      * @param obj
      */
     public static void daoInject(Object obj){
         //獲取當前類的不包括繼承下來的方法
         Method[] methods = obj.getClass().getDeclaredMethods();
         try {
             //對方法篩選出setXXX方法
             for (Method method : methods){
                 //若是有Dao這個Annotation,則處理
                 if (method.isAnnotationPresent(Dao. class )){
                     //獲取當前這個Anonotation
                     Dao 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()時候的缺點

這裏寫圖片描述

相關文章
相關標籤/搜索