日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用抽象工厂创建DAO、利用依赖注入去除客户端对工厂的直接依赖、将有关Article的各种Servlet封装到一个Servlet中(通过BaseServlet进行

發布時間:2025/6/15 编程问答 29 豆豆

利用抽象工廠創建DAO、利用依賴注入去除客戶端對工廠的直接依賴、將有關Article的各種Servlet全部封裝到一個Servlet中(通過BaseServlet來進行ArticleServlet方法的導向)

(這篇文章中只總結了ArticleServlet,而并沒有分析ChannelServlet,兩者其實差不多,關于ArticleServlet的基本都可以用于ChannelServlet的分析

總體分析:

1、利用PropertiesBeanFactory抽象工廠根據beans.properties配置文件創建各種DAO,放入ServletContext中。

2、在BaseServlet中(實際上用戶訪問的是繼承了BaseServletArticleServlet、…)根據屬性PropertiesBeanFactory取出ArticleServlet、…需要的DAO向具體ArticleServletChannelServletLoginServlet注入需要的某些DAO,以避免客戶端直接依賴于具體的DAO實現類。

3、將各種關于Article功能的Servlet全部集中到一個ArticleServlet中(關于Channel功能的Servlet全部集中到一個ChannelServlet中、……),通過BaseServlet中的process()方法實現導向ArticleServletChannelServlet…)中的不同方法(add()del()、update()、…方法)的功能(即原先的直接訪問各種AddArticleServletDelArticleServletUpdateArticleServlet、…)。

1、利用PropertiesBeanFactory抽象工廠根據beans.properties配置文件創建各種DAO,放入ServletContext中。

大體的思路是這樣的:

首先在web.xml中定義

??<servlet>

????<servlet-name>InitBeanFactoryServlet</servlet-name>

<servlet-class>cn.com.leadfar.cms.backend.view.InitBeanFactoryServlet</servlet-class>

????<init-param>

????<param-name>configLocation</param-name>

????<param-value>beans.properties</param-value>

????</init-param>

????<load-on-startup>0</load-on-startup>

??</servlet>

1、<load-on-startup>表示容器是否在啟動的時候就加載這個servlet(實例化并調用其init()方法);

2、它的值必須是一個整數,表示該servlet應該被載入的順序;

3、當值為0或者大于0時,表示容器在啟動時加載并初始化這個servlet;當值小于0或者沒有指定時,表示容器在該servlet被使用時才去加載(即用戶第一次請求時);

4、正數的值越小,該servlet的優先級越高,應用啟動時就越先加載;

5、當值相同時,容器會自己選擇順序來加載。

由于<load-on-startup>0</load-on-startup>,所以首先實例化并調用InitBeanFactoryServlet這個servletinit()方法,同時配置了init-param

?????在InitBeanFactoryServletString中,通過String??configLocation?=?config.getInitParameter("configLocation");取出param-valuebeans.properties賦值給configLocation?,通過執行factory?=?new?PropertiesBeanFactory(configLocation);創建PropertiesBeanFactory對象(PropertiesBeanFactory實現了BeanFactory接口,因為BeanFactory不一定都是通過Properties配置文件來創建bean產品的)。

?

Beans.propertiesproperties類型的配置文件)的內容為:

HashMap是線程不安全的對象,而Hashtable<>是線程安全的對象。

public?class?Hashtable<K,V>?

extends?Dictionary<K,V>?

implements?Map<K,V>,?Cloneable,?java.io.Serializable?{}

Properties?extends?Hashtable<Object,Object>繼承了Hashtable,它有更強大的功能,Properties?調用load方法(HashMapHashtable中沒有load方法),可以直接讀取文件,而且可以將文件中的鍵值對直接放到Map中來(Properties就是一個Map),props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(configurationFile));由于PropertiesMap沒有iterator方法,iteratorcollectionSetList特有的)沒有iterator方法,所以

因為DAO是無狀態的(即~~~,得上網補齊),所以在最開始的時候就根據Beans.properties文件的配置率先把所有需要用到的DAO全創建好,同時beans.put(key,?bean);?//緩存DAO對象,將創建的DAO放到PropertiesBeanFactory中的Map中。

創建完PropertiesBeanFactory對象后,InitBeanFactoryServletString調用getServletContext().setAttribute(INIT_FACTORY_NAME,?factory);PropertiesBeanFactory放入ServletContext中(ServletContextservlet中范圍最大的~~~不會寫了,從網上看看這句話怎么寫吧),意即所有的servlet全能訪問到這個PropertiesBeanFactory(以及它里面的各種DAO),即單例化了DAO,而不需要在每個servlet中都new一個DAO

