首先准备好环境所需要的所有jar包,下载链接为点击链接
搭建的顺序为 hibernate-spring-Struts,搭建完成的目录结构图如下:
将下载的jar包扔到lib文件夹中,在config文件夹中加入log4j配置文件
### 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
一. 持久层
1.首先创建一个名为Electric的数据库,编码设为UTF-8,然后建表,创建表的SQL语句为
CREATE TABLE `elec_text` (
`textId` varchar(50) NOT NULL,
`textName` varchar(50) default NULL,
`textDate` datetime default NULL,
`textRemark` varchar(30) default NULL,
PRIMARY KEY (`textId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.创建项目。项目编码设为UTF-8.。
(1). 在po包下创建ElecText.java
package cn.elec.po;
import java.io.Serializable;
import java.util.Date;
public class ElecText implements Serializable{
private String textId;
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;
}
}
(2). 在同目录下创建其映射文件ElecText.hbm.xml
其中textId为自动生成的UUID。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.elec.po.ElecText" table="Elec_Text">
<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/Electric?useUnicode=true&characterEncoding=utf8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- 其他的配置 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.show_sql">true</property>
<!-- 事务自动提交,由spring代为管理 -->
<!-- <property name="hibernate.connection.autocommit">true</property> -->
<!-- 加载映射文件 -->
<mapping resource="cn/elec/po/ElecText.hbm.xml"/>
</session-factory>
</hibernate-configuration>
(4) 在test包下创建测试类TestHibernate.java
<pre name="code" class="java">package cn.elec.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import cn.elec.po.ElecText;
public class TestHibernate {
@Test
public void save() {
Configuration config = new Configuration();
config.configure();
SessionFactory sf = config.buildSessionFactory();
Session s = sf.openSession();
Transaction tr = s.beginTransaction();
ElecText elecText = new ElecText();
elecText.setTextName("测试hibernate");
elecText.setTextDate(new Date());
elecText.setTextRemark("测试remark");
s.save(elecText);
tr.commit();
s.close();
}
}
如果数据库中插入成功,则说明Hibernate环境搭建成功
二. dao层
1. 在dao包下创建两个接口类,公共dao接口ICommonDao和IElecTextDao,之后会让IElecTextDao继承ICommonDao
package cn.elec.dao;
public interface ICommonDao<T> {
void save(T t);
}
业务接口
package cn.elec.dao;
import cn.elec.po.ElecText;
public interface IElecTextDao extends ICommonDao<ElecText>{
public static final String SERVICE_NAME = "cn.elec.dao.impl.ElecTextDaoImpl";
}
2. 随后再分别创建两接口的实现类CommonDaoImpl和ElecTextDaoImpl
package cn.elec.dao.impl;
import javax.annotation.Resource;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import cn.elec.dao.ICommonDao;
//HibernateDaoSupport是spring对hibernate事务的封装,使用它需要动态注入sessionFactory
public class CommonDaoImpl<T> extends HibernateDaoSupport implements ICommonDao<T>{
//使用注解注入
@Resource(name="sessionFactory")
public void setSessionFactoryDI(SessionFactory sessionFactory) {
this.setSessionFactory(sessionFactory);
}
public void save(T t) {
getHibernateTemplate().save(t);
}
}
package cn.elec.dao.impl;
import org.springframework.stereotype.Repository;
import cn.elec.dao.IElecTextDao;
import cn.elec.po.ElecText;
@Repository(IElecTextDao.SERVICE_NAME)
public class ElecTextDaoImpl extends CommonDaoImpl<ElecText> implements IElecTextDao{
}
3.创建spring的配置文件(beans.xml)
<?xml version="1.0" encoding="UTF-8"?>
<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. 开启对注解 的支持,组件的自动扫描,扫描 cn.elec包下
所有包含@Controller,@Service,@Repository的类 -->
<context:component-scan base-package="cn.elec"></context:component-scan>
<!-- 2. ? -->
<!-- 3. 创建SessionFactory,这是Spring整合Hibernate的核心 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 加载类路径下的hibernate.cfg.xml -->
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- 4. 声明事务管理器(切面) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 5. 注解,在Service的类或者是Service的方法上,添加@Transcational()注解,用来控制事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 也可以使用spring的配置文件的方式管理事务
<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="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* cn.itcast.elec.service..*.*(..))" id="bb"/>
<aop:advisor advice-ref="aa" pointcut-ref="bb"/>
</aop:config>-->
</beans>
package cn.elec.test;
import java.util.Date;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.elec.dao.IElecTextDao;
import cn.elec.po.ElecText;
public class TestDao {
@Test
public void save() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
IElecTextDao dao = (IElecTextDao) context.getBean(IElecTextDao.SERVICE_NAME);
ElecText elecText = new ElecText();
elecText.setTextName("测试dao");
elecText.setTextDate(new Date());
elecText.setTextRemark("测试remark");
dao.save(elecText);
}
}
如果数据没有保存,需要设置事务自动提交:在hibernate.cfg.xml中去掉<property name="hibernate.connection.autocommit">true</property>的注释。
三. service层
1.创建接口IElecTextService
package cn.elec.service;
import cn.elec.po.ElecText;
public interface IElecTextService {
public static String SERVICE_NAME = "cn.elec.service.impl.ElecTextServiceImpl";
void saveElecText(ElecText elecText);
}
2.实现接口
package cn.elec.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import cn.elec.dao.IElecTextDao;
import cn.elec.po.ElecText;
import cn.elec.service.IElecTextService;
@Service(IElecTextService.SERVICE_NAME)
@Transactional(readOnly=true)
public class ElecTextServiceImpl implements IElecTextService {
/**
* @Resource和@Autowired都可使用,前者属于J2EE可减少与spring的耦合
* 指定名称即自动装配
*/
@Resource(name=IElecTextDao.SERVICE_NAME)
private IElecTextDao dao;
/**
* Isolation:底层数据库的事务隔离级别(读取未提交或已提交数据、可重复读、不可重复读),通常设置为默认的即可
* Propagation:事务传播行为(如果有事务则加入事务,没有则创建,默认为此!)
* readOnly: 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false
*/
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
public void saveElecText(ElecText elecText) {
dao.save(elecText);
}
}
3.创建TestService类测试
package cn.elec.test;
import java.util.Date;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.elec.po.ElecText;
import cn.elec.service.IElecTextService;
public class TestService {
@Test
public void save() {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IElecTextService service = (IElecTextService) ac.getBean(IElecTextService.SERVICE_NAME);
ElecText elecText = new ElecText();
elecText.setTextName("测试service");
elecText.setTextDate(new Date());
elecText.setTextRemark("测试remark");
service.saveElecText(elecText);
}
}
四. 控制层
1. 在action包中创建Action(业务Action)类和BaseAction(公用Action)
Action类:(注意:这里要设置成多例,即@Scope(value=prototype),因为struts2的Action是多实例,多线程)
package cn.elec.web.action;
import javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import cn.elec.po.ElecText;
import cn.elec.service.IElecTextService;
@Controller("elecTextAction")
//每次接收请求就创建一个对象,即多线程多例
@Scope(value="prototype")
public class ElecTextAction extends BaseAction<ElecText>{
ElecText elecText = this.getModel();
@Resource(name=IElecTextService.SERVICE_NAME)
private IElecTextService elecTextService;
public String save() {
elecTextService.saveElecText(elecText);
return "save";
}
}
BaseAction类(封装模型驱动对象,HttpServletRequest和HttpServletResponse对象):
package cn.elec.web.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import cn.elec.util.TUtils;
public class BaseAction<T> extends ActionSupport implements ModelDriven<T>,ServletRequestAware,ServletResponseAware{
private static final long serialVersionUID = 1L;
protected HttpServletRequest request;
protected HttpServletResponse response;
protected T entity;
public BaseAction() {
Class clazz = TUtils.getTClass(this.getClass());
try {
entity = (T) clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public T getModel() {
return entity;
}
@Override
public void setServletResponse(HttpServletResponse resp) {
response = resp;
}
@Override
public void setServletRequest(HttpServletRequest req) {
request = req;
}
}
在util包中创建TUtils类
package cn.elec.util;
import java.lang.reflect.ParameterizedType;
public class TUtils {
/**
* 得到泛型的子类真实对象类型
* @param clazz
* @return
*/
public static Class getTClass(Class clazz) {
ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass();
return (Class)type.getActualTypeArguments()[0];
}
}
在config中创建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>
<constant name="struts.ui.theme" value="simple"></constant>
<constant name="struts.action.extension" value="do"></constant>
<package name="system" namespace="/system" extends="struts-default">
<!-- struts2单独使用时class必须写全称,但是这里struts2被spring代理,
而spring中使用注解来注入该action,故此处与ElecTextAction中注解值一致即可!-->
<action name="elecTextAction_*" class="elecTextAction" method="{1}">
<result name="save">/system/textAdd.jsp</result>
</action>
</package>
</struts>
在web中添加配置
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>Elec2</display-name>
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<!-- web容器启动的时候,自动加载spring容器(监听器) -->
<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>
在WebContent下新增文件夹system,创建文件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" οnkeydοwn="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 οnclick="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" οnkeydοwn="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="保存" οnclick="checkchar()" id="BT_Submit" style="font-size:12px; color:black; height=20;width=50">
</td>
</tr>
</table>
</form>
</body>
</html>
里面有用到一个时间插件WdatePicker.js自己去下,css容量有点大就不上传了,也不影响后台逻辑
进入system/textAdd.jsp进行测试,添加记录到数据库。
至此SSH环境简单搭建完成,纯手敲,有误之处还请见谅指正。