ssh整合示例

ssh整合的一个demo。

准备

spring4-required
struts2.3.15.3-blank
hibernate-release-4.2.4.Final

步骤

加入Spring

加入jar包

spring4-required

配置web.xml文件

在web.xml文件中 alt+ / 选择 ContextLoaderListener。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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"
id="WebApp_ID" version="3.0">
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>location</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

修改web.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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"
id="WebApp_ID" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

加入Spring的配置文件

new -> Source Folder新建一个源码包conf。
在conf源码包下新建applicationContext.xml配置文件。

加入Hibernate

1).同时建立持久化类,和其对应的 .hbm.xml文件,生成对应的数据表。
2).Spring整合Hibernate。
3).步骤:
①.加入jar包
加入hibernate-release-4.2.4.Final->lib->required文件夹下的全部8个jar包。
②.在类路径下加入hibernate.cfg.xml文件,在其中配置hibernate的基本属性。
新建hibernate.cfg.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 配置 hibernate的基本属性 -->
<!-- 方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 是否显示及格式化SQL -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- 生成数据表的策略 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 二级缓存相关 -->
</session-factory>
</hibernate-configuration>

③.建立持久化类,和其对应的 .hbm.xml文件
在src下新建包com.leezp.ssh.entities。
在该包下新建Department.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.leezp.ssh.entities;
public class Department {
private Integer id;
private String departmentName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
}

在该包下新建Employee.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.leezp.ssh.entities;
import java.sql.Date;
public class Employee {
private Integer id;
// 不能被修改
private String lastName;
private String email;
// 从前端传入的是String类型,所以需要注意转换
private Date birth;
// 不能被修改
private Date createTime;
// 单向多对一的关联关系
private Department department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}

在该包下新建 Hibernate XML Mapping file(hbm.xml)。
Hibernate会帮助我们根据entities自动生成内容。
查看Employee.hbm.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-14 15:46:11 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.leezp.ssh.entities.Employee" table="EMPLOYEE">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="assigned" />
</id>
<property name="lastName" type="java.lang.String">
<column name="LASTNAME" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<property name="birth" type="java.sql.Date">
<column name="BIRTH" />
</property>
<property name="createTime" type="java.sql.Date">
<column name="CREATETIME" />
</property>
<many-to-one name="department" class="com.leezp.ssh.entities.Department" fetch="join">
<column name="DEPARTMENT" />
</many-to-one>
</class>
</hibernate-mapping>

查看Department.hbm.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-14 15:46:11 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.leezp.ssh.entities.Department" table="DEPARTMENT">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="assigned" />
</id>
<property name="departmentName" type="java.lang.String">
<column name="DEPARTMENTNAME" />
</property>
</class>
</hibernate-mapping>

修改Department.hbm.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-14 15:46:11 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.leezp.ssh.entities.Department" table="SSH_DEPARTMENT">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="departmentName" type="java.lang.String">
<column name="DEPARTMENT_NAME" />
</property>
</class>
</hibernate-mapping>

修改Employee.hbm.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-14 15:46:11 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.leezp.ssh.entities.Employee" table="SSH_EMPLOYEE">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="lastName" type="java.lang.String">
<column name="LAST_NAME" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<property name="birth" type="java.sql.Date">
<column name="BIRTH" />
</property>
<property name="createTime" type="java.sql.Date">
<column name="CREATE_TIME" />
</property>
<!-- 映射单向多对一的关联关系 -->
<many-to-one name="department" class="com.leezp.ssh.entities.Department">
<column name="DEPARTMENT_ID" />
</many-to-one>
</class>
</hibernate-mapping>

④.和Spring进行整合
i.加入c3p0和MySQL的驱动。
c3p0-0.9.1.2.jar
mysql-connector-java-5.1.22-bin.jar
ii.在Spring的配置文件中配置:数据源,SessionFactory。

在conf源码包下面新建db.properties属性文件。

1
2
3
4
5
6
7
jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssh_demo
jdbc.initPoolSize=5
jdbc.maxPoolSize=10