接下來分析DAO

這個DAO是關于CRUD?Article對象對應的數據庫中的article表的DAOarticle表可能建立在MySQLOracleDB2SQL?server中…,所以ArticleDao是個接口,而有ArticleDaoImplMySQL)和ArticleDaoImplForOracle…等等實現了ArticleDao接口的具體Dao

接下來分析ArticleDaoImpl(都是最簡單的CRUD,后面會用MyBatis更好的實現,當然我看Hibernate也不錯,學著看吧):

2在BaseServlet中(實際上用戶訪問的是繼承了BaseServletArticleServlet、…)根據屬性PropertiesBeanFactory取出ArticleServlet、…需要的DAO向具體ArticleServletChannelServletLoginServlet注入需要的某些DAO,以避免客戶端直接依賴于具體的DAO實現類。

接下來分析ArticleServlet以及BaseServlet

原先有AddArticleServletDelArticleServletOpenUpdateArticleServletUpdateArticleServletSearchArticleServlet…一堆關于Articleservlet,現在將與Article有關的Servlet全部合成到ArticleServlet類中將與Channel有關的Servlet全部合成到ChannelServlet類中)。

BaseServlet的代碼:

ArticleServlet繼承BaseServlet,任何servlet都有一個唯一的入口,即service()方法。BaseServletservice()方法中,實現了向ArticleServlet注入ArticleDaoImpl的功能(ChannelServlet注入ChannelDaoImpl、向LoginServlet注入AdminDaoImpl)

首先先從ServletContext中取出BeanFactoryBeanFactory?factory?=?(BeanFactory)getServletContext().getAttribute(InitBeanFactoryServlet.INIT_FACTORY_NAME);

Method[]?methods?=?this.getClass().getMethods();這里的this雖然是在BaseServletservice中寫的,但實際上是用戶訪問的是ArticleServletthis表示的是ArticleServletArticleServlet繼承了BaseServlet,而ArticleServlet并沒有重寫service()方法)。this.getClass().getMethods()即得到了ArticleServlet中的方法,

if(m.getName().startsWith("set"))的意思即判斷方法名是不是以set開頭,如果是,就可能是setArticleDao()方法之類的了(看ArticleServlet的代碼就懂了),String?propertyName?=?m.getName().substring(3);將前面的set三個字符截掉,得到ArticleDao,接下來:

StringBuffer?sb?=?new?StringBuffer(propertyName);

sb.replace(0,?1,?(propertyName.charAt(0)+"").toLowerCase());

propertyName?=?sb.toString();

Object?bean?=?factory.getBean(propertyName);

ArticleDao轉換為articleDao,賦值給propertyName,通過propertyName參數名,來從InitBeanFactoryServlet中獲取articleDao名對應的cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl對象。

約定:setters方法所決定的屬性(property)名articleDao,與配置文件Beans.properties中相應的對象命名articleDao一致!

m.invoke(this,?bean);最后這句是將依賴對象注入客戶端m.invoke()中第一個參數是要調用的對象,this表示ArticleServlet后邊的beanbean即為cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)是要調用的方法的參數,實際上相當于調用ArticleServlet對象的setArticleDaocn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)方法。

ArticleServletArticleDao屬性運用了DI(Dependency?Injection依賴注入)的方法,即ArticleServlet對象不自己設置自己的ArticleDao屬性,而是依賴~~~注入。

3、將各種關于Article功能的Servlet全部集中到一個ArticleServlet中(關于Channel功能的Servlet全部集中到一個ChannelServlet中、……),通過BaseServlet中的process()方法實現導向ArticleServletChannelServlet…)中的不同方法(add()del()、update()、…方法)的功能(即原先的直接訪問各種AddArticleServletDelArticleServletUpdateArticleServlet、…)。

原先有AddArticleServletDelArticleServletOpenUpdateArticleServletUpdateArticleServletSearchArticleServlet…一堆關于Articleservlet,現在將與Article有關的Servlet全部合成到ArticleServlet類中將與Channel有關的Servlet全部合成到ChannelServlet類中)。

super.service(arg0,?arg1);的意思是執行父類HttpServlet的職責:根據請求是GET還是POST方法,調用doGet或doPost!但在doGet或doPost()方法中只是簡單的導向執行process(req,resp);方法,而ArticleServlet也并沒有重寫doGet()、doPost()、

process(req,resp)方法,

用戶訪問ArticleServletArticleServletaddArticleServletdelArticleServletupdate…,

