分享

Spring学习笔记

 iversion 2007-09-24

Spring学习笔记

bleakoasis 转贴   更新:2006-05-30 12:54:29  版本: 1.0   



ApplicationContext ctx 

1,定义资源文件获得资源文件的消息,国际化信息
<bean id="messageResource" class="org.springFramework.context.support.ResourceBoundleMessageSource">
<property name="basenames">
  xxxx
</property>
</bean>
将会搜索xxxx.properties,xxxx_zh.properties ,xxxx_ch.properties等。

2,
程序里使用资源文件 :ctx.getMessage('key',arg);
页面上使用资源文件:<spring:message code="keyxxx"/>


3,使用其他文件。
Resource rs = ctx.getResource("classpath:config.properties");
File file = rs.getFile();
目录规则:
file:c:/test。txt
/config.properties
classpath:config.properties
三种方式。

4,事件传播
  不过没有找到ApplicationListener这个类。

5, WebApp获取ApplicaionContext的方法,
首先是在web。xml中进行配置,可以配置成一个listener,也可以配置成一个servlet。
然后程序里使用WebApplicationContextUtils.getWebApplicationContext.获得饮用。

6,Spring可以和很多框架进行集成。
Struts+Spring,Webwork+Spring。

7,Spring可以有自己的调度类,DispatherServlet。
使用的配置文件就是beans的配置,名字可以随便取。

8,Sping配置文件(具体名字见web.xml中对ContextLoaderServlet的参数)类似于Struts的配置文件。
定义viewer使用的是系统类:
  org.springframework.web.servlet.view.InternalResourceViewResolver
Request mapping 使用的系统类:
  org.springframework.web.servlet.handler.SimpleUrlHandleMapping
对Action的定义使用自定义类,但这些类都是下面类的子类:
  SimpleFormController
Actoin的属性包括:
  1,跳转的页面,和view关联
  2,封装form类,就是一个普通的javabean。
  
9,Acition类的内容,
  实现onsubmit( 封装的form,异常对象) 返回一个ModelAndView。
  ModelAndView用字符串初始化,字符串来自Action的两个跳转view名称。
  还可以把Map传入ModelAndView构造函数,用来返回消息。


10,Spring自带的数据验证功能。
10.1,验证类作为Aciotn的一个名为“validator”的属性在配置文件中配置。
此类继承org.springframework.validation.Validator
需要实现两个接口,support(传入一个类),验证此类是否是Action对应的form类。
validator(object obj,Errors err )首先把obj转为form类对象,如果有错误放到errors里,用法和
  struts类似。

10.2,表现层页面需要的显示错误
  全部错误:
  <spring:bind path="command.*">
   //遍历status.errorMessages
  </spring:bind>  

  单个错误:
  <spring:bind path="command.username">
   <input type="text" value="${staus.value}" name="${status.expression}">
   <c:if test="${status.error}">
    //遍历status.errorMessages
   </c:if>
  </spring:bind>
  如果已经在Action中配置了commandName,那么就不使用command了,而是使用配置的名字
  <bean id=‘loginActoni’>
   <property name="commandName">
    <value>RegisterInfo</value>
   </property>
  </bean>

11, 异常处理
在Dispather的配置文件中配置
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
定义两个属性:
<property name="defaultErrorView">
<property name="exceptionMapping">
  <props>
   <prop key="java.sql.SQLException">sss</prop>
   <prop key="java.lang.RuntimeException">yyy</prop>
  </props>
</property> 
可以按不同异常映射到不同的页面。
异常页面从request.getAttribute("Exception")取得Exception对象。显示他的message属性。

12,国际化
看完1后,补充如下:
Spring判断用户Locale的方式有三种,request中取,session中取,cookie中取客户端的locale。
分别用三个类,配置到配置文件中。

13,数据持久层(重要)对事务的封装
Spring是依赖容器的参数化事务管理不用写代码。
见p67。
1,在配置文件中配置完数据源,
2,之后配置事务管理的bean,数据源是它的属性。
3,DAO,事务员是它的属性。
4,事务beanDAOProxy,事务策略,事务bean,DAO都是它的属性。

