Spring+Struts+Hibernate整合笔记

前言

  在来写这篇笔记之前,去看了一篇别人的美文。自从入行以来,已经记不得有多久没有去看真正的文学作品了。甚至曾经一度以为那些能引起我们心灵共鸣的文章对我们的生活并没有什么作用。毕业以来,我也从未放弃看书,但看的书却更具功利性,比如《XXX从入门到精通》、《XXX指南》一类的书。貌似这类书更具价值,因为它能变现。不管出于什么样的目的,现在真正能静下心来欣赏文学作品的人越来越少。功名利禄,灯红酒绿更能吸引人心。但偶尔静下心来,与心灵对话,也会让我们这种无产阶级短暂的放下压力,产生出幸福感。也许风雨后的彩虹来得太晚,但明天的路还长,我不会在今天就倒在路上。
  继续我们的成长之旅,这个标题已经是老生常谈,这些技能也几乎是所有java程序员的基本技能。关于这三个框架的整合的教程已经很多了。但是比较系统的、或者说比较详细的并且能在容易入坑的地方着重强调的文章却不多。对于像我这种初学者来说,是越详细越好,最好能在坑多的地方多做提醒。
  我在写这篇笔记的时候会尽可能详细的介绍这三个框架的整合过程,并在我掉坑的地方着重强调,一方面让我记忆更深,另一方面希望对后来者有所帮助。我也是初学者,如有不妥,也希望能留言指点,先行谢过。

使用Struts框架搭建Web项目

  1、首先下载好Struts库(点击下载),在官方下载页下载struts-2.5.14.1-all.zip。
  2、创建Web Project:打开Eclipse => File => New => Web Project。
  3、在 ... => struts-2.5.14.1-all.zip => struts-2.5.14.1 => lib目录下将如下图的这些库(也可下载struts-2.5.14.1-min.zip,其中的库是搭建Struts项目必须要导入的库)拷贝到项目的WebRoot => WEB-INF => lib目录下,并添加到build path

image.png

  4、在WEB-INF下创建web.xml文件。
  5、在web.xml文件中配置struts拦截器(注意拦截器不要配错了,新版本的拦截器和旧版本拦截器不一样,具体的可以看struts-core.jar下面是否有响应的java类):

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>MyWeb</display-name>
  <welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
  <!-- 新版本struts用下面这个拦截器 -->
    <!--<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter> -->
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>
</web-app>

  6、在src目录下创建struts配置文件struts.xml (记住是src目录,不是WEB-INF目录,如果要放在WEB-INF目录下,请在WEB-INF目录下创建classes目录,并将struts.xml放在classes目录下。这样做的原因:在编译的时候会将src下的文件拷贝到classes目录下,WEB-INF/classes目录下的文件也都全部会被拷到编译路径的classes目录下,而WEB-INF下的文件不会被拷贝到classes目录下,在程序运行的时候默认是在classes目录下查找web.xml和struts.xml)
  7、在com.xxx.action下创建LoginAction类:

package com.xxx.action;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{

    private String userName;
    private String password;
    
    
    public String getUserName() {
        return userName;
    }


    public void setUserName(String userName) {
        this.userName = userName;
    }


    public String getPassword() {
        return password;
    }


    public void setPassword(String password) {
        this.password = password;
    }


    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    

    @Override
    public String execute() throws Exception {
        if ("test".equals(getUserName()) && "123456".equals(getPassword())) {
            return SUCCESS;
        }
        return ERROR;
    }

}

  8、在WEB-INF/content目录下创建登录成功和失败的显示页success.jsp、error.jsp:

success.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'success.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    登录成功!<br>
  </body>
</html>

error.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'error.jsp' starting page</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

</head>

<body>
    账户名或密码错误
    <br>