修改Spring配置文件applicationContext.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置C3P0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- 配置SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 路径给Spring用的情况可以加classpath:,指的是编译后的class路径。/WEB-INF/classes/,编译后的class文件,资源文件,依赖文件等都会放在这个路径下。 -->
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<!-- 注意将复制的com.leezp.ssh.entities中的"."换成"/"并在最后加上"/*.hbm.xml" -->
<property name="mappingLocations" value="classpath:com/leezp/ssh/entities/*.hbm.xml"></property>
</bean>
</beans>

在mysql新建一个空的数据库ssh_demo。启动项目,会看到生成对应的数据表

在数据库里向ssh_department表添加数据。

修改Spring配置文件applicationContext.xml配置声明式事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置C3P0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- 配置SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 路径给Spring用的情况可以加classpath:,指的是编译后的class路径。/WEB-INF/classes/,编译后的class文件,资源文件,依赖文件等都会放在这个路径下。 -->
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<!-- 注意将复制的com.leezp.ssh.entities中的"."换成"/"并在最后加上"/*.hbm.xml" -->
<property name="mappingLocations" value="classpath:com/leezp/ssh/entities/*.hbm.xml"></property>
</bean>
<!-- 配置Spring的声明式事务 -->
<!-- 1.配置hibernate的事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 2.配置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 配置get开头的 read-only="true -->
<tx:method name="get*" read-only="true" />
<!-- 配置默认值 -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!-- 3.配置事务切入点 -->
<aop:config>
<!-- com.leezp.ssh.service包下的所有类的所有方法所有参数 -->
<aop:pointcut expression="execution(* com.leezp.ssh.service.*.*(..))"
id="txPointCut" />
<!-- 4.把事务属性和事务切入点关联起来 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>
</beans>

新建包com.leezp.ssh.service。

获取源代码

加入Struts2

加入jar包

asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-fileupload-1.3.jar
commons-io-2.0.1.jar
commons-lang3-3.1.jar
commons-logging-1.1.3.jar
freemarker-2.3.19.jar
javassist-3.11.0.GA.jar
log4j-1.2.17.jar
ognl-3.0.6.jar
struts2-core-2.3.15.3.jar
xwork-core-2.3.15.3.jar
若有重复的jar包,则需要删除版本较低的。javassist-3.11.0.GA.jar

在web.xml文件中配置Struts2的Filter

复制struts2官方示例web.xml中的如下代码到项目的web.xml文件中。

1
2
3
4
5
6
7
8
9
<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>

加入Struts2的配置文件

复制struts2官方配置文件struts.xml到conf源码包下。

修改struts.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<!-- 这是利用Struts2里面的自动匹配特性。*代表通配符,可以匹配任何一个字符串,[1]表示匹配的参数。 -->
<!-- 举个例子来说,如果你在xml文件中做了这个配置,那么当你页面里面有一个form <form action="/emp-add" method="post">
那么,*匹配到的就是“add”,同时method="{1}",实际上就是method="add"。 -->
<!-- 假设有两个参数,如果在xml里面的配置是 <action name="emp-*-*" class="{1}Action" method="{2}">
那么第一个星号对应的是{1},第二个星号对应的是{2} -->
<!-- 例如,页面里面有<form action="/emp-employee-add" method="post"> 那么实际上的意思就是
class="employeeAction" method="add" -->
<!-- **这样做的好处就是我们不必为增、删、改、查方法写四个<action>配置。** -->
<!-- 通配符还可以用来节省xml文件中的代码量 -->
<package name="default" namespace="/" extends="struts-default">
</package>
</struts>

Struts2整合Spring

①.加入Struts2的Spring插件的jar包。
struts2-spring-plugin-2.3.15.3.jar
②.在Spring的配置文件中正常配置Action,注意Action的scope为prototype。

在conf源码包下新建applicationContext-beans.xml配置文件。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

在src下新建包com.leezp.ssh.actions。

在该包下新建EmployeeAction.java。