14,数据持久层,对JDBC的封装
org.springframework.jdbc.core.JdbcTemplate.
JdbcTemplate jdbctemplate = new JdbcTemptlate( datasource );
jdbctemplate.update("xxxxx");
jdbctemplate.update("xxxxx",new PreparedStatementSetter(){
  public void setValues( PreparedStatementSetter ps ){
   ps.setInt(1,15);
   ps.setString(2,"jjjjjjj");
  }
});
jdbctemplate.query("select ...",new RollbackHandler(){
  public void processRow( ResultSet rs ){
   User user = new User();
   user.setName= rs.getString("name");
   userList.add( user );
  }
});

.call()可以调用存储过程。
query,update还有很多不同版本的实现。


15, JDBC封装还要引入事务管理机制,默认是没有事务的。
两种方式
1,代码控制的,在DAO里TransactionTemplate使用它的方法。
2,参数化配置的事务。配置一个ProxyDAO,不用写这个类,只需要在配置文件里增加他对DAO的事物设置。
  使得DAO代码十分简洁。

测试代码:
InputStream is = new FileInputStream("xxx.xml");
XmlBeanFactory factory = new XmlBeanFactoy( is );
UserDAO dao = (UserDAO)factory.getBean("ProxyDAO");
dao.insert();//这样就行了

16,Hibernate in Spring
只需修改配置文件增加一个bean名字为sessionFactory,数据源作为他的属性。
TrsactionManager的属性:sessionFactory
IDAO接口:定义数据库操作方法。
DAO的属性:sessionFactory。继承HibernateDAOSupport,并实现IDAO接口。
   里面使用getHibernateTemplate模版进行数据库操作。
ProxyDAO的属性:transactionManager,DAO.

测试例子:
IUserDAO dao=(IUserDAO)factory.getBean("ProxyUserDAO"); 
User user = new User();
user.setxxx...
dao.insertOrUpdate(user);
1,配置文件的配置头
<?xml version="1.0" encoding="UTF-8"?>

<!--
  - Application context definition for JPetStore's business layer.
  - Contains bean references to the transaction manager and to the DAOs in
  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").
  -->
<beans xmlns="http://www./schema/beans"
    xmlns:xsi="http://www./2001/XMLSchema-instance"
    xmlns:aop="http://www./schema/aop"
    xmlns:tx="http://www./schema/tx"
    xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans.xsd
       http://www./schema/aop http://www./schema/aop/spring-aop.xsd
       http://www./schema/tx http://www./schema/tx/spring-tx.xsd">
这样写才对

2,配置文件可以使用多个属性文件
<!-- Configurer that replaces ${...} placeholders with values from properties files -->
<!-- (in this case, mail and JDBC related properties) -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>WEB-INF/mail.properties</value>
    <value>WEB-INF/jdbc.properties</value>
   </list>
  </property>
</bean>
类是框架的。
里面包含两个属性文件,属性文件里都是“key=value”这种形式的。这样配置文件里就可以使用属性文件里的key,使用方法
${key},这样转移出属性设置,维护起来比较方便。

3,定义Validator供web层使用,自定义类。
<bean id="accountValidator" class="org.springframework.samples.jpetstore.domain.logic.AccountValidator"/>
类里面使用了ValidatorUtils系统类来进行处理。

4,服务层的定义。
PetStoreImpl定义在配置文件中,是自己的类。
所有的DAO都是它的属性,注意,DAO是interface,而不是class.
PetStoreImpl中定义了所有的DAO接口作为属性,定义了他们的set方法,但是没有定义get方法。
这样所有的业务操作就可以不用管DAO是如何实现的了,而只管使用这个PetStoreImpl就好了。