</body>
</html>

  9、打开刚才创建好的struts.xml文件,开始配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <package name="xxx" extends="struts-default">
        <action name="login.action" class="com.xxx.action.LoginAction">
            <result name="success">/WEB-INF/content/success.jsp</result>
            <result name="error">/WEB-INF/content/error.jsp</result>
        </action>
    </package>
</struts>    

说明:package的name属性是自己取的,用于管理action,必须要继承extends="struts-default"。
特别注意:如果你使用的是旧版本的拦截器,那么在配置的时候action的name属性login.action要写全(因为后面请求的时候用的就是这个),如果你使用的是新版本的拦截器,那么只需要将action的name属性配置为login就可以了(请求时的action name还是login.action)

  10、创建登录页,在WebRoot目录下创建login.jsp(因为在web.xml文件在设置的welcome-file是login.jsp因此输入网址会直接导航到这个界面),login.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'login.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    <form action="login.action">
        用户名:<input type="text" name="userName"><br>
        密码: <input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>
  </body>
</html>

说明:form的action属性要和struts.xml文件中配置是action的name属性一致(旧版本,如果是新版本,在struts配置的时候如果是以.cation结尾,那么去掉.action),input的name属性对应LoginAction中的userName属性和password属性,且名字必须保持一致。

  到此为之,struts项目就搭建完成了,可以先运行下项目,测试运行过程是否正常,如果有问题,在下一步之前,请确保已经解决。

Spring整合Struts

  首先,下载spring,下载地址http://repo.springsource.org/libs-release-local/org/springframework/spring/。根据需要下载相应的版本,我下载的是5.0.1版。
  下载下来后,解压并找到libs文件夹,将libs下面的所有jar文件拷贝到项目的WebRoot/WEB-INF/libs目录下,并且add to build path。
  修改web.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>MyWeb</display-name>
  <welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <filter>
    <filter-name>struts2</filter-name>
   <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>
</web-app>

ContextLoaderListener这个监听器负责查找spring配置文件并启动spring。context-param用于配置spring配置文件的路径,如果不配置,则默认在WEB-INF下找applicationContext.xml文件。
  然后在WEB-INF/目录下(请根据自己在context-param中配置的参数进行修改,路径不对,将找不到spring配置文件),创建applicationContext.xml文件。
  创建LoginService接口:

package com.xxx.service;

public interface LoginService {
    String doLogin(String userName,String password);
}

  创建LoginServiceImpl类:

package com.xxx.service;

import com.opensymphony.xwork2.ActionSupport;

public class LoginServiceImpl implements LoginService{
    
    private String userName = "xxx";
    private String password = "123456";

    @Override
    public String doLogin(String userName, String password) {
        if (this.userName.equals(userName) && this.password.equals(password)) {
            return ActionSupport.SUCCESS;
        }
        return ActionSupport.ERROR;
    }

}

  修改LoginAction类:

package com.xxx.action;

import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.ActionSupport;
import com.xxx.service.LoginService;

public class LoginAction extends ActionSupport{

    private String userName;
    private String password;
    private LoginService loginService;
    
    
    
    
    public LoginService getLoginService() {
        return loginService;
    }


    public void setLoginService(LoginService loginService) {
        this.loginService = loginService;
    }


    public String getUserName() {
        return userName;
    }


    public void setUserName(String userName) {
        this.userName = userName;
    }


    public String getPassword() {
        return password;
    }


    public void setPassword(String password) {
        this.password = password;
    }


    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    

    @Override
    public String execute() throws Exception {
        return loginService.doLogin(userName, password);
    }

}

  最终的项目结构:


image.png

  现在开始配置spring:在applicationContext中配置bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="loginService" class="com.xxx.service.LoginServiceImpl"/>
    
    <bean id="loginAction" scope="prototype" class="com.xxx.action.LoginAction">
        <property name="loginService" ref="loginService"></property>
    </bean>