1
2
3
4
5
package com.leezp.ssh.actions;
public class EmployeeAction {
}

修改applicationContext-beans.xml配置文件。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeAction" class="com.leezp.ssh.actions.EmployeeAction"
scope="prototype"></bean>
</beans>

③.在Struts2的配置文件中配置Action时,class属性指向该Action在IOC中的id。

修改struts.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="emp-*" class="employeeAction" method="{1}"></action>
</package>
</struts>

向数据库中的表ssh_employee添加两条用于测试的数据。

新建一个web页面index.jsp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="emp-list">List All Employees</a>
</body>
</html>

修改前面建好的EmployeeAction.java。为它添加与index.jsp里”emp-list”对应的list()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.leezp.ssh.actions;
import com.opensymphony.xwork2.ActionSupport;
public class EmployeeAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
public String list() {
return "list";
}
}

添加包com.leezp.ssh.dao。在该包下新建EmployeeDao.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.leezp.ssh.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.leezp.ssh.entities.Employee;
public class EmployeeDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return this.sessionFactory.getCurrentSession();
}
public List<Employee> getAll() {
// 迫切左外连接
// Query query =
// getSession.createQuery(" from Employee e left outer join fetch e.department o");
// Iterator iter = query.list().iterator();
// 说明:
// 关键字:left join fetch
// 返回结果为Employee类型,再通过Employee对象导航到department对象
String hql = " from Employee e left outer join fetch e.department ";
return getSession().createQuery(hql).list();
}
}

在包com.leezp.ssh.service下新建EmployeeService.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.leezp.ssh.service;
import java.util.List;
import com.leezp.ssh.dao.EmployeeDao;
import com.leezp.ssh.entities.Employee;
public class EmployeeService {
private EmployeeDao employeeDao;
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
public List<Employee> getAll() {
return employeeDao.getAll();
}
}

修改EmployeeAction.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.leezp.ssh.actions;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.leezp.ssh.service.EmployeeService;
import com.opensymphony.xwork2.ActionSupport;
/**
* 实现RequestAware请求域
*
* @author Lee
*
*/
public class EmployeeAction extends ActionSupport implements RequestAware {
/**
*
*/
private static final long serialVersionUID = 1L;
private EmployeeService employeeService;
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
public String list() {
request.put("employees", employeeService.getAll());
return "list";
}
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> arg0) {
this.request = arg0;
}
}

在applicationContext.xml中配置bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeDao" class="com.leezp.ssh.dao.EmployeeDao">
<!-- 这里的ref指向的sessionFactory在另一个配置文件 -->
<!-- ref指向不同配置文件时,需要在web.xml的<context-param>中修改配置为 <param-value>classpath:applicationContext*.xml</param-value> -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="employeeService" class="com.leezp.ssh.service.EmployeeService">
<property name="employeeDao" ref="employeeDao"></property>
</bean>
<bean id="employeeAction" class="com.leezp.ssh.actions.EmployeeAction"
scope="prototype">
<property name="employeeService" ref="employeeService"></property>
</bean>
</beans>

修改web.xml中的<param-value>标签为<param-value>classpath:applicationContext*.xml</param-value>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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"
id="WebApp_ID" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置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>
</web-app>

修改struts.xml配置文件,添加一个结果集的返回页面emp-list.jsp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<!-- 这是利用Struts2里面的自动匹配特性。*代表通配符,可以匹配任何一个字符串,[1]表示匹配的参数。 -->
<!-- 举个例子来说,如果你在xml文件中做了这个配置,那么当你页面里面有一个form <form action="/emp-add" method="post">
那么,*匹配到的就是“add”,同时method="{1}",实际上就是method="add"。 -->
<!-- 假设有两个参数,如果在xml里面的配置是 <action name="emp-*-*" class="{1}Action" method="{2}">
那么第一个星号对应的是{1},第二个星号对应的是{2} -->
<!-- 例如,页面里面有<form action="/emp-employee-add" method="post"> 那么实际上的意思就是
class="employeeAction" method="add" -->
<!-- **这样做的好处就是我们不必为增、删、改、查方法写四个<action>配置。** -->
<!-- 通配符还可以用来节省xml文件中的代码量 -->
<action name="emp-*" class="employeeAction" method="{1}">
<result name="list">/WEB-INF/views/emp-list.jsp</result>
</action>
</package>
</struts>

