巴巴运动网-整合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里面实现了相应的方法,构成相应的抽象类,这个里面使用了泛型,这样分页的算法就更加具有低耦合性。
时间: 2024-10-09 20:12:42