<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3 ## 11.2? 實現通用層 ### 11.2.1? 功能概述 通過抽象通用的功能,從而復用,減少重復工作: * 對于一些通用的常量使用一個專門的常量類進行定義; * 對于視圖分頁,也應該抽象出來,如JSP做出JSP標簽; * 通用的數據層代碼,如通用的CRUD,減少重復勞動,節約時間; * 通用的業務邏輯層代碼,如通用的CRUD,減少重復勞動,節約時間; * 通用的表現層代碼,同樣用于減少重復,并提供更好的代碼結構規范。 ### 11.2.2 通用的常量定義 目標:在一個常量類中定義通用的常量的好處是如果需要修改這些常量值只需在一個地方修改即可,變的地方只有一處而不是多處。 如默認分頁大小如果在多處硬編碼定義為10,突然發生變故需要將默認分頁大小10為5,怎么辦?如果當初我們提取出來放在一個通用的常量類中是不是只有一處變動。 ``` package cn.javass.commons; public class Constants { public static final int DEFAULT_PAGE_SIZE = 5; //默認分頁大小 public static final String DEFAULT_PAGE_NAME = "page"; public static final String CONTEXT_PATH = "ctx"; } ``` 如上代碼定義了通用的常量,如默認分頁大小。 ### 11.2.2通用分頁功能 分頁功能是項目中必不可少的功能,因此通用分頁功能十分有必要,有了通用的分頁功能,即有了規范,從而保證視圖頁面的干凈并節約了開發時間。 **1、?分頁對象定義,用于存放是否有上一頁或下一頁、當前頁記錄、當前頁碼、分頁上下文,該對象是分頁中必不可少對象,一般在業務邏輯層組裝Page對象,然后傳送到表現層展示,然后通用的分頁標簽使用該對象來決定如何顯示分頁:** ``` package cn.javass.commons.pagination; import java.util.Collections; import java.util.List; public class Page<E> {/** 表示分頁中的一頁。*/ private boolean hasPre; //是否有上一頁 private boolean hasNext; //是否有下一頁 private List<E> items; //當前頁包含的記錄列表 private int index; //當前頁頁碼(起始為1) //省略setter public int getIndex() { return this.index; } public boolean isHasPre() { return this.hasPre; } public boolean isHasNext() { return this.hasNext; } public List<E> getItems() { return this.items == null ? Collections.<E>emptyList() : this.items; } } ``` 2、??**分頁標簽實現**,將使用Page對象數據決定如何展示分頁,如圖11-9和11-10所示: ![](https://box.kancloud.cn/2016-05-13_573547235e5f1.JPG)?? 圖11-9 11-10 通用分頁標簽實現 圖11-9和11-10展示了兩種分頁展示策略,由于分頁標簽和集成SSH沒多大關系且不是必須的并由于篇幅問題不再列出分頁標簽源代碼,有興趣的朋友請參考cn.javass.commons.pagination.NavigationTag類文件。[代碼下載地址](http://sishuok.com/forum/blogPost/list/2561.html) ### 11.2.3 通用數據訪問層 目標:通過抽象實現最基本的CURD操作,提高代碼復用,可變部分按需實現。 **1、通用數據訪問層接口定義** ``` package cn.javass.commons.dao; import java.io.Serializable; import java.util.List; public interface IBaseDao<M extends Serializable, PK extends Serializable> { public void save(M model);// 保存模型對象 public void saveOrUpdate(M model);// 保存或更新模型對象 public void update(M model);// 更新模型對象 public void merge(M model);// 合并模型對象狀態到底層會話 public void delete(PK id);// 根據主鍵刪除模型對象 public M get(PK id);// 根據主鍵獲取模型對象 public int countAll();//統計模型對象對應數據庫表中的記錄數 public List<M> listAll();//查詢所有模型對象 public List<M> listAll(int pn, int pageSize);// 分頁獲取所有模型對象 } ``` 通用DAO接口定義了如CRUD通用操作,而可變的(如查詢所有已發布的接口,即有條件查詢等)需要在相應DAO接口中定義,并通過泛型“M”指定數據模型類型和“PK”指定數據模型主鍵類型。 **2、通用數據訪問層DAO實現** 此處使用Hibernate實現,即實現是可變的,對業務邏輯層只提供面向接口編程,從而隱藏數據訪問層實現細節。 實現時首先通過反射獲取數據模型類型信息,并根據這些信息獲取Hibernate對應的數據模型的實體名,再根據實體名組裝出通用的查詢和統計記錄的HQL,從而達到同樣目的。 注意我們為什么把實現生成HQL時放到init方法中而不是構造器中呢?因為SessionFactory是通過setter注入,setter注入晚于構造器注入,因此在構造器中使用SessionFactory會是null,因此放到init方法中,并在Spring配置文件中指定初始化方法為init來完成生成HQL。 ``` package cn.javass.commons.dao.hibernate; //為節省篇幅省略import public abstract class BaseHibernateDao<M extends Serializable, PK extends Serializable> extends HibernateDaoSupport implements IBaseDao<M, PK> { private Class<M> entityClass; private String HQL_LIST_ALL; private String HQL_COUNT_ALL; @SuppressWarnings("unchecked") public void init() {//通過初始化方法在依賴注入完畢時生成HQL //1、通過反射獲取注解“M”(即模型對象)的類類型 this.entityClass = (Class<M>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; //2、得到模型對象的實體名 String entityName = getSessionFactory().getClassMetadata(this.entityClass).getEntityName(); //3、根據實體名生成HQL HQL_LIST_ALL = "from " + entityName; HQL_COUNT_ALL = " select count(*) from " + entityName; } protected String getListAllHql() {//獲取查詢所有記錄的HQL return HQL_LIST_ALL; } protected String getCountAllHql() {//獲取統計所有記錄的HQL return HQL_COUNT_ALL; } public void save(M model) { getHibernateTemplate().save(model); } public void saveOrUpdate(M model) { getHibernateTemplate().saveOrUpdate(model); } public void update(M model) { getHibernateTemplate().update(model); } public void merge(M model) { getHibernateTemplate().merge(model); } public void delete(PK id) { getHibernateTemplate().delete(this.get(id)); } public M get(PK id) { return getHibernateTemplate().get(this.entityClass, id); } public int countAll() { Number total = unique(getCountAllHql()); return total.intValue(); } public List<M> listAll() { return list(getListAllHql()); } public List<M> listAll(int pn, int pageSize) { return list(getListAllHql(), pn, pageSize); } protected <T> List<T> list(final String hql, final Object... paramlist) { return list(hql, -1, -1, paramlist);//查詢所有記錄 } /** 通用列表查詢,當pn<=-1 且 pageSize<=-1表示查詢所有記錄 * @param <T> 模型類型 * @param hql Hibernate查詢語句 * @param pn 頁碼 從1開始, * @param pageSize 每頁記錄數 * @param paramlist 可變參數列表 * @return 模型對象列表 */ @SuppressWarnings("unchecked") protected <T> List<T> list(final String hql, final int pn, final int pageSize, final Object... paramlist) { return getHibernateTemplate(). executeFind(new HibernateCallback<List<T>>() { public List<T> doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery(hql); if (paramlist != null) { for (int i = 0; i < paramlist.length; i++) { query.setParameter(i, paramlist[i]);//設置占位符參數 } } if (pn > -1 && pageSize > -1) {//分頁處理 query.setMaxResults(pageSize);//設置將獲取的最大記錄數 int start = PageUtil.getPageStart(pn, pageSize); if(start != 0) { query.setFirstResult(start);//設置記錄開始位置 } } return query.list(); } }); } /** 根據查詢條件返回唯一一條記錄 * @param <T> 返回類型 * @param hql Hibernate查詢語句 * @param paramlist 參數列表 * @return 返回唯一記錄 */ @SuppressWarnings("unchecked") protected <T> T unique(final String hql, final Object... paramlist) { return getHibernateTemplate().execute(new HibernateCallback<T>() { public T doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery(hql); if (paramlist != null) { for (int i = 0; i < paramlist.length; i++) { query.setParameter(i, paramlist[i]); } } return (T) query.setMaxResults(1).uniqueResult(); } }); } //省略部分可選的便利方法,想了解更多請參考源代碼 } ``` 通用DAO實現代碼相當長,但麻煩一次,以后有了這套通用代碼將會讓工作很輕松,該通用DAO還有其他便利方法因為本示例不需要且由于篇幅原因沒加上,請參考源代碼。 ### 11.2.4 通用業務邏輯層 目標:實現通用的業務邏輯操作,將常用操作封裝提高復用,可變部分同樣按需實現。 **1、通用業務邏輯層接口定義** ``` package cn.javass.commons.service; //由于篇幅問題省略import public interface IBaseService<M extends Serializable, PK extends Serializable> { public M save(M model); //保存模型對象 public void saveOrUpdate(M model);// 保存或更新模型對象 public void update(M model);// 更新模型對象 public void merge(M model);// 合并模型對象狀態 public void delete(PK id);// 刪除模型對象 public M get(PK id);// 根據主鍵獲取模型對象 public int countAll();//統計模型對象對應數據庫表中的記錄數 public List<M> listAll();//獲取所有模型對象 public Page<M> listAll(int pn);// 分頁獲取默認分頁大小的所有模型對象 public Page<M> listAll(int pn, int pageSize);// 分頁獲取所有模型對象 } ``` **3、?通用業務邏輯層接口實現** 通用業務邏輯層通過將通用的持久化操作委托給DAO層來實現通用的數據模型CRUD等操作。 通過通用的setDao方法注入通用DAO實現,在各Service實現時可以通過強制轉型獲取各轉型后的DAO。 ``` package cn.javass.commons.service.impl; //由于篇幅問題省略import public abstract class BaseServiceImpl<M extends Serializable, PK extends Serializable> implements IBaseService<M, PK> { protected IBaseDao<M, PK> dao; public void setDao(IBaseDao<M, PK> dao) {//需要依賴注入 this.dao = dao; } public IBaseDao<M, PK> getDao() { return this.dao; } public M save(M model) { getDao().save(model); return model; } public void merge(M model) { getDao().merge(model); } public void saveOrUpdate(M model) { getDao().saveOrUpdate(model); } public void update(M model) { getDao().update(model); } public void delete(PK id) { getDao().delete(id); } public void deleteObject(M model) { getDao().deleteObject(model); } public M get(PK id) { return getDao().get(id); } public int countAll() { return getDao().countAll(); } public List<M> listAll() { return getDao().listAll(); } public Page<M> listAll(int pn) { return this.listAll(pn, Constants.DEFAULT_PAGE_SIZE); } public Page<M> listAll(int pn, int pageSize) { Integer count = countAll(); List<M> items = getDao().listAll(pn, pageSize); return PageUtil.getPage(count, pn, items, pageSize); } } ``` ### 11.2.6通用表現層 目標:規約化常見請求和響應操作,將常見的CURD規約化,采用規約編程提供開發效率,減少重復勞動。 Struts2常見規約編程: * **通用字段驅動注入:**如分頁字段一般使用“pn”或“page”來指定當前分頁頁碼參數名,通過Struts2的字段驅動注入實現分頁頁碼獲取的通用化; * **通用Result:**對于CURD操作完全可以提取公共的Result名字,然后在Strust2配置文件中進行規約配置; * **數據模型屬性名:**在頁面展示中,如新增和修改需要向值棧或請求中設置數據模型,在此我們定義統一的數據模型名如“model”,這樣在項目組中形成約定,大家只要按照約定來能提高開發效率; * **分頁對象屬性名:**與數據模型屬性名同理,在此我們指定為“page”; * **便利方法:**如獲取值棧、請求等可以提供公司內部需要的便利方法。 **1、通用表現層Action實現:** ``` package cn.javass.commons.web.action; import cn.javass.commons.Constants; //省略import public class BaseAction extends ActionSupport { /** 通用Result */ public static final String LIST = "list"; public static final String REDIRECT = "redirect"; public static final String ADD = "add"; /** 模型對象屬性名*/ public static final String MODEL = "model"; /** 列表模型對象屬性名*/ public static final String PAGE = Constants.DEFAULT_PAGE_NAME; public static final int DEFAULT_PAGE_SIZE = Constants.DEFAULT_PAGE_SIZE; private int pn = 1; /** 頁碼,默認為1 */ //省略pn的getter和setter,自己補上 public ActionContext getActionContext() { return ActionContext.getContext(); } public ValueStack getValueStack() {//獲取值棧的便利方法 return getActionContext().getValueStack(); } } ``` **2、通用表現層JSP視圖實現:** 將視圖展示的通用部分抽象出來減少頁面設計的工作量。 **2.1、通用JSP頁頭文件(WEB-INF/jsp/common/inc/header.jsp):** 此處實現比較簡單,實際中可能包含如菜單等信息,對于可變部分使用請求參數來獲取,從而保證了可變與不可變分離,如標題使用“${param.title}”來獲取。 ``` <%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${param.title}</title> </head> <body> ``` **2.2、通用JSP頁尾文件(WEB-INF/jsp/common/inc/footer.jsp):** 此處比較簡單,實際中可能包含公司版權等信息。 ``` </body> </html> ``` **2.3、通用JSP標簽定義文件(WEB-INF/jsp/common/inc/tld.jsp):** 在一處定義所有標簽,避免標簽定義使代碼變得凌亂,且如果有多個頁面需要新增或刪除標簽即費事又費力。 ``` <%@taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@taglib prefix="s" uri="/struts-tags" % ``` **2.4、通用錯誤JSP文件(WEB-INF/jsp/common/error.jsp):** 當系統遇到錯誤或異常時應該跳到該頁面來顯示統一的錯誤信息并可能在該頁保存異常信息。 ``` <%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <jsp:include page="inc/header.jsp"/> 失敗或遇到異常! <jsp:include page="inc/footer.jsp"/> ``` **2.5、通用正確JSP文件(WEB-INF/jsp/common/success.jsp):** 對于執行成功的操作可以使用通用的頁面表示,可變部分同樣可以使用可變的請求參數傳入。 ``` <%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <jsp:include page="inc/header.jsp"/> 成功! <jsp:include page="inc/footer.jsp"/> ``` **3、通用設置web環境上下文路徑攔截器:** 用于設置當前web項目的上下文路徑,即可以在JSP頁面使用“${ctx}”獲取當前上下文路徑。 ``` package cn.javass.commons.web.filter; //省略import /** 用戶設置當前web環境上下文,用于方便如JSP頁面使用 */ public class ContextPathFilter implements Filter { @Override public void init(FilterConfig config) throws ServletException { } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String contextPath = ((HttpServletRequest) request).getContextPath(); request.setAttribute(Constants.CONTEXT_PATH, contextPath); chain.doFilter(request, response); } @Override public void destroy() { } } ``` ### 11.2.7通用配置文件 目標:通用化某些常用且不可變的配置文件,同樣目標是提高復用,減少工作量。 **1、Spring資源配置文件(resources/applicationContext-resources.xml):** 定義如配置元數據替換Bean、數據源Bean等通用的Bean。 ``` <bean class= "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:resources.properties</value> </list> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"> <property name="targetDataSource"> <bean class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="driver" value="${db.driver.class}" /> <property name="driverUrl" value="${db.url}" /> <property name="user" value="${db.username}" /> <property name="password" value="${db.password}" /> <property name="maximumConnectionCount" value="${proxool.maxConnCount}" /> <property name="minimumConnectionCount" value="${proxool.minConnCount}" /> <property name="statistics" value="${proxool.statistics}" /> <property name="simultaneousBuildThrottle" value="${proxool.simultaneousBuildThrottle}" /> <property name="trace" value="${proxool.trace}" /> </bean> </property> </bean> </beans> ``` 通過通用化如數據源來提高復用,對可變的如數據庫驅動、URL、用戶名等采用替換配置元數據形式進行配置,具體配置含義請參考【7.5集成Spring JDBC及最佳實踐】。 **2、替換配置元數據的資源文件(resources/resources.properties):** 定義替換配置元數據鍵值對用于替換Spring配置文件中可變的配置元數據。 ``` #數據庫連接池屬性 proxool.maxConnCount=10 proxool.minConnCount=5 proxool.statistics=1m,15m,1h,1d proxool.simultaneousBuildThrottle=30 proxool.trace=false db.driver.class=com.mysql.jdbc.Driver db.url=jdbc:mysql://localhost:3306/point_shop?useUnicode=true&characterEncoding=utf8 db.username=root db.password= ``` **3、通用Struts2配置文件(WEB-INF/struts.xml):** 由于是要集成Spring,因此需要使用StrutsSpringObjectFactory,我們需要在action名字中出現“/”因此定義struts.enable.SlashesInActionNames=true。 在此還定義了“custom-default”包繼承struts-default包,且是抽象的,在包里定義了如全局結果集全局異常映射。 ``` <?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> <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory"/> <!-- 允許action的名字中出現"/" --> <constant name="struts.enable.SlashesInActionNames" value="true"/> <package name="custom-default" extends="struts-default" abstract="true"> <global-results> <result name="success">/WEB-INF/jsp/common/success.jsp</result> <result name="error">/WEB-INF/jsp/common/error.jsp</result> <result name="exception">/WEB-INF/jsp/common/error.jsp</result> </global-results> <global-exception-mappings> <exception-mapping result="exception" exception="java.lang.Exception"/> </global-exception-mappings> </package> </struts> ``` **4、通用log4j日志記錄配置文件(resources/log4j.xml):** 可以配置基本的log4j配置文件然后在其他地方通過拷貝來定制需要的日志記錄配置。 ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <!-- Appenders --> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p: %c - %m%n" /> </layout> </appender> <!-- Root Logger --> <root> <priority value="DEBUG" /> <appender-ref ref="console" /> </root> </log4j:configuration> ``` **4、通用web.xml配置文件定義(WEB-INF/web.xml):** **定義如通用的集成配置、設置web環境上下文過濾器、字符過濾器(防止亂碼)、通用的Web框架攔截器(如Struts2的)等等,從而可以通過拷貝復用。** ``` <?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 通用配置開始 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext-resources.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- 通用配置結束 --> <!-- 設置web環境上下文(方便JSP頁面獲取)開始 --> <filter> <filter-name>Set Context Path</filter-name> <filter-class>cn.javass.commons.web.filter.ContextPathFilter</filter-class> </filter> <filter-mapping> <filter-name>Set Context Path</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 設置web環境上下文(方便JSP頁面獲取)結束 --> <!-- 字符編碼過濾器(防止亂碼)開始 --> <filter> <filter-name>Set Character Encoding</filter-name> <filter-class> org.springframework.web.filter.CharacterEncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>Set Character Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 字符編碼過濾器(防止亂碼)結束 --> <!-- Struts2.x前端控制器配置開始 --> <filter> <filter-name>struts2Filter</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2Filter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <!-- Struts2.x前端控制器配置結束 --> </web-app> ``` 原創內容,轉載請注明私塾在線【[http://sishuok.com/forum/blogPost/list/2515.html](http://sishuok.com/forum/blogPost/list/2515.html#7240)】
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看