SSH的整合

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>&nbsp;
		<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>

(完)

转载于:https://my.oschina.net/pmos/blog/793961

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值