12.Spring + Hibernate + Struts2



故事Struts的公司,在开发了Struts1之后,一直发展到大概Struts1.4,struts

与webwork的开发团队合并的原因,然后才开发了Struts2.x系列,因为struts2实质上

是得益于webwork的架构,而不是源于struts1。




一.Spring + Hibernate


导入双方的包:这个不做多提,前面Spring + Hibernate + Struts 有。




设计实体类(表):

package com.zyy.bean;


public class Person {

    private Integer id;

    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


实体类对应的配置文件(Person.hbm.xml):

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zyy.bean">

    <class name="com.zyy.bean.Person">
    <!-- 配置ehcache缓存 -->
    <cache usage="read-write" region="com.zyy.service.Person"></cache>
        <id name="id">
            <generator class="native"></generator>
        </id>

        <property name="name"></property>

    </class>

</hibernate-mapping>


创建对应的ehcache缓存配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    defaultCache节点为缺省的缓存策略
     maxElementsInMemory 内存中最大允许存在的对象数量
     eternal 设置缓存中的对象是否永远不过期
     overflowToDisk 把溢出的对象存放到硬盘上
     timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉
     timeToLiveSeconds 指定缓存对象总的存活时间
     diskPersistent 当jvm结束是是否持久化对象
     diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间
 -->
<ehcache>
    <diskStore path="D:\cache"/>
    <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true"
                  timeToIdleSeconds="120"
                  timeToLiveSeconds="180"
                  diskPersistent="false"
                  diskExpiryThreadIntervalSeconds="60"/>
    <cache name="com.zyy.service.Person" maxElementsInMemory="100" eternal="false"
           overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" diskPersistent="false"/>
</ehcache>


然后配置Spring的beans.xml:

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

    <!-- 配置自动扫描bean 包含注解 -->
    <context:component-scan base-package="com.zyy.service"></context:component-scan>
    <context:component-scan base-package="com.zyy.control"></context:component-scan>


    <!-- 配置AOP -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>


    <!-- 配置资源文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="${dataSource}" destroy-method="close">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <!-- 连接池启动时的初始值 -->
        <property name="initialSize" value="${initialSize}"/>
        <!-- 连接池的最大值 -->
        <property name="maxActive" value="${maxActive}"/>
        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
        <property name="maxIdle" value="${maxIdle}"/>
        <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
        <property name="minIdle" value="${minIdle}"/>
    </bean>


    <!-- 配置Hibernate二级缓存 -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>com/zyy/bean/Person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
                hibernate.hbm2ddl.auto=update
                hibernate.show_sql=false
                hibernate.format_sql=false

                <!-- 配置hibernate二级缓存 -->
                hibernate.cache.use_second_level_cache=true
                <!-- 不配置查询缓存 -->
                hibernate.cache.use_query_cache=false
                <!-- 配置EhCache -->
                hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider

            </value>
        </property>
    </bean>

    <!-- 配置事务 -->
    <!-- 这里使用Spring的bean和Spring对Hibernate支持的HibernateTransactionManager -->
    <!-- 属性注入的是Hibernate的二级缓存 -->
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- 打开事务注解的支持 -->
    <tx:annotation-driven transaction-manager="txManager"/>


</beans>


创建beans.xml所需的资源文件jdbc.properties:

dataSource = org.apache.commons.dbcp.BasicDataSource

driverClassName = org.gjt.mm.mysql.Driver

url = jdbc:mysql://localhost:3306/ceshi_1?useUnicode=true&characterEncoding=UTF-8

username = root

password = root

initialSize = 1

maxActive = 500

maxIdle = 2

minIdle = 1



建立数据库操作的 接口实现bean 


PersonService

package com.zyy.service;

import com.zyy.bean.Person;

import java.util.List;


public interface PersonService {

    /**
     * 保存对象
     *
     * @param peroson
     */
    public void save(Person peroson);

    /**
     * 更新对象
     *
     * @param peroson
     */
    public void update(Person peroson);

    /**
     * 删除单个对象
     *
     * @param personId
     */
    public void delete(Integer personId);

