- javaWEB簡單商城項目(一)
-
項目中使用到了上一篇博文的分頁框架,還有mybatis,重點是學習mybatis.
現在有些小迷茫,不知道該干啥,唉,不想那么多了,學就對了
一.項目功能結構
1.功能
2.實體
3.對應sql語句
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960<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為例.
注意對於數據庫中外鍵,比如adress表中有外鍵user_id,那么在Adress.java中就可以直接給個User對象,在取adress表的時候就把user一並取出來.
User.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465<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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354<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通用分頁框架
完整建立后如下
-
- javaWEB簡單商城項目(三)
-
一.通用的BaseDao.java
既然要大家都能用,所以使用了泛型.其中要注意的問題就是類似User.getClass().getName()這樣的代碼是需要修改的.修改方法就是使用參數Class tc傳遞過來,然后在使用tc.getName()即可.
完整代碼:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140<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也需要相應的修改
12345678910111213<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的實體類,如下123456789<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
123456<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
123456789101112<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>
上面配置完,當搜索出來的時候,mybatis就會自動調用其相應的set方法,把屬性設置到實體類中.
測試
12345678910111213141516171819<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代碼:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970<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的實例,這就是利用到了反射
123456789101112131415<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()方法,這樣做的好處是需要調用的信息,字符串等我們可以寫在配置文件中,然后修改就可以直接在配置文件中修改了,后期維護方便太多了
123456789101112131415161718192021222324252627<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的工廠來管理,如下面例子
12345678910111213141516<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.工廠方法模式
工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣做的目的是將類的實例化操作延遲到子類中完成。
首先定義抽象父類接口
12345678910<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>
接着定義實現具體方法的子類
123456789101112131415161718192021222324252627282930<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
12<code
class
=
"hljs avrasm"
>userdao = com.dao.UserDao
addressdao = com.dao.AddressDao</code>
2.創建抽象工廠 ,工廠里面有一個通用的創建DAO方法
123<code
class
=
"hljs cs"
>
public
interface
AbstractFactory {
public
Object createDao(String name);
}</code>
3.創建peopertiesUtil,用來方便的讀取配置文件
12345678910111213141516171819202122232425262728<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實體類
123456789101112131415161718192021222324252627282930313233343536<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集合.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152<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進行賦值123456789101112<code
class
=
"hljs java"
>
/**
* 通過依賴注入進行賦值
*/
private
UserDao userDao;
public
UserDao getUserDao() {
return
userDao;
}
public
void
setUserDao(UserDao userDao) {
this
.userDao = userDao;
}</code>
2.為了方便,寫一個DaoUtil用來存放依賴注入的代碼
123456789101112131415161718192021222324252627282930313233343536<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的時候就會先執行父類的構造方法,所以我們可以在父類的方法中調用依賴注入這個方法
123456<code
class
=
"hljs java"
>
/**
* 調用依賴注入方法
*/
public
BaseDao() {
DaoUtil.daoInject(
this
);
}</code>
這樣做是可以實現創建AddressDao的時候就初始化userDao變量,但是如果AddressDao還有其他set方法的話,那么程序因為在配置文件中找不到相應的數據,就會報錯
2.使用Annotation優化注入
什么是Annotation?就是在方法前面@符號引出的代碼,如下圖
當@Dao(“UserDao”)的時候注入UserDao 當@Dao不帶參數的時候使用setXXX()注入
因此我們可以創建自己的Annotation:Dao,想要實現的效果如下1.創建自己的Annotation,從代碼可以看到Annotation標識是@interface
12345678910<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,使用很簡單,在需要注入的代碼上面添加標識就好了
1234<code
class
=
"hljs java"
>
@Dao
(
"UserDao"
)
public
void
setUserDao(UserDao userDao) {
this
.userDao = userDao;
}</code>
3.修改注入代碼,實現上面所說的邏輯
12345678910111213141516171819202122232425262728293031323334353637383940414243444546<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()時候的缺點