DAO都是接口这种做法与平时开发不一样,我以前使用hibernate生成工具生成的dao都是默认好的实现类。
而此处的DAO却都是接口。他们的实现方法是这样的:
interface PetStoreFacade { } //定义所有的业务方法。
interface AccountDao{} //定义所有帐户的业务方法。
interface CategoryDao{} //定义类别的业务方法。
interface ProductDao{} //定义产品的业务方法。
。。。其他DAO接口,定义自己的业务方法。
class PetStoreImpl implements PetStoreFacade //这个类就是一个javabean,操作的都是接口。
//定义所有DAO接口当作自己的属性。
//实现set方法
//实现PetStoreFacade 定义的业务接口,实现的时候调用DAO接口的方法。

如果是我自己,那么就会定义IDAO当作接口,因为hibernate插件自动生成dao类,容易混淆。

5,配置文件中定义dataSource
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>
可见,可以直接使用properties中的key。另外可以将数据库操作弄成另外一个配置文件。只要在web.xml中设置好就可以了,
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /WEB-INF/dataAccessContext-local.xml  /WEB-INF/applicationContext.xml
  </param-value>
</context-param>

6,配置文件中定义事务管理
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>
使用了数据源作为属性。

7,dao具体实现类。
JPetStore使用ibatis作为ORM层。所以dao类的定义也都使用了ibatis。
PetStoreImpl五个接口接受五个实现了对应接口的实现类。这里的实现类,
<bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
  <property name="accountDao" ref="accountDao"/>
  <property name="categoryDao" ref="categoryDao"/>
  <property name="productDao" ref="productDao"/>
  <property name="itemDao" ref="itemDao"/>
  <property name="orderDao" ref="orderDao"/>
</bean>
<bean id="accountDao" class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapAccountDao">
  <property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
实现类,使用ibatis。在配置文件中对英。
public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao{
//实现了业务接口,继承了ibatis基本类。
}


8,ibatis基础类。
    <!-- SqlMap setup for iBATIS Database Layer -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
  <property name="configLocation" value="WEB-INF/sql-map-config.xml"/>
  <property name="dataSource" ref="dataSource"/>
</bean>
dao实现类都由他作属性。
    <bean id="accountDao" class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapAccountDao">
  <property name="sqlMapClient" ref="sqlMapClient"/>
</bean>

9,我竟然找不到action对应的mapping在什么地方定义的。
后来找到了是petstore-servlet.xml,by default defined in "{servlet-name}-servlet.xml"...
<!--
   - Spring web MVC servlet that dispatches requests to registered handlers.
   - Has its own application context, by default defined in "{servlet-name}-servlet.xml",
   - i.e. "petstore-servlet.xml" in this case.
   -
   - A web app can contain any number of such servlets.
   - Note that this web app has a shared root application context, serving as parent
   - of all DispatcherServlet contexts.
   -->
<servlet>
  <servlet-name>petstore</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
</servlet>
原来是根据servlet名字命名影射文件的。
影射文件和配置文件的结构完全一致,也是beans开头的。主要是web层的url影射,
<beans>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  <property name="prefix" value="/WEB-INF/jsp/spring/"/>
  <property name="suffix" value=".jsp"/>
</bean>
....
</beans>
ok,现在把petstore-servlet.xml也放到SpringIDE里察看。

10,配置文件petstore-servlet.xml
viewResolver,定义了一个表现层的基本配置,此bean名字固定。
属性viewClass使用了jstl技术。
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  <property name="prefix" value="/WEB-INF/jsp/spring/"/>
  <property name="suffix" value=".jsp"/>
</bean>

11,配置文件petstore-servlet.xml
defaultHandlerMapping使用默认的BeanNameUrl影射,具体不太明白。
<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

12,配置文件petstore-servlet.xml
定义*.do
<bean name="/shop/addItemToCart.do" class="org.springframework.samples.jpetstore.web.spring.AddItemToCartController">
  <property name="petStore" ref="petStore"/>
</bean>
属性petStore是在applicationContext.xml里定义的,看来这里也可以使用其他<beans>定义的bean。

