【j2ee spring】30、巴巴荆楚网-综合hibernate4+spring4(5)分页
巴巴荆楚网-综合hibernate4+spring4(5)分页
1、图文项目
2、首先我们引入对应的jar包
3、我们配置一下数据库中对应的实体对象
ProductType.java
/** * 功能:这是产品类别的 * 文件:ProductType.java * 时间:2015年5月12日10:16:21 * 作者:cutter_point */ package com.cutter_point.bean.product; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.SequenceGenerator; @Entity @SequenceGenerator(name="seq_1",sequenceName="seq_1",allocationSize=1,initialValue=1) public class ProductType implementsSerializable { privatestatic final long serialVersionUID = -6904074615993718149L; /** 类型id **/ privateInteger typeid; privateString name; //类别名 privateString note; //备注,用于百度搜索 privateboolean visible = true; //是否可见 //子类别分类 privateSet<ProductType> childtypes = new HashSet<ProductType>(); //父类别分类 privateProductType parent; @Override publicint hashCode() { finalint prime = 31; intresult = 1; result= prime * result + ((typeid == null) ? 0 : typeid.hashCode()); returnresult; } @Override publicboolean equals(Object obj) { if(this == obj) returntrue; if(obj == null) returnfalse; if(getClass() != obj.getClass()) returnfalse; ProductTypeother = (ProductType) obj; if(typeid == null) { if(other.typeid != null) returnfalse; }else if (!typeid.equals(other.typeid)) returnfalse; returntrue; } @OneToMany(cascade={CascadeType.REFRESH,CascadeType.REMOVE}, mappedBy="parent")//这个是级联更新和删除,mappedBy指向是定义在被拥有方的,他指向拥有方 //parent来映射,一个子类别相应 publicSet<ProductType> getChildtypes() { returnchildtypes; } publicvoid setChildtypes(Set<ProductType> childtypes) { this.childtypes= childtypes; } @ManyToOne(cascade=CascadeType.REFRESH) @JoinColumn(name="parentid") publicProductType getParent() { returnparent; } publicvoid setParent(ProductType parent) { this.parent= parent; } publicProductType() { } @Column(length=36,nullable=false) publicString getName() { returnname; } publicvoid setName(String name) { this.name= name; } @Column(length=200) publicString getNote() { returnnote; } publicvoid setNote(String note) { this.note= note; } @Column(nullable=false) publicboolean isVisible() { returnvisible; } publicvoid setVisible(boolean visible) { this.visible= visible; } @Id @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="seq_1") //自增长 publicInteger getTypeid() { returntypeid; } publicvoid setTypeid(Integer typeid) { this.typeid= typeid; } }
这里的xml文件我们也不必去配置了
这里做了一个分了无限极分类得处理,就是把当前表加一个属性parentid,这个属性參照本表的id号。这个就是一对多的关系,仅仅只是是自己对自己
QueryResult.java
/** * 功能:这儿类是为了存放分页的时候从数据库里面查找出来的数据和记录数 * 文件:QueryResult.java * 时间:2015年5月14日21:45:42 * 作者:cutter_point */ package com.cutter_point.bean; import java.util.List; publicclassQueryResult<T> { private List<T> resultList; privatelongtotalrecord; //总记录数 public List<T>getResultList() { returnresultList; } publicvoidsetResultList(List<T> resultList) { this.resultList = resultList; } publiclong getTotalrecord() { returntotalrecord; } publicvoid setTotalrecord(long totalrecord) { this.totalrecord = totalrecord; } }
当我们分页的时候,会产生一个分页搜索出来的数据,第二个是我们搜索出来的总条数
4、我们配置一下spring的配置文件beans.xml
<?xml version="1.0"encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 扫描带有spring特殊机制的类,这是把这些包以下全部的类都加入到spring中进行管理 --> <context:component-scan base-package="com.cutter_point" /> <!-- 属性遍历器 --> <!-- <context:property-placeholderlocation="classpath:jdbc.properties" /> --> <!-- 连接数据库属性配置。destroy-method="close"就是说在这个bean被摧毁的情况下能够调用这个bean默认的close方法--> <bean id="myDataSource" class="org.apache.commons.dbcp2.BasicDataSource"destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url"value="jdbc:oracle:thin:@localhost:1522:orcl"/> <property name="username"value="xf1205020116"/> <property name="password"value="xf1205020116"/> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="1"/> <!-- 连接池的最大值 dbcp2里面似乎没有--> <!-- <property name="maxActive"value="500"/> --> <!-- 最大空暇值.当经过一个高峰时间后,连接池能够慢慢将已经用不到的连接慢慢释放一部分,一直降低到maxIdle为止 --> <property name="maxIdle" value="2"/> <!-- 最小空暇值.当空暇的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="1"/> </bean> <!-- hibernate二级缓存的配置 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- configuration elided for brevity --> <property name="dataSource" ref="myDataSource" /> <!-- <propertyname="mappingResources"> <list> 映射文件 <value>com/cutter_point/bean/product/ProductType.hbm.xml</value> </list> </property>--> <property name="hibernateProperties"> <!-- 用来配置hibernate的属性配置 --> <value> hibernate.dialect=org.hibernate.dialect.OracleDialect hibernate.hbm2ddl.auto=update <!--其它取值 create、create-drop、update、validate none--> hibernate.show_sql=true hibernate.format_sql=true <!-- 开启二级缓存功能 --> hibernate.cache.use_second_level_cache= true hibernate.cache.use_query_cache= false hibernate.cache.region.factory_class= org.hibernate.cache.ehcache.EhCacheRegionFactory <!-- hibernate3的二级缓存配置 --> <!-- <propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>--> </value> </property> <property name="packagesToScan" value="com.cutter_point.bean" /> </bean> <!-- 事务管理器,吧上面配置的bean注入到这个里面 --> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 我们採用注解的方式来使用这个事务,首先我们开启事务 --> <tx:annotation-driven transaction-manager="txManager" /> </beans>
注意我们的spring配置文件中面也不必再写相应的xml文件在哪了
5、建立底层的DAO层的接口实现增删盖查
实现底层DAO接口
/** * 功能:这是对数据库进行增删改查的接口类 * 文件:DAO.java * 时间:2015年5月14日18:51:24 * 作者:cutter_point */ package com.cutter_point.service.base; import java.util.LinkedHashMap; import com.cutter_point.bean.QueryResult; public interface DAO { /** * 保存一个实体类 * @param entity 实体类 */ publicvoid save(Object entity); /** * 依据id号删除数据 * @param entityClass 类别 * @param entityid 实体类id号 */ public<T> void delete(Class<T> entityClass, Object entityid); /** * 依据数组id删除一堆数据 * @param entityClass 类别 * @param entityids id号的数组 */ public<T> void delete(Class<T> entityClass, Object[] entityids); /** * 更具实体类改动对应的数据 * @param entity 实体类 */ publicvoid update(Object entity); /** * 依据类别和id来查找不同的类别下的实体 * @param entityClass 类别 * @param entityId 实体id * @return 返回一个实体类 */ public<T> T find(Class<T> entityClass, Object entityId); /** * 这个是对对应的实体bean进行分类 * @param entityClass 实体类型 * @param firstindex 第一个索引 * @param maxresult 须要获取的记录数 * @return */ //最后一个參数就是,判定是升序还是降序 public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult,String whereSql, Object[] queryParams, LinkedHashMap<String,String> orderby); public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult,String whereSql, Object[] queryParams); public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult, LinkedHashMap<String, String> orderby); public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult); public<T> QueryResult<T> getScrollData(Class<T> entityClass); }
我们吧一些公用方法实现。使用一个抽象类来实现DaoSupport.java
/** * 功能:这是对数据库进行增删改查的抽象类。实现一些方法 * 文件:DaoSupport.java * 时间:2015年5月14日19:03:52 * 作者:cutter_point */ package com.cutter_point.service.base; import java.io.Serializable; import java.util.LinkedHashMap; import java.util.List; import javax.annotation.Resource; import javax.persistence.Entity; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; importorg.springframework.transaction.annotation.Propagation; importorg.springframework.transaction.annotation.Transactional; import com.cutter_point.bean.QueryResult; @Transactional //吧这个类里面的方法提交给spring管理,方法都开上事务 public abstract class DaoSupport implementsDAO { //通过spring取得sessionFactory @Resource publicSessionFactory sessionFactory; @Override publicvoid save(Object entity) { Sessionsession = sessionFactory.getCurrentSession(); session.persist(entity); } /** * 开启事务 */ @Override public<T> void delete(Class<T> entityClass, Object entityid) { this.delete(entityClass,new Object[]{entityid}); } /** * 关闭事务 */ @Override public<T> void delete(Class<T> entityClass, Object[] entityids) { Sessionsession = sessionFactory.getCurrentSession(); for(Objectid : entityids) { //循环删除对应的id号 session.delete(session.get(entityClass,(Serializable) id)); } } @Override @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult) { returnthis.getScrollData(entityClass, firstindex, maxresult, null, null, null); } @Override @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) public<T> QueryResult<T> getScrollData(Class<T> entityClass) { returnthis.getScrollData(entityClass, -1, -1); } @Override publicvoid update(Object entity) { Sessionsession = sessionFactory.getCurrentSession(); session.merge(entity); } /** * 这种方法不须要开启事务,并且不会更改数据库的数据 */ @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) @Override public<T> T find(Class<T> entityClass, Object entityId) { Sessionsession = sessionFactory.getCurrentSession(); return(T) session.get(entityClass, (Serializable) entityId); } /** * 从firstindex開始,查询长度为maxresult的结果出来。用来分页 * @param entityClass 实体类型 * @param firstindex 从第几个開始查询 * @param maxresult 查询的数目 * @param whereSql 就是预处理的指令,里面包括? * @param queryParams SQL中where 后面接的条件集合,须要传什么參数 * @param orderby 排序的方式。升序,降序,首先以那个元素为基准。然后以那个元素为基准 * @return QueryResult<T> 这是一个包括long和List的类型的类。保存返回的结果集。和记录的个数 */ @SuppressWarnings({"rawtypes", "unchecked" }) @Override @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult,String whereSql, Object[] queryParams, LinkedHashMap<String,String> orderby) { Sessions = sessionFactory.getCurrentSession(); QueryResultqr = new QueryResult<T>(); //结果集 Stringentityname = this.getEntityName(entityClass); Queryquery = s.createSQLQuery("select * from "+entityname+" o "+ (whereSql == null ? "" : "where " + whereSql) +this.buildOrderBy(orderby)).addEntity(entityClass); this.setQueryParams(query,queryParams); //假设初始的索引不是-1,或者查询的个数不是-1 if(firstindex!= -1 && maxresult != -1) { //获取第一个结果索引,以及设置获取的数目 query.setFirstResult(firstindex).setMaxResults(maxresult); } //获取结果赋值给qr List<T>ls = query.list(); qr.setResultList(ls); //接下来我们要取出记录的数目 query= s.createSQLQuery("select count(*) from "+entityname+" o "+ (whereSql == null ? "" : "where " + whereSql)); this.setQueryParams(query,queryParams); // System.out.println(query.uniqueResult()); //进行一下数据类型的转换 Stringst = query.uniqueResult().toString(); qr.setTotalrecord(Long.valueOf(st)); //取得单一的结果 returnqr; } @Override @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult, String whereSql, Object[] queryParams) { returnthis.getScrollData(entityClass, firstindex, maxresult, whereSql, queryParams,null); } @Override @Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED) public<T> QueryResult<T> getScrollData(Class<T> entityClass, intfirstindex, int maxresult, LinkedHashMap<String, String> orderby) { returnthis.getScrollData(entityClass, firstindex, maxresult, null, null, orderby); } /** * 这个就是用来处理SQL语句里面有非常多的限制条件的时候,用这个来填补预处理的? * @param query * @param queryParams */ protectedvoid setQueryParams(Query query, Object[] queryParams) { if(queryParams!= null && queryParams.length > 0) { //假设我们要限制的元素个数不是空,那么就能够循环 for(inti = 0; i < queryParams.length; ++i) { query.setParameter(i,queryParams[i]); //吧?一个个地填上 } } } /** * 组装order by语句 * @param orderby * @return */ //组成的语句是首先按什么排序,然后按什么key排序 protectedString buildOrderBy(LinkedHashMap<String, String> orderby) { StringBuilderorderbyq1 = new StringBuilder(); //等会用来组合语句 if(orderby!= null && orderby.size() > 0) { orderbyq1.append("order by ");//注意留空格,免得后面直接加上去之后和那个by连在了一起 //map不是为空 for(Stringkey : orderby.keySet()) { //拼接语句 orderbyq1.append("o.").append(key).append("").append(orderby.get(key)).append(","); } orderbyq1.deleteCharAt(orderbyq1.length()- 1); //去掉最后的那个逗号 } returnorderbyq1.toString(); } /** * 获取实体的名称 * @param entityClass 实体类 * @return */ protected<T> String getEntityName(Class<T> entityClass) { Stringentityname = entityClass.getSimpleName(); Entityentity = entityClass.getAnnotation(Entity.class); if(entity.name()!= null && !"".equals(entity.name())) { entityname= entity.name(); } returnentityname; } }
6、使用依赖注入
首先实现一个业务接口
ProductService.java
packagecom.cutter_point.service.product; import com.cutter_point.bean.product.ProductType; importcom.cutter_point.service.base.DAO; public interfaceProductTypeService extends DAO { //这里面定义ProductTypeService专有的方法 }
实现接口ProductServiceBean.java
/** * 功能:这是产品类别的服务类 * 文件:ProductService.java * 时间:2015年5月13日15:36:06 * 作者:cutter_point */ packagecom.cutter_point.service.product.impl; import org.hibernate.Query; import org.hibernate.Session; importorg.springframework.stereotype.Service; importorg.springframework.transaction.annotation.Transactional; importcom.cutter_point.service.base.DaoSupport; importcom.cutter_point.service.product.ProductTypeService; @Service //相当于在spring里面定义一个bean,这是注解的方式<context:component-scanbase-package="com.cutter_point" /> @Transactional //在方法运行的时候开启事务 public class ProductTypeServiceBean extendsDaoSupport implements ProductTypeService { /** * 当我们删除的时候,会吧对应的对象进行假删除,也就是把对应的对象设置为不可见 */ @Override public<T> void delete(Class<T> entityClass, Object[] entityids) { //取得和数据库的连接 Sessions = sessionFactory.getCurrentSession(); //我们首先推断这个传进来的id不是空的 if(entityids!= null && entityids.length > 0) { StringBuildersb = new StringBuilder(); for(inti = 0; i < entityids.length; ++i) { sb.append("?").append(","); } //在这个语句加入到最后的时候会多余一个, sb.deleteCharAt(sb.length()-1); //删除最后一个就是,号 Queryquery = s.createSQLQuery("update producttype p set p.visible = ? wherep.typeid in("+sb.toString()+")").setParameter(0, false); for(inti = 0; i < entityids.length; ++i) { query.setParameter(i+ 1, entityids[i]); } query.executeUpdate(); } } }
这里使用一个函数覆盖的方式吧底层的delete方法给覆盖了,我们不直接删除数据。而是把数据的一个是否可见的字段属性设置为不可见
7、接下来我们測试一下分页是否配置成功
/** * 功能:这是产品类别的单元測试 * 文件:ProductTest.java * 时间:2015年5月12日10:27:24 * 作者:cutter_point */ package junit.test; import java.util.LinkedHashMap; import javax.sql.DataSource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.ClassPathXmlApplicationContext; import com.cutter_point.bean.QueryResult; importcom.cutter_point.bean.product.ProductType; importcom.cutter_point.service.product.ProductTypeService; public class ProductTest { //測试spring能否够运作 privatestatic ApplicationContext cxt; privatestatic ProductTypeService pts; @BeforeClass publicstatic void setUpBeforeClass() throws Exception { try { cxt= new ClassPathXmlApplicationContext("config/spring/beans.xml"); pts= (ProductTypeService) cxt.getBean("productTypeServiceBean"); } catch(Exception e) { e.printStackTrace(); } } @Test publicvoid test() { ProductTypept = new ProductType(); //new一个对象 pt.setTypeid(78); //设置id号码 Configurationcfg = new Configuration(); //得到Configuration @SuppressWarnings("deprecation") SessionFactorysf =cfg.configure("/config/hibernate/hibernate.cfg.xml").buildSessionFactory(); //取得session工厂 Sessionsession = sf.openSession(); session.beginTransaction(); session.save(pt); session.getTransaction().commit(); session.close(); sf.close(); } @SuppressWarnings("resource") @Test publicvoid testSpring() { //測试spring能否够运作 ApplicationContextcxt = new ClassPathXmlApplicationContext("config/spring/beans.xml"); DataSourcedatasource = (DataSource)cxt.getBean("myDataSource"); //取出一个对象 System.out.println(datasource); //推断是不是为空, } @Test publicvoid testSH() { //測试spring能否够运作 @SuppressWarnings("resource") ApplicationContextcxt = new ClassPathXmlApplicationContext("config/spring/beans.xml"); ProductTypeServiceproductService =(ProductTypeService)cxt.getBean("productTypeService"); //取出一个对象 ProductTypept = new ProductType(); pt.setName("cutter_point"); pt.setNote("很好"); productService.save(pt); } @Test publicvoid testSave() { for(inti = 0; i < 20; ++i) { ProductTypetype = new ProductType(); type.setName(i+ " 跑步用品"); type.setNote("中国好跑步2"); pts.save(type); } } @Test publicvoid testFind() { ProductTypept = pts.find(ProductType.class, 5); Assert.assertNotNull(pt); System.out.println(pt); } @Test publicvoid testUpdate() { ProductTypept = pts.find(ProductType.class, 5); pt.setName("cutter_point666"); pt.setNote("出彩中国人"); pts.update(pt); } @Test publicvoid testDelete() { pts.delete(ProductType.class,3); } @Test publicvoid testgetScrollData() { LinkedHashMap<String,String> orderby = new LinkedHashMap<String, String>(); orderby.put("typeid","asc"); QueryResult<ProductType>qr = pts.getScrollData(ProductType.class);//取出0到5条的数据 // Iterator<ProductType>it = qr.getResultList().iterator(); // while(it.hasNext()) // { // ProductTypept = it.next(); // System.out.println(pt.getName()); // } for(Objecto : qr.getResultList()) { ProductTypet = (ProductType) o; System.out.println(t.getName()); } } }
6、总结
这里我们实现了公有的增删改查和分页,然后对应的在DaoSupport里面实现了对应的方法,构成对应的抽象类,这个里面使用了泛型,这样分页的算法就更加具有低耦合性。
版权声明:本文博主原创文章,博客,未经同意不得转载。