项目快速搭建已在上一篇当中介绍(包含,c3p0、hibernate、spring文件)
在这篇当中,完善spring
下图是各层之间的联系
因为在实际开发中,不可能所有操作都是增删改查,可能有很复杂的操作,再复杂的操作都是由基本的操作组合成,所以一般都是面向业务编程,业务,就是在service层。service跟dao是两个层面,service力度比较粗,可以不断的去丰富和扩展,但是dao不变(因为我们一般先设计数据库表),BaseDao接口只有一个,而service可以有很多个接口(增加业务),所以:
首先编写BaseDao接口,为了一般性,包含一个泛型:
然后编写BaseDaoImpl抽象类实现BaseDao,其中sf依赖于hibernate:
/* BaseDao接口的实现类 */ public abstract class BaseDaoImpl<T> implements BaseDao<T> { private SessionFactory sf;//会话工厂,相当于连接池 private Class<T> clazz; public void setSf(SessionFactory sf) { this.sf = sf; } public BaseDaoImpl(){ //取得子类的泛型化超类 ParameterizedType type= (ParameterizedType) this.getClass().getGenericSuperclass(); //得到第一个实际参数 clazz = (Class) type.getActualTypeArguments()[0]; } public void saveEntity(T t) { sf.getCurrentSession().save(t); } public void updateEntity(T t) { sf.getCurrentSession().update(t); } public void saveOrUpdateEntity(T t) { sf.getCurrentSession().saveOrUpdate(t); } public void deleteEntity(T t) { sf.getCurrentSession().delete(t); } public T getEntity(Integer id) { return (T) sf.getCurrentSession().get(clazz,id); } /* 按照HQL查询数据 Hibernate Query Language */ public List<T> findByHQL(String hql, Object... objects) { Query query = sf.getCurrentSession().createQuery(hql); for (int i=0;i<objects.length;i++){ query.setParameter(i,objects[i]); } return query.list(); } /* 按照HQL进行批量写操作 */ public void execHQL(String hql, Object... objects) { Query query = sf.getCurrentSession().createQuery(hql); for (int i=0;i<objects.length;i++){ query.setParameter(i,objects[i]); } query.executeUpdate(); } }
注意!一个很常见的问题:如何得到超类的泛型化参数,比如如何传递User,在BaseDaoImpl得到传递过来的是User
需走构造函数:
目前基准类已经创建好,现在创建UserDaoImpl:
创建BaseService接口:
因为service跟dao打交道,所以在service中声明dao对象,调用dao实现方法就OK:
创建BaseServiceImpl抽象类:
/* service跟Dao打交道,在service声明dao对象,调用dao实现方法。 */ public abstract class BaseServiceImpl<T> implements BaseService<T> { private BaseDao<T> baseDao; public BaseDao<T> getBaseDao() { return baseDao; } public void saveEntity(T t) { baseDao.saveEntity(t); } public void updateEntity(T t) { baseDao.updateEntity(t); } public void saveOrUpdateEntity(T t) { baseDao.saveOrUpdateEntity(t); } public void setBaseDao(BaseDao<T> baseDao) { this.baseDao = baseDao; } public void deleteEntity(T t) { baseDao.deleteEntity(t); } public T getEntity(Integer id) { return baseDao.getEntity(id); } public List<T> findByHQL(String hql, Object... objects) { return baseDao.findByHQL(hql,objects); } public void execHQL(String hql, Object... objects) { baseDao.execHQL(hql,objects); } }
创建UserService接口:
创建UserServiceImpl:
接下来配置到Spring里(一个bean依赖另外一个):
<?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 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"></property> </bean> <!--c3p0数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverclass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="maxPoolSize" value="${c3p0.pool.size.max}"></property> <property name="minPoolSize" value="${c3p0.pool.size.min}"></property> <property name="initialPoolSize" value="${c3p0.pool.size.ini}"></property> <property name="acquireIncrement" value="${c3p0.pool.size.increment}"></property> </bean> <!--hibernate会话工厂类--> <bean id="sf" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <!--数据源属性--> <property name="dataSource" ref="dataSource"></property> <!--hibernate自身属性--> <property name="hibernateProperties"> <props> <!--dialect方言--> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> </props> </property> <!--映射文件位置--> <property name="mappingDirectoryLocations"> <list> <value>classpath:com/chenway/eshop/model</value> </list> </property> </bean> <!--UserDao--> <bean id="userDao" class="com.chenway.eshop.dao.impl.UserDaoImpl"> <property name="sf" ref="sf"></property> </bean> <!--userService--> <bean id="userService" class="com.chenway.eshop.service.impl.UserServiceImpl"> <property name="baseDao" ref="userDao"></property> </bean> </beans>
jdbc.properties:
jdbc.driverclass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/eshop jdbc.username=root jdbc.password=123456 c3p0.pool.size.max=10 c3p0.pool.size.min=2 c3p0.pool.size.ini=3 c3p0.pool.size.increment=2 hibernate.dialect=org.hibernate.dialect.MySQL5Dialect hibernate.show_sql=true
注意,还有一个事务问题:
1.transaction.
2.acid
atomic //原子性,不可分割.要么全成功,要么全失败
consistent //一致性,操作前,结束后,操作不能被破坏
isolate //隔离性,相互独立
durable //持久化性,
谈到mysql的隔离级别:
来历由并发现象产生:
脏读 //读未提交,一个事务读取了另外一个事务改写还没有提交的数据,如果另外一个事务在稍后回滚不可重复读 //读不回去,只要在两个同样查询的情况下发现了不一致,每次结果不一样
幻读 //读多了,在稍后同样条件查询情况下,被插入了
怎么办?隔离级别
----------------
1.读未提交 read uncommitted
2.读已提交 read committed
4.可以重复读repeatable read
8.serializable 串行化
----------------
runtime Data area.
heap //堆,共享
stack
native method stack
counter register
method area //共享,所有线程共享
heap:
堆 //堆,年轻代(伊甸区 + 幸存一区 + 幸存二区) + 年老代
非堆 non-heap //method area.
在beans引入名字空间mvc、tx、sop、context:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd ">
添加mvc依赖:
<!--hibernate事务管理器--> <bean id="txManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory" ref="sf"></property> </bean>
<!--事务通知--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <!--以save开头的所有方法都开启事务--> <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="exec*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="find*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="get*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice>
<!--配置spring扫描的包,自动管理需要的bean对象--> <context:component-scan base-package="com.chenway.eshop.dao.impl,com.chenway.eshop.service.impl"></context:component-scan> <!--aop配置--> <aop:config> <!--切入点--> <aop:pointcut id="txPoint" expression="execution(* com.chenway.eshop.service.*Service.*(..))"></aop:pointcut> <!--切入点通知--> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor> </aop:config>
所以最终spring文件:
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd "> <!--配置spring扫描的包,自动管理需要的bean对象--> <context:component-scan base-package="com.chenway.eshop.dao.impl,com.chenway.eshop.service.impl"></context:component-scan> <!--aop配置--> <aop:config> <!--切入点--> <aop:pointcut id="txPoint" expression="execution(* com.chenway.eshop.service.*Service.*(..))"></aop:pointcut> <!--切入点通知--> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor> </aop:config> <!--事务通知--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <!--以save开头的所有方法都开启事务--> <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="exec*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="find*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="get*" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"></property> </bean> <!--c3p0数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverclass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="maxPoolSize" value="${c3p0.pool.size.max}"></property> <property name="minPoolSize" value="${c3p0.pool.size.min}"></property> <property name="initialPoolSize" value="${c3p0.pool.size.ini}"></property> <property name="acquireIncrement" value="${c3p0.pool.size.increment}"></property> </bean> <!--hibernate会话工厂类--> <bean id="sf" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <!--数据源属性--> <property name="dataSource" ref="dataSource"></property> <!--hibernate自身属性--> <property name="hibernateProperties"> <props> <!--dialect方言--> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> </props> </property> <!--映射文件位置--> <property name="mappingDirectoryLocations"> <list> <value>classpath:com/chenway/eshop/model</value> </list> </property> </bean> <!--hibernate事务管理器--> <bean id="txManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory" ref="sf"></property> </bean> </beans>
创建测试类,插入数据,没问题的话目前已经搭建好,接下来要搭建mvc:
Tomcat之所以能够对外提供服务,是因为里边有很多写好的servlet(服务器端程序,固定的API)。很多第三方框架,都会给出自己的servlet实现,所以如果我们要部署到tomcat去,就要使用它给的servlet,springmvc提供一个DispatcherServlet(分发请求),处理请求的时候,会交给HandlerMapping(处理映射),通过url来映射某个组件来处理它,这个组件就是controller,controller会返回ModelAndView,ModelAndView会返回给DispathcerServlet,还需进一步解析,所以交给ViewResolver,把逻辑名映射到真正的一个资源文件(通常为JSP)
在resources文件夹中创建webmvc.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" 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.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> <!-- 注解方法处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> </list> </property> </bean> </list> </property> </bean> <!-- 内部资源视图解析器(解析的是jsp的路径) --> <bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/jsps/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
接下来在web-inf/web.xml中配置:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--上下文配置参数,指定的是spring的beans.xml文件位置--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <!--通过监听器方式在tomcat启动时,完成beans的初始化--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--配置spring的分发器控制器--> <servlet> <servlet-name>controller</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--初始化参数,确保web服务器启东时,初始化springmvc容器--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:webmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>controller</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
创建
/** *主页控制器 */ @Controller @RequestMapping(value = "/") public class HomeController { public HomeController(){ System.out.println("hello world"); } /** *到主页 */ @RequestMapping(value = "home",method =RequestMethod.GET) public String toHome(){ System.out.println("hello world!!"); return "index" ; } }