在WEB-INF目录下新建views文件夹。
配置Eclipse中新建的web页面的默认编码
Window->Preferences->输入encoding,选择JSP Files,在右侧的Encoding下拉框选择UTF-8,点击保存。

在views文件夹下新建web页面emp-list.jsp,这时看到它的默认编码已经变成了UTF-8。

在emp-list.jsp中导入struts2的标签<%@ taglib prefix=”s” uri=”/struts-tags”%>并和前台页面显示绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Employee List Page</h4>
<s:if test="#request.employees==null || #request.employees.size()==0 ">
没有任何员工信息
</s:if>
<s:else>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>ID</td>
<td>LASTNAME</td>
<td>EMAIL</td>
<td>BIRTH</td>
<td>CREATETIME</td>
<td>DEPT</td>
</tr>
<s:iterator value="#request.employees">
<tr>
<td>${id }</td>
<td>${lastName }</td>
<td>${email }</td>
<td>${birth }</td>
<td>${createTime }</td>
<td>${department.departmentName }</td>
</tr>
</s:iterator>
</table>
</s:else>
</body>
</html>

开启服务器运行项目。

获取源代码

业务需求

获取所有的员工信息

若在Dao中只查询Employee的信息,而且Employee和Department还是使用的懒加载,页面上如果需要显示员工信息,此时会出现懒加载异常,代理对象不能被初始化org.hibernate.LazyInitializationException: could not initialize proxy - no Session
eg:
EmployeeDao.java没有查询department。

同时修改Employee.hbm.xml文件禁止懒加载。

解决方法:
①.关闭懒加载 lazy=”false”,不推荐使用,因为查询了很多不需要的数据,影响性能。获取源代码
②.获取Employee时使用迫切左外连接同时初始化其关联的Department对象。
③.使用OpenSessionInViewFilter:页面加载时开启Session,页面加载完关Session,见文末参考文献《懒加载异常的解决办法》

删除员工信息

在emp-list.jsp页面里添加“删除”功能的超链接。

在EmployeeAction.java里添加id属性和delete方法。

在EmployeeDao.java里添加delete()方法的数据库操作语句。

在业务层EmployeeService.java里添加调用employeeDao。

修改EmployeeAction.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.leezp.ssh.actions;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.leezp.ssh.service.EmployeeService;
import com.opensymphony.xwork2.ActionSupport;
/**
* 实现RequestAware请求域
*
* @author Lee
*
*/
public class EmployeeAction extends ActionSupport implements RequestAware {
/**
*
*/
private static final long serialVersionUID = 1L;
private EmployeeService employeeService;
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
public String list() {
request.put("employees", employeeService.getAll());
return "list";
}
private Integer id;
public void setId(Integer id) {
this.id = id;
}
public String delete() {
employeeService.delete(id);
return SUCCESS;
}
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> arg0) {
this.request = arg0;
}
}

这时候要在struts.xml里配置返回的数据如何绑定web页面。

注意:name后参数应该小写,应该改成如下图。

启动服务器运行项目。

点击“删除”超链接可以删除一行数据。

获取源代码

删除时弹出“确定删除吗?”提示信息并使用ajax异步删除

在WebContent文件夹下新建文件夹scripts。将jquery-1.9.1.min.js添加到scripts文件夹下。

