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

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

(这篇文章中只总结了ArticleServlet,而并没有分析ChannelServlet,两者其实差不多,关于ArticleServlet的基本都可以用于ChannelServlet的分析

总体分析:

1、利用PropertiesBeanFactory抽象工厂根据beans.properties配置文件创建各种DAO,放入ServletContext中。

2、在BaseServlet中(实际上用户访问的是继承了BaseServletArticleServlet、…)根据属性取出ArticleServlet、…需要的DAO向具体ArticleServletChannelServletLoginServlet注入需要的某些DAO,以避免客户端直接依赖于具体的DAO实现类。

3、将各种关于Article功能的Servlet全部集中到一个ArticleServlet中(关于Channel功能的Servlet全部集中到一个ChannelServlet中、……),通过BaseServlet中的process()方法实现导向ArticleServletChannelServlet…)中的不同方法(add()del()、update()、…方法)的功能(即原先的直接访问各种AddArticleServletDelArticleServletUpdateArticleServlet、…)。

1、利用中。

大体的思路是这样的:

首先在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>

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

1、<load-on-startup>表示容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法);

2、它的值必须是一个整数,表示该servlet应该被载入的顺序;

3、当值为0或者大于0时,表示容器在启动时加载并初始化这个servlet;当值小于0或者没有指定时,表示容器在该servlet被使用时才去加载(即用户第一次请求时);

4、正数的值越小,该servlet的优先级越高,应用启动时就越先加载;

5、当值相同时,容器会自己选择顺序来加载。

由于<load-on-startup>,所以首先实例化并调用InitBeanFactoryServlet这个servletinit()方法,同时配置了init-param

String中,通过StringconfigLocation=config.getInitParameter("configLocation");取出param-value赋值给configLocation,通过执行factory=newPropertiesBeanFactory(configLocation);创建PropertiesBeanFactory对象(实现了BeanFactory接口,因为不一定都是通过Properties配置文件来创建bean产品的)。

Beans.propertiesproperties类型的配置文件)的内容为:

HashMap是线程不安全的对象,而Hashtable<>是线程安全的对象。

publicclassHashtable<K,V>

extendsDictionary<K,V>

implementsMap<K,V>,Cloneable,java.io.Serializable{}

PropertiesextendsHashtable<Object,Object>继承了Hashtable,它有更强大的功能,Properties调用load方法(HashMapHashtable中没有load方法),可以直接读取文件,而且可以将文件中的键值对直接放到Map中来(Properties就是一个Map),props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(configurationFile));由于Map没有iterator方法,iteratorcollectionSetList特有的)没有iterator方法,所以

因为DAO是无状态的(即~~~,得上网补齐),所以在最开始的时候就根据Beans.properties文件的配置率先把所有需要用到的DAO全创建好,同时beans.put(key,bean);//缓存DAO对象,将创建的DAO放到中的Map中。

创建完对象后,调用getServletContext().setAttribute(INIT_FACTORY_NAME,factory);放入ServletContext中(ServletContextservlet中范围最大的~~~不会写了,从网上看看这句话怎么写吧),意即所有的servlet全能访问到这个(以及它里面的各种DAO),即单例化了DAO,而不需要在每个servlet中都new一个DAO

接下来分析DAO

这个DAO是关于CRUDArticle对象对应的数据库中的article表的DAOarticle表可能建立在MySQLOracleDB2SQLserver中…,所以ArticleDao是个接口,而有ArticleDaoImplMySQL)和ForOracle…等等实现了ArticleDao接口的具体Dao

接下来分析ArticleDaoImpl(都是最简单的CRUD,后面会用MyBatis更好的实现,当然我看Hibernate也不错,学着看吧):

2在BaseServlet中(实际上用户访问的是继承了BaseServletArticleServlet、…)根据属性DAO向具体ArticleServletChannelServletLoginServlet注入需要的某些DAO,以避免客户端直接依赖于具体的DAO实现类。

接下来分析ArticleServlet以及BaseServlet

原先有AddArticleServletDelArticleServletOpenUpdateArticleServletUpdateArticleServletSearchArticleServlet…一堆关于Articleservlet,现在将与Article有关的Servlet全部合成到ArticleServlet类中将与Channel有关的Servlet全部合成到ChannelServlet类中)。

BaseServlet的代码:

继承,任何servlet都有一个唯一的入口,即service()方法。BaseServletservice()方法中,实现了向ArticleServlet注入ArticleDaoImpl的功能(ChannelServletChannelDaoImpl、向LoginServletAdminDaoImpl)

首先先从ServletContext中取出BeanFactoryBeanFactoryfactory=()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()方法之类的了(看的代码就懂了),StringpropertyName=m.getName().substring(3);将前面的set三个字符截掉,得到ArticleDao,接下来:

StringBuffersb=new(propertyName);

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

propertyName=sb.toString();

Objectbean=factory.getBean(propertyName转换为articleDao,赋值给propertyName,通过参数名,来从中获取articleDao名对应的cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl对象。

约定:setters方法所决定的属性(property)名,与配置文件Beans.properties中相应的对象命名articleDao一致!

m.invoke(this最后这句是将依赖对象注入客户端m.invoke()中第一个参数是要调用的对象,this表示后边的beanbean即为cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)是要调用的方法的参数,实际上相当于调用对象的cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)方法。

ArticleDao属性运用了DI(DependencyInjection依赖注入)的方法,即对象不自己设置自己的属性,而是依赖~~~注入。

3、将各种关于Article功能的Servlet全部集中到一个ArticleServlet中(关于Channel功能的Servlet全部集中到一个ChannelServlet中、……),通过BaseServlet中的process()方法实现导向ArticleServletChannelServlet…)中的不同方法(add()del()、update()、…方法)的功能(即原先的直接访问各种AddArticleServletDelArticleServletUpdateArticleServlet、…)。

super.service(arg0,arg1);的意思是执行父类HttpServlet的职责:根据请求是GET还是POST方法,调用doGet或doPost!但在doGet或doPost()方法中只是简单的导向执行process(req,resp);方法,而也并没有重写doGet()、doPost()、

方法,

用户访问ArticleServletArticleServletaddArticleServletdelArticleServletupdate…,

Stringmethod=request.getParameter("method"即取出adddelupdate

如果客户端只是ArticleServlet不传递method参数,则默认调用execute()方法即查询操作。BaseServletexecute()方法什么也不做,但是有重写了这个方法,在这个方法中执行查询工作

在这里并没有用

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

//执行添加动作,同时执行完成之后,转向成功页面

}elseif(method.equals("del")){

//执行删除界面…

}elseif(method.equals("update")){

//执行更新界面…

}

而是使用了反射机制,更便捷的实现了功能:

Methodm=this.getClass().getMethod(method,HttpServletRequest.class 获取ArticleServlet中的adddelupdate…之类的方法。

m.invoke(this后边的request,response是要调用的方法的参数,实际上相当于调用add(HttpServletRequestrequest,HttpServletResponseresponse)…之类的方法。

接下来该分析的代码了,其实也没啥可分析的,就是从request中获取客户端传过来的参数,然后调用articleDao的相应CRUD方法

关于del方法有个小注意点:如果执行完删除操作后,转向页面语句写成:request.getRequestDispatcher("/backend/ArticleServlet").forward(request,response);因为forward服务器端重定向时request中的数据不会丢失,虽然表面上写的是转向//ArticleServlet页面,实际上还是method=del&id=…页面。所以我们这里需要写成redirect重定向:response.sendRedirect(request.getContextPath()+"/backend/ArticleServlet"在添加页面add_article.jsp中,提交时并没有写成

formaction="ArticleServlet?method=add"method="post">

而是写成:

="ArticleServlet"methodinputtype="hidden"name="method"value="add">

其实两者都对,但在post提交的方式中一般不在action后面再加method=add参数,而是将这参数写成隐含参数。当然需要用户输入的参数肯定也是写成<inputtype="text"name="title"id="title"value=""size="60"maxlength="200"/>这种格式。

在更新界面update_article.jsp中这么写:

="id"value="${article.id}">

="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的部分源代码如下所示:

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

publicabstractclassGenericServlet

implementsServlet{

privatetransientServletConfigconfig;

publicvoid(ServletConfig)throwsServletException{

this.config=this.init();

}

()throwsServletException{

publicServletConfiggetServletConfig(){

returnpublicServletContextgetServletContext(){

returngetServletConfig().getServletContext();

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

login.jsp页面中还有一个小知识点:

functionreloadcheckcode(img){

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

在重新载入验证码时,只需在后面加个&"+Math.random()随机数,系统即会自动调用LoginServletcheckcode()方法(注意“&”符号)。

下面的是LoginServlet的代码:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结