</beans>

  修改struts配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <!-- <constant name="struts.objectFactory" value="spring" />
    <constant name="struts.devMode" value="true" /> -->
    <package name="xxx" extends="struts-default" namespace="/">
        <action name="login" class="loginAction">
            <result name="success">/WEB-INF/content/success.jsp</result>
            <result name="error">/WEB-INF/content/error.jsp</result>
        </action>
    </package>
</struts>    


主要的变化是:login这个action的class属性改成了在applicationContext中的id。这样action的实例的创建将交由spring来管理。
  到这里就结束了吗?当然不是,我们忘了一件重要的事。在整合的过程中还要加入一个重要的库struts2-spring-plugin-2.5.14.1.jar,加入方法还是拷贝到WEB-INF/lib下,并加入到build path(注意:这个库的版本一定要和struts的版本一致,否则可能出错)。好了,到这里就可以运行程序了。如果在登录页面输入用户名xxx密码123456能成功实现“登录”功能,那么整合就基本实现了。
  在这里再补充一点,如果按照刚才的配置,应该会出现一个ERRO,意思是说没有导入log4j。log4j这个包负责打印日志,对调试程序很有帮助。导入这个包也比较简单,首先导入log4j的jar包:

image.png

log4j的包自己网上找一下,这里不多说。
然后在src下创建log4j2.xml文件,用于配置log4j:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/2002/xmlspec/dtd/2.10/xmlspec.dtd">
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p] %d %c - %m%n" />
        </Console>
        <File name="File" fileName="dist/my.log">
            <PatternLayout pattern="%m%n" />
        </File>
    </Appenders>

    <Loggers>
        <Logger name="mh.sample2.Log4jTest2" level="DEBUG">
            <AppenderRef ref="File" />
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>  

重启应用,如果那个ERRO消失了,那么log4j就配置成功了,如果还是有那个错误,就要根据错误提示,检查错误可能是什么原因引起的。