13,*.do类研究
实现了Controller,接口public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) 
有一个属性petstore,是一个接口PetStoreFacade,包括全部业务逻辑接口。

14,首页index
在mapping文件里定义了系统ParameterizableViewController,相当于forwardAction。
<bean name="/shop/index.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
  <property name="viewName" value="index"/>
</bean>
而首页里大量使用了jstl语言,最重要的地方是所有 a href=, action=,处都使用了<c:url value="/xxxx"/>
这样的定义,这样换域名或者设置虚拟目录名,就会运行正常了。例如,
<center>
<a href="<c:url value="/shop/viewCategory.do?categoryId=FISH"/>">
<img border="0" src="../images/sm_fish.gif" /></a>
<img border="0" src="../images/separator.gif" />
<a href="<c:url value="/shop/viewCategory.do?categoryId=DOGS"/>">
<img border="0" src="../images/sm_dogs.gif" /></a>
<img border="0" src="../images/separator.gif" />
<a href="<c:url value="/shop/viewCategory.do?categoryId=REPTILES"/>">
<img border="0" src="../images/sm_reptiles.gif" /></a>
<img border="0" src="../images/separator.gif" />
<a href="<c:url value="/shop/viewCategory.do?categoryId=CATS"/>">
<img border="0" src="../images/sm_cats.gif" /></a>
<img border="0" src="../images/separator.gif" />
<a href="<c:url value="/shop/viewCategory.do?categoryId=BIRDS"/>">
<img border="0" src="../images/sm_birds.gif" /></a>
</center>

15, 进入首页后点左边的链接都指向同一个viewCategory.do,
<bean name="/shop/viewCategory.do" class="org.springframework.samples.jpetstore.web.spring.ViewCategoryController">
  <property name="petStore" ref="petStore"/>
</bean>
类研究:
ViewCategoryController implement Controller
里面只使用了PetStore实现类的方法,并没有DAO对象。只有Domain对象。
很好,把主要的和业务相关的东西都在Controller中展现出来了,其他辅助的东西都被隐藏了,使得Controller非常简洁。
另外,在业务PetStoreImp类中,使用了DAO,这样就使得后台程序也开始分层了。

|--层Controller及使用的daomain对象 /// 第一层
            |----层PetStoreFacade 接口及他的实现类PetStoreImpl //第二层
   |-------- 层DAO接口 ,DAO接口实现类,//第三层
    |------------实现类中使用的ORM类  //第四层
层次非常的分明。
    
daomain符合javabean规范,并且有些javabean还有自己的public方法。大多数javabean没有必要有public方法。

16, 点击分类后,显示分类中的items,点items可以进入viewProduct.do?productId=xxx,来观看产品。
<bean name="/shop/viewProduct.do" class="org.springframework.samples.jpetstore.web.spring.ViewProductController">
  <property name="petStore" ref="petStore"/>
</bean>
这是一个翻页功能的Controller。
没弄清楚成功后跳转到什么地方? return new ModelAndView("Product", model);没有理解。

public class ModelAndViewextends ObjectHolder for both Model and View in the web MVC framework. Note that these are entirely distinct. This class merely holds both to make it possible for a controller to return both model and view in a single return value. 

Class to represent a model and view returned by a handler used by a DispatcherServlet. The view can take the form of a reference to a View object, or a String view name which will need to be resolved by a ViewResolver object. The model is a Map, allowing the use of multiple data objects keyed by name. 

public ModelAndView(String viewName,
                    Map model)Creates new ModelAndView given a view name and a model. 

Parameters:
viewName - name of the View to render, to be resolved by the DispatcherServlet
model - Map of model names (Strings) to model objects (Objects). Model entries may not be null, but the model Map may be null if there is no model data.

这样viewName就知道了,返回给DispatcherServerlet,再根据viewResolver中的定义,就可以知道是/jsp/spring/Product.jsp了。
也就是说,viewName也就是jsp文件的名字。

