一、 SSH整合理论
Javaweb开发一般采用三层的架构,即web层、service层、dao层。对应3层,web层采用struts2和jsp,service层采用javabean,dao层采用hibernate,3层采用spring来整合。在web层,由spring来管理action对象,service层的javabean对象交给spring来管理,在dao层,hibernate的sessionFactory、session的获得和aop事务交给spring管理。
二、 SSH整合步骤
1. 新建web工程项目
2. 导入所需的jar包
Hibernate的包,hibernate/lib/required和hibernate/lib/jpa和数据库驱动
Struts2的包,struts-blank.war/WEB-INF/lib/和struts2整合spring的包
Spring的包,基本包4+2,整合web的包,整合aop的包4个,整合jdbc和事务的4个包,junit4测试的test包
Eclipse下请导入标签库的包
3. 创建工程结构化包
包括web层(action类),service接口层、实现层,dao接口层、实现层,实体层(domain或者pojo)
4. 编写配置文件
1) 配置spring容器
创建applicationContext.xml文件。主要配置对于hibernate、struts2、事务和三层中的其他对象bean的管理。对于hibernate的管理主要包括,sessionFactory,c3p0连接池,引入orm元数据,其中对于sessionFactory的管理在配置原来hibernate配置文件上有两种方案,详见例子。对于struts2的管理主要是将action类对象装配到spring,同时在struts2的配置文件中,设置将对象工厂交给spring管理。对于事务的管理,主要是配置核心事务管理器、通知和切面等。对于其他对象bean的管理按照spring原本的配置。
例子:
<?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: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/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
<!-- 读取db.properties文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置c3p0连接池 -->
<bean name="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl"value="${jdbc.jdbcUrl}" ></property>
<property name="driverClass"value="${jdbc.driverClass}" ></property>
<property name="user"value="${jdbc.user}" ></property>
<property name="password"value="${jdbc.password}" ></property>
</bean>
<!-- 配置核心事务管理器 -->
<bean name="transactionManager"class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory"ref="sessionFactory"></property>
</bean>
<!-- 配置通知 -->
<!--<tx:advice id="txAdvice"transaction-manager="transactionManager" >
<tx:attributes>
<tx:methodname="add*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="save*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="persist*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="update*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="modify*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="delete*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="remove*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="false" />
<tx:methodname="get*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="true" />
<tx:methodname="find*" isolation="REPEATABLE_READ"propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice> -->
<!-- 配置将通知织入目标对象
配置切入点和切面-->
<!--<aop:config>
<aop:pointcutexpression="execution(* com.ssh.service.impl.*ServiceImpl.*(..))"id="txPc"/>
<aop:advisoradvice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config> -->
<!-- 采用注解的方式,开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 将sessionFactory配置到spring容器 -->
<!--<bean name="sessionFactory"class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
加载配置方案1:仍然使用外部的hibernate.cfg.xml的配置信息
不推荐
<propertyname="configLocation"value="classpath:hibernate.cfg.xml"></property>
</bean> -->
<bean name="sessionFactory"class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 将连接池注入sessionFactory -->
<property name="dataSource"ref="dataSource"></property>
<!-- 加载配置方案2:在spring配置中放置hibernate的配置信息 -->
<property name="hibernateProperties">
<props>
<!-- <propkey="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
<propkey="hibernate.connection.url">jdbc:mysql:///ssh?characterEncoding=utf-8</prop>
<propkey="hibernate.connection.username">root</prop>
<propkey="hibernate.connection.password">1234</prop> -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 引入orm元数据,指定orm所在的包路径,spring会自动读取包中的所有配置 -->
<property name="mappingDirectoryLocations"value="classpath:com/ssh/domain"></property>
</bean>
<!-- 使用由spring完整管理action的生命周期,需要手动注入action的bean的属性,并配置bean的作用范围为多例的 -->
<bean name="userAction"class="com.ssh.web.action.UserAction" scope="prototype">
<property name="userService"ref="userService"></property>
</bean>
<bean name="userService"class="com.ssh.service.impl.UserServiceImpl">
<property name="ud"ref="userDao"></property>
</bean>
<bean name="userDao"class="com.ssh.dao.impl.UserDaoImpl">
<!-- 注入sessionFactory -->
<property name="sessionFactory"ref="sessionFactory"></property>
</bean>
</beans>
2) 配置struts.xml文件
struts.xml的配置基本同单独配置struts2。区别主要是将struts2的对象工厂交给spring管理。
例子:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE strutsPUBLIC
"-//ApacheSoftware Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
struts.objectFactory= spring,将对象工厂交给spring管理
struts.objectFactory.spring.autoWire= name,自动装配依赖spring,默认打开,无需配置
-->
<constant name="struts.objectFactory"value="spring"></constant>
<package name="ssh"namespace="/" extends="struts-default">
<!-- 配置错误信息 -->
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.RuntimeException"></exception-mapping>
</global-exception-mappings>
<!-- 整合方案1:在action标签的class属性上仍然配置完整的类型
效果:半整合状态,struts2仍然创建action,由spring负责组装action中的依赖属性
不推荐使用
-->
<!-- 整合方案2:在action标签的class属性上填写spring中action对象的bean的name
效果:完全由spring管理action的生命周期。包括action的创建。
注意:这样需要在spring的bean中手动组装action的bean的依赖属性。并且配置action的bean的作用范围为多例的。
-->
<action name="UserAction_*"class="userAction" method="{1}">
<result name="home"type="redirect">/index.jsp</result>
<result name="error">/login.jsp</result>
</action>
</package>
</struts>
3) Hibernate的实体映射文件
实体的映射文件配置完全同单独配置hibernate时的映射配置方式,没有区别。
例子:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.domain.User"table="user">
<id name="id"column="id">
<!-- <generator class="native" /> -->
<!-- 获取主键最大值,然后+1作为新行的主键值 -->
<generator class="increment"/>
</id>
<property name="username"column="username" length="30"/>
<property name="password"column="password" />
</class>
</hibernate-mapping>
4) db.properties和log4j2.xml
db.properties用于提供装配c3p0连接池时使用的属性信息。这两个文件没有特殊的注意事项。
例子:
jdbc.jdbcUrl=jdbc:mysql:///ssh?characterEncoding=utf-8
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=1234
<?xml version="1.0"encoding="UTF-8"?>
<Configuration>
<!-- 输出目的地 -->
<Appenders>
<!-- 控制台 -->
<Console name="console"target="SYSTEM_OUT">
<!-- 输出格式 -->
<PatternLayout pattern="%m%n"/>
</Console>
<!-- 文件 -->
<File name="file"fileName="d:/chizixinrecord.log">
<!-- 输出格式 -->
<PatternLayout pattern="%d %p %c [%t]%m%n" />
</File>
<!-- 文件:异步 -->
<Async name="async">
<AppenderRef ref="file"/>
</Async>
<!-- 滚动式文件 -->
<RollingFile name="rollingFile"fileName="d:/logs/estore/estore.log"
filePattern="d:/logs/estore/%d{yyyy-MM}/estore-%d{MM-dd-yyyy}-%i.log.gz">
<!-- 输出格式 -->
<PatternLayout pattern="%d %p %c [%t]%m%n" />
<!-- 滚动政策 -->
<Policies>
<!-- 6小时一个文件 -->
<TimeBasedTriggeringPolicy interval="6" />
<!-- 超过100MB,创建新文件 -->
<SizeBasedTriggeringPolicy size="100MB" />
</Policies>
</RollingFile>
</Appenders>
<!-- 日志记录器 -->
<Loggers>
<!-- level:设置日志输出级别 -->
<Root level="info">
<!-- AppenderRefref="console" /-->
<AppenderRef ref="async"/>
<!--AppenderRef ref="rollingFile" /-->
</Root>
</Loggers>
</Configuration>
5) web.xml文件
web.xml文件主要是配置加载spring文件的监听器,扩大session的作用域范围,struts2的核心过滤器,以及其他未知的需要。
例子:
<?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/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>ssh</display-name>
<!-- 配置随web启动而加载spring文件的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 設置spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 为了避免使用懒加载时出现no-session问题,需要扩大session的作用范围,请将任何过滤器配置在struts2的过滤器之前 -->
<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-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.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
5. 创建或使用jsp页面
略
6. 编写action,按照3层来处理业务需求。
三、 使用整合的SSH实现登录功能
1. Jsp页面略
2. 主要配置文件同上,略
3. 创建实体类User以及hibernate对象关系映射
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public voidsetId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public voidsetUsername(String username){
this.username = username;
}
public String getPassword() {
return password;
}
public voidsetPassword(String password){
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username="+ username+ ", password=" + password+ "]";
}
}
映射文件
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.domain.User"table="user">
<id name="id"column="id">
<!-- <generator class="native" /> -->
<!-- 获取主键最大值,然后+1作为新行的主键值 -->
<generator class="increment"/>
</id>
<property name="username"column="username" length="30"/>
<property name="password"column="password" />
</class>
</hibernate-mapping>
4. 编写UserAction类的login方法
注入UserService对象以及编写jsp页面取值的模型。
public class UserAction extends ActionSupport implementsModelDriven<User>{
private User user= newUser();
private UserService userService;
public voidsetUserService(UserService userService) {
this.userService = userService;
}
public String login()throws Exception{
System.out.println(user);
User u=userService.getUserByAll(user);
System.out.println("会话");
System.out.println(u);
//ActionContext.getContext().getSession().put("user",u);
return "home";
}
@Override
public User getModel() {
return user;
}
}
5. 在struts.xml中配置userAction
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.domain.User"table="user">
<id name="id"column="id">
<!-- <generator class="native" /> -->
<!-- 获取主键最大值,然后+1作为新行的主键值 -->
<generator class="increment"/>
</id>
<property name="username"column="username" length="30"/>
<property name="password"column="password" />
</class>
</hibernate-mapping>
6. 编写service层
UserService接口
public interface UserService {
User getUserByAll(User u);
void addUser(User u);
}
实现类,注入dao层UserDao对象和使用事务注解
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class UserServiceImpl implements UserService{
private UserDao ud;
public voidsetUd(UserDao ud) {
this.ud = ud;
}
@Override
public User getUserByAll(User u) {
System.out.println(u);
User existU = ud.getUserByAll(u);
System.out.println(existU);
if(existU==null){
throw new RuntimeException("用户或密码错误");
}
return existU;
}
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
public voidaddUser(User u) {
ud.save(u);
}
}
7. 编写dao层
UserDao接口
public interface UserDao {
User getUserByAll(final User user);
void save(User u);
}
实现类,继承HibernateDaoSupport类,使用HibernateTemplate模板。
public class UserDaoImpl extends HibernateDaoSupport implements UserDao{
@Override
public User getUserByAll(final User user){
//HQL
System.out.println(user);
return getHibernateTemplate().execute(newHibernateCallback<User>() {
public User doInHibernate(Session session) throws HibernateException {
String hql="from Userwhere username=? and password=?";
Query query=session.createQuery(hql);
query.setParameter(0, user.getUsername());
query.setParameter(1, user.getPassword());
System.out.println(user);
User u=(User)query.uniqueResult();
System.out.println(u);
return u;
}
});
//Criteria
/*DetachedCriteriadc=DetachedCriteria.forClass(User.class);
dc.add(Restrictions.eq("username",user.getUsername()));
dc.add(Restrictions.eq("password",user.getPassword()));
List<User>list=(List<User>)getHibernateTemplate().findByCriteria(dc);
if(list!=null&&list.size()>0){
return list.get(0);
}else{
return null;
}*/
}
@Override
public voidsave(User u) {
getHibernateTemplate().save(u);
}
}
8. 测试略