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

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

总体分析:

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

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

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

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这个servlet的init()方法,同时配置了init-param。

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

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

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方法(HashMap、Hashtable中没有load方法),可以直接读取文件,而且可以将文件中的键值对直接放到Map中来(Properties就是一个Map),props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(configurationFile));由于Properties(Map没有iterator方法,iterator是collection:Set、List特有的)没有iterator方法,所以

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

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

接下来分析DAO:

这个DAO是关于CRUD Article对象对应的数据库中的article表的DAO,article表可能建立在MySQL、Oracle、DB2、SQL server中…,所以ArticleDao是个接口,而有ArticleDaoImpl(MySQL)和ArticleDaoImplForOracle…等等实现了ArticleDao接口的具体Dao。

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

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

接下来分析ArticleServlet以及BaseServlet

原先有AddArticleServlet、DelArticleServlet、OpenUpdateArticleServlet、UpdateArticleServlet、SearchArticleServlet…一堆关于Article的servlet,现在将与Article有关的Servlet全部合成到ArticleServlet类中(将与Channel有关的Servlet全部合成到ChannelServlet类中)。

BaseServlet的代码:

ArticleServlet继承BaseServlet,任何servlet都有一个唯一的入口,即service()方法。在BaseServlet的service()方法中,实现了向ArticleServlet注入ArticleDaoImpl的功能(向ChannelServlet注入ChannelDaoImpl、向LoginServlet注入AdminDaoImpl)

首先先从ServletContext中取出BeanFactory,BeanFactory factory = (BeanFactory)getServletContext().getAttribute(InitBeanFactoryServlet.INIT_FACTORY_NAME);

Method[] methods = this.getClass().getMethods();这里的this虽然是在BaseServlet的service中写的,但实际上是用户访问的是ArticleServlet,this表示的是ArticleServlet(ArticleServlet继承了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,后边的bean(bean即为cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)是要调用的方法的参数,实际上相当于调用ArticleServlet对象的setArticleDao(cn.com.leadfar.cms.backend.dao.impl.ArticleDaoImpl)方法。

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

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

原先有AddArticleServlet、DelArticleServlet、OpenUpdateArticleServlet、UpdateArticleServlet、SearchArticleServlet…一堆关于Article的servlet,现在将与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)方法,

用户访问ArticleServlet是ArticleServlet?add、ArticleServlet?del、ArticleServlet?update…,

String method = request.getParameter("method");即取出add、del、update。

如果客户端只是ArticleServlet而不传递method参数,则默认调用execute()方法,即查询操作。在BaseServlet中execute()方法什么也不做,但是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中的add、del、update…之类的方法。

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/ArticleServlet?method=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()随机数,系统即会自动调用LoginServlet的checkcode()方法(注意“&”符号)。

下面的是LoginServlet的代码:

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

  1. 依赖注入及AOP简述(一)——“依赖”的概念 .

    一.入门:依赖注入 作为一种全新的设计模式理念,"依赖注入"这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的"依赖注入框架",也越来越多的 ...

  2. go 依赖注入 哪个好_go与java的依赖注入实现的一些差异

    go语言是一门开源的语言,我这里说开源,并不是指go的编译器等是开源,而是指go在机制上决定了当我们引入一个类库的时候,实质上是引入类库的源码. 纯go实现的类库.模块,基本是无法以编译后二进制的形式 ...

  3. Angular 依赖注入学习笔记之工厂函数的用法

    网址:https://angular.institute/di We can transfer any data through our apps, transform it and replace ...

  4. java中依赖注入_关于Java:什么是依赖注入?

    本问题已经有最佳答案,请猛点这里访问. Possible Duplicate: What is Inversion of Control? 我真的很困惑依赖注入的概念. 我对软件领域非常陌生,我对下面 ...

  5. 依赖注入及AOP简述(五)——依赖注入的方式 .

    二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1.     依赖注入的方 ...

  6. spring依赖注入_Spring源码阅读:Spring依赖注入容器

    依赖注入 依赖注入是Spring框架最核心的能力,Spring框架提供的AOP,WebMVC等其它功能都是以依赖注入容器作为基础构建的,Spring依赖注入容器类似于一个用于组装对象的框架内核,任何应 ...

  7. phalapi可以依赖注入么_phalapi-进阶篇2(DI依赖注入和单例模式)

    phalapi-进阶篇2(DI依赖注入和单例模式) 前言 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架. 离上一次更新过去了快两周,在其中编写了一个关于DB ...

  8. 类继承和依赖注入的关系_管理类依赖关系:依赖关系注入,服务定位符和工厂简介,第1部分...

    类继承和依赖注入的关系 Let's face it: for good or bad, OOP has been actively drilling deep holes in the soil of ...

  9. factorybean 代理类不能按照类型注入_彻底搞懂依赖注入(一)Bean实例创建过程

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 上一章介绍了Bean的加载过程(IOC初始化过程),加载完成后,紧接着就要用到它的依赖注入 ...

最新文章

  1. java中ajax概念_Java之AJAX概念和实现方式
  2. C# 判断字符串是否符合十六进制,八进制,二进制和十进制整数格式的正则表达式...
  3. 一致性问题和Raft一致性算法——一致性问题是无法彻底解决的,可以说一个分布式系统可靠性达到99.99…%,但不能说它达到了100%...
  4. protocol buffer相关
  5. 三大开源生信基础教程和视频课程
  6. deepnode处理过的图片_微信图文排版用什么软件?文章图片大小不一样排版不齐怎么办?...
  7. Linux教程系列-命令大全
  8. jdk 文档下载地址
  9. 使用SAX读取XML文件
  10. DiskGenius分区助手,5.1.2.766绿色单文件版更新上传
  11. php保存pdf旋转90度,怎么把pdf旋转90度 多个pdf文件页面旋转的方法|支持选择要旋转的页面及旋转角度...
  12. ◎◎首都机场大巴最新路线时刻表◎◎
  13. 大小写字母c语言,C语言 大小写字母转换
  14. 创宇区块链|Inverse Finance 安全事件分析
  15. 《北京DRGs系统的研究与应用》学习笔记
  16. Oracle 常用语句大全
  17. 2022-06-06 FUSE用户态文件系统
  18. 量子计算核心突破!Shor算法实现或使密码成摆设
  19. 【编译原理】Python语法分析LL(1)、LR(1)
  20. Unity3d NGUI控件知识

热门文章

  1. 【C 语言】一级指针 易犯错误 模型 ( 判定指针合法性 | 数组越界 | 不断修改指针变量值 | 函数中将栈内存数组返回 | 函数间接赋值形参操作 | 指针取值与自增操作 )
  2. 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )
  3. 【错误记录】Android 应用 release 打包报错处理 ( 关闭语法检查 | 日志处理 | release 配置 )
  4. 【运筹学】线性规划 人工变量法 ( 人工变量法案例 | 第三次迭代 | 中心元变换 | 检验数计算 | 最优解判定 )
  5. qt 提高图片加载速度
  6. POJ 3264 Balanced Lineup
  7. 感知机模型及其对偶形式
  8. [Phonegap+Sencha Touch] 移动开发18 Sencha Touch项目通过phonegap打包后的程序名字的问题...
  9. JQuery选择器大全
  10. ROS学习(九):ROS URDF-link