SSH框架完全整合

大三学期渐末,事情也挺多的,上周就开始着手整合SSH框架,到现在才真正的完成,过程中碰到了许多小问题(小问题大折腾,哭脸.jpg)。本着善始善终的原则,最终把它给完成了。

本篇文章就在:

win7 64位,eclipse最新版(2017.9),Spring4.3.13,Hibernate5.0.1,Struts2.3.34 环境下,整合SSH。在下一篇文章,我们也来使用Maven来整合一下(毕竟学了就要用嘛,哈哈)。

首先先介绍一下jar包:

以上是我使用完整的jar包清单,我们分别导入了三个框架所需要的jar包,在导jar包的时候需要注意以下几点:

  • jar包冲突:struts2的javassist和Hibernate的javassist有冲突,我们选择最新的版本的(根据你的自身情况选择)。
  • log4j,log4j-api,log4jcore,slf4j-api,slf4j-log4j12的的冲突,我们依旧看情况选择最新版本。
  • c3p0jar包,我们选择最新的(框架之间有重复的记得删除重复)。
  • Spring整合struts2需要导入Spring-web和struts2-spring-plugin jar包,不要丢掉。
  • 数据库jar驱动jar包,根据自身使用的数据库进行选择
  • 因为我这里使用Spring对事务的管理,所以还要导入事务的jar包,spring -jdbc的jar包,spring-orm,Aspectj的jar包。

以上都是我们需要特别注意的,否则整合的过程中会给你带来不小的麻烦

jar包就介绍差不多了,那我们就来开始吧:

首先看一下我的目录结构:

项目大体可以分为三层,视图层,service层,DAO层,因为我们这里没有什么业务,单纯的是调用DAO,所以可能service层和DAO层之间的区别不是很明显。

其实三个框架的整合,就是将Hibernate的session创建交给Spring,将Struts2的Action交给Spring。

(一)在Hibernate中,我们自己通过以下的一系列操作获取session:

//加载配置文件
        Configuration config = new Configuration().configure();
        //根据配置文件创建会话工厂
        SessionFactory factory = config.buildSessionFactory();
        //根据会话工厂创建会话
        Session session = factory.getCurrentSession();
        //创建一个事物对象
        Transaction tx = session.beginTransaction();
        //new 一个学生对象
        Student student = new Student("小三",19,99);
        //将对象持久化到数据表中
        session.save(student);
        //提交事务
        tx.commit();
        //关闭会话
        session.close();
        //关闭工厂
        factory.close();

同样为了解耦,在项目中,我们不再自己手动的来获取session了,而是通过Spring来帮我们创建,并且service层中需要DAO,DAO需要session,也是Spring进行注入。

(二)在Struts2中,我们通过自己在Struts2的主配置文件中指定对应请求的Action的全限定类名,Struts2和Spring整合则是将Action的创建交给了Spring,由Spring来管理Action对象。

接下来我们就这两个方面分别整合Spring和Hibernate,Spring和Struts2,最后在Struts2 Action的execute方法中调用service,对业务进行操作。

下面为了代码的可读性,博主不会将代码分块分析,很重要的将会指出,大多数的过程说明将在注释中给出:

整合Spring和Hibernate:

先给出我们的基本代码:

//DAO接口:
public interface StudentDao {
    void insert(Student student);
    void delete(Student student);
    void update(Student student);
    List selectAllStudents();
    boolean selectStudentByIdAndName(String name,int age);
}
//DAO的实现类,里面注入了SessionFactory对象,利用这个我们可以获取session

public class StudentDaoImpl implements StudentDao{
    //这里的sessionFactory由Spring进行注入
    private SessionFactory sessionFactory;
    //所以这里需要setter方法,这里的getter方法顺带添上,如果以后需要获取sessionFactory的话可以调用
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    //依赖注入,需要setter方法
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public void insert(Student student) {
        sessionFactory.getCurrentSession().save(student);
    }

    @Override
    public void delete(Student student) {
        sessionFactory.getCurrentSession().delete(student);
    }

    @Override
    public void update(Student student) {
        sessionFactory.getCurrentSession().update(student);
    }