String?method?=?request.getParameter("method");即取出adddelupdate

如果客戶端只是ArticleServlet不傳遞method參數,則默認調用execute()方法即查詢操作。BaseServletexecute()方法什么也不做,但是ArticleServlet有重寫了這個方法,在這個方法中執行查詢工作

在這里并沒有用

if(method.equals("add"))?{

//執行添加動作,同時執行完成之后,轉向成功頁面

}else?if(method.equals("del"))?{

//執行刪除界面…

}else?if(method.equals("update"))?{

//執行更新界面…

}

而是使用了反射機制,更便捷的實現了功能:

Method?m?=?this.getClass().getMethod(method,?HttpServletRequest.class,HttpServletResponse.class);

獲取ArticleServlet中的adddelupdate…之類的方法。

m.invoke(this,?request,response);

m.invoke()中第一個參數是要調用的對象,this表示ArticleServlet后邊的request,response是要調用的方法的參數,實際上相當于調用ArticleServlet對象的add(HttpServletRequest?request,?HttpServletResponse?response)…之類的方法。

接下來該分析ArticleServlet的代碼了,其實也沒啥可分析的,就是從request中獲取客戶端傳過來的參數,然后調用articleDao的相應CRUD方法

關于del(HttpServletRequest?request,?HttpServletResponse?response)方法有個小注意點:如果執行完刪除操作后,轉向頁面語句寫成:request.getRequestDispatcher("/backend/ArticleServlet").forward(request,?response);因為forward服務器端重定向時request中的數據不會丟失,雖然表面上寫的是轉向/backend/ArticleServlet頁面,實際上還是/backend/ArticleServletmethod=del&id=…頁面。所以我們這里需要寫成redirect重定向:response.sendRedirect(request.getContextPath()+"/backend/ArticleServlet");

在添加頁面add_article.jsp中,提交時并沒有寫成

<form?action="ArticleServlet?method=add"?method="post">

而是寫成:

<form?action="ArticleServlet"?method="post">

<input?type="hidden"?name="method"?value="add">

其實兩者都對,但在post提交的方式中一般不在action后面再加method=add參數,而是將這參數寫成隱含參數。當然需要用戶輸入的參數肯定也是寫成<input?type="text"?name="title"?id="title"?value=""?size="60"?maxlength="200"?/>這種格式。

在更新界面update_article.jsp中這么寫:

<form?action="ArticleServlet"?method="post">

<input?type="hidden"?name="id"?value="${article.id?}">

<input?type="hidden"?name="method"?value="update">

4、關于LoginServlet的一些小分析

將LoginServlet、LogoutServlet、CheckCodeServlet這些與登錄有關的Servlet,全部合成到LoginServlet中(LoginServlet也繼承了BaseServlet)!

-?LoginServlet中的方法checkcode用于生成驗證碼

-?LoginServlet中的方法execute用于登錄用戶名和密碼驗證

-?LoginServlet中的方法quit用于退出后臺系統

servlet重寫init(ServletConfig)方法的時候,記得調用super.init(ServletConfig),調用super.init(ServletConfig)的目的,主要是由于在父類(GenericServlet)中有一個ServletConfig實例變量,super.init(ServletConfig)就是給這個實例變量賦值。這樣,在后續的getServletContext()操作,才可以拿到ServletContext對象:

GenericServlet的部分源代碼如下所示:

----------------------------------------------------

public?abstract?class?GenericServlet?

????implements?Servlet,?ServletConfig,?java.io.Serializable

{

????private?transient?ServletConfig?config;

????

????public?void?init(ServletConfig?config)?throws?ServletException?{

this.config?=?config;

this.init();

????}

????public?void?init()?throws?ServletException?{

????}????

????public?ServletConfig?getServletConfig()?{

return?config;

????}

????public?ServletContext?getServletContext()?{

return?getServletConfig().getServletContext();

????}

-----------------------------------------------------????

login.jsp頁面中還有一個小知識點:

function?reloadcheckcode(img){

img.src?=?"LoginServlet?method=checkcode&"+Math.random();

}

在重新載入驗證碼時,只需在后面加個&"+Math.random()隨機數,系統即會自動調用LoginServletcheckcode()方法(注意“&”符號)。

下面的是LoginServlet的代碼:

總結

以上是生活随笔為你收集整理的利用抽象工厂创建DAO、利用依赖注入去除客户端对工厂的直接依赖、将有关Article的各种Servlet封装到一个Servlet中(通过BaseServlet进行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。