整合Hibernate

  到这里真不容易,已经过半了,再坚持一下。该项目已经整合了spring+struts,现在将hibernate也整合进来就大功告成!
  首先还是下载hibernate,下载地址(http://hibernate.org/orm/releases/5.2/),点击最右侧的Download zip archive下载。
  解压后将...\hibernate-release-5.2.12.Final\hibernate-release-5.2.12.Final\lib\required目录下的全部jar包拷贝到WEB-INF/lib目录下,并且都添加到build path中。
  将...\hibernate-release-5.2.12.Final\hibernate-release-5.2.12.Final\lib\optional\c3p0目录下的所有jar文件拷贝到WEB-INF/lib下,并添加都build path。
  在这里,不要忘了还有两个需要导入的jar包。一个是AspectJ包,下载地址:https://www.eclipse.org/aspectj/downloads.php。Spring的AOP需要依赖这个包。另外一个是MySql的驱动JDBC Driver for MySQL ,下载地址:https://www.mysql.com/products/connector/
  安装MySql,此处不做相信说明,自行百度。
  在MySql的test数据库下创建tb_employee表,通过下面的sql创建

CREATE TABLE `tb_employee` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `firstName` varchar(32) NOT NULL DEFAULT '',
  `lastName` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8

  创建com.xxx.dao包,创建BaseDao接口:

package com.xxx.dao;

import java.io.Serializable;
import java.util.List;

public interface BaseDao<T> {

    /**
     * 根据实体加载数据
     * @param entityClazz
     * @param id
     * @return
     */
    T get(Class<T> entityClazz,Serializable id);
    /**
     * 保存实体
     * @param entity
     * @return
     */
    Serializable save(T entity);
    /**
     * 更新实体
     * @param entity
     */
    void update(T entity);
    /**
     * 删除实体
     * @param entity
     */
    void delete(T entity);
    /**
     * 根据ID删除实体
     * @param entityClazz
     * @param id
     */
    void delete(Class<T> entityClazz,Serializable id);
    /**
     * 获取所有实体
     * @param entityClazz
     * @return
     */
    List<T> findAll(Class<T> entityClazz);
    /**
     * 获取实体总数
     * @param entityClazz
     * @return
     */
    long findCount(Class<T> entityClazz);
}

  创建BaseDaoHibernate3

package com.xxx.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;

public class BaseDaoHibernate3<T> implements BaseDao<T> {
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public T get(Class<T> entityClass, Serializable id) {
        return getSessionFactory().getCurrentSession().get(entityClass, id);
    }

    @Override
    public Serializable save(T entity) {
        SessionFactory sf = getSessionFactory();
        @SuppressWarnings("unused")
        Session s = sf.getCurrentSession();
        return getSessionFactory().getCurrentSession().save(entity);
    }

    @Override
    public void update(T entity) {
        getSessionFactory().getCurrentSession().update(entity);
    }

    @Override
    public void delete(T entity) {
        getSessionFactory().getCurrentSession().delete(entity);
    }

    @Override
    public void delete(Class<T> entityClass, Serializable id) {
        getSessionFactory().getCurrentSession()
                .createQuery("delet " + entityClass.getSimpleName() + " en where en.id=?0").setParameter(0, id)
                .executeUpdate();
    }

    @Override
    public List<T> findAll(Class<T> entityClass) {
        return (List<T>) find("select en from " + entityClass.getSimpleName() + " en");
    }

    @SuppressWarnings("unchecked")
    @Override
    public long findCount(Class<T> entityClass) {
        List<Long> list = (List<Long>) find("select count(*) from " + entityClass.getSimpleName() + " en");

        if (list != null && list.size() == 1) {
            return (long) list.get(0);
        }
        return 0;
    }

    /**
     * 分页查询
     * 
     * @param hql
     * @param pageNo
     * @param pageSize
     * @return
     */
    @SuppressWarnings("unchecked")
    protected List<T> findBypage(String hql, final int pageNo, final int pageSize) {
        List<T> list = getSessionFactory().getCurrentSession().createQuery(hql).setFirstResult((pageNo - 1) * pageSize)
                .setMaxResults(pageSize).list();

        return list;

    }

    /**
     * 带占位符的分页查询
     * 
     * @param hql
     * @param pageNo
     * @param pageSize
     * @param params
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected List<T> findBypage(String hql, int pageNo, int pageSize, Object... params) {
        Query query = getSessionFactory().getCurrentSession().createQuery(hql);

        for (int i = 0; i < params.length; i++) {
            query.setParameter(i, params[i]);
        }
        return query.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
    }

    @SuppressWarnings("unchecked")
    protected List<T> find(String hql) {
        return getSessionFactory().getCurrentSession().createQuery(hql).list();

    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected List<T> find(String hql, Object... paramas) {
        Query query = getSessionFactory().getCurrentSession().createQuery(hql);
        for (int i = 0; i < paramas.length; i++) {
            query.setParameter(i, paramas[i]);
        }

        return query.list();
    }
}

  创建BaseDaoHibernate4

package com.xxx.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

public class BaseDaoHibernate4<T> extends HibernateDaoSupport implements BaseDao<T>{
    


    @Override
    public T get(Class<T> entityClass, Serializable id) {
        return getHibernateTemplate().get(entityClass, id);
    }

    @Override
    public Serializable save(T entity) {
        return getHibernateTemplate().save(entity);
    }

    @Override
    public void update(T entity) {
        getHibernateTemplate().update(entity);
    }

    @Override
    public void delete(T entity) {
        getHibernateTemplate().delete(entity);
    }

    @Override
    public void delete(Class<T> entityClass, Serializable id) {
        getHibernateTemplate().delete(get(entityClass, id));
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll(Class<T> entityClass) {
        return (List<T>) getHibernateTemplate().find("select en from " + entityClass.getSimpleName() + " en");
    }

    @SuppressWarnings("unchecked")
    @Override
    public long findCount(Class<T> entityClass) {
        List<Long> list = (List<Long>) getHibernateTemplate().find("select count(*) from " + entityClass.getSimpleName()+" en");
        
        if (list != null && list.size() == 1) {
            return (long) list.get(0);
        }
        return 0;
    }


    /**
     * 分页查询
     * 
     * @param hql
     * @param pageNo
     * @param pageSize
     * @return
     */
    @SuppressWarnings("unchecked")
    protected List<T> findBypage(final String hql,final int pageNo,final int pageSize) {
        List<T> list =  getHibernateTemplate().execute(new HibernateCallback<List<T>>() {

            @Override
            public List<T> doInHibernate(Session session) throws HibernateException {
                List<T> result = session.createQuery(hql).setFirstResult((pageNo - 1) * pageSize)
                .setMaxResults(pageSize).list();
                return result;
            }
        });

        return list;

    }

    /**
     * 带占位符的分页查询
     * 
     * @param hql
     * @param pageNo
     * @param pageSize
     * @param params
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected List<T> findBypage(final String hql, final int pageNo, final int pageSize, final Object... params) {
        List<T> list = getHibernateTemplate().execute(new HibernateCallback<List<T>>() {

            @Override
            public List<T> doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(hql).setFirstResult((pageNo - 1)*pageSize)
                        .setMaxResults(pageSize);
                
                for (int i = 0; i < params.length; i++) {
                    query.setParameter(i, params[i]);
                }
                 List<T> result = query.list();
                return result;
            }
        });
        return list;
    }
}

  创建实体类Employee

package com.xxx.dao;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "tb_employee")
public class Employee {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    @Column(name = "firstName")
    private String firstName;
    @Column(name = "lastName")
    private String lastName;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

 emsp;创建EmployeeDao

package com.xxx.dao;

public interface EmployeeDao extends BaseDao<Employee>{

}

这个接口看似没用,其实暗藏玄机。如果EmployeeDao 有它特定的业务时,可以写在这个接口中,一方面满足面向接口编程的原则,一方面又不污染BaseDao接口。
  创建EmployeeDaoHibernate

package com.xxx.dao;


public class EmployeeDaoHibernate extends BaseDaoHibernate3<Employee> implements EmployeeDao{
    
}
 

项目结构截图:


image.png

  BaseDaoHibernate3和BaseDaoHibernate4是两种不同是实现,更推荐前者,因为前者的代码污染更小。
  现在来添加一个Action:EmployeeAction。用于响应添加Employee请求。

package com.xxx.action;


import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionSupport;
import com.xxx.dao.Employee;
import com.xxx.service.EmployeeService;

public class EmployeeAction extends ActionSupport {
    @Autowired
    private EmployeeService employeeService;
    private String firstName, lastName;
    private Employee employee;
    

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public EmployeeService getEmployeeService() {
        return employeeService;
    }

    public void setEmployeeService(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    /**
     * 
     */
    private static final long serialVersionUID = -8442995807620521709L;

    @Override
    public String execute() throws Exception {
        Employee employee = new Employee();
//      System.out.println(firstName+lastName);
        employee.setFirstName(firstName);
        employee.setLastName(lastName);
        employeeService.add(employee);
//      System.out.println(id);
        return super.execute();
    }
}

  这个action中真正进行数据存储的是EmployeeService,于是接着创建EmployeeService接口和实现类,实现添加和获取两个方法:
EmployeeService

package com.xxx.service;

import java.io.Serializable;

import com.xxx.dao.Employee;

public interface EmployeeService {
    Serializable add(Employee employee);
    Employee get(Serializable id);
}

EmployeeServiceImpl

package com.xxx.service;

import java.io.Serializable;

import com.xxx.dao.Employee;
import com.xxx.dao.EmployeeDao;

public class EmployeeServiceImpl implements EmployeeService {
    private EmployeeDao employeeDao;
    
    

    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }

    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }

    public Serializable add(Employee employee) {
        return employeeDao.save(employee);
    }

    public Employee get(Serializable id) {
        return employeeDao.get(Employee.class, id);
    }

}

  好了,代码已写完,下面就来配置。
  首先配置applicationContext:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!--基于 <tx> 和 <aop> 命名空间的声明式事务 -->
    <!-- 配置事务传播特性 -->
    <tx:advice id="TestAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"
                timeout="5" />
        </tx:attributes>
    </tx:advice>

    <tx:annotation-driven />

    <!-- 配置参与事务的类 -->
    <aop:config>
        <aop:pointcut id="allTestServiceMethod" expression="bean(employeeService)" />
        <aop:advisor pointcut-ref="allTestServiceMethod"
            advice-ref="TestAdvice" />
    </aop:config>




    <!-- *********************************************************** -->

    <!-- hibernate 配置 -->
    <!-- 定义数据源bean 使用c3p0数据源 并注入相关参数 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" p:driverClass="com.mysql.jdbc.Driver"
        p:jdbcUrl="jdbc:mysql://localhost/test?useSSL=false" p:user="root"
        p:password="194061" p:maxPoolSize="40" p:minPoolSize="2"
        p:initialPoolSize="2" p:maxIdleTime="30" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
        p:dataSource-ref="dataSource">

        <!--annotateClasses用来列出所有持久化类 -->
        <property name="annotatedClasses">
            <list>
                <value>com.xxx.dao.Employee</value>
            </list>
        </property>

        <!-- 定义hibernate sessionFactory的属性 -->
        <property name="hibernateProperties">
            <props>
                <!-- 定义hibernate方言 -->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <!-- 是否根据hibernate映射创建数据表 -->
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
    </bean>
    <!-- ************************************************************* -->


    <bean id="employeeService" class="com.xxx.service.EmployeeServiceImpl"
        scope="prototype">
        <property name="employeeDao" ref="employeeDao"></property>
    </bean>

    <bean id="employeeDao" class="com.xxx.dao.EmployeeDaoHibernate">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    
    <bean id="employeeAction" scope="prototype" class="com.xxx.action.EmployeeAction">
        <property name="employeeService" ref="employeeService"></property>
    </bean>

    <bean id="loginService" class="com.xxx.service.LoginServiceImpl" />

    <bean id="loginAction" scope="prototype" class="com.xxx.action.LoginAction">
        <property name="loginService" ref="loginService"></property>
    </bean>

