SSH开发环境搭建

Posted qlqwjy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SSH开发环境搭建相关的知识,希望对你有一定的参考价值。

  断断续续学习hibernate也有一段时间了,在这里研究一下SSH开发环境的搭建过程,自己简单的搭建一个SSH的开发环境。采用maven搭建。

0.项目结构:

技术分享图片

 

 

1.导包:(maven项目)

 pom.xml配置文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.qlq</groupId>
    <artifactId>SSHWeb</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <!-- 声明变量,下面用类似于el表达式提取 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <spring.version>4.2.4.RELEASE</spring.version>
        <mysql.version>5.1.37</mysql.version>
        <aspectj.version>1.6.10</aspectj.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- spring 依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- myql 依赖包 -->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.0.7.Final</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-convention-plugin</artifactId>
            <version>2.3.24</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>2.3.24</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-json-plugin</artifactId>
            <version>2.3.24</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-spring-plugin</artifactId>
            <version>2.3.24</version>
        </dependency>
        <!-- slf4j 依赖包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.0-rc1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.0-rc1</version>
        </dependency>
    </dependencies>

    <build>
        <!-- 配置了很多插件 -->
        <plugins>

            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- tomcat7插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>80</port>
                    <path>/ssh</path>
                    <uriEncoding>UTF-8</uriEncoding>
                    <server>tomcat7</server>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

 

 2.配置文件介绍:

1.db.properties和log4j.properties

hibernate.dialect=org.hibernate.dialect.MySQLDialect
driverClassName=com.mysql.jdbc.Driver
validationQuery=SELECT 1
url=jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=UTF-8
username=sa
password=123456


hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.format_sql=true

 

 

log4j.rootLogger=debug,A,B

log4j.appender.A=org.apache.log4j.ConsoleAppender
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.Threshold=info
log4j.appender.B.File=E:\\ssh.log
log4j.appender.B.MaxFileSize=10MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

 

 1.spring相关配置文件:

 spring.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"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">

    <!-- 引入属性文件 -->
    <context:property-placeholder location="classpath:db.properties" />

    <!-- 自动扫描dao和service包(自动注入) -->
    <context:component-scan base-package="cn.qlq" />
    
</beans>

 

spring-hibernate.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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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-3.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    ">
    <!-- 使用C3P0数据源,MySQL数据库 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <!-- MySQL5 -->
        <property name="driverClass" value="${driverClassName}"></property>
        <property name="jdbcUrl" value="${url}"></property>
        <property name="user" value="${username}"></property>
        <property name="password" value="${password}"></property>
        <property name="maxPoolSize" value="40"></property>
        <property name="minPoolSize" value="1"></property>
        <property name="initialPoolSize" value="1"></property>
        <property name="maxIdleTime" value="20"></property>
    </bean>

    <!-- session工厂 -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocations" value="classpath:hibernate.cfg.xml"></property>
        <property name="packagesToScan" value="cn.qlq.domain" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>

    <!-- 配置事务 -->
    <bean name="txManager"
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />

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

</beans>

 

2.struts.xml

  配置一些常量,采用注解开发。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <constant name="struts.i18n.encoding" value="utf-8"></constant>
    <constant name="devMode" value="true"></constant>
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <constant name="" value="true" />
    <!-- 配置拦截的后缀 -->
    <constant name="struts.action.extension" value="action,do" />
    <!-- 与spring整合 -->
    <constant name="struts.objectFactory" value="spring"></constant>
    <package name="default" extends="json-default"></package>


</struts>

 

3.hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <mapping resource="cn/qlq/domain/Customer.hbm.xml" />
        <mapping resource="cn/qlq/domain/LinkMan.hbm.xml" />
    </session-factory>
