2. Struts2+Spring+Hibernate[注解开发, service层和struts2的action层分离]
框架: Struts2+Spring+Hibernate, 注解式开发
数据库: mysql
----------------------------------
项目工程结构预览:
----------------------------------------------------
数据库设计:( itcast0201crm )
CREATE TABLE `sys_user_group` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `principal` varchar(255) DEFAULT NULL, `incumbent` varchar(255) DEFAULT NULL, `remark` longtext, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
创建web工程:crm
需要的jar包(这里导入全部的开发包, 示例只是一个简单的框架搭建, 实际开发中要在此基础上不断丰富功能, 所以导入了大部分的jar包)
antlr-2.7.6.jar aspectjrt.jar aspectjweaver.jar backport-util-concurrent.jar c3p0-0.9.1.2.jar cglib-2.2.jar common-annotations.jar commons-beanutils-1.8.3.jar commons-collections-3.2.1.jar commons-fileupload-1.2.1.jar commons-io-1.3.2.jar commons-lang-2.5.jar commons-logging.jar dom4j-1.6.1.jar ehcache-1.5.0.jar ezmorph-1.0.6.jar freemarker-2.3.15.jar hibernate-annotations.jar hibernate-commons-annotations.jar hibernate3.jar javassist-3.9.0.GA.jar jcommon-1.0.16.jar jfreechart-1.0.13.jar json-lib-2.3-jdk15.jar jstl.jar jta-1.1.jar junit-4.8.2.jar log4j-1.2.15.jar morph-1.1.1.jar morph-sandbox-1.1.1.jar mysql-connector-java-5.1.10-bin.jar ognl-2.7.3.jar pinyin4j-2.5.0.jar slf4j-api-1.5.8.jar slf4j-log4j12.jar spring.jar standard.jar struts2-core-2.1.8.1.jar xwork-core-2.1.6.jar
=======================<Hibernate的搭建开始>============================
创建包:cn.itcast.crm.domain
创建POJO类SysUserGroup.java
package cn.itcast.crm.domain; /* * po对象,这里的值要和数据库对象 */ @SuppressWarnings("serial") public class SysUserGroup implements java.io.Serializable { private Integer id; private String remark; // 备注 private String name; // 部门名称 private String principal; // 部门负责人 private String incumbent; // 部门职能 //一个部门包含多个用户,不做配置 //private Set users=new HashSet(0); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPrincipal() { return principal; } public void setPrincipal(String principal) { this.principal = principal; } public String getIncumbent() { return incumbent; } public void setIncumbent(String incumbent) { this.incumbent = incumbent; } }
在同级包下创建POJO类的映射文件SysUserGroup.hbm.xml
<?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.itcast.crm.domain.SysUserGroup" table="sys_user_group"> <id name="id" type="integer"> <column name="id" /> <generator class="identity" /> </id> <property name="name" type="string"> <column name="name" sql-type="varchar(100)" /> </property> <property name="principal" type="string"> <column name="principal" sql-type="varchar(50)" /> </property> <property name="incumbent" type="string"> <column name="incumbent" sql-type="varchar(200)" /> </property> <property name="remark" type="text"> <column name="remark" /> </property> </class> </hibernate-mapping>
在src下创建hibernate的配置文件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> <!-- 连接数据库, 这里的信息要配置到一个资源文件中jdbc.properties中, 然后引入取值 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/itcast0201crm?useUnicode=true&characterEncoding=UTF-8</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- hibernate的属性 --> <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="cn/itcast/crm/domain/SysUserGroup.hbm.xml"/> </session-factory> </hibernate-configuration>
创建包junit, 创建测试类HibernateTest.java
package junit; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import cn.itcast.crm.domain.SysUserGroup; public class HibernateTest { @Test public void test() { Configuration config = new Configuration(); config.configure(); SessionFactory sf = config.buildSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("销售部"); sysUserGroup.setPrincipal("张三"); sysUserGroup.setIncumbent("aaa"); sysUserGroup.setRemark("bbb"); s.save(sysUserGroup); tx.commit(); s.close(); } }
运行, 数据库中插入了一条记录:
------------------------------------测试通过, 下面是各层的搭建-------------------------------------
创建包cn.itcast.crm.dao
创建基础接口ICommonDao
package cn.itcast.crm.dao; /** * 基础DAO */ public interface ICommonDao<T> { // 保存对象 public void save(T entity); }
创建包cn.itcast.crm.dao.impl
创建类基础接口的实现类CommonDaoImpl
package cn.itcast.crm.dao.impl; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import cn.itcast.crm.dao.ICommonDao; public class CommonDaoImpl<T> extends HibernateDaoSupport implements ICommonDao<T> { // 保存对象 @Override public void save(T entity) { this.getHibernateTemplate().save(entity); } }
因为这个dao继承了HibernateDaoSupport类, 而这个类是Spring为了整合Hibernate的方法封装的实现类, 所以接下来要搭建Spring的配置
在src下创建bean.xml(名字可以自定义), 创建包cn.itcast.crm.service和cn.itcast.crm.service.impl, 配置中用到, 事先创建好
bean.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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 配置注解的自动扫描 --> <context:component-scan base-package="cn.itcast.crm"/> <!-- 配置本地化代理工厂bean, 这是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> <!-- 创建事务管理器 --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 如果采用纯注解的事务的方式, 就不要配置通知和AOP配置, 两种方法都可行, 选其一 --> <tx:annotation-driven transaction-manager="txManager"/> <!-- 配置通知(已经使用注解驱动, 不需要配置此项) <tx:advice id="advice" transaction-manager="txManager"> <tx:attributes> isolation:事务的隔离级别 propagation:事务的传播行为 read-only:是否只读 <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*" read-only="true"/> </tx:attributes> </tx:advice> 配置AOP(已经使用注解驱动, 不需要配置此项) <aop:config> 配置切入点 <aop:pointcut id="perform" expression="(* cn.itcast.crm.service..*.*(..))"/> 连接切入点和通知 <aop:advisor advice-ref="advice" pointcut-ref="perform"/> </aop:config> --> <!-- 配置dao, 也可以使用注解的方式配置, 在类中使用@XXX代替此方式, 如下所示: --> <!-- @Resource(name="sessionFactory") public void setSessionFactoryDI(SessionFactory sessionFactory) { super.setSessionFactory(sessionFactory); } --> <!-- <bean id="xx" class="cn.itcast.crm.dao.impl.CommonDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> --> </beans>
在CommonDaoImpl.java中添加:
// 采用注解的方式注入sessionFactory @Resource(name="sessionFactory") public void setSessionFactoryDI(SessionFactory sessionFactory) { // 调用父类的setSessionFactory方法注入setSessionFactory, // 这样HibernateTemplate中就有setSessionFactory了, 就可以对数据库进行CRUD操作 super.setSessionFactory(sessionFactory); }
在cn.itcast.crm.dao包下创建ISysUserGroupDao接口
package cn.itcast.crm.dao; import cn.itcast.crm.domain.SysUserGroup; /** * 用户DAO, 这个具体的用户dao去继承基础接口ICommonDao */ public interface ISysUserGroupDao extends ICommonDao<SysUserGroup> { // 定义常量, 表示包.类 public final static String SERVICE_NAME = "cn.itcast.crm.dao.impl.SysUserGroupDaoImpl"; }
在包cn.itcast.crm.dao.impl下创建SysUserGroupDaoImpl.java
package cn.itcast.crm.dao.impl; import org.springframework.stereotype.Repository; import cn.itcast.crm.dao.ISysUserGroupDao; import cn.itcast.crm.domain.SysUserGroup; //此注解表示持久层, 但是包.类这个名称太长, 可以在ISysUserGroupDao接口中定义成常量 //@Repository("cn.itcast.crm.dao.impl.SysUserGroupDaoImpl") @Repository(ISysUserGroupDao.SERVICE_NAME) public class SysUserGroupDaoImpl extends CommonDaoImpl<SysUserGroup> implements ISysUserGroupDao { }
在junit包下创建TestSysUserGroupDao.java
package junit; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.crm.dao.ISysUserGroupDao; import cn.itcast.crm.domain.SysUserGroup; public class TestSysUserGroupDao { @Test public void testSave() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ISysUserGroupDao sysUserGroupDao = (ISysUserGroupDao) ctx.getBean(ISysUserGroupDao.SERVICE_NAME); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("技术部"); sysUserGroup.setPrincipal("李四"); sysUserGroup.setIncumbent("ccc"); sysUserGroup.setRemark("ddd"); sysUserGroupDao.save(sysUserGroup); } }
后台打印INSERT语句, 但是数据库却没有插入记录, 原因是没有开发service事务层, 这里还没有开发到service层, 所以先在hibernate.cfg.xml中配置自动提交事务
在hibernate.cfg.xml中添加:
<property name="hibernate.connection.autocommit">true</property>
再次测试:插入成功
============================<Hibernate的搭建完成>======================
============================<spring的搭建开始>======================
在cn.itcast.crm.service下创建接口ISysUserGroupService.java
package cn.itcast.crm.service; import cn.itcast.crm.domain.SysUserGroup; public interface ISysUserGroupService { public final static String SERVICE_NAME = "cn.itcast.crm.service.impl.SysUserGroupServiceImpl"; // 保存对象 public void saveSysUserGroup(SysUserGroup sysUserGroup); }
在cn.itcast.crm.service.impl下创建实现类SysUserGroupServiceImpl.java
package cn.itcast.crm.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.itcast.crm.dao.ISysUserGroupDao; import cn.itcast.crm.domain.SysUserGroup; import cn.itcast.crm.service.ISysUserGroupService; // 添加事务: 类级别的事务都配置成只读, 在方法中全部改成可写, 方法级别的事务会覆盖类级别的事务 @Transactional(readOnly=true) // 业务层, 这里的@Service注解同理ISysUserGroupDao, 面向接口编程:ISysUserGroupService.SERVICE_NAME @Service(ISysUserGroupService.SERVICE_NAME) public class SysUserGroupServiceImpl implements ISysUserGroupService { // 注入DAO @Resource(name=ISysUserGroupDao.SERVICE_NAME) private ISysUserGroupDao sysUserGroupDao; // 保存对象 @Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRED, readOnly=false) @Override public void saveSysUserGroup(SysUserGroup sysUserGroup) { sysUserGroupDao.save(sysUserGroup); } }
在junit下创建测试类:TestSysUserGroupService.java
package junit; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.crm.domain.SysUserGroup; import cn.itcast.crm.service.ISysUserGroupService; public class TestSysUserGroupService { @Test public void testSaveSysUserGroup() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ISysUserGroupService sysUserGroupService = (ISysUserGroupService) ctx.getBean(ISysUserGroupService.SERVICE_NAME); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("市场部"); sysUserGroup.setPrincipal("王五"); sysUserGroup.setIncumbent("eee"); sysUserGroup.setRemark("fff"); sysUserGroupService.saveSysUserGroup(sysUserGroup); } }
运行, 测试通过, 数据库中成功插入一条数据
==========================Service层搭建完成===========================
到这里就可以准备jsp, js, css的开发:
点击保存, 将表单记录插入到数据库, 表单action路径:${pageContext.request.contextPath}/sys/sysUserGroupAction_save.do
创建cn.itcast.crm.web.form包, 包下创建formbean, SysUserGroupForm.java
/** * VO对象, 保存jsp页面的值, 所有属性都是string类型, 因为从jsp页面接收过来的值都是字符串类型, 而domain中的SysUserGroup.java是和数据库中字段一 一 对应的 */ public class SysUserGroupForm implements Serializable { private static final long serialVersionUID = 5931957782834117943L; private String id; private String name; private String principal; private String incumbent; private String remark; + getter()/setter() }
在src下创建struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 配置请求后缀名.do --> <constant name="struts.action.extension" value="do"/> <!-- 配置主题为简单主题 --> <constant name="struts.ui.theme" value="simple"/> <!--配置struts2的模式为开发模式--> <constant name="struts.devMode" value="true"/> <!-- 用户模块action --> <package name="sys" namespace="/sys" extends="struts-default"> <action name="sysUserGroupAction_*" class="cn.itcast.crm.web.action.SysUserGroupAction" method="{1}"> <result name="add">/sys/group/add.jsp</result> </action> </package> </struts>
在WEB-INF下创建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"> <display-name>crm</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <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>
创建包cn.itcast.crm.container, 包下创建两个类:
1. ServiceProvinderCore.java: 提供ApplicationContext容器对象
package cn.itcast.crm.container; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 提供service的容器, 这里自定义一个容器, 和action分离, 达到解耦的目的 */ public class ServiceProvinderCore { protected ApplicationContext ctx; /** * @param filename beans.xml */ public void load(String filename) { ctx = new ClassPathXmlApplicationContext(filename); } }
2. ServiceProvinder.java:
package cn.itcast.crm.container; import org.apache.commons.lang.StringUtils; /** * 该类的主要作用的是加载beans.xml文件 */ public class ServiceProvinder { private static ServiceProvinderCore sc; static { sc = new ServiceProvinderCore(); sc.load("beans.xml"); } public static Object getService(String beanName) { if (StringUtils.isBlank(beanName)) { throw new RuntimeException("您要访问的服务名称不能为空"); } Object bean = null; // 如果spring容器中包含beanName if (sc.ctx.containsBean(beanName)) { bean = sc.ctx.getBean(beanName); } // 如果spring容器不包含beanName if (bean == null) { throw new RuntimeException("您要访问的服务名称[ " + beanName + " ]不存在"); } return bean; } }
创建包cn.itcast.crm.web.action, 创建SysUserGroupAction.java, 调用service, 分离的, 在大项目中便于项目的维护, 但是直接注入servcie也是可以的
package cn.itcast.crm.web.action; import java.lang.reflect.InvocationTargetException; import org.apache.commons.beanutils.BeanUtils; import cn.itcast.crm.container.ServiceProvinder; import cn.itcast.crm.domain.SysUserGroup; import cn.itcast.crm.service.ISysUserGroupService; import cn.itcast.crm.web.form.SysUserGroupForm; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class SysUserGroupAction extends ActionSupport implements ModelDriven<SysUserGroupForm> { private static final long serialVersionUID = -3120948109033899684L; // 模型驱动 private SysUserGroupForm sysUserGroupForm = new SysUserGroupForm(); // 注入service, 这里不注入, 自定义容器, 达到解耦 // @Resource(name=ISysUserGroupService.SERVICE_NAME) // private ISysUserGroupService sysUserGroupService; // 新增用户 public String save() throws IllegalAccessException, InvocationTargetException { // 实例化po对象 SysUserGroup sysUserGroup = new SysUserGroup(); // 将vo复制到po BeanUtils.copyProperties(sysUserGroup, sysUserGroupForm); // 调用service保存po对象到数据库, 由于这里要实现action和service分离, 达到解耦目的, 所以不直接注入servcie, 自己写一个容器 // sysUserGroupService.saveSysUserGroup(sysUserGroup); // 调用service提供类 ISysUserGroupService sysUserGroupService = (ISysUserGroupService) ServiceProvinder.getService(ISysUserGroupService.SERVICE_NAME); sysUserGroupService.saveSysUserGroup(sysUserGroup); return null; } // 模型驱动 @Override public SysUserGroupForm getModel() { return this.sysUserGroupForm; } }
测试, 成功插入一个对象
============================================================
以上已经搭好了开发框架, 以后使用时, 只需按以下形式注入service和dao即可使用:
1. 在页面定义请求路径, 比如:action="${pageContext.request.contextPath}/sys/sysUserAction_isLogin.do"
2. 在struts.xml中配置请求的路径, 安排跳转:
<package name="sys" namespace="/sys" extends="struts-default"> <action name="sysUserAction_*" class="cn.itcast.crm.web.action.SysUserAction" method="{1}"> <result name="login">/WEB-INF/page/login.jsp</result> </action> </package>
3. SysUserAction.java(action层和service层和dao层的分离的底层核心代码在:https://i.cnblogs.com/EditArticles.aspx?postid=6915434)
// 注入service private ISysUserService sysUserService = (ISysUserService) ServiceProvinder.getService(ISysUserService.SERVER_NAME);
public String isLogin() { // 在这里调用service层进行业务逻辑的处理 SysUser sysUser = sysUserService.findSysUserByNameAndPassword(name, password); return "main"; }
4. ISysUserService.java
public interface ISysUserService { public static final String SERVER_NAME = "cn.itcast.crm.service.impl.SysUserServiceImpl"; // 用户登录校验 public SysUser findSysUserByNameAndPassword(String name, String password); }
5. SysUserServiceImpl.java
@Service(ISysUserService.SERVER_NAME) public class SysUserServiceImpl implements ISysUserService { // 注入dao @Resource(name=ISysUserDao.SERVER_NAME) private ISysUserDao sysUserDao; // 用户登录校验 @Override public SysUser findSysUserByNameAndPassword(String name, String password) { // 在这里处理业务逻辑 } }
6. ISysUserDao.java
public interface ISysUserDao extends ICommonDao<SysUser> { public static final String SERVER_NAME = "cn.itcast.crm.dao.impl.SysUserDaoImpl"; }
7. SysUserDaoImpl.java
@Repository(ISysUserDao.SERVER_NAME) public class SysUserDaoImpl extends CommonDaoImpl<SysUser> implements ISysUserDao { // 底层和数据库的交互方法写在CommonDaoImpl类中, 这里省略, 请看上面的链接 }
==========================================================
以上是依赖注入, 在使用的时候直接注入各接口即可使用!
CommonDaoImpl