</beans>

  配置struts.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <!-- <constant name="struts.objectFactory" value="spring" /> <constant name="struts.devMode" 
        value="true" /> -->
    <package name="xxx" extends="struts-default" namespace="/">
        <action name="login" class="loginAction">
            <result name="success">/WEB-INF/content/success.jsp</result>
            <result name="error">/WEB-INF/content/error.jsp</result>
        </action>

        <action name="employee" class="employeeAction">
            <result name="success">/WEB-INF/content/success.jsp</result>
            <result name="error">/WEB-INF/content/error.jsp</result>
        </action>
    </package>
</struts>    

  在login.jsp中添加一个表单用于测试hibernate整合是否成功:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'login.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">

  </head>
  
  <body>
    <form action="login.action">
        用户名:<input type="text" name="userName"><br>
        密码: <input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>
  </body>
  <br>
  <form action="employee.action">
    FristName:<input type="text" name="firstName"/> <br>
    LastName:<input type="text" name="lastName"><br>
    <input type="submit" value="add">
  </form>
</html>

  到这里就算整合成功了,最后的项目结构如图:


image.png
image.png

  启动服务器,输入firstName、lastName,点击add会跳转到成功页面,打开MySQL Workbench查看tb_employee表的记录可以看到已添加的数据:

image.png

最后附上项目下载地址:https://github.com/xudefei/WebTest

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容