</hibernate-configuration>

 

 4.web.xml

  spring监听器、配置文件路径、hibernate会话过滤器(一次请求前开启session,请求完成关闭session)、struts入口过滤器(注意hibernate打开会话过滤器必须配置在struts入口前面)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <display-name>ssh</display-name>

    <!-- Spring ApplicationContext配置文件的路径,可使用通配符,多个路径用,号分隔 此参数用于后面的Spring Context 
        Loader -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml,classpath:spring-hibernate.xml</param-value>
    </context-param>

    <!-- spring 监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Filter 定义 -->
    <!-- Character Encoding filter -->
    <filter>
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--Hibernate的session丢失解决方法 -->
    <filter>
        <filter-name>openSessionInView</filter-name>
        <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInView</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- struts2 filter -->
    <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>


    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

 

 

 3.接下来就是测试代码:

 0.实体类以及xml配置文件

 Customer.java

package cn.qlq.domain;

import java.util.HashSet;
import java.util.Set;

public class Customer {
    private Long cust_id;
    
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;
    //使用set集合,表达一对多关系
    private Set<LinkMan> linkMens = new HashSet<LinkMan>();
    public Set<LinkMan> getLinkMens() {
        return linkMens;
    }
    public void setLinkMens(Set<LinkMan> linkMens) {
        this.linkMens = linkMens;
    }
    public Long getCust_id() {
        return cust_id;
    }
    public void setCust_id(Long cust_id) {
        this.cust_id = cust_id;
    }
    public String getCust_name() {
        return cust_name;
    }
    public void setCust_name(String cust_name) {
        this.cust_name = cust_name;
    }
    public String getCust_source() {
        return cust_source;
    }
    public void setCust_source(String cust_source) {
        this.cust_source = cust_source;
    }
    public String getCust_industry() {
        return cust_industry;
    }
    public void setCust_industry(String cust_industry) {
        this.cust_industry = cust_industry;
    }
    public String getCust_level() {
        return cust_level;
    }
    public void setCust_level(String cust_level) {
        this.cust_level = cust_level;
    }
    public String getCust_linkman() {
        return cust_linkman;
    }
    public void setCust_linkman(String cust_linkman) {
        this.cust_linkman = cust_linkman;
    }
    public String getCust_phone() {
        return cust_phone;
    }
    public void setCust_phone(String cust_phone) {
        this.cust_phone = cust_phone;
    }
    public String getCust_mobile() {
        return cust_mobile;
    }
    public void setCust_mobile(String cust_mobile) {
        this.cust_mobile = cust_mobile;
    }
    @Override
    public String toString() {
        return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
    }
    
    public Customer(Long cust_id, String cust_name) {
        super();
        this.cust_id = cust_id;
        this.cust_name = cust_name;
    }
    public Customer() {
    }    

}

 

 

Customer.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.qlq.domain" >
    <class name="Customer" table="cst_customer">
        <id name="cust_id"  >
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name" >
        </property>
        <property name="cust_source" column="cust_source" ></property>
        <property name="cust_industry" column="cust_industry" ></property>
        <property name="cust_level" column="cust_level" ></property>
        <property name="cust_linkman" column="cust_linkman" ></property>
        <property name="cust_phone" column="cust_phone" ></property>
        <property name="cust_mobile" column="cust_mobile" ></property>
    
    <!-- 
        lazy属性: 决定是否延迟加载
            true(默认值): 延迟加载,懒加载
            false: 立即加载
            extra: 极其懒惰
        fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据
            select(默认值): 单表查询加载
            join: 使用多表查询加载集合
            subselect:使用子查询加载集合
     -->
     <!-- batch-size: 5   抓取集合的数量为5.
             抓取客户的集合时,一次抓取几个客户的联系人集合.
      -->
        <set name="linkMens" batch-size="5">
            <key column="lkm_cust_id" ></key>
            <one-to-many class="LinkMan" />
        </set>
    </class>
</hibernate-mapping>

 

 

 

 

LinkMan.java

package cn.qlq.domain;

//联系人实体
public class LinkMan {
    private Long lkm_id;
    private Character lkm_gender;
    private String lkm_name;
    private String lkm_phone;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_mobile;
    private String lkm_memo;
    private String lkm_position;