修改emp-list.jsp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<!-- 开发时推荐写绝对路径-->
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
//1.点击delete时,弹出 确定是要删除xx的信息吗?若确定,执行删除,若不确定,则取消
$(".delete").click(function() {
var lastName = $(this).next(":input").val();
//var lastName = $(this).next(":hidden").val();//等价于上面一句
var flag = confirm("确定要删除" + lastName + "的信息吗?");
if (flag) {
var $tr = $(this).parent().parent();//,$(this)取出当前对象并转换为jQuery对象
//删除,使用Ajax的方式
//获取url
var url = this.href;
//获取删除时间
var args = {
"time" : new Date()
};
$.post(url, args, function(data) {
//若data的返回值为1,则提示删除成功,且把当前行删除
if (data == "1") {
alert("删除成功!");
$tr.remove();//删除页面显示的整行
} else {
//若data的返回值不是1,提示删除失败
alert("删除失败!");
}
});
}
//取消超链接的默认行为
return false;
});
})
</script>
</head>
<body>
<h4>Employee List Page</h4>
<s:if test="#request.employees==null || #request.employees.size()==0 ">
没有任何员工信息
</s:if>
<s:else>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>ID</td>
<td>LASTNAME</td>
<td>EMAIL</td>
<td>BIRTH</td>
<td>CREATETIME</td>
<td>DEPT</td>
<td>DELETE</td>
</tr>
<s:iterator value="#request.employees">
<tr>
<td>${id }</td>
<td>${lastName }</td>
<td>${email }</td>
<td>${birth }</td>
<td>${createTime }</td>
<td>${department.departmentName }</td>
<td><a href="emp-delete?id=${id }" class="delete">Delete</a> <input
type="hidden" value="${lastName }"></td>
<!-- 设置一个隐藏域 -->
</tr>
</s:iterator>
</table>
</s:else>
</body>
</html>

修改EmployeeAction.java。

修改struts.xml配置文件。

获取源代码

建立添加员工页面并绑定部门信息下拉框

①.显示表单页面:需要先查询所有的部门信息
②.使用Struts2的ModelDriven和Preparable拦截器
③.时间是一个字符串,需要转为一个Date类型的对象

在index.jsp添加一个新增员工的链接。

向EmployeeAction.java类中新增一个input()方法。

1
2
3
public String input(){
return INPUT;
}

在com.leezp.ssh.dao包下面新建一个Dao,DepartmentDao.java。
因为EmployeeDao.java和DepartmentDao.java都需要使用相同的代码操作SessionFactory,所以这里将处理SessionFactory的代码提取出来。

1
2
3
4
5
6
7
8
9
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return this.sessionFactory.getCurrentSession();
}

再com.leezp.ssh.dao包下新建一个BaseDao.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.leezp.ssh.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class BaseDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return this.sessionFactory.getCurrentSession();
}
}

使EmployeeDao.java继承BaseDao.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.leezp.ssh.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.leezp.ssh.entities.Employee;
public class EmployeeDao extends BaseDao {
public void delete(Integer id) {
// 注意大小写与entities里面一致
String hql = " delete from Employee e where e.id=? ";
getSession().createQuery(hql).setInteger(0, id).executeUpdate();
}
public List<Employee> getAll() {
// 迫切左外连接
// Query query =
// getSession.createQuery(" from Employee e left outer join fetch e.department o");
// Iterator iter = query.list().iterator();
// 说明:
// 关键字:left join fetch
// 返回结果为Employee类型,再通过Employee对象导航到department对象
// String hql = " from Employee e ";
String hql = " from Employee e left outer join fetch e.department ";
return getSession().createQuery(hql).list();
}
}

修改DepartmentDao.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.leezp.ssh.dao;
import java.util.List;
import com.leezp.ssh.entities.Department;
public class DepartmentDao extends BaseDao {
public List<Department> getAll() {
String hql = " from Department ";
return getSession().createQuery(hql).list();
}
}

在com.leezp.ssh.service包下新建DepartmentService.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.leezp.ssh.service;
import java.util.List;
import com.leezp.ssh.dao.DepartmentDao;
import com.leezp.ssh.entities.Department;
public class DepartmentService {
private DepartmentDao departmentDao;
public void setDepartmentDao(DepartmentDao departmentDao) {
this.departmentDao = departmentDao;
}
public List<Department> getAll() {
return departmentDao.getAll();
}
}

