4、SSH的整合:
整合三者的第一步:导入相应的包(注意检查包中的冲突)。
4.1、和Hibernate的整合
集成Hibernate5与之前的版本Hibernate3和4有一定的区别,该部分的内容以Hibernate5为基础。
1、导入Hibernate的jar包和Spring的jar包
·导入Spring的依赖包
·导入log4j的依赖包
·导入dbcp的依赖包(dbcp2、pool2)
·导入Hibernate5的依赖包(required文件夹下的所有jar包、jpa-metamodel-generator文件夹中
的包、slf4j-api.jar)
2、创建beans.xml
2.1、使用DBCP创建dataSource(与集成JDBC一样,详细参见Spring集成JDBC)
2.2、创建Hibernate的SessionFactory
<!-- 创建Spring的sessionFactory工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 设置Spring去哪个包中查找相应的实体类 -->
<property name="packagesToScan">
<value>org.pm.spring.model</value>
</property>
<property name="hibernateProperties">
<!-- <value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value> -->
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
3、为实体类添加Hibernate的Annotation或者hbm文件
@Entity
@Table(name="t_user")
public class User {
private int id;
private String username;
private String password;
private String nickname;
private Group group;
@ManyToOne
@JoinColumn(name="gid")
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
4、创建基于Hibernate的DAO
4.1、在相应的DAO中注入相应的SessionFactory
public class BaseDao {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Resource
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
//获取session,注意:没有使用openSession(),getCurrentSession()才能被spring所管理
return sessionFactory.getCurrentSession();
}
}
4.2、如果通过Spring来管理SessionFactory,不再使用factory.openSession()开启session,而应该使
用 factory.getCurrentSession()来打开session,这个session就会被Spring所管理,此时开发人员不用
进行事务控制,也不用关闭session,全部由Spring来完成。
@Repository("groupHibernateDao")
public class GroupHibernateDao extends BaseDao implements IGroupDao {
@Override
public void add(Group group) {
//getSession是通过getCurrentSession来获取session,它会被spring所管理,
//所以不用进行其它操作
getSession().save(group);
}
@Override
public Group load(int id) {
//load()方法报错:could not initialize proxy - no Session
//报错原因:Hibernate延迟加载问题
return getSession().get(Group.class, id);
}
5、在beans.xml中加入Spring的事务控制
<!-- 配置Spring的事务处理 -->
<!-- 创建事务管理器 -->
<bean id="txManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置AOP,Spring是通过AOP来进行事务管理的 -->
<aop:config>
<!-- 设置pointCut表示哪些事务要加入事务处理 -->
<aop:pointcut id="allMethods"
expression="execution(* org.pm.spring.dao.*.*(..))"/>
<!-- 通过advisor来确定具体要加入事务控制的方法 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods"/>
</aop:config>
<!-- 配置哪些方法要加入事务控制 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 让所有的方法都加入事务管理 -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
5.1、连接池的简单配置(特别注意:dbcp2与dbcp连接池配置参数不一样)
<!-- 特别注意:class="org.apache.commons.dbcp2.BasicDataSource",用的是dbcp2,
api文档中是dbcp。 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 当连接池被启动时初始化的创建的连接个数,起始生效版本:1.2 -->
<property name="initialSize" value="1" />
<!-- 连接池中同时被分配的有效连接数的最大值,如设置为负数,则不限制 -->
<property name="maxTotal" value="100"></property>
<!-- 连接池中保持空闲的最小连接数,超出设置值之外的空闲连接将被创建,如设置为0,则不创建 -->
<property name="minIdle" value="1" />
<!-- 连接池中保持空闲的最大连接数,超出设置值之外的空闲连接将被回收,如设置为负数,则不限制 -->
<property name="maxIdle" value="20" />
<!-- (如果没有可用连接)池在抛出异常前等待的一个连接被归还的最大毫秒数,设置为-1则等待时间不确定 -->
<property name="maxWaitMillis" value="1000" />
</bean>
4.2、HibernateTemplate的使用(模板方法的设计模式(尽可能掌握))
使用HibernateTemplate可以比较方便的来做一些相应的操作。
1、为HibernateTemplate注入SessionFactory
<!-- 开启HibernateTemplate,并且为其注入sessionFactory
使用HibernateTemplate不太方便的就是要获取session得通过getSessionFactory()方法获取 -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
2、直接可以使用hibernateTemplate调用相应的方法
public class BaseDao {
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
@Resource
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
@Override
public void add(User user, int gid) {
Group g = groupHibernateDao.load(gid);
user.setGroup(g);
this.getHibernateTemplate().save(user);
}
@Override
public void update(User user) {
this.getHibernateTemplate().update(user);
}
@Override
public void delete(int id) {
User u = this.load(id);
this.getHibernateTemplate().delete(u);
}
@Override
public User load(int id) {
return this.getHibernateTemplate().load(User.class, id);
}
@Override
public List<User> list(String sql, Object[] args) {
Query q = this.getHibernateTemplate().getSessionFactory()
.getCurrentSession().createQuery(sql);
if(args!=null) {
for(int i=0;i<args.length;i++) {
q.setParameter(i, args[i]);
}
}
return q.getResultList();
}
4.3、HibernateDaoSupport
Spring为Hibernate提供了一个HibernateDaoSupport的基类方便我们来处理数据信息。
只用继承HibernateDaoSupport就可以了,特别注意需要注入的方式。
public class BaseDao extends HibernateDaoSupport {
@Resource(name="sessionFactory")
//setXX名称不能为setSessionFactory(),因为setSessionFactory()已经在
//HibernateDaoSupport中被定义为final的方法了
public void setSuperSessionFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
}
使用HibernateDaoSupport最大的好处在于可以方便的获取到hibernate的session。
public List<T> list(String hql, Object[] args) {
Query<T> q = this.currentSession().createQuery(hql,this.getClz());
if(args!=null) {
for(int i=0;i<args.length;i++) {
q.setParameter(i, args[i]);
}
}
List<T> list = q.getResultList();
return list;
}
特别注意:不一定非得这样使用。
创建一个基础BaseDao:公共方法都写在BaseDao中,让所有DAO都继承BaseDao。
public interface IBaseDao<T> {
public void add(T t);
public void delete(int id);
public void update(T t);
public T load(int id);
public List<T> list(String hql,Object[] args);
}
/**
* 可以考虑把所有公共的方法都写在BaseDao中,这个时候让所有的DAO都继承BaseDao。
* 这样基本上就实现了大量的基础方法,如果DAO中有一些特殊的方法,再在具体的实现类的DAO中创建
* @author PM
*
* @param <T>
*/
public class BaseDao<T> extends HibernateDaoSupport implements IBaseDao<T> {
@Resource(name="sessionFactory")
public void setSuperSessionFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
/**
* 创建一个Class的对象来获取泛型的class
*/
private Class<T> clz;
@SuppressWarnings("unchecked")
public Class<T> getClz() {
/*if(clz==null) {
Type genType = this.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
clz = (Class<T>) params[0];
}
return clz;*/
if(clz==null) {
//获取泛型的Class对象
clz = ((Class<T>)
(((ParameterizedType)(this.getClass()
.getGenericSuperclass())).getActualTypeArguments()[0]));
}
return clz;
}
@Override
public void add(T t) {
this.getHibernateTemplate().save(t);
}
@Override
public void delete(int id) {
this.getHibernateTemplate().delete(this.load(id));
}
@Override
public void update(T t) {
this.getHibernateTemplate().update(t);
}
@Override
public T load(int id) {
return this.getHibernateTemplate().load(getClz(), id);
}
@Override
public List<T> list(String hql, Object[] args) {
Query<T> q = this.currentSession().createQuery(hql,this.getClz());
if(args!=null) {
for(int i=0;i<args.length;i++) {
q.setParameter(i, args[i]);
}
}
List<T> list = q.getResultList();
return list;
}
分层设计:4层
一般中小型项目通常都会分为四个层
视图层:Viewer(页面显示)
服务层:Service(用来做整个项目的逻辑控制,异常处理,对象判断等都使用服务层)
DAO层:DAO(仅仅做对象的基本CRUD,不做任何判断和任何异常处理)
数据层:Data(数据库,专门存储数据)
Service层:
public interface IUserService {
public void add(User user,int gid);
public void delete(int id);
public void update(User user);
public User load(int id);
public List<User> listAllUser();
public List<User> listByGroup(int gid);
}
@Service("userService")
public class UserService implements IUserService {
private IUserDao userHibernateDao;
private IGroupDao groupHibernateDao;
public IUserDao getUserHibernateDao() {
return userHibernateDao;
}
@Resource
public void setUserHibernateDao(IUserDao userHibernateDao) {
this.userHibernateDao = userHibernateDao;
}
public IGroupDao getGroupHibernateDao() {
return groupHibernateDao;
}
@Resource
public void setGroupHibernateDao(IGroupDao groupHibernateDao) {
this.groupHibernateDao = groupHibernateDao;
}
@Override
public void add(User user, int gid) {
Group g = this.groupHibernateDao.load(gid);
if(g==null) throw new UserException("添加的用户组不存在");
user.setGroup(g);
this.userHibernateDao.add(user);
}
@Override
public void delete(int id) {
this.userHibernateDao.delete(id);
}
@Override
public void update(User user) {
this.userHibernateDao.update(user);
}
@Override
public User load(int id) {
return this.userHibernateDao.load(id);
}
@Override
public List<User> listAllUser() {
String hql = "from User";
return this.userHibernateDao.list(hql);
}
@Override
public List<User> listByGroup(int gid) {
String hql = "from User where group.id=?";
return this.userHibernateDao.list(hql, gid);
}
}
4.4、和Struts2整合
1、导入struts2的jar包(特别注意:导入之后检查一下是否存在有冲突的jar包)
2、导入struts2和spring的整合包(struts2-spring-plugin-2.3.31.jar)
3、配置struts2的struts.xml文件
<!-- 表示Action由spring来进行创建,可以直接使用spring依赖注入来注入 -->
<constant name="struts.objectFactory" value="spring" />
4、创建action
/**
* 此时等于用spring来创建了userAction对象,在struts的配置文件中写action的class的时候
* 就不能写类,而应该写userAction这个对象
* @author PM
*
*/
@Controller("userAction")
public class UserAction extends ActionSupport implements ModelDriven<User> {
5、重新配置struts.xml的基于通配符的访问方式
<!-- 基于通配符的方式:由于整合了Spring,在class中就不用再使用完整的类了,而应该使用Spring所注入的
对象,如UserAction就应该使用userAction来创建。
此处特别注意:第一个字母是小写,文件夹就应该使用小写的 -->
<action name="*_*" class="{1}Action" method="{2}">
<!-- 在action中引入相应的拦截器,如果在action中引入了相应的拦截器之后,
原有的继承于struts-default.xml的拦截器就不起作用了,此时需要手动导入 -->
<!-- <interceptor-ref name="helloStack"/> -->
<!-- 只要方法返回的是success就会去/WEB-INF/下找相应的jsp文件,如果是
User_add.action表示会去找/WEB-INF/User/add.jsp文件 -->
<result>/WEB-INF/jsp/{1}/{2}.jsp</result>
<result name="input">/WEB-INF/jsp/{1}/{2}Input.jsp</result>
<!-- 设置客户端跳转,方法返回的名称为name="r_list" -->
<result type="redirect" name="redirect">/${url}</result>
</action>
6、在web.xml中配置获取BeanFactory的操作
6.1、创建监听器获取Spring的工厂
<!-- 创建Spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring的监听器可以通过这个上下文参数来获取beans.xml的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:beans.xml</param-value>
</context-param>
6.2、创建struts2的过滤器
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
OpenSessionInViewer:
由于Hibernate存在延迟加载的问题,当DAO的事务提交之后,session就关闭,此时如果到显示层就没有办法获取对象,使用OpenSessionInViewer是解决延迟加载问题的方案。
解决的思路:
1、在表示层开启session
需要在表示层获取Spring的工厂,以此获取Hibernate的SessionFactory。
2、在DAO层获取表示层的session
如果希望在DAO层获取表示层的数据,应该将要获取的数据存储到ThreadLocal中。
3、当整个过程执行完毕之后再关闭session
需要通过Filter来解决问题
1、创建一个OpenSessionFilter
/**
* 以下方法用来获取Spring的工厂和Hibernate的sessionFactory
*/
@Override
public void init(FilterConfig cfg) throws ServletException {
/**
* 使用WebApplicationContextUtils.getWebApplicationContext(ServletContext)
* 来获取web中的spring工厂
* 这种手段非常重要,一定要熟悉
*/
wac = WebApplicationContextUtils.getWebApplicationContext(cfg.getServletContext());
sessionFactory = (SessionFactory)wac.getBean("sessionFactory");
}
2、通过ThreadLocal来处理session
//Spring的工厂,在init()中获取
private static WebApplicationContext wac;
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> sessionHolder = new ThreadLocal<Session>();
private static void setSession(Session session) {
sessionHolder.set(session);
}
public static Session getSession() {
return sessionHolder.get();
}
private static void removeSession() {
sessionHolder.remove();
}
OpenSessionFilter:
public class OpenSessionFilter implements Filter {
//Spring的工厂,在init()中获取
private static WebApplicationContext wac;
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> sessionHolder = new ThreadLocal<Session>();
private static void setSession(Session session) {
sessionHolder.set(session);
}
public static Session getSession() {
return sessionHolder.get();
}
private static void removeSession() {
sessionHolder.remove();
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//开启session
/**
* 需要获取Spring的工厂
* 如果使用new ClassPathXmlApplicationContext()这种方式来获取Spring的工厂,
* 最大的问题是这是一个新工厂,和servlet初始化时的工厂是两个对象
* 必须通过其它方法来获取
*/
try {
System.out.println("aaaaa");
//设置session
setSession(sessionFactory.openSession());
chain.doFilter(req, resp);
} finally {
//关闭session
removeSession();
}
}
/**
* 以下方法用来获取Spring的工厂和Hibernate的sessionFactory
*/
@Override
public void init(FilterConfig cfg) throws ServletException {
/**
* 使用WebApplicationContextUtils.getWebApplicationContext(ServletContext)
* 来获取web中的spring工厂
* 这种手段非常重要,一定要熟悉
*/
wac = WebApplicationContextUtils.getWebApplicationContext(cfg.getServletContext());
sessionFactory = (SessionFactory)wac.getBean("sessionFactory");
}
}
@Override
public T load(int id) {
// return this.getHibernateTemplate().load(getClz(), id);
/**
* 如果使用了自定义的OpenSessionFiltr,需要按照如下方法来获取
*/
// return OpenSessionFilter.getSession().load(getClz(), id);
//如果使用Spring所提供的OpenSessionInViewFilter就按照整合的方法处理即可
return this.getHibernateTemplate().load(getClz(), id);
}
web.xml:
<!-- Spring中提供了 org.springframework.orm.hibernate5.support.OpenSessionInViewFilter,
这个类来实现OpenSessionInViewer的操作 -->
<filter>
<filter-name>openSessionInViewerFilter</filter-name>
<filter-class> org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInViewerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 如果把这个Filter放在Struts2的Filter之后,所有的请求都会被Struts2给控制,
所以这个Filter就不起作用了。
必须将这个Filter放在Struts2的Filter之前 -->
<!-- <filter>
<filter-name>openSessionInViewerFilter</filter-name>
<filter-class>org.pm.spring.filter.OpenSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInViewerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> -->
Spring声明式事务:
/**
* 删除组中的用户
* @param gid
*/
public void deleteByGroup(int gid);
@Override
public void deleteByGroup(int gid) {
//注意删除的写法:Hibernate提供的DML
String hql = "delete User u where u.group.id=?";
this.currentSession().createQuery(hql).setParameter(0, gid).executeUpdate();
}
@Override
public void delete(int id) {
/*long count = this.userHibernateDao.getGroupUserCount(id);
if(count>0) throw new UserException("删除的组中还有用户");*/
userHibernateDao.deleteByGroup(id);
//如果在这个位置抛出异常,会出现用户被删除,而组没有删除的数据不完整情况
if(id>0) throw new UserException();
this.groupHibernateDao.delete(id);
}
public String delete() {
groupService.delete(group.getId());
ActionContext.getContext().put("url", "/group_list.action");
return "redirect";
}
<a href="group_delete.action?id=${id }">删除</a>
<!-- 配置Spring的事务处理 -->
<!-- 创建事务管理器 -->
<bean id="txManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置AOP,Spring是通过AOP来进行事务管理的 -->
<aop:config>
<!-- 设置pointCut表示哪些事务要加入事务处理 -->
<!-- 以下的事务是声明在DAO中的,但是通常都会在service层来处理多个对象逻辑的关系,诸如更新、删除等,
此时如果在执行了一个步骤之后抛出异常就会导致数据不完整,所以事务不应该在DAO层处理,而应该在service层处理,
这也就是spring所提供的一个非常方便的工具,声明式事务 -->
<aop:pointcut id="allMethods"
expression="execution(* org.pm.spring.service.*.*(..))"/>
<!-- 通过advisor来确定具体要加入事务控制的方法 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods"/>
</aop:config>
<!-- 配置哪些方法要加入事务控制 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 让所有的方法都加入事务管理,为了提高效率,可以把一些查询之类的方法设置为只读的事务 -->
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
<!-- 以下方法都是可能涉及修改的方法,就无法设置为只读 -->
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
基于原生态session的BaseDao,不使用HibernateDaoSupport:
/**
* 可以考虑把所有公共的方法都写在BaseDao中,这个时候让所有的DAO都继承BaseDao。
* 这样基本上就实现了大量的基础方法,如果DAO中有一些特殊的方法,再在具体的实现类的DAO中创建
* @author PM
*
* @param <T>
*/
public class BaseDao<T> implements IBaseDao<T> {
private SessionFactory sessionFactory;
/**
* 使用原生态的session查询,不使用HibernateDaoSupport
* @param sessionFactory
*/
@Resource(name="sessionFactory")
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
/**
* 创建一个Class的对象来获取泛型的class
*/
private Class<T> clz;
@SuppressWarnings("unchecked")
public Class<T> getClz() {
/*if(clz==null) {
Type genType = this.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
clz = (Class<T>) params[0];
}
return clz;*/
if(clz==null) {
//获取泛型的Class对象
clz = ((Class<T>)
(((ParameterizedType)(this.getClass()
.getGenericSuperclass())).getActualTypeArguments()[0]));
}
return clz;
}
@Override
public void add(T t) {
this.getSession().save(t);
}
@Override
public void delete(int id) {
this.getSession().delete(this.load(id));
}
@Override
public void update(T t) {
this.getSession().update(t);
}
@Override
public T load(int id) {
// return this.getHibernateTemplate().load(getClz(), id);
/**
* 如果使用了自定义的OpenSessionFiltr,需要按照如下方法来获取
*/
// return OpenSessionFilter.getSession().load(getClz(), id);
//如果使用Spring所提供的OpenSessionInViewFilter就按照整合的方法处理即可
return this.getSession().load(getClz(), id);
}
@Override
public List<T> list(String hql, Object[] args) {
Query<T> q = this.getSession().createQuery(hql,this.getClz());
if(args!=null) {
for(int i=0;i<args.length;i++) {
q.setParameter(i, args[i]);
}
}
List<T> list = q.getResultList();
return list;
}
@Override
public List<T> list(String hql) {
return this.list(hql,null);
}
@Override
public List<T> list(String hql, Object arg) {
return this.list(hql, new Object[]{arg});
}
@Override
public Pager<T> find(String hql, Object[] args) {
Pager<T> pages = new Pager<T>();
int pageOffset = SystemContext.getPageOffset();
int pageSize = SystemContext.getPageSize();
Query<T> q = this.getSession().createQuery(hql,this.getClz());
//sql查询返回BigInteger,hql查询返回Long
Query<Long> cq = this.getSession().createQuery(getCountHql(hql),Long.class);
if(args!=null) {
int index = 0;
for(Object arg:args) {
q.setParameter(index, arg);
cq.setParameter(index, arg);
index++;
}
}
long totalRecord = cq.getSingleResult();
q.setFirstResult(pageOffset);
q.setMaxResults(pageSize);
List<T> datas = q.getResultList();
pages.setDatas(datas);
pages.setPageOffset(pageOffset);
pages.setPageSize(pageSize);
pages.setTotalRecord(totalRecord);
return pages;
}
private String getCountHql(String hql) {
//1、获取from前面的字符串
String f = hql.substring(0,hql.indexOf("from"));
//2、将from前面的字符串替换为select count(*)
if(f.equals("")) {
hql = "select count(*) "+hql;
} else {
hql = hql.replace(f, "select count(*) ");
}
//3、将fetch替换为"",因为抓取查询不能使用count(*)
hql = hql.replace("fetch", " ");
return hql;
}
@Override
public Pager<T> find(String hql, Object arg) {
return this.find(hql, new Object[]{arg});
}
@Override
public Pager<T> find(String hql) {
return this.find(hql, null);
}
bean.xml中关闭HibernateTemplate:
<!-- 开启HibernateTemplate,并且为其注入sessionFactory
使用HibernateTemplate不太方便的就是要获取session得通过getSessionFactory()方法获取 -->
<!-- <bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean> -->
乱码问题解决:
<!-- 进行字符编码处理的filter,必须在OpenSessionInViewer之前 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
分页设置:
(导入pager-taglib.jar包,jstl的jar包[taglibs-standard-compat-1.2.5.jar、taglibs-standard-impl-1.2.5.jar、taglibs-standard-jstlel-1.2.5.jar、taglibs-standard-spec-1.2.5.jar])
分页对象:
public class Pager<T> {
private List<T> datas;
private int pageOffset;
private long totalRecord;
private int pageSize;
public class SystemContext {
private static ThreadLocal<Integer> pageOffset = new ThreadLocal<Integer>();
private static ThreadLocal<Integer> pageSize = new ThreadLocal<Integer>();
public static int getPageOffset() {
return pageOffset.get();
}
public static void setPageOffset(int _pageOffset) {
pageOffset.set(_pageOffset);
}
public static int getPageSize() {
return pageSize.get();
}
public static void setPageSize(int _pageSize) {
pageSize.set(_pageSize);
}
public static void removePageOffset() {
pageOffset.remove();
}
public static void removePageSize() {
pageSize.remove();
}
}
IBaseDao增加如下方法:
public Pager<T> find(String hql,Object[] args);
public Pager<T> find(String hql,Object arg);
public Pager<T> find(String hql);
BaseDao增加如下方法:
@Override
public Pager<T> find(String hql, Object[] args) {
Pager<T> pages = new Pager<T>();
int pageOffset = SystemContext.getPageOffset();
int pageSize = SystemContext.getPageSize();
Query<T> q = this.getSession().createQuery(hql,this.getClz());
//sql查询返回BigInteger,hql查询返回Long
Query<Long> cq = this.getSession().createQuery(getCountHql(hql),Long.class);
if(args!=null) {
int index = 0;
for(Object arg:args) {
q.setParameter(index, arg);
cq.setParameter(index, arg);
index++;
}
}
long totalRecord = cq.getSingleResult();
q.setFirstResult(pageOffset);
q.setMaxResults(pageSize);
List<T> datas = q.getResultList();
pages.setDatas(datas);
pages.setPageOffset(pageOffset);
pages.setPageSize(pageSize);
pages.setTotalRecord(totalRecord);
return pages;
}
private String getCountHql(String hql) {
//1、获取from前面的字符串
String f = hql.substring(0,hql.indexOf("from"));
//2、将from前面的字符串替换为select count(*)
if(f.equals("")) {
hql = "select count(*) "+hql;
} else {
hql = hql.replace(f, "select count(*) ");
}
//3、将fetch替换为"",因为抓取查询不能使用count(*)
hql = hql.replace("fetch", " ");
return hql;
}
@Override
public Pager<T> find(String hql, Object arg) {
return this.find(hql, new Object[]{arg});
}
@Override
public Pager<T> find(String hql) {
return this.find(hql, null);
}
IUserService增加如下方法:
public Pager<User> findUser();
UserService增加如下方法:
@Override
public Pager<User> findUser() {
String hql = "from User u left join fetch u.group";
return this.userHibernateDao.find(hql);
}
UserAction:
/**
* 此时等于用spring来创建了userAction对象,在struts的配置文件中写action的class的时候
* 就不能写类,而应该写userAction这个对象
* @author PM
*
*/
@Controller("userAction")
@Scope("prototype") //注意:action不能使用单例
public class UserAction extends ActionSupport implements ModelDriven<User> {
private static final long serialVersionUID = -3198489302580189122L;
private User user;
private IGroupService groupService;
private IUserService userService;
private int gid;
private int uid; //不能使用id注入,会报错,注意页面传值时使用?uid=${id}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public int getGid() {
return gid;
}
public void setGid(int gid) {
this.gid = gid;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public IUserService getUserService() {
return userService;
}
@Resource
public void setUserService(IUserService userService) {
this.userService = userService;
}
public IGroupService getGroupService() {
return groupService;
}
@Resource
public void setGroupService(IGroupService groupService) {
this.groupService = groupService;
}
@Override
public User getModel() {
if(user==null) user = new User();
return user;
}
public String addInput() {
ActionContext.getContext().put("gs", groupService.listAllGroup());
return SUCCESS;
}
public void validateAdd() {
if(user.getUsername()==null||"".equals(user.getUsername())) {
this.addFieldError("username", "用户名称不能为空");
}
if(user.getNickname()==null||"".equals(user.getNickname())) {
this.addFieldError("nickname", "用户昵称不能为空");
}
//如果有错误,得需要重新调用addInput()方法把组的信息设置进去
if(this.hasFieldErrors()) {
addInput();
}
}
public String add() {
userService.add(user, gid);
ActionContext.getContext().put("url", "/user_list.action");
return "redirect";
}
public String list() {
ActionContext.getContext().put("us", userService.findUser());
return SUCCESS;
}
public String delete() {
userService.delete(user.getId());
ActionContext.getContext().put("url", "/user_list.action");
return "redirect";
}
public String updateInput() {
ActionContext.getContext().put("gs", groupService.listAllGroup());
User tu = userService.load(user.getId());
user.setUsername(tu.getUsername());
user.setPassword(tu.getPassword());
user.setNickname(tu.getNickname());
this.setGid(tu.getGroup().getId());
return SUCCESS;
}
public String update() {
User tu = userService.load(user.getId());
tu.setNickname(user.getNickname());
tu.setUsername(user.getUsername());
userService.update(tu,gid);
ActionContext.getContext().put("url", "/user_list.action");
return "redirect";
}
public String show() {
// System.out.println(user.getId());
System.out.println(uid);
user = userService.load(uid);
return SUCCESS;
}
}
SystemContextFilter:
public class SystemContextFilter implements Filter {
private int pageSize = 0;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
try {
int pageOffset = 0;
try {
if(req.getParameter("pager.offset")!=null)
pageOffset = Integer.parseInt(req.getParameter("pager.offset"));
} catch (NumberFormatException e) {
e.printStackTrace();
}
SystemContext.setPageOffset(pageOffset);
SystemContext.setPageSize(pageSize);
chain.doFilter(req, resp);
} finally {
SystemContext.removePageOffset();
SystemContext.removePageSize();
}
}
@Override
public void init(FilterConfig cfg) throws ServletException {
try {
if(cfg.getInitParameter("pageSize")!=null)
pageSize = Integer.parseInt(cfg.getInitParameter("pageSize"));
} catch (NumberFormatException e) {
pageSize = 10;
e.printStackTrace();
}
}
}
list.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:iterator value="#us.datas">
${id }-----><a href="user_show.action?uid=${id }">${username }</a>
-----${password }-----${nickname }-----${group.name }
<a href="user_delete.action?id=${id }">删除</a>
<a href="user_updateInput.action?id=${id}">更新</a>
<br/>
</s:iterator>
<jsp:include page="/inc/pager.jsp">
<jsp:param value="user_list.action" name="url"/>
<jsp:param value="${us.totalRecord }" name="items"/>
</jsp:include>
</body>
</html>
web.xml:
<filter>
<filter-name>SystemContextFilter</filter-name>
<filter-class>org.pm.spring.filter.SystemContextFilter</filter-class>
<init-param>
<param-name>pageSize</param-name>
<param-value>15</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SystemContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
pager.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="pg" uri="http://jsptags.com/tags/navigation/pager" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- items:总记录数,maxPageItems:每页显示多少条,curPage=pageNumber:
将导出的参数pageNumber重新命名为curPage,用来表示当前页 -->
<pg:pager maxPageItems="15" items="${param.items }" export="curPage=pageNumber" url="${param.url }">
<c:forEach items="${param.params }" var="p">
<pg:param name="${p }"/>
</c:forEach>
<pg:last>
共[${param.items }]条记录,共${pageNumber }页,当前第${curPage }页。
</pg:last>
<!-- pg:first表示首页,会默认导出pageUrl -->
<pg:first>
<a href="${pageUrl }">首页</a>
</pg:first>
<pg:prev>
<a href="${pageUrl }">上一页</a>
</pg:prev>
<pg:pages>
<!-- curPage是在pg:pager中导出的,pageNumber表示页码,curPage是pg:pager
中的pageNumber表示的是当前页 -->
<c:if test="${curPage eq pageNumber }">[${pageNumber }]</c:if>
<c:if test="${curPage ne pageNumber }">
<a href="${pageUrl }">${pageNumber }</a>
</c:if>
</pg:pages>
<pg:next>
<a href="${pageUrl }">下一页</a>
</pg:next>
<pg:last>
<a href="${pageUrl }">尾页</a>
</pg:last>
</pg:pager>
(完)