17,ModelAndView传递给页面之后页面如何使用其中的数据 ?
Controller传递的model是一个map,一共传递了两个key-value对。
model.put("itemList", itemList);
model.put("product", product);
ok,看jsp页面。<c:out value="${product.name}"/>
<c:forEach var="item" items="${itemList.pageList}">
  <tr bgcolor="#FFFF88">
  <td><b>
  <a href="<c:url value="/shop/viewItem.do"><c:param name="itemId" value="${item.itemId}"/></c:url>">
    <c:out value="${item.itemId}"/>
  </a></b></td>
  <td><c:out value="${item.productId}"/></td>
  <td>
    <c:out value="${item.attribute1}"/>
    <c:out value="${item.attribute2}"/>
    <c:out value="${item.attribute3}"/>
    <c:out value="${item.attribute4}"/>
    <c:out value="${item.attribute5}"/>
    <c:out value="${product.name}"/>
  </td>
  <td><fmt:formatNumber value="${item.listPrice}" pattern="$#,##0.00"/></td>
  <td><a href="<c:url value="/shop/addItemToCart.do"><c:param name="workingItemId" value="${item.itemId}"/></c:url>">
    <img border="0" src="../images/button_add_to_cart.gif"/>
  </a></td>
  </tr>
</c:forEach>
原来是把key当作attributename放到了request范围内了。这样就ok了,model的key实际上就是request的属性名字啊。
model的value就是request的属性值。jstl真正发挥简洁的威力了。

18,viewProduct.do里还有一个翻页的逻辑,没看明白怎么回事。


19,viewProduct.do之后再点链接就进入了viewItem.do,相对简单。不用看了。
PagedListHolder itemList = new PagedListHolder(this.petStore.getItemListByProduct(productId));
java.lang.Object
  org.springframework.beans.support.PagedListHolder
PagedListHolder is a simple state holder for handling lists of objects, separating them into pages. Page numbering starts with 0. 
Constructor Summary 
PagedListHolder() 
          Create a new holder instance. 
PagedListHolder(List source) 
          Create a new holder instance with the given source list, starting with a default sort definition (with "toggleAscendingOnProperty" activated). 
PagedListHolder(List source, SortDefinition sort) 
          Create a new holder instance with the given source list. 
boolean isFirstPage() 
          Return if the current page is the first one. 
boolean isLastPage() 
          Return if the current page is the last one. 
void nextPage() 
          Switch to next page. 
void previousPage() 
          Switch to previous page. 
可以排序。可以设置页数。
这个类明显是把所有的结果一次性查询出来后,设定每页个数,之后再把当页数据发送给页面。虽然不是把全部数据发送给页面由页面来分页,但是一次把全部数据都查询出来的做法只适合少量数据。如果多量数据几万条的话同时查出来,存放到session,用不了多久服务器的内存就被耗光了。
还不太清楚放到session中的对象什么时候被晴空,好像只有在退出的时候才晴空一次。

20,addItemToCart.do?workingItemId=EST-11,代码很清楚。有两点主意:
一,webUtil org.springframework.web.util.webUtil提供了有限的几个方法。
二,return new ModelAndView("Cart", "cart", cart); // Cart.jsp , key ,value
因为不熟悉ibatis所以ORM层的代码都没有阅读,也就是PetsoreImpl实现类的各个DAO实例都没有阅读。

    removeItemFromCart.do?workingItemId=EST-11 也是同一页面上的购物车操作 ,过于简单。略
updateCartQuantities.do //更新的是内存中的数据,所以没有什么技术。

21,checkout.do有一点需要注意,别的Controller没有传入viewName。它传了,
<bean name="/shop/checkout.do" class="org.springframework.samples.jpetstore.web.spring.ViewCartController">
  <property name="successView" value="Checkout"/>
</bean>
Controller中:
private String successView;

public void setSuccessView(String successView) {
  this.successView = successView;
}
最后return new ModelAndView(this.successView, "cart", cart);

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多