代码框架图
基本开发流程
1.加入Spring
1)加入jar包
2)配置web.xml文件
3)加入Spring配置文件
2.加入Hibernate
1)同时建立持久化类,和其对应的.hbm.xml文件,生成对应的数据表
2) Spring整合Hibernate
a)加入jar包
b)在类路径下加入Hibernate.cfg.xml文件,在其中配置Hibernate的基本属性
c)建立持久化类和其对应的.hbm.xml文件
d)和Spring进行整合
i)加入 从c3p0和MySql的驱动
ii)在Spring的配置文件中配置:数据源,SessionFactory,声明式事务
e)启动项目,会看到生成的数据包
3.加入Struts2
1) 加入jar包, 如果有重复的jar包,则删除版本低的
2) 在web.xml文件中配置Struts2 的Filter
3) 加入Struts2的配置文件
4) 整合Spring
a)加入Struts2的Spring插件的jar包
b)在spring的配置文件中正常配置Action,注意Action的Scope为prototype(非单例)
c)在Struts2的配置文件中配置Action时,class属性指向该Action在IOC中id
4.完成功能
1. 获取所有的员工信息:如果在DAO中只查询Employee的信息,而且Employee和Department还是使用的懒加载:
页面上还需要显示员工信息,此时会出现懒加载异常,代理对象不能被初始化:org.hibernate.LazyInitializationException
解决方案:
a) 打开懒加载:不推荐使用,增加了sql查询语句
<many-to-one name="department" class="com.wyw.shh.entities.Department" lazy="false">
<column name="DEPARTMENT_ID" />
</many-to-one>
b)获取Employee时使用迫切左外连接同时初始化关联的Department对象
FROM Employee e LEFT OUTER JOIN FETCH e.department
c)使用OpenSessionInFilter:在页面加载完开Session
2.删除员工信息:
a) 正常删除,返回值是redirect类型,而且重定向到emp-list
b) 确定要删除吗?的提示使用jQuery完成
c)Ajax的使用参见struts-2.3.15.3/docs/WW/docs/ajax.html
3.添加员工
a)显示表单页面,需要先查询所有的部门信息
b)显示使用struts2的ModelDriven和Preparable拦截器(点击提交的时候把表单封装成一个对象)
c)时间是一个字符串,需要转为一个Data类型的对象
核心代码
配置文件
- applicationContext.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: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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.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>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath:com/wyw/shh/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="txAdvie" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="LastNameIsValid" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 3.配置事务切入点,再把事务属性和事务切入点关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* com.wyw.ssh.service.*.*(..))" id="txPointcut"/>
<aop:advisor advice-ref="txAdvie" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
- applicationContext-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeDao" class="com.wyw.ssh.dao.EmployeeDao">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="employeeService" class="com.wyw.ssh.service.EmployeeService">
<property name="employeeDao" ref="employeeDao"></property>
</bean>
<bean id="departmentDao" class="com.wyw.ssh.dao.DepartmentDao">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="departmentServie" class="com.wyw.ssh.service.DepartmentServie">
<property name="departmentDao" ref="departmentDao"></property>
</bean>
<bean id="employeeAction" class="com.wyw.shh.actions.EmployeeAction"
scope="protoatype">
<property name="employeeService" ref="employeeService"></property>
<property name="departmentServie" ref="departmentServie"></property>
</bean>
</beans>
- hibernate.cfg.xml
<?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>
- 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.devMode" value="false" />
<constant name="struts.action.extension" value="action,do,html,"></constant>
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<constant name="struts.ui.theme" value="xhtml"></constant>
<!--
package:组织模块
name:用于其他包应用当前包
extends:当前包继承的包
-->
<package name="product" extends="struts-default" namespace="/">
<!-- 定义新的拦截器栈,配置prepare拦截器栈的参数值alwaysInvokePrepare为false -->
<interceptors>
<interceptor-stack name="sshStack">
<interceptor-ref name="paramsPrepareParamsStack">
<param name="prepare.alwaysInvokePrepare">false</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 使用新的拦截器栈 -->
<default-interceptor-ref name="sshStack"></default-interceptor-ref>
<!-- 配置一个action -->
<action name="test" class="com.wyw.shh.actions.EmployeeAction"
method="test">
<result name="test">/WEB-INF/views/success.jsp</result>
</action>
<action name="emp-*" class="com.wyw.shh.actions.EmployeeAction"
method="{1}">
<result name="{1}">/WEB-INF/views/emp-{1}.jsp</result>
<result type="stream" name="ajax-success">
<param name="contentType">text/html</param>
<param name="inputName">inputStream</param>
</result>
<!--<result name="success" type="redirect">/emp-list</result>-->
<result name="success" type="redirect">/emp-list</result>
</action>
</package>
</struts>
- xwork-conversion.properties
java.util.Date=com.wyw.shh.converters.SSHDateConverters
- java.util.Date=com.wyw.shh.converters.SSHDateConverters
jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
- web.xml
<?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>classpath:applicationContext*.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<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>
<welcome-file-list>
<welcome-file>/WEB-INF/views/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
持久化类
- com.wyw.shh.entities
(1)Department.java
package com.wyw.shh.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;
}
}
(2) Employee.java
package com.wyw.shh.entities;
import java.util.Date;
public class Employee {
private Integer id;
//不能被修改
private String lastName;
private String email;
//从前端传入的是String类型,需要类型转化
private Date birth;
//不能被修改
private Date createTime;
//单项n-1的关联关系
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;
}
@Override
public String toString() {
return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", birth=" + birth
+ ", createTime=" + createTime + ", department=" + department + "]";
}
}
- com.wyw.ssh.dao
(1) BaseDao.java
package com.wyw.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();
}
}
(2) DepartmentDao.java
package com.wyw.ssh.dao;
import java.util.List;
import com.wyw.shh.entities.Department;
public class DepartmentDao extends BaseDao{
public List<Department> getAll(){
String hql = "FROM Department";
return getSession().createQuery(hql).list();
}
}
(3) EmployeeDao.java
package com.wyw.ssh.dao;
import java.util.List;
import org.hibernate.Query;
import com.wyw.shh.entities.Employee;
public class EmployeeDao extends BaseDao{
public List<Employee> getAll(){
String hql = "FROM Employee e LEFT OUTER JOIN FETCH e.department";
return getSession().createQuery(hql).list();
}
public void delete(Integer id){
String hql = "DELETE FROM Employee e WHERE e.id = ?";
getSession().createQuery(hql).setInteger(0, id).executeUpdate();
}
public void saveOrUpdate(Employee employee){
getSession().saveOrUpdate(employee);
}
public Employee getEmployeeByLastName(String lastName){
String hql = "FROM Employee e WHERE e.lastName = ?";
Query query = getSession().createQuery(hql).setString(0, lastName);
return (Employee)query.uniqueResult();
}
public Employee get(Integer id){
return (Employee) getSession().get(Employee.class, id);
}
}
- com.wyw.ssh.service
(1) DepartmentServie.java
package com.wyw.ssh.service;
import java.util.List;
import com.wyw.shh.entities.Department;
import com.wyw.ssh.dao.DepartmentDao;
public class DepartmentServie {
private DepartmentDao departmentDao;
public void setDepartmentDao(DepartmentDao departmentDao) {
this.departmentDao = departmentDao;
}
public List<Department> getAll(){
return departmentDao.getAll();
}
}
(2) EmployeeService.java
package com.wyw.ssh.service;
import java.util.List;
import com.wyw.shh.entities.Employee;
import com.wyw.ssh.dao.EmployeeDao;
public class EmployeeService {
private EmployeeDao employeeDao;
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
public List<Employee> getAll(){
List<Employee> employees = employeeDao.getAll();
//employees.clear();
return employees;
}
public void delete(Integer id){
employeeDao.delete(id);
}
public void saveOrUpdate(Employee employee){
employeeDao.saveOrUpdate(employee);
}
public boolean LastNameIsValid(String lastName){
return employeeDao.getEmployeeByLastName(lastName) == null;
}
public Employee get(Integer id){
return employeeDao.get(id);
}
}
- com.wyw.shh.actions
(1) EmployeeAction.java
package com.wyw.shh.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.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.wyw.shh.entities.Employee;
import com.wyw.ssh.service.DepartmentServie;
import com.wyw.ssh.service.EmployeeService;
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 DepartmentServie departmentServie;
public void setDepartmentServie(DepartmentServie departmentServie) {
this.departmentServie = departmentServie;
}
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 (Exception e) {
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
return "ajax-success";
}
public String input(){
request.put("departments", departmentServie.getAll());
return "input";
}
public void prepareInput(){
if(id != null){
model = employeeService.get(id);
}
}
public String save(){
if(id == null){
model.setCreateTime(new Date());
}
employeeService.saveOrUpdate(model);
//System.err.println(model);
return SUCCESS;
}
public void prepareSave(){
if(id == null){
model = new Employee();
}else{
model = employeeService.get(id);
}
}
private String lastName;
public void setLastName(String lastName) {
this.lastName = lastName;
}
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";
}
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> arg0) {
this.request = arg0;
}
public String test(){
System.out.println("test.....");
return "test";
}
@Override
public void prepare() throws Exception {
}
private Employee model;
@Override
public Employee getModel() {
return model;
}
public Employee get(Integer id){
return employeeService.get(id);
}
}
- com.wyw.shh.converters
(1) SSHDateConverters.java
package com.wyw.shh.converters;
import java.util.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 SSHDateConverters extends StrutsTypeConverter{
private DateFormat dateFormate;
{
dateFormate = new SimpleDateFormat("yyyy-MM-dd");
}
@Override
public Object convertFromString(Map arg0, String[] arg1, Class arg2) {
if(arg2 == Date.class){
try {
return dateFormate.parse(arg1[0]);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String convertToString(Map arg0, Object arg1) {
if(arg1 instanceof Date){
return dateFormate.format((Date)arg1);
}
return null;
}
}
JSP文件
- emp-input.jsp
<%@ 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-2.2.3.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 != ""){
//把当前节点后面的所有的font兄弟节点清除
$this.nextAll("font").remove();
var url = "emp-validateLastName";
var args = {"lastName":val,"time":new Date()};
$.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不能为空");
}
});
})
</script>
</head>
<body>
<h4>Employee Input Page</h4>
<s:form action="emp-save" method="post">
<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>
<s:hidden name="createTime"></s:hidden>
--%>
</s:if>
<s:else>
<s:textfield name="lastName" label="LastName"> </s:textfield>
</s:else>
<s:textfield name="email" label="Email"> </s:textfield>
<s:textfield name="birth" label="Birth"> </s:textfield>
<s:select list="#request.departments"
listKey="id" listValue="departmentName" name="department.id"
label="Department"></s:select>
<s:submit></s:submit>
</s:form>
</body>
</html>
- emp-list.jsp
<%@ 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-2.2.3.min.js"></script>
<script type="text/javascript">
$(function(){
//1.点击的delete时,弹出确定是要删除信息吗?若确定则执行删除,否则取消
$(".delete").click(function() {
//取消超链接的默认行为
var lastName = $(this).next(":input").val();
var flag = confirm("确定要删除" + lastName + " 的信息吗?");
if (flag) {
var $tr = $(this).parent().parent();
//删除,使用ajax方式
var url = this.href;
var args = {"time":new Date()}
$.post(url,args,function(data){
//如果data的返回值为1,则提示删除成功,且把当前行删除
if(data == 1){
alert("删除成功");
$tr.remove();
}else{
//否则,则提示删除失败
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="1" cellspacing="0">
<tr>
<td>ID</td>
<td>LASTNAME</td>
<td>EMAIL</td>
<td>BIRTH</td>
<td>CREATETIME</td>
<td>DEPT</td>
<td>DELETE</td>
<td>EDITE</td>
</tr>
<s:iterator value="#request.employees">
<tr>
<td>${id }</td>
<td>${lastName }</td>
<td>${email }</td>
<td>
<s:date name="birth" format="yyyy-MM-dd"/>
</td>
<td>
<s:date name="createTime" format="yyyy-MM-dd hh:mm:ss"/>
</td>
<td>${department.departmentName }</td>
<td>
<a href="emp-delete?id=${id }" class="delete">Delete</a>
<input type="hidden" value="${lastName }"/>
</td>
<td>
<a href="emp-input?id=${id }">Edite</a>
</td>
</tr>
</s:iterator>
</table>
</s:else>
</body>
</html>
- index.jsp
<%@ 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>
<a href="test">test</a>
<br><br>
<a href="emp-list">All Employees</a>
<br><br>
<a href="emp-input">Add New Employee</a>
</body>
</html>
-
Previous
leetcode 116. Populating Next Right Pointers in Each Node -
Next
leetcode 349. Intersection of Two Arrays