    // 表达多对一关系
    private Customer customer;

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Long getLkm_id() {
        return lkm_id;
    }

    public void setLkm_id(Long lkm_id) {
        this.lkm_id = lkm_id;
    }

    public Character getLkm_gender() {
        return lkm_gender;
    }

    public void setLkm_gender(Character lkm_gender) {
        this.lkm_gender = lkm_gender;
    }

    public String getLkm_name() {
        return lkm_name;
    }

    public void setLkm_name(String lkm_name) {
        this.lkm_name = lkm_name;
    }

    public String getLkm_phone() {
        return lkm_phone;
    }

    public void setLkm_phone(String lkm_phone) {
        this.lkm_phone = lkm_phone;
    }

    public String getLkm_email() {
        return lkm_email;
    }

    public void setLkm_email(String lkm_email) {
        this.lkm_email = lkm_email;
    }

    public String getLkm_qq() {
        return lkm_qq;
    }

    public void setLkm_qq(String lkm_qq) {
        this.lkm_qq = lkm_qq;
    }

    public String getLkm_mobile() {
        return lkm_mobile;
    }

    public void setLkm_mobile(String lkm_mobile) {
        this.lkm_mobile = lkm_mobile;
    }

    public String getLkm_memo() {
        return lkm_memo;
    }

    public void setLkm_memo(String lkm_memo) {
        this.lkm_memo = lkm_memo;
    }

    public String getLkm_position() {
        return lkm_position;
    }

    public void setLkm_position(String lkm_position) {
        this.lkm_position = lkm_position;
    }

    @Override
    public String toString() {
        return "LinkMan [lkm_id=" + lkm_id + ", lkm_gender=" + lkm_gender + ", lkm_name=" + lkm_name + ", lkm_phone="
                + lkm_phone + ", lkm_email=" + lkm_email + ", lkm_qq=" + lkm_qq + ", lkm_mobile=" + lkm_mobile
                + ", lkm_memo=" + lkm_memo + ", lkm_position=" + lkm_position + ", customer=" + customer + "]";
    }

}

 

 

 LinkMan.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.qlq.domain" >
    <class name="LinkMan" table="cst_linkman" >
        <id name="lkm_id"  >
            <generator class="native"></generator>
        </id>
        <property name="lkm_gender"  ></property>
        <property name="lkm_name"  ></property>
        <property name="lkm_phone"  ></property>
        <property name="lkm_email"  ></property>
        <property name="lkm_qq"  ></property>
        <property name="lkm_mobile"  ></property>
        <property name="lkm_memo"  ></property>
        <property name="lkm_position"  ></property>
        <!-- 
        fetch 决定加载的sql语句
            select: 使用单表查询
            join : 多表查询 (会导致lazy失效)
        lazy  决定加载时机
            false: 立即加载
            proxy: 由customer的类级别加载策略决定.
         -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy"></many-to-one>
    </class>
</hibernate-mapping>

 

 

1.dao接口以及实现

package cn.qlq.dao;

import org.hibernate.Session;

import cn.qlq.domain.Customer;

public interface CustomerDao {
    /**
     * 保存客户
     * 
     * @param c
     */
    public void saveCustomer(Customer c);

    /**
     * 根据ID查询
     * 
     * @param cusId
     * @return
     */
    public Customer getCustomerById(Long cusId);

    /**
     * 测试通过hibernate获取的session是否同一线程是一样的
     */
    public Session testSessionIsSameInOneThread();
}

 

 

package cn.qlq.dao;

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

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import cn.qlq.domain.Customer;

/**
 * dao操作一般继承HibernateDaoSupport,里面获取hibernateTemplete也可以进行许多操作
 * 
 * @author liqiang
 *
 */