在IOC容器里配置刚才添加的bean,在applicationContext-beans.xml配置文件里配置bean添加如下图所示代码。

修改EmployeeAction.java里调用DepartmentService。

修改struts.xml配置文件添加如下图所示代码。

在views文件夹下新建emp-input.jsp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Employee Input Page</h4>
<s:form action="emp-save" method="post">
<!-- label属性为在页面显示的值 -->
<s:textfield name="lastName" label="LastName"></s:textfield>
<s:textfield name="email" label="Email"></s:textfield>
<s:textfield name="birth" label="Birth"></s:textfield>
<!-- struts2的下拉框有listKey和listValue两个属性 -->
<s:select list="#request.departments" listKey="id"
listValue="departmentName" name="department.id" label="Department"></s:select>
<s:submit></s:submit>
</s:form>
</body>
</html>

获取源代码

添加员工

首先在EmployeeAction.java里面实现ModelDriven和Preparable接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.leezp.ssh.actions;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.leezp.ssh.entities.Employee;
import com.leezp.ssh.service.DepartmentService;
import com.leezp.ssh.service.EmployeeService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
/**
* 实现RequestAware请求域
*
* @author Lee
*
*/
public class EmployeeAction extends ActionSupport implements RequestAware,
ModelDriven<Employee>, Preparable {
/**
*
*/
private static final long serialVersionUID = 1L;
private EmployeeService employeeService;
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
private DepartmentService departmentService;
public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
public String input() {
request.put("departments", departmentService.getAll());
return INPUT;
}
public String list() {
request.put("employees", employeeService.getAll());
return "list";
}
private Integer id;
public void setId(Integer id) {
this.id = id;
}
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public String delete() {
try {
employeeService.delete(id);
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
// return SUCCESS;
// 使用ajax异步,删除后不再需要刷新页面,所以注释掉上一句。
return "delete";
}
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> arg0) {
this.request = arg0;
}
// struts2执行Save()方法之前会先执行prepareSave()方法
public void prepareSave() {
model = new Employee();
}
// 保存员工信息的方法
public String save() {
// System.out.println(model);// 打印model查看
model.setCreateTime(new Date());
employeeService.saveOrUpdate(model);
return SUCCESS;
}
@Override
public void prepare() throws Exception {
}
// 定义一个model来接受表单提交的值
private Employee model;
@Override
public Employee getModel() {
return model;
}
}

修改struts.xml配置拦截器。

