javaWEB简单商城项目
- 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()时候的缺点
![这里写图片描述]()






浙公网安备 33010602011771号