@Repository
public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao {

    private static Logger log = LoggerFactory.getLogger(CustomerDaoImpl.class);

    @Override
    public void saveCustomer(Customer c) {
        Serializable obj = getHibernateTemplate().save(c);// 返回值是生成的主键的值
        log.info("save customer success,userId is:{}", obj.toString());
    }

    @Resource
    public void setSessionFacotry(SessionFactory sessionFacotry) {
        super.setSessionFactory(sessionFacotry);
    }

    @Override
    public Customer getCustomerById(Long cusId) {
        // 第一种:session.get方法
        Session session = getSessionFactory().openSession();
        Customer customer = session.get(Customer.class, cusId);
        log.info("第一种方法(session获取):{}", customer.toString());

        // 第二种:HQL
        String hql = "from Customer where cust_id=" + cusId;
        Query query = session.createQuery(hql);
        Customer cus = (Customer) query.uniqueResult();
        log.info("第二种方法(HQL获取):{}", customer.toString());

        // 第三种:Criteria查询
        Criteria c = session.createCriteria(Customer.class);
        c.add(Restrictions.eq("cust_name", "ttt"));
        List list = c.list();
        log.info("Criteria方法获取的:{}", list.toString());

        // 第四种:原生SQL查询
        String sql = "select * from cst_customer where cust_id = " + cusId;
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        sqlQuery.addEntity(Customer.class);
        log.info("原生SQL查询方法获取的:{}", sqlQuery.list().toString());

        return customer;
    }

    @Override
    public Session testSessionIsSameInOneThread() {
        return getHibernateTemplate().getSessionFactory().getCurrentSession();
    }
}

 

 

  dao实现一般要继承HibernateDaoSupport,我们项目中也是采用所有的Dao都继承HibernateDaoSupport。这个抽象类有好多直接可以用的方法。原理都是调用hibernateTemplate。所以在Dao实现层我们可以选择继承HibernateDaoSupport,或者直接注入HibernateTemplate。

    也可以用HibernateTemplate进行操作(直接注入HibernateTemplate),此方法的实例我们已经在XML中注入,通过此对象可以获取session执行原生SQL,或者直接注入SessionFactory获取Session(不建议这种)。

  

 

2.service接口和实现

package cn.qlq.service;

import cn.qlq.domain.Customer;

public interface CustomerService {
    public boolean saveCustomer(Customer c);

    /**
     * 根据ID查询
     * 
     * @param cusId
     * @return
     */
    public Customer getCustomerById(Long cusId);

    /**
     * 测试通过hibernateTemplete获取的session是否同一线程是一样的
     */
    public boolean testSessionIsSameInOneThread();
}

 

 

package cn.qlq.service;

import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.qlq.dao.CustomerDao;
import cn.qlq.domain.Customer;

@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {
    private static Logger log = LoggerFactory.getLogger(CustomerServiceImpl.class);
    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private HibernateTemplate hibernateTemplate;

    @Override
    public boolean saveCustomer(Customer c) {
        customerDao.saveCustomer(c);
        return true;
    }

    @Override
    public Customer getCustomerById(Long cusId) {
        return customerDao.getCustomerById(cusId);
    }

    @Override
    public boolean testSessionIsSameInOneThread() {
        //getCurrentSession获取与线程绑定的session(返回true),而openSession不是同一个(会返回false)
//        Session serviceSession = hibernateTemplate.getSessionFactory().openSession();
        Session serviceSession = hibernateTemplate.getSessionFactory().getCurrentSession();
        log.info("serviceSession---------------{}", serviceSession.toString());
        Session daoSession = customerDao.testSessionIsSameInOneThread();
        log.info("daoSession---------------{}", daoSession.toString());
        log.info("daoSession.equals(serviceSession) is :{}", daoSession.equals(serviceSession));
        return daoSession.equals(serviceSession);
    }
}

 

3.Action层代码

package cn.qlq.action;

import java.util.HashMap;
import java.util.Map;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import cn.qlq.domain.Customer;
import cn.qlq.service.CustomerService;

/**
 * 客户Action
 * 
 * @author liqiang
 *
 */
@Namespace("/cus")
@ParentPackage("default")
@SuppressWarnings("all")
public class CustomerAction {