因为表单提交和回显涉及到要把String日期和Date相互转换,所以在src下新建包com.leezp.ssh.converters。在该包下新建SSHDateConverter.java转换类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.leezp.ssh.converters;
import java.sql.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class SSHDateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
{
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
}
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
if (toClass == Date.class) {
try {
dateFormat.parse(values[0]);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String convertToString(Map context, Object o) {
if (o instanceof Date) {
return dateFormat.format((Date) o);
}
return null;
}
}

在conf源码包下新建xwork-conversion.properties属性文件配置日期转换类。

1
2
# 复制 SSHDateConverter的全类名
java.util.Date=com.leezp.ssh.converters.SSHDateConverter

配置自定义的类型转换器的两种方法:
在应用程序里使用一个自定义的类型转换器之前,必须先对它进行配置,这种配置既可以基于字段,也可以基于类型。
1.基于字段配置:可以为某个Model(该Model类也可能是Action)的各个属性分别配置一个自定义的转换器。
①.创建一个属性文件:ModelClassName-conversion.properties,该文件需和相对应的Model类放在同一个目录下。
②.编辑属性文件:
field1=customConverter1
field2=customConverter2

2.基于类型配置
①.在WEB-INF/classes/目录下创建xwork-conversion.properties文件。
②.在xwork-conversion.properties文件里把每一个需要进行类型转换的类与一个类型转换器关联起来。
fullyQualifiedClassName=CustomConvertor1

修改EmployeeDao.java添加保存的方法。

修改EmployeeService.java添加保存的方法。

获取源代码

添加员工的流程

访问index.jsp,点击添加员工的超链接<a href=”emp-input”>Add New Employee</a>,经过struts.xml配置文件解析,

1
2
3
4
<action name="emp-*" class="employeeAction" method="{1}">
<result name="input">/WEB-INF/views/emp-input.jsp
</result>
</action>

进入EmployeeAction.java的input()方法处理页面请求,

1
2
3
4
public String input() {
request.put("departments", departmentService.getAll());
return INPUT;
}

获取department的list返回到 emp-input.jsp从而绑定下拉框。

1
2
<s:form action="emp-save" method="post">
</s:form>

把crud方法放在一个action类中,就必定会涉及到一些数据准备的事情,所以用Preparable接口就再合适不过了,实现这个接口的prepare()方法,这个方法会在action类的所有方法执行前执行,另外我们也可以按照它的规则来写一些其它形式的prepare方法,例如aciton中有一个方法叫input(),那么我们可以实现一个prepareInput方法,这样在input()执行前,会执行prepareInput()方法。

保存操作的流程(ModelDriven和Preparable 拦截器):
prepareSave()->getModel()将上一步创建的值放到栈顶->由Preparable拦截器将表单的值赋给栈顶对象对应的属性 -> Save()
可以在struts-default.xml中查看拦截器执行顺序,
prepare->modelDriven->params(表单参数值赋给栈顶对象对应的属性)->setParameters ->prepareX()

ajax检验添加时的用户名是否可用

修改emp-input.jsp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
$(":input[name=lastName]").change(function() {
var val = $(this).val();
val = $.trim(val);
var $this = $(this);
if (val != "") {
var url = "emp-validateLastName";
var args = {
"lastName" : val,
"time" : new Date()
};
$this.nextAll("font").remove();//清空节点后内容,防止文字累加
$.post(url, args, function(data) {
//可用
if (data == "1") {
$this.after("<font color='green'>LastName可用!</font>");
}
//不可用
else if (data == "0") {
$this.after("<font color='red'>LastName不可用!</font>");
}//服务器错误
else {
alert("服务器错误!");
}
});
} else {
alert("lastName 不能为空!");
this.focus();
}
});
});
</script>
</head>
<body>
<h4>Employee Input Page</h4>
<s:form action="emp-save" method="post">
<!-- label属性为在页面显示的值 -->
<s:textfield name="lastName" label="LastName"></s:textfield>
<s:textfield name="email" label="Email"></s:textfield>
<s:textfield name="birth" label="Birth"></s:textfield>
<!-- struts2的下拉框有listKey和listValue两个属性 -->
<!-- department.id为属性department的属性 -->
<s:select list="#request.departments" listKey="id"
listValue="departmentName" name="department.id" label="Department">
</s:select>
<s:submit>
</s:submit>
</s:form>
</body>
</html>

在EmployeeDao.java添加查询用户名重复的方法。

在EmployeeService.java添加调用它的方法。

修改EmployeeAction.java。

修改struts.xml。

获取源代码

员工信息的修改

修改input.jsp页面,添加了修改链接等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
$(":input[name=lastName]").change(function() {
var val = $(this).val();
val = $.trim(val);
var $this = $(this);
if (val != "") {
var url = "emp-validateLastName";
var args = {
"lastName" : val,
"time" : new Date()
};
$this.nextAll("font").remove();//清空节点后内容,防止文字累加
$.post(url, args, function(data) {
//可用
if (data == "1") {
$this.after("<font color='green'>LastName可用!</font>");
}
//不可用
else if (data == "0") {
$this.after("<font color='red'>LastName不可用!</font>");
}//服务器错误
else {
alert("服务器错误!");
}
});
} else {
alert("lastName 不能为空!");
this.focus();
}
});
});
</script>
</head>
<body>
<h4>Employee Input Page</h4>
<s:form action="emp-save" method="post">
<!-- Edit -->
<s:if test="id !=null">
<s:textfield name="lastName" label="LastName" disabled="true"></s:textfield>
<s:hidden name="id"></s:hidden>
<%--
<!--通过添加隐藏域的方式把未提交的字段值提交到服务器-->
<s:hidden name="lastName"/>
<s:hidden name="createTime"/>
缺点:每个属性都要再另写一行
优点:不需要使用查一遍数据库的方式获取数据
--%>
</s:if>
<!-- Add -->
<s:else>
<s:textfield name="lastName" label="LastName"></s:textfield>
</s:else>
<!-- label属性为在页面显示的值 -->
<s:textfield name="email" label="Email"></s:textfield>
<s:textfield name="birth" label="Birth"></s:textfield>
<!-- struts2的下拉框有listKey和listValue两个属性 -->
<!-- department.id为属性department的属性 -->
<s:select list="#request.departments" listKey="id"
listValue="departmentName" name="department.id" label="Department">
</s:select>
<s:submit>
</s:submit>
</s:form>
</body>
</html>

