javaWEB简单商城项目(一)

项目中使用到了上一篇博文的分页框架,还有mybatis,重点是学习mybatis.
现在有些小迷茫,不知道该干啥,唉,不想那么多了,学就对了


一.项目功能结构

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为例.

注意对于数据库中外键,比如adress表中有外键user_id,那么在Adress.java中就可以直接给个User对象,在取adress表的时候就把user一并取出来.

User.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
<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通用分页框架


完整建立后如下

javaWEB简单商城项目(三)

一.通用的BaseDao.java

既然要大家都能用,所以使用了泛型.其中要注意的问题就是类似User.getClass().getName()这样的代码是需要修改的.修改方法就是使用参数Class tc传递过来,然后在使用tc.getName()即可.

完整代码:

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也需要相应的修改

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()时候的缺点

 

javaWEB简单商城项目的更多相关文章

  1. JavaWeb网上商城项目中sql语句问题的解决

    出现的问题 解决方法 对ProductDaoImpl建立Junit测试得到问题所在 学到了 Junit case测试验证和debug分步执行 mysql是关系型数据库.Redis是非关系型数据库且比m ...

  2. JavaWeb网上商城项目中用户注册,使用MailServer和FoxMail搭建本地邮件服务器

    下载并安装易邮邮件服务器MailServer和腾讯邮箱FoxMail,下载地址  https://download.csdn.net/download/checkerror2/10130538 具体步 ...

  3. 尝试从零开始构建我的商城 (一) :使用Abp vNext快速一个简单的商城项目

    尝试从零开始构建我的商城 (一) :使用Abp vNext快速搭建一个简单的项目 前言 GitHub地址 https://github.com/yingpanwang/MyShop 此文目的 本文将尝 ...

  4. java web课程设计(简单商城的前后端双系统,基于maven三模块开发)

    1.系统分析 1.1需求分析 实现一个简单但功能完整的商城项目,从设计到实现,规范化完成该项目,锻炼javaweb项目的编写能力,理解软件工程的软件设计思想 1.2编程技术简介 本次课程主要使用的软件 ...

  5. 商城项目实战 | 1.1 Android 仿京东商城底部布局的选择效果 —— Selector 选择器的实现

    前言 本文为菜鸟窝作者刘婷的连载."商城项目实战"系列来聊聊仿"京东淘宝的购物商城"如何实现. 京东商城的底部布局的选择效果看上去很复杂,其实很简单,这主要是要 ...

  6. 商城项目实战 | 2.1 Android 仿京东商城——自定义 Toolbar (一)

    前言 本文为菜鸟窝作者刘婷的连载."商城项目实战"系列来聊聊仿"京东淘宝的购物商城"如何实现. 现在很多的 APP 里面都有自己的自定义风格,特别是京东商城中自 ...

  7. 商城项目实战 | 2.2 Android 仿京东商城——自定义 Toolbar (二)

    本文为菜鸟窝作者刘婷的连载."商城项目实战"系列来聊聊仿"京东淘宝的购物商城"如何实现. 上一篇文章<商城项目实战 | 2.1 Android 仿京东商城 ...

  8. Django商城项目笔记No.7用户部分-注册接口-判断用户名和手机号是否存在

    Django商城项目笔记No.7用户部分-注册接口-判断用户名和手机号是否存在 判断用户名是否存在 后端视图代码实现,在users/view.py里编写如下代码 class UsernameCount ...

  9. 【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布

     转自:https://blog.csdn.net/wwww_com/article/details/54405355 前面陆陆续续的完成了网上商城的一些基本功能,虽然还有很多地方有待完善,但是不影响 ...

随机推荐

  1. Socket连接时,端口是怎么分配的

    socket 客户端连接socket 的端口每个是唯一的,每个新的连接,端口号+1 从1024-65534 最大到65534 然后再开始循环 中间遇到已经使用的端口就跳过

  2. 使用sqlyog连接ubuntu mysql server错误解决方案

    现在很多服务都部署在linux环境中,但是在开发阶段,使用windows远程连接工具,直观,这对开发人员更友好. 下面是我在ubuntu16.04使用mysql- server时,遇到了一下的问题,以 ...

  3. ALPS语言学校(西雅图)|ALPS Language School (Seattle)

    http://www.swliuxue.com/school-3879.html 所属国家: 美国 所在省洲: 华盛顿州 所在城市: 华盛顿州 建校时间: 1992年 学校类型: 院校 学校类别: 私 ...

  4. jquery对checkbox的操作汇总

    1.全选 $("#btn1").click(function(){ $("input[name='checkbox']").attr("checked ...

  5. vs2008使用mysql链接错误

    原因是因为安装了64位的mysql,而开发工具室32位的,需要安装32位的开发库就可以了

  6. BSP和JSP里的UI元素ID生成逻辑

    CRM WebClient UI WebClient UI渲染出来的DOM元素的这些C#_W#格式的id是在哪行ABAP代码被生成出来的? 参考我的博客WebClient UI element ID ...

  7. php中的脚本加速扩展opcache

    今儿在azure里装php5.5.4,发现原先php5.4.php5.3中的zend guard laoder以及php5.2中的Zend Optimizer均不能再用,一直很喜欢用的eacceler ...

  8. paper-list

    1.yolo-v1,yolo-v2,yolo-v3 2.ssd,focal loss,dssd 3.fast-rcnn,faster-rcnn,r-fcn,Light-Head R-CNN,R-FCN ...

  9. Python基础之字符串(str)常用操作

    1.字符串常用的方法 len()返回字符串的长度 ##Python3 >>> print(len('ab12我')) 5 ##Python2 >>> print(l ...

  10. 分页查询关键代码 多条件查询关键代码 删除选中商品关键代码 修改要先回显再修改 修改要先回显再修改 同一业务集中使用同一servlet的方法

    分页查询关键代码: 通过servlet转发回来的各种信息进行分页的设计(转发回的信息有 分页查询的List集合 查询的页码 查询的条数 查询的数据库总条数 查询的总页码) 从开始时循环10次出现十个数 ...