    private static Logger log = LoggerFactory.getLogger(CustomerAction.class);
    @Autowired
    private CustomerService customerService;

    private Map responseMap = new HashMap();

    private Customer c;// 对象驱动保存对象

    @Action(value = "saveCus", results = {
            @Result(name = "success", type = "json", params = { "root", "responseMap" }) })
    public String saveCus() {
        try {
            customerService.saveCustomer(c);
        } catch (Exception e) {
            responseMap.put("msg", "保存客户失败!");
            return "success";
        }
        responseMap.put("msg", "保存客户成功!");
        return "success";
    }

    @Action(value = "getCusById", results = {
            @Result(name = "success", type = "json", params = { "root", "responseMap" }) })
    public String getCusById() {
        Customer cus = null;
        try {
            cus = customerService.getCustomerById(15l);
        } catch (Exception e) {
            responseMap.put("msg", "查询客户失败!");
            return "success";
        }

        responseMap.put("msg", "查询客户成功!");
        responseMap.put("data", cus);
        return "success";
    }

    @Action(value = "testSessionIsSameInOneThread", results = {
            @Result(name = "success", type = "json", params = { "root", "responseMap" }) })
    public String testSessionIsSameInOneThread() {
        responseMap.put("data", customerService.testSessionIsSameInOneThread());
        return "success";
    }

    public Customer getC() {
        return c;
    }

    public void setC(Customer c) {
        this.c = c;
    }

    public Map getResponseMap() {
        return responseMap;
    }

    public void setResponseMap(Map responseMap) {
        this.responseMap = responseMap;
    }

}

 

 

 

3.测试(就不搭建页面了,直接get请求访问根据返回的JSON值判断结果)

1.测试保存:

http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt

 

结果:

  技术分享图片

 

日志:

  2018-08-25 20:42:19 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:18



 2.测试查询:

http://localhost/SSHWeb/cus/getCusById.do

 

结果:(会关联查询联系人)

技术分享图片

 

 日志:

2018-08-25 20:45:26 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 第一种方法(session获取):Customer [cust_id=15, cust_name=ttt]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 第二种方法(HQL获取):Customer [cust_id=15, cust_name=ttt]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] Criteria方法获取的:[Customer [cust_id=15, cust_name=ttt], Customer [cust_id=18, cust_name=ttt]]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 原生SQL查询方法获取的:[Customer [cust_id=15, cust_name=ttt]]

 

3.测试获取与线程绑定的Session

 http://localhost/SSHWeb/cus/testSessionIsSameInOneThread.do

结果:

技术分享图片

 

日志:

2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] serviceSession---------------SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])
2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] daoSession---------------SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])
2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] daoSession.equals(serviceSession) is :true

 

 

4.测试事务(一般我们都要在service层打事务注解进行事务控制)

  上面的搭建环境基本完成了,但是事务控制非常重要,下面测试事务是否生效。

原来数据:

mysql> select * from cst_customer;
+---------+-----------+-------------+---------------+------------+-------------
| cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkman
+---------+-----------+-------------+---------------+------------+-------------
|      15 | ttt       | NULL        | NULL          | NULL       | NULL
|      18 | ttt       | NULL        | NULL          | NULL       | NULL
+---------+-----------+-------------+---------------+------------+-------------
2 rows in set (0.00 sec)

 

1.测试事务是否生效

  service层制造一个保存之后的异常,修改保存的代码:

技术分享图片

 

访问请求:

  http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt

 结果:

  技术分享图片

日志

Hibernate: 
    insert 
    into
        cst_customer
        (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile) 
    values
        (?, ?, ?, ?, ?, ?, ?)