在EmployeeDao.java里添加获取员工信息的get()方法。

修改EmployeeService.java。

修改EmployeeAction.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package com.leezp.ssh.actions;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.leezp.ssh.entities.Employee;
import com.leezp.ssh.service.DepartmentService;
import com.leezp.ssh.service.EmployeeService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
/**
* 实现RequestAware请求域
*
* @author Lee
*
*/
public class EmployeeAction extends ActionSupport implements RequestAware,
ModelDriven<Employee>, Preparable {
/**
*
*/
private static final long serialVersionUID = 1L;
private EmployeeService employeeService;
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
private DepartmentService departmentService;
public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
private String lastName;
public void setLastName(String lastName) {
this.lastName = lastName;
}
// **注意,这个方法validateLastName()里加参数(String lastName),struts.xml会找不到这个方法而报错**
public String validateLastName() throws UnsupportedEncodingException {
if (employeeService.lastNameIsValid(lastName)) {
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} else {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
}
return "ajax-success";
}
public String input() {
request.put("departments", departmentService.getAll());
return INPUT;
}
public void prepareInput() {
if (id != null) {
// 回显到页面
model = employeeService.get(id);
}
}
public String list() {
request.put("employees", employeeService.getAll());
return "list";
}
private Integer id;
public void setId(Integer id) {
this.id = id;
}
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public String delete() {
try {
employeeService.delete(id);
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
// return SUCCESS;
// 使用ajax异步,删除后不再需要刷新页面,所以注释掉上一句。
return "ajax-success";
}
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> arg0) {
this.request = arg0;
}
// struts2执行Save()方法之前会先执行prepareSave()方法
public void prepareSave() {
// 根据id来判断为save()方法准备的model是new的还是从数据库获取的!
// add
if (id == null) {
model = new Employee();
// edit //防止 id为空
} else {
model = employeeService.get(id);
}
}
// 保存员工信息的方法
public String save() {
// System.out.println(model);// 打印model查看
if (id == null) {
// add
model.setCreateTime(new Date());
}
employeeService.saveOrUpdate(model);
return SUCCESS;
}
@Override
public void prepare() throws Exception {
}
// 定义一个model来接受表单提交的值
private Employee model;
@Override
public Employee getModel() {
return model;
}
}

获取源代码

总结

因本人水平有限,本demo还有很多不足之处,还望各位批评指正。

参考文献
JavaBean中DAO设计模式介绍
Hibernate高级查询方法
Hibernate学习笔记-懒加载Lazy-true
JQuery this和$(this)的区别及获取$(this)子元素对象的方法
Preparable接口和自定义拦截器总结
Java过滤器与SpringMVC拦截器之间的关系与区别
ModelDriven拦截器、Preparable 拦截器
关于struts2/webwork中prepare接口中的二次绑定
hibernate——Session接口中定义的saveOrUpdate()方法浅析
Hibernate之Query接口的uniqueResult()方法
懒加载异常的解决办法

版权声明:本文为博主原创文章,转载请注明出处 Leezp’s Blog

点击按钮打赏作者!