    /**
     * 取得单个对象
     *
     * @return
     */
    public Person getPerson(Integer personId);

    /**
     * 取得全部对象
     *
     * @return
     */
    public List<Person> getPersons();


}


PersonServiceBean

package com.zyy.service.impl;

import com.zyy.bean.Person;
import com.zyy.service.PersonService;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


@Service("personService")
@Transactional
public class PersonServiceBean implements PersonService {


    /**
     * 将Autowired转换为按 名称匹配
     * 就加上 @Qualifier("sessionFactory")
     * 按名称查找sessionFactory 为名字的bean
     */

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    public void save(Person peroson) {

        this.sessionFactory.getCurrentSession().persist(peroson);

    }

    public void update(Person peroson) {

        this.sessionFactory.getCurrentSession().merge(peroson);

    }

    public void delete(Integer personId) {

        this.sessionFactory.getCurrentSession().delete(
                this.sessionFactory.getCurrentSession().load(Person.class, personId));

    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Person getPerson(Integer personId) {

        return (Person) this.sessionFactory.getCurrentSession().get(Person.class, personId);

    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<Person> getPersons() {

        //from 类名   不是from 数据库里的表名
        //noinspection JpaQlInspection
        String hql = "from Person";

        return this.sessionFactory.getCurrentSession().createQuery(hql).list();


    }
}



在类路径(src)下可选择性添加: 

log4j.properties

log4j.rootLogger=WARN, Console

log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=(%r ms) [%t] %-5p: %c#%M %x: %m%n

log4j.logger.com.genuitec.eclipse.sqlexplorer=DEBUG
log4j.logger.org.apache=WARN
log4j.logger.org.hibernate=WARN



最后编写一个junit4.4测试类,进行测试:

package test.com.zyy.service.impl;

import com.zyy.bean.Person;
import com.zyy.service.PersonService;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * PersonServiceBean Tester.
 *
 * @author <Authors name>
 * @version 1.0
 */
public class PersonServiceBeanTest {


    private PersonService personService;

    @Before
    public void before() throws Exception {


        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");

        this.personService = (PersonService) applicationContext.getBean("personService");


    }

    @After
    public void after() throws Exception {
    }

    /**
     * Method: save(Person peroson)
     */
    @Test
    public void testSave() throws Exception {

        this.personService.save(new Person("CaMnter_SSH_save"));

        for (int i = 0; i < 15; i++) {

            this.personService.save(new Person("CaMnter_SSH_save_" + i));

        }


    }

    /**
     * Method: update(Person peroson)
     */
    @Test
    public void testUpdate() throws Exception {

        Person person = new Person("CaMnter_SSH_update");

        person.setId(4);

        this.personService.update(person);

    }

    /**
     * Method: delete(Integer personId)
     */
    @Test
    public void testDelete() throws Exception {

        this.personService.delete(6);

    }

    /**
     * Method: getPerson(Integer personId)
     */
    @Test
    public void testGetPerson() throws Exception {

        Person person = this.personService.getPerson(7);

        System.out.println("id: " + person.getId() + "    name: " + person.getName());

    }

    /**
     * Method: getPersons()
     */
    @Test
    public void testGetPersons() throws Exception {

        for (Person person : this.personService.getPersons()) {
            System.out.println("id: " + person.getId() + "    name: " + person.getName());
        }


    }

    @Test
    public void testCache() {

        Person person = this.personService.getPerson(7);

        System.out.println("id: " + person.getId() + "    name: " + person.getName());

        try {
            Thread.sleep(1000 * 7);

            System.out.println("请关闭Mysql数据库");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("第二次获取");

        person = this.personService.getPerson(7);

        System.out.println("id: " + person.getId() + "    name: " + person.getName());


    }


} 



这里,我就测试了getPersons()方法:




如上,成了搭建 Spring + HIbernate








二. Spring + Hibernate + Struts2


在类路径(src)下创建一个struts.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。
     如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 -->
    <constant name="struts.action.extension" value="action"/>
    <!-- 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 -->
    <constant name="struts.serve.static.browserCache" value="false"/>
    <!-- 当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 -->
    <constant name="struts.configuration.xml.reload" value="true"/>
    <!-- 开发模式下使用,这样可以打印出更详细的错误信息 -->
    <constant name="struts.devMode" value="true"/>
    <!-- 默认的视图主题 -->
    <constant name="struts.ui.theme" value="simple"/>

    <!-- 这里才是真正的Struts2.x把action交付给Spring容器管理 -->
    <!-- 配置Action类 由Spring负责创建 -->
    <constant name="struts.objectFactory" value="spring"/>


    <package name="person" namespace="/person" extends="struts-default">
        <global-results>
            <result name="message">/WEB-INF/jsp/message.jsp</result>
        </global-results>
        <action name="action_*" class="personList" method="{1}">

            <!-- 相当于struts1.x中的forward -->
            <result name="list">/WEB-INF/jsp/personlist.jsp</result>
            <result name="add">/WEB-INF/jsp/add_person.jsp</result>

        </action>
    </package>
</struts>


其中:

1.<constant name="struts.objectFactory" value="spring"/>  这里才是真正的

  Struts2.x把action交付给Spring容器管理,相当于struts1.x在配置文件中定义一个

  Spring 的controller一样交付Sping容器管理。


2.这里定义了一个package,所以想访问package里的action的话需要加上package的namespace

  即 /person。


3.action里定义了一个class,这个就是action要交付给Spring管理时,Spring用注解

  命名必须与这个class保持一致,即personList。


4.<action name="action_*" class="personList" method="{1}">如果想访问

  action 就必须加上package 的namespace 和action 的name。即 /person/action_*。

  这里用*指定了一个占位符,后面的method={1},提醒了第一个*表示的是方法的名字,由此可

  得访问路径最终为:/person/action_(action中的方法名)。




由于Struts2的配置文件需求,在WEB-INF下创建JSP文件夹,再分别建立personlist.jsp、

message.jsp、add_person.jsp:



personlist.jsp

<%--
  Created by IntelliJ IDEA.
  User: CaMnter
  Date: 2014/8/23
  Time: 0:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title></title>
  </head>
  <body>

    <s:iterator value="persons" >

        <h4>id=<s:property value="id"></s:property>   name=<s:property value="name"></s:property></h4>

    </s:iterator>

  </body>
</html>



add_person.jsp

<%--
  Created by IntelliJ IDEA.
  User: CaMnter
  Date: 2014/8/23
  Time: 0:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title></title>
  </head>
  <body>

    <s:form action="action_add" namespace="/person">

        名称:<s:textfield name="person.name"></s:textfield>
        <input type="submit" value="添加">

    </s:form>

  </body>
</html>





message.jsp


<%--
  Created by IntelliJ IDEA.
  User: CaMnter
  Date: 2014/8/23
  Time: 0:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title></title>
  </head>
  <body>

     <s:property value="message"></s:property>

  </body>
</html>




接下来我们设计一个符合@Service("personList") - > 与action中的class保

持一致的Action :



package com.zyy.control.action;

import com.zyy.bean.Person;
import com.zyy.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 交给Spring管理的 Struts1.x 的action 必须与配置文件的 action 中的path一致
 *
 * 但是
 * 
 * 交给Spring管理的 Struts2.x 的action 必须与配置文件的 action 中的class一致
 */
@Service("personList")
@Transactional
public class PersonAction {

    @Autowired
    @Qualifier("personService")
    private PersonService personService;

    private String message;

    private List<Person> persons;

    private Person person;


    /**
     * 人员列表显示
     *
     * @return
     */
    public String list() {

        this.persons = this.personService.getPersons();

        //返回到 result 的path上
        return "list";

    }

    /**
     * 人员添加界面
     *
     * @return
     */
    public String addUI() {

        return "add";

    }

    /**
     * 人员添加
     *
     * @return
     */
    public String add() {

        this.personService.save(this.person);

        this.message = "添加成功";

        return "message";

    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


以上:

1.每个方法的名字都可以表示配置文件中action_*里面的*的内容。例如:action_list、

  action_addUI、action_add,都可以。不过切记,别忘了后缀.action,当然也可以

  改为.do,这需要修改Strut2.x的配置文件。


2.return “String” ,这里的String 表示的是action的子节点result的name属性。

  这就好比,是返回了一个ActionMapping,在Struts1.x里是需要找到forward的name

  只不过Struts2.x简化了操作,十分类似,你只要以String的形式直接返回,result的name

  就相当于执行ActionMapping,Struts2.x对Action和ActionMapping进行了封装,所

  以简化了操作


3.注解@Service("personList")指定Action的名字时,必须和 action 的 class名字保持一致


4.Action里属性的名字,对应的各个页面的表单提交过来或者响应出去的数据的类型和名字,

  别是名字必须保持一致。

  譬如<1>.执行了list()方法后,返回result中的“list”,封装成ActionMapping

           后跳转到personlist.jsp,Action的private List<Person> persons

           与其打印的persons对应;

       <2>. 执行了add()方法后,返回result中的“message”,封装成ActionMapping

            后跳转到message.jsp,Action的private String message与其打印的

            message对应;



最后,再修改WEB-INF下的web.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- 指定spring的配置文件,默认从web根目录寻找配置文件,我们可以通过spring提供的classpath:前缀指定从类路径下寻找 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:beans.xml</param-value>
    </context-param>


    <!-- 对Spring容器进行实例化 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 使用spring解决hibernate因session关闭导致的延迟加载例外问题 -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置struts2 -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


</web-app>


这里,其实和SH+Struts1.x混搭基本一样,只不过这里配置的是Struts2.x。







三.测试


输入:http://localhost:8080/SSH2/person/action_list.action


这里,上面已经反复强调过了:/person = pageage的namespace、/action_list =

 action_*,这里的list是PersonAction里的方法list(),用list指明了*的内容,所

以是/action_list。struts2.x的后缀不是.do ,是.actin 。当然在struts2.x的配

置文件中可以进行修改。





由于PersonAction中有一个addUI方法。所以输入:http://localhost:8080/SSH2

/person/action_addUI.action。


























四.总结(对以上内容和SH+Struts2搭建的心得)


1.Spring + Hibernate + Struts2.x 比 Spring + Hibernate + Struts1.x  简

  化了很多操作,没了ActiomForm,优化了Action的代码,使得Action变成了POJO类型的类。


2.切记访问路径的设置,与package的namespace 和 action的name 息息相关,一定要加上

  namespace/action的name,这里namespace 一定要有前缀/,然后根据action的name是

  否有*,并在跳转的时候指定对应的方法名字,最后再加上Struts2.x的后缀.action,也可以

  通过更改Struts2.x配置文件改为.do。


3.Struts2.x的Action交付给Spring容器管理的时候,注解@Service("***")指定Action的

  名字时,必须和 action 的 class名字保持一致。


4.切记,在Struts2.x配置文件中,真正意义上起到Struts2.x把action交付给Spring容器管理

  作用的是<constant name="struts.objectFactory" value="spring"/>


5.Action中方法返回的String类型,就必须是result其中一个的name的值,这里优化了Action跳

  转时的操作,String返回后,根据String的值生成ActionMapping后,就可以跳转了。


6.Action里属性的名字,对应的各个页面的表单提交过来或者响应出去的数据的类型和名字,

  别是名字必须保持一致。

  譬如<1>.执行了list()方法后,返回result中的“list”,封装成ActionMapping

           后跳转到personlist.jsp,Action的private List<Person> persons

           与其打印的persons对应;

       <2>. 执行了add()方法后,返回result中的“message”,封装成ActionMapping

            后跳转到message.jsp,Action的private String message与其打印的

            message对应;


7.虽然开始有点不适应,因为代码优化的原因,但是建议多多使用SH+Struts2.x。 Struts2.x

  和 Struts1.x 关系很小,Struts2是以Webwork的设计思想为核心,吸收了Struts1的优点

  因此,可以认为Struts2是Struts1和Webwork。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值