2018-08-25 20:54:19 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:19
2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Initiating transaction rollback
2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[cn.qlq.domain.Customer#19]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Not closing pre-bound Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
2018-08-25 20:54:19 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 5, unused: 3, excluded: 0] (e.g. [email protected])
2018-08-25 20:54:19 [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean ‘org.springframework.transaction.config.internalTransactionAdvisor‘
2018-08-25 20:54:19 [org.apache.struts2.json.JSONUtil]-[DEBUG] [JSON]{"msg":"保存客户失败!"}

 

分析:

  插进去数据之后报异常然后进行 回滚操作,证明事务生效。

 

为了验证,我们在查询数据库:

mysql> select * from cst_customer;
+---------+-----------+-------------+---------------+------------+------------
| cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkma
+---------+-----------+-------------+---------------+------------+------------
|      15 | ttt       | NULL        | NULL          | NULL       | NULL
|      18 | ttt       | NULL        | NULL          | NULL       | NULL
+---------+-----------+-------------+---------------+------------+------------
2 rows in set (0.00 sec)

 

 

2.在还存在异常的情况下,我们将事务注解去掉:

补充:

进行此测试,我们首先需要将重写OpenSessionInViewFilter过滤器的openSession方法,否则报错:Write operations are not allowed in read-only mode (FlushMode.MANUAL),

参考:https://www.cnblogs.com/qlqwjy/p/9535500.html

 

 

技术分享图片

 

访问请求:

  http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt

结果:

  技术分享图片

日志: (虽然报错了,但是错误是在执行save之后,所以会提交数据库并且没有事务控制不会回滚,造成异常数据)

Hibernate: 
    insert 
    into
        cst_customer
        (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile) 
    values
        (?, ?, ?, ?, ?, ?, ?)
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] acquire test -- pool size: 1; target_pool_size: 1; desired target? 2
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 1
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 2
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 3
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] awaitAvailable(): [email protected]
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 1, unused: 0, excluded: 0] (e.g. [email protected])
2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 
2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 2, unused: 1, excluded: 0] (e.g. [email protected])
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 2
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 3, unused: 2, excluded: 0] (e.g. [email protected])
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 1
2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 4, unused: 3, excluded: 0] (e.g. [email protected])
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 0
2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 4, unused: 2, excluded: 0] (e.g. [email protected])
2018-08-25 21:38:52 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:20
2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:38:55 CST 2018 [[email protected]]
2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources.  [[email protected]]
2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources.  [[email protected]]
2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:39:00 CST 2018 [[email protected]]
2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources.  [[email protected]]
2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources.  [[email protected]]
2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:39:05 CST 2018 [[email protected]]
2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources.  [[email protected]]
2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources.  [[email protected]]
2018-08-25 21:39:07 [cn.qlq.action.CustomerAction]-[ERROR] 
java.lang.ArithmeticException: / by zero
    at cn.qlq.service.CustomerServiceImpl.saveCustomer(CustomerServiceImpl.java:27)
    at cn.qlq.action.CustomerAction.saveCus(CustomerAction.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

 

 

 查看SQL:

mysql> select * from cst_customer;
+---------+-----------+-------------+---------------+------------+-------------
| cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkman
+---------+-----------+-------------+---------------+------------+-------------
|      15 | ttt       | NULL        | NULL          | NULL       | NULL
|      18 | ttt       | NULL        | NULL          | NULL       | NULL
|      20 | ttt       | NULL        | NULL          | NULL       | NULL
+---------+-----------+-------------+---------------+------------+-------------
3 rows in set (0.00 sec)

 

 

总结:

  证明我们上面的事务配置 是正确,并且也生效了。总结出来一条:在我们进行增(save)、改(update)、删(delete)的时候要在service层打上注解,否则会报Write operations are not allowed in read-only mode (FlushMode.MANUAL),除非我们重写OpenSessionInViewFilter的openSession方法(一般不推荐这种)。

 

5.测试DAO直接注入hibernateTemplate:

1.dao代码

package cn.qlq.dao;

import org.hibernate.Session;

import cn.qlq.domain.Customer;

public interface CustomerDao2 {
    /**
     * 保存客户
     * 
     * @param c
     */
    public void saveCustomer(Customer c);

    /**
     * 根据ID查询
     * 
     * @param cusId
     * @return
     */
    public Customer getCustomerById(Long cusId);

    /**
     * 测试通过hibernate获取的session是否同一线程是一样的
     */
    public Session testSessionIsSameInOneThread();
}

 

 

package cn.qlq.dao;

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

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import cn.qlq.domain.Customer;

/**
 * 
 * 测试Dao层直接注入hibernateTemplate
 * 
 * @author liqiang
 *
 */
@Repository
public class CustomerDaoImpl2 implements CustomerDao2 {

    private static Logger log = LoggerFactory.getLogger(CustomerDaoImpl2.class);
    @Autowired
    private HibernateTemplate hibernateTemplate;

    @Override
    public void saveCustomer(Customer c) {
        Serializable obj = hibernateTemplate.save(c);// 返回值是生成的主键的值
        log.info("save customer success,userId is:{}", obj.toString());
    }

    @Override
    public Customer getCustomerById(Long cusId) {
        // 第一种:session.get方法
        Session session = hibernateTemplate.getSessionFactory().openSession();
        Customer customer = session.get(Customer.class, cusId);
        log.info("第一种方法(session获取):{}", customer.toString());

        // 第二种:HQL
        String hql = "from Customer where cust_id=" + cusId;
        Query query = session.createQuery(hql);
        Customer cus = (Customer) query.uniqueResult();
        log.info("第二种方法(HQL获取):{}", customer.toString());

        // 第三种:Criteria查询
        Criteria c = session.createCriteria(Customer.class);
        c.add(Restrictions.eq("cust_name", "ttt"));
        List list = c.list();
        log.info("Criteria方法获取的:{}", list.toString());

        // 第四种:原生SQL查询
        String sql = "select * from cst_customer where cust_id = " + cusId;
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        sqlQuery.addEntity(Customer.class);
        log.info("原生SQL查询方法获取的:{}", sqlQuery.list().toString());

        return customer;
    }

    @Override
    public Session testSessionIsSameInOneThread() {
        return hibernateTemplate.getSessionFactory().getCurrentSession();
    }
}

 

 

 2.service代码:

 技术分享图片

 

 

 

 技术分享图片

 

 

 3.Action层代码:

 

    /**
     * 测试Dao层直接注入hibernateTemplate
     * 
     * @return
     */
    @Action(value = "saveCus2", results = {
            @Result(name = "success", type = "json", params = { "root", "responseMap" }) })
    public String saveCus2() {
        try {
            customerService.saveCustomer2(c);
        } catch (Exception e) {
            log.error("", e);
            responseMap.put("msg", "保存客户失败!");
            return "success";
        }
        responseMap.put("msg", "保存客户成功!");
        return "success";
    }

 

 

4.测试:

     http://localhost/SSHWeb/cus/saveCus2.do?c.cust_name=ttt2

结果:

    技术分享图片

 

 6.总结:

   SSH整合与SSM整合大体类似,在这里就基本完成了SSH的整合。总结一下SSH整合过程。

1.Struts配置:配置struts的对象工程为spring,然后struts采用注解配置,struts整合spring比较简单

2.spring:配置扫描的包,引入配置文件。

3.spring整合hibernate:配置数据源(连接池)、

          配置sessionFactory(注入数据源、hibernate配置文件位置(configLocations)、hibernate一些打印SQL等配置(hibernateProperties))

          配置事务管理器并开启注解事务。

          配置hibernateTemplate,需要注入会话工厂(sessionFactory)

 

 

接下来还有hibernate的二级缓存与注解的使用未完成,将会在之后补充。

 

以上是关于SSH开发环境搭建的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式平台ssh开发环境搭建

教程 | 一步步从零开始:使用PyCharm和SSH搭建远程TensorFlow开发环境

处理新SSH开发环境搭建扫描mapper文件的主要配置

前端环境的安装与配置

树莓派开发环境搭建

搭建GitLab服务器