    @Override
    public List selectAllStudents() {
        String hql = "from Student";
        return sessionFactory.getCurrentSession().createQuery(hql).list();
    }

    //通过name和age来判别学生是否存在
    @Override
    public boolean selectStudentByIdAndName(String name, int age) {
        String hql = "from Student where name=? and age=?";
        boolean flag = false;
        if(sessionFactory.getCurrentSession().createQuery(hql).setString(0, name).setInteger(1, age).uniqueResult()!=null) {
            flag = true;
        }
        return flag;
    }
}

上面的DAO,我们获取session不再使用原始的方法了,而是使用Spring注入的方式为我们程序获取session,具体的SessionFactory配置,将在后面的Spring配置文件给出。

接下来我们看Service:

//service接口
public interface StudentService {
    void add(Student student);
    void remove(Student student);
    void modify(Student student);
    List findAllStudents();
    boolean findByNameAndAge(String name,int age);
}
//service实现类
public class StudentServiceImpl implements StudentService {
    //这里的Dao对象是由Spring注入,下面要有setter方法
    private StudentDao studentdao; 
    public StudentDao getStudentdao() {
        return studentdao;
    }
    public void setStudentdao(StudentDao studentdao) {
        this.studentdao = studentdao;
    }
    @Override
    public void add(Student student) {
        studentdao.insert(student);
    }

    @Override
    public void remove(Student student) {
        studentdao.delete(student);
        
    }

    @Override
    public void modify(Student student) {
        studentdao.update(student);
        
    }

    @Override
    public List findAllStudents() {
        return studentdao.selectAllStudents();
    }
    @Override
    public boolean findByNameAndAge(String name, int age) {
        return studentdao.selectStudentByIdAndName(name, age);
    }
    
}

接着便是我们Spring的配置文件(下面的配置文件是完整的配置文件,即整合ssh的完整配置文件,其实也就是在整合Hibernate的基础上注册了Action类的bean):

    

    
    
        
        
        
        
        
        
    
    
    
    
        
        
        
        
        
            
                org.hibernate.dialect.MySQL5Dialect
                update
                true
                true
                org.springframework.orm.hibernate5.SpringSessionContext
            
        
    
    
    
    
        
    
    
    
    
        
    
    
    
    
        
    
    
    
    
        
    
    
    
    
        
            
            
            
            
            
        
    
    
    
    
        
        
    

整合Hibernate,

我们需要注册SessionFactory,

class为 org.springframework.orm.hibernate5.LocalSessionFactoryBean ,位于我们Spring orm包下,对于不同版本的Hibernate,我们应该选用不同的整合class。

上面的Spring主配置文件中用 属性来替代了我们导入Hibernate的主配置文件,当然我们也可以直接导入Hibernate的主配置文件,不过为了简洁,我们这样比较方便。

关于配置文件后面对事务的管理,我们这里就不多说了,我的前几篇文章都有详细的介绍,有兴趣的同学可以去看看:

http://blog.csdn.net/qq_39266910/article/details/78826171

如果做到上面的这些,我们便可以进行测试了:

//测试类
public class Test01 {
    private StudentService service;
    
    @Before
    public void before() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        service = (StudentService)ac.getBean("studentservice");
    }

    @Test
    public void test01() {
        service.add(new Student("中文",18));
        System.out.println("Success");
    }
    
    @Test
    public void test02() {
        Student student = new Student();
        student.setId(1);
        service.remove(student);
    }
    
    @Test
    public void test03() {
        Student student = new Student("张三",25);
        student.setId(10);
        service.modify(student);
    }
    
    @Test
    public void test06() {
        System.out.println(service.findAllStudents());
    }
    
    @Test
    public void test07() {
        System.out.println(service.findByNameAndAge("中", 18));
    }
}

以上就是Spring整合Hibernate的全过程,接下来我们来整合Struts2:

Spring整合Struts2

首先是Struts2的主配置文件:

    

     
     

     
     
            
            /welcome.jsp
            /error.jsp
        
    

接着是对应的Action:

public class RegisterAction extends ActionSupport{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    //Spring会为我们自动注入service,但是这个属性名要和Spring主配置文件里面注册的studentservice的id保持一致。
    //或者将Action交由Spring管理,在Spring配置Action的bean,为bean注入service,如果这样,我们在struts2主配置文件的class就不必写成Action的全限定类名,而是Spring中注册的id。
    private StudentService studentservice;
    public RegisterAction() {
        super();
    }
    
    public RegisterAction(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    
    //  注入Service,我们需要保留set方法
    public void setStudentservice(StudentService studentservice) {
        this.studentservice = studentservice;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String execute() {
        System.out.println(studentservice);
        System.out.println(name);
        System.out.println(age);
        studentservice.add(new Student(name,age));
        return SUCCESS;
    }
}

以上是模拟完成一个注册功能,view层发送一个请求,包含姓名和年龄,后台负责接收,并调用service层进行处理,service层调用DAO,DAO调用SessionFactory获取session,最终达到对数据库的操作。

如果仅仅这样你是不是忘了些什么?

①我们需要在web.xml中添加Struts2的核心过滤器。

②设置一个监听器,监听当web容器创建的时候,即创建我们的Spring容器,这样我们不再需要自己加载Spring的主配置文件。

③设置web容器全局参数,自定义Spring主配置文件的位置和命名

具体的看web.xml:


    
  
  
    contextConfigLocation
    classpath:applicationContext.xml
  
  
  
  
      org.springframework.web.context.ContextLoaderListener
  
    
  
  
      struts2
      org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  
  
  
      struts2
      /*
  
  
  
    index.jsp
  

我们一并给出jsp页面(success和error页面就不写了,一个形式):





register


    
姓名
年龄

接下来我们进行测试:

点击后,跳转到:

最后看看数据库:

以上的ssh整合大体上是没有什么问题的,但是碰上延时加载的话会出现一些意想不到的事情,在讲Hibernate的session的时候,我们说过session有两种获取的方式,一个是getCurrentSession,另一个是openSession,它们两个获取的session的区别是,getSession获得的session必须要在事务中执行,也就说没有事务是不能获取session的,当我们使用session.load进行查询的时候,这就是一个延时加载,执行加载方法的时候会产生一个代理,这个代理是一个空代理,只有当我们真正需要这个代理的详细数据的时候,才会真正的进行查询,但是当它真正的查询的时候,已经没有了事务(因为我们这里的事务是通过Spring整合AspectJ,通过AOP的方式实现添加事务的),所以这个时候也就没有了session,所以当再执行详情查询的时候就会报错(no session)。

所以我们需要在web.xml中添加一个过滤器,来获取session,这个过滤器的名字叫做 OpenSessionInViewFilter ,添上这个过滤器后,当我们进行延时加载的话,就不会再出现no session的情况了!

在OpenSessionInViewFilter的源码中,获取session是利用的SessionFactory,也就是我们自己在Spring的注册的SessionFactory,且在里面,这个类有一个默认的SessionFactory名字就叫做sessionFactory:

注意:添加这个过滤器,一定要在Struts2的核心过滤器之前!

具体原因是:Struts2的核心过滤器中,当有Action请求的时候,会执行executeAction方法,即执行Action,不会有chain.doFilter(执行下一个过滤器),有源码有真相:

这里的mapping就是对应的action请求。

下面是openSessionInViewFilter的具体配置方法,初始化参数是为了自定义我们的sessionFactory的bean id,因为openSessionInViewFilter里面有setter方法,可以为之前设置好的默认值进行修改。

总结:当代码都写出来了,觉得很简单,但是这过程中一直小bug不断(当然大多数都是由自己的粗心造成的),其实三个框架之间的真核无非就是将所有关于类的创建管理交由Spring,由Spring来为需要的注入所需要的bean,不再需要手动的创建一个个的类,使得各个层级之间耦合度降低,即使一层代码出现了问题不需要修改另一层的代码,便于我们项目的维护和更新,也便于出现问题能够即使定位出错的位置。

以上是自己的心得体会,代码均由博主亲自验证,可以运行,文章方便博主以后查阅,也供大家参考,如有错误不吝赐教!

博客园精华区责编内容来自:博客园精华区 (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » SSH框架完全整合

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录