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"> <!-- 1.添加组件对注解的支持 :表示这个包下都支持注解 --> <context:component-scan base-package="com.kangjie.elec"/> <!-- --> <!-- 3.spring整合hibernate的核心:session工厂 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 注入资源 --> <property name="configLocation"> <value> classpath:hibernate.cfg.xml </value> </property> </bean> <!-- 4.创建事务管理器 :管理session工厂,即:hibernate --> <bean id="trManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <!-- 注入 sessionfactory --> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 5:事务处理 注解,在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目录下找到,复制到项目中去就可以了