Hibernate所需要的基本文件:
ElectText.java
ElecText.hbm.xml
hibernate.cfg.xml
第一步:创建测试表Elec_Text:
create table Elec_Text(textID varchar(50) not null primary key,textName varchar(50),textDate datetime,textRemark varchar(500) );
第二步:创建项目,导入jar包
第三步:持久层
(1)在com.elec.domain中创建ElecText.java
ElecText.java 说明:持久层要实现一个序列化接口:Serializable
public class ElecText implements java.io.Serializable { private String textID; //主键ID
private String textName; //测试名称
private Date textDate; //测试日期
private String textRemark; //测试备注 public String getTextID() {
return textID;
}
public void setTextID(String textID) {
this.textID = textID;
}
public String getTextName() {
return textName;
}
public void setTextName(String textName) {
this.textName = textName;
}
public Date getTextDate() {
return textDate;
}
public void setTextDate(Date textDate) {
this.textDate = textDate;
}
public String getTextRemark() {
return textRemark;
}
public void setTextRemark(String textRemark) {
this.textRemark = textRemark;
}
}
在com.elec.domain目录下,创建ElecText.java对应的映射文件 ElecText.hbm.xml
到对应的jar包中找到约束,复制到配置文件中:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 打开hibernate包,找到约束文件 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 有了约束,就可以写mapping -->
<hibernate-mapping>
<class name="com.kangjie.elec.domain.ElecText" table="Elec_Text"><!-- name是类型 ,在类名上按F2选中全路径名-->
<id name="textID" type="string" column="textID">
<generator class="uuid"></generator>
</id>
<property name="textName" type="string" column="textName"></property>
<property name="textDate" type="date" column="textDate"></property>
<property name="textRemark" type="string" column="textRemark"></property>
</class>
</hibernate-mapping>
<!-- 然后写映射文件 -->
(3) 在工程下创建文件夹config,config下创建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>
<!-- 连接数据库信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/kangjie?useUnicode=true&characterEncoding=utf8</property>
<property name="hibernate.connection.username">admin</property>
<property name="hibernate.connection.password">admin</property>
<!-- 其他配置 --><!-- 测试业务层的时候,不用自动提交 -->
<property name="hibernate.connection.autocommit">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.hbm2ddl.auto">update</property><!-- 没有表就自动创建 -->
<property name="hibernate.show_sql">true</property>
<!-- 添加映射 -->
<mapping resource="com/kangjie/elec/domain/ElecText.hbm.xml"/>
<!-- 修改了项目名称,可以还需要修改myeclipse下的web选项的名称 -->
</session-factory> </hibernate-configuration>
(4) 使用junit在test包中进行测试(并且导入log4j的配置文件)
public class TestHibernate {
/**
* 测试保存
*/
@Test
public void save(){
Configuration configuration = new Configuration();
configuration.configure();//加载classpath下的hibernate.cfg.xml文件
SessionFactory sf = configuration.buildSessionFactory();
Session s = sf.openSession();
Transaction ts = s.beginTransaction(); ElecText elecText = new ElecText();
elecText.setTextName("测试数据");
elecText.setTextDate(new Date());
elecText.setTextRemark("备注");
s.save(elecText);
ts.commit();
s.close();
/**
* 测试的过程中可能会有日志警告,因为hibernate需要配置log4j日志
*/
}
}
然后添加log4j.propertities
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=error, stdout #log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug ### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug ### log just the SQL
#log4j.logger.org.hibernate.SQL=debug ### log JDBC bind parameters ###
#log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug ### log schema export/update ###
#log4j.logger.org.hibernate.tool.hbm2ddl=debug ### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug ### log cache activity ###
#log4j.logger.org.hibernate.cache=debug ### log transaction activity
#log4j.logger.org.hibernate.transaction=debug ### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug ### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
测试结果:
数据库中的显示
第四步:DAO层
每个持久化对象都会对应一个Dao,都有操作单标的CRUD的操作;为了避免重复,抽取一个公用的Dao:CommonDao
(1) 在com.elec.dao中创建2个接口(公用接口和业务接口)
* 公共接口
public interface ICommonDao<T> {
void save(T entity);
}
* 业务接口(需要继承公共接口,并且指定泛型T所对应的对象:
/**
* 每个持久化对象都会对应一个Dao,都有操作单单表的CRUD:create , Retrieve,update,delete
*
*/
public interface IElecTextDao extends ICommonDao<ElecText>{
public static final String SERVICE_NAME="com.kangjie.elec.dao.impl.ElecTextDaoImpl";
}
(2)在com.elec.dao.impl中创建2个接口的实现类
* 公用类(需要继承HibernateDaoSupport,这样可以方便使用HibernateTemplate对象):
public class CommonDaoImpl<T> extends HibernateDaoSupport implements ICommonDao<T> { /**
* 使用hibernate模板保存:
*/
@Resource(name="sessionFactory")
public void setDi(SessionFactory sessionFactory){
System.out.println("sessionFactory" + sessionFactory);
this.setSessionFactory(sessionFactory);
} public void save(T entity) {
this.getHibernateTemplate().save(entity);
} }
* 业务类(需要继承公用类,这样可以使用公用类中的定义的方法)
/**
* spring容器:
* * 创建Action,Service,Dao的对象(IOC)
* * * <bean id="" class=""></bean>
* * 每层进行注入(DI)
* ** <property name="" ref=""/>
* * 声明式事务(AOP)切面编程
* **** 声明事务管理器
* * 电力项目(注解方式)
* * @Controller @Service , @Repository @Commponent
*
*/
//注解支持
/**
* 相当于正在spring容器中定义:
* <bean id="elecTextDaoImpl" class="com.itheima.elec.dao.impl.ElecTextImpl">
*这种写法过于繁琐,在接口IElecTextDao中指定 标示 public static final String SERVICE_NAME="com.kangjie.elec.dao.impl.ElecTextDaoImpl"; */
//唯一的属性
@Repository(IElecTextDao.SERVICE_NAME)
public class ElecTextDaoImpl extends CommonDaoImpl<ElecText> implements IElecTextDao { }
(3) 在config中创建spring的配置文件(beans.xml)
<beans 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"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-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">
<!-- .添加组件对注解的支持 :表示这个包下都支持注解 -->
<context:component-scan base-package="com.kangjie.elec"/>
<!-- --> <!-- .spring整合hibernate的核心:session工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 注入资源 -->
<property name="configLocation">
<value>
classpath:hibernate.cfg.xml
</value>
</property>
</bean>
<!-- .创建事务管理器 :管理session工厂,即:hibernate -->
<bean id="trManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- 注入 sessionfactory -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- :事务处理 注解,在Service层填写一个注解@Transcational -->
<tx:annotation-driven transaction-manager="trManager" />
<!--下边这部分是设置配置文件,只做演示-->
<!-- 事务处理配置文件-->
<!--
<tx:advice id="aa" transaction-manager="trManager">
<tx:attributes>
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="*" read-only="false"/>
</tx:attributes>
</tx:advice>
<aop:config>
-->
<!-- * com.itheima.elec.service..* .* (..) -->
<!-- 返回任意类型 service包及其子包 中所有类, 类中所有方法 参数任意-->
<!--
<aop:pointcut expression="execution(* com.kangjie.elec.service..*.*(..))" id="bb"/>
<aop:advisor advice-ref="aa" pointcut-ref="bb"/>
</aop:config>
-->
</beans>
(4) 使用junit完成测试
public class TestDao { //保存
@Test
public void save(){
//加载spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IElecTextDao elecTextDao = (IElecTextDao) ac.getBean(IElecTextDao.SERVICE_NAME);//找节点
ElecText elecText = new ElecText();
elecText.setTextName("abcde");
elecText.setTextDate(new Date());
elecText.setTextRemark("make a difference");
elecTextDao.save(elecText);
}
}
注意:如果数据没有保存,需要设置事务自动提交:在hibernate.cfg.xml中添加:
<!-- 使用hibernate的方式提交事务(自动提交) -->
<property name="hibernate.connection.autocommit">true</property>
第五步:Service层
(1) 在com.elec.service中创建接口:
public interface IElecTextService {
public static final String SERVICE_NAME="com.kangjie.elec.service.impl.ElecTextServiceImpl"; public void saveElecText(ElecText elecText);
}
(2) 在com.elec.service.impl中创建接口的实现类:
/**
* spring框架使用的是分层的注解
* @Repository 持久层
* @Service 服务层
* @Controller 控制层
* 在Service层添加注解: @Transactional
*
* @Service
*相当于在spring中定义:
* <bean id ="" class="">
*/
@Service(IElecTextService.SERVICE_NAME)
@Transactional(readOnly=true) //由于spring提供的声明式事务处理,进行事务的控制,在业务层的类和方法上定义@Transactional(),同时去掉hibernate.cfg.xml中的配置,由spring统一控制。
public class ElecTextServiceImpl implements IElecTextService { @Resource(name=IElecTextDao.SERVICE_NAME)
IElecTextDao elecTextDao;
/*由于spring提供的声明式事务处理,进行事务的控制,在业务层的类和方法上定义@Transactional(),同时去掉hibernate.cfg.xml中的配置,由spring统一控制。去掉的代码是
<!-- 使用hibernate的方式提交事务(自动提交) -->
<property name="hibernate.connection.autocommit">true</property>
*/
@Override
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
public void saveElecText(ElecText elecText) {
elecTextDao.save(elecText);
//然后测试
} }
(3) 测试
public class TestService { @Test
public void save(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IElecTextService elecTextService = (IElecTextService)ac.getBean(IElecTextService.SERVICE_NAME); ElecText elecText = new ElecText();
elecText.setTextName("测试service名称3");
elecText.setTextDate(new Date());
elecText.setTextRemark("备注service3");
elecTextService.saveElecText(elecText);
}
}
由于spring提供的声明式事务处理,进行事务的控制,在业务层的类和方法上定义@Transactional(),同时去掉hibernate.cfg.xml中的配置,由spring统一控制。去掉的代码是:
<!-- 使用hibernate的方式提交事务(自动提交) -->
<property name="hibernate.connection.autocommit">true</property>
第六步:
(1)在com.elec.web.action中创建Action(业务Action)类和BaseAction(公用Action)
Action类:(注意:这里要设置成多例,即@Scope(value=prototype),因为struts2的Action是多实例,多线程)
struts2是模型驱动 ?
@SuppressWarnings("serial")
@Controller("elecTextAction")
@Scope(value="prototype")
public class ElecTextAction extends ActionSupport implements ModelDriven<ElecText>{ ElecText elecText = new ElecText(); //注入Service
@Resource(name=IElecTextService.SERVICE_NAME)
IElecTextService elecTextService; //执行保存
public String save(){
elecTextService.saveElecText(elecText);
return "save";
} @Override
public ElecText getModel() { // TODO Auto-generated method stub
return elecText;
}
}
然后将复用的内容抽取为一个公用类BaseAction类
package com.elec.web.action;
import java.lang.reflect.ParameterizedType;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
T entity;
// T型实例化
public BaseAction(){
//T型转换
// this.getClass().getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
Class entityClass = (Class) parameterizedType.getActualTypeArguments()[0] ;
try {
entity = (T) entityClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public T getModel() {
return entity;
}
}
断点调试,使用watch查看this.Class的值 :
继续查看
转换成功
首先
在com.elec.util包下创建公用类(用于泛型转换)。
泛型转换的目的子类传递真实对象类型,在父类中使用泛型转换成真实对象类型。
以后util包下封装的就是公用类。
package com.elec.utils; import java.lang.reflect.ParameterizedType; public class TUtils { public static Class getActualType(Class entity){
ParameterizedType parameterizedType = (ParameterizedType) entity.getGenericSuperclass();
Class entityClass = (Class) parameterizedType.getActualTypeArguments()[0];
return entityClass;
}
}
然后抽取BaseAction类,调用TUtils中的方法
BaseAction.java
package com.elec.web.action;
public class BaseAction<T> extends ActionSupport implements ModelDriven<T>,ServletRequestAware,ServletResponseAware{ T entity; protected HttpServletRequest request;
protected HttpServletResponse response; // protected HttpServletRequest request;
//实例化泛型
public BaseAction(){
//T型转换
Class entityClass = TUtils.getActualType(this.getClass()); try {
entity = (T) entityClass.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public T getModel(){
return entity;
} @Override
public void setServletResponse(HttpServletResponse response) {
// TODO Auto-generated method stub
this.response = response;
} @Override
public void setServletRequest(HttpServletRequest request) {
// TODO Auto-generated method stub
this.request = request;
} }
ElecTextAction.java 继承BaseAction
package com.elec.web.action; @SuppressWarnings("serial")
@Controller("elecTextAction")
@Scope(value="prototype")
public class ElecTextAction extends BaseAction<ElecText>{ ElecText elecText = this.getModel(); //注入Service
@Resource(name=IElecTextService.SERVICE_NAME)
IElecTextService elecTextService; //执行保存
public String save(){
elecTextService.saveElecText(elecText);
String textDate = request.getParameter("textDate");
System.out.println(textDate);
return "save";
} }
创建struts2的配置文件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="true"></constant>
<!-- ui主题,简单主题 -->
<constant name="struts.ui.theme" value="simple"></constant>
<!-- 修改struts的后缀 改成do -->
<constant name="struts.action.extension" value="do"></constant> <!-- 系统管理 -->
<package name="system" namespace="/system" extends="struts-default">
<!-- 测试 -->
<action name="elecTextAction_*" class="elecTextAction" method="{1}">
<result name="save">/system/textAdd.jsp</result>
</action>
</package>
</struts>
在web.xml中添加配置:
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<!-- 配置struts2的过滤器,这是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>
<!-- web容器启动的时候,自动加载spring容器(监听器) -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
测试页面:
textAdd.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<script type="text/javascript" src="${pageContext.request.contextPath}/My97DatePicker/WdatePicker.js"></script>
<html>
<head>
<title>测试专用jsp</title>
<link href="${pageContext.request.contextPath }/css/Style.css" type="text/css" rel="stylesheet"> <script language="javascript">
function checkchar(){
document.Form1.action="${pageContext.request.contextPath }/system/elecTextAction_save.do";
document.Form1.submit();
}
function addEnter(element){
document.getElementById(element).value = document.getElementById(element).value+"<br>"; }
</script> </head> <body>
<form name="Form1" id="Form1" method=post> <table cellspacing="1" cellpadding="5" width="90%" align="center" bgcolor="#f5fafe" style="border:1px solid #8ba7e3" border="0"> <tr>
<td class="ta_01" colspan=2 align="center" background="${pageContext.request.contextPath }/images/b-info.gif">
<font face="宋体" size="2"><strong>测试专用jsp</strong></font>
</td>
</tr>
<TR height=10><td></td><td></td></TR> <tr>
<td class="ta_01" align="center" bgcolor="#f5fafe" width="15%">测试名称:</td>
<td class="ta_01" bgcolor="#ffffff" style="word-break: break-all"> <textarea name="textName" id="textName" style="width: 500px; height: 160px; padding: 1;FONT-FAMILY: 宋体; FONT-SIZE: 9pt" onkeydown="if(event.keyCode==13)addEnter('textName');"></textarea>
</td> </tr>
<tr>
<td class="ta_01" align="center" bgcolor="#f5fafe" width="15%">测试日期:</td>
<td class="ta_01" bgcolor="#ffffff" style="word-break: break-all"> <input name="textDate" type="text" maxlength="50" size=20 onclick="WdatePicker()">
</td> </tr>
<tr>
<td class="ta_01" align="center" bgcolor="#f5fafe" width="15%">测试备注:</td>
<td class="ta_01" bgcolor="#ffffff" style="word-break: break-all">
<textarea name="textRemark" id="textRemark" style="width: 500px; height: 160px; padding: 1;FONT-FAMILY: 宋体; FONT-SIZE: 9pt" onkeydown="if(event.keyCode==13)addEnter('textRemark');"></textarea>
</td> </tr>
<tr>
<td class="ta_01" style="width: 100%" align="center" bgcolor="#f5fafe" colspan="2">
<input type="button" name="BT_Submit" value="保存" onclick="checkchar()" id="BT_Submit" style="font-size:12px; color:black; height=20;width=50">
</td>
</tr>
</table>
</form> </body>
</html>
实现ServletRequestAware,ServletResponseAware报错:
can not implement the missing methods,either due to compile errors or the projects build path does not resolve all dependencies
上面的错误提示的意思是:不能实现丢失的方法,或许是因为编译错误或者工程创建的路径不能解决所有依赖;也就是缺少Servlet相关的jar包了,这里是servlet-api.jar
解决办法:添加servlet-api.jar。
这个jar包可以在tomcat的lib目录下找到,复制到项目中去就可以了