|
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(); 目錄規(guī)則: 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使用的是系統(tǒng)類: org.springframework.web.servlet.view.InternalResourceViewResolver Request mapping 使用的系統(tǒng)類: 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系統(tǒng)類來進行處理。 4,服務層的定義。 PetStoreImpl定義在配置文件中,是自己的類。 所有的DAO都是它的屬性,注意,DAO是interface,而不是class. PetStoreImpl中定義了所有的DAO接口作為屬性,定義了他們的set方法,但是沒有定義get方法。 這樣所有的業(yè)務操作就可以不用管DAO是如何實現的了,而只管使用這個PetStoreImpl就好了。 DAO都是接口這種做法與平時開發(fā)不一樣,我以前使用hibernate生成工具生成的dao都是默認好的實現類。 而此處的DAO卻都是接口。他們的實現方法是這樣的: interface PetStoreFacade { } //定義所有的業(yè)務方法。 interface AccountDao{} //定義所有帳戶的業(yè)務方法。 interface CategoryDao{} //定義類別的業(yè)務方法。 interface ProductDao{} //定義產品的業(yè)務方法。 。。。其他DAO接口,定義自己的業(yè)務方法。 class PetStoreImpl implements PetStoreFacade //這個類就是一個javabean,操作的都是接口。 //定義所有DAO接口當作自己的屬性。 //實現set方法 //實現PetStoreFacade 定義的業(yè)務接口,實現的時候調用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{ //實現了業(yè)務接口,繼承了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,包括全部業(yè)務邏輯接口。 14,首頁index 在mapping文件里定義了系統(tǒng)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對象。 很好,把主要的和業(yè)務相關的東西都在Controller中展現出來了,其他輔助的東西都被隱藏了,使得Controller非常簡潔。 另外,在業(yè)務PetStoreImp類中,使用了DAO,這樣就使得后臺程序也開始分層了。 |--層Controller及使用的daomain對象 /// 第一層 |----層PetStoreFacade 接口及他的實現類PetStoreImpl //第二層 |-------- 層DAO接口 ,DAO接口實現類,//第三層 |------------實現類中使用的ORM類 //第四層 層次非常的分明。 daomain符合javabean規(guī)范,并且有些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真正發(fā)揮簡潔的威力了。 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. 可以排序??梢栽O置頁數。 這個類明顯是把所有的結果一次性查詢出來后,設定每頁個數,之后再把當頁數據發(fā)送給頁面。雖然不是把全部數據發(fā)送給頁面由頁面來分頁,但是一次把全部數據都查詢出來的做法只適合少量數據。如果多量數據幾萬條的話同時查出來,存放到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); |
|
|