Tomcat服务器开发教程_webapp及服务器代码解耦合1

Tomcat服务器开发教程_webapp及服务器代码解耦合1

更新时间:2017年04月07日

  • 视频类型:java
  • 适合对象:Java学员、Java爱好者、开发人员
  • qq号:2158476996
一键免费下载

下载介绍

更多>>
Tomcat服务器开发教程_webapp及服务器代码解耦合1

【Web 服务器代码和 WebApp 代码解耦合】

    分析以上代码, LoginServlet 类是 JavaWeb 程序员开发的, 而 HandlerRequest 类是服务器开发人员开发的,在服务器中的代码关心了具体的 Servlet 类,显然服务器的程序和 JavaWeb 程序产生了依赖,具有高强度的耦合,实际上对于 Web 服务器来说,根本就不知道 Web 应用中有一个 LoginServlet 类,上面的程序中还使用了“new LoginServlet();”,这显然是错误的。另外在上面的 Web 服务器程序中编写了具体的请求路径/oa/login,这显然是不合理的, 对于 Web 服务器来说浏览器客户端发送的请求是未知的。但是我们知道浏览器发送的请求路径/oa/login 是和底层 WebApp 中的 LoginServlet 存在映射关系/绑定关系的。而这种关系的指定必须由 WebApp 的开发人员来指定,我相信大家此时应该想到了“配置文件”,在配置文件中指定请求 URI 和对应要执行的 Servlet。该配置文件的编写由 WebApp程序员来完成,但是该文件由 Web 服务器开发人员读取并解析,所以该文件的名字、该文件的存放位置、该文件中所编写的配置元素都不能随意编写,必须提前制定好一个规范,那么这个规范由谁来制定呢?当然是由 SUN 公司来负责制定。

    接下来我们的角色再次发生了转变,我们现在是规范的制定者 SUN。制定规范如下所示,规范就是规定,没有为什么,以后服务器开发人员和 WebApp 的开发人员只要严格按照规范开发即可。下面这段规范是这样制定的:

(1)SUN 制定的配置文件规范:

  A、在配置文件 web.xml 中描述请求 URI 和对应的 Servlet 类之间的关系

  B、web.xml 文件统一存放到 WebAppRoot/WEB-INF/目录下

  C、web.xml 文件中采用这样的标签描述请求 URI 和对应 Servlet 类之间的关系

    以上配置文件规定了什么呢?第一:配置文件的名字;第二:配置文件存放位置;第三:配置文件中编写哪些标签。接下来我们的角色转变为 WebApp 的开发人员,按照规范新建 web.xml 文件,并将其存放到规范中要求的路径下,在该文件中编写规范中规定的标签,如下图所示 

  D、在 OA 应用下创建 WEB-INF 文件夹,并且在该文件夹下创建 web.xml

  E、在 org.bjpowernode.oa.servlet 下创建 LoginServlet 类,处理登录信息

  角色:web 服务器开发人员

  A、服务器开发者负责解析 web.xml 文件

   a、通过 Dom4j+xpath 解析 web.xml

  B、在 Web 服务器启动阶段解析 web.xml 文件

    接下来我们的角色再次转变为  Web 服务器的开发人员,服务器开发者负责解析 web.xml 文件,那么这个文件在什么时候解析呢?解析出来的数据存放到哪里呢?这些问题由服务器开发者决定,SUN 的规范中并没有特殊的要求。web.xml 文件中主要配置了请求 URI 和对应的 Servlet 完整类名,请求 URI 更像一个 Map 集合的 key,对应的 Servlet 完整类名更像一个 Map 集合的 value,所以我们决定采用一个 Map 集合存储解析出来的数据。在浏览器发送请求的时候再去解析 web.xml 文件时有点晚了,

    所以我们决定在 Web 服务器启动阶段解析 web.xml 文件,以下是 Web 服务器开发人员编写的解析

web.xml 文件的代码

public class WebParser{

public static Mapparser(String webAppName){

String webFilePath = webAppName+”/WEB-INF/web.xml”; //获取 web.xml 路径

SAXReader saxReader = new SAXReader();//获取解析器

//将 web.xml 读取到 Document 对象中

Document document = saxReader.read(webFilePath); 

//获取 web-app 下 servlet 节点

ListservletNodes = document.selectNodes(“/web-app/servlet”);

//获取 servlet-name 和 servlet-class 值存放到 servletInfoMap 中

MapservletInfoMap = new HashMap();

//遍历 servletNodes 获取 servlet-name 和 servlet-class 值

for(Element servletNode : servletNodes){

String servletName =

(Element)(servletNode.selectSingleNode(“servlet-name”)).getTextTrim();

String servletClass =

servletNode.selectSingleNode(“servlet-class”).getTextTrim();

servletInfoMap.put(servletName,servletClass);


}

//将相同 servletName 的值分别当作 key 和 value 存放到 servletMap 中

MapservletMap = new HashMap();

//获取 servletMappingInfoMap 中 key 的所有 servlet-name

SetservletNames = servletMappinInfoMap.keySet();

for(String servletName : servletNames){

//获取 servlet 请求路径

String servletPath = servletMappinInfoMap.get(servletName);

//获取 servlet 完整类名

String servletClassName = servletInfoMap.get(servletName);

servletMap.put(servletPath,servletClassName);

}

}

//遍历每一个应用的 web.xml

public static Map<String,Map> servletMaps = new 

HashMap<String,Map>();

public static void parser(String[] webAppNames){

for(String webAppName : webAppNames){

MapservletMap = parser(webAppName);

servletMaps.put(webAppName,servletMap);

}

}

(3)在服务器启动阶段解析每个 WebApp 的 web.xml 文件,在 BootStrap

中加入如下代码

  A、修改 BootStrap 类中 start()方法

   a、在服务端套接字绑定端口号之后,添加如下代码,开始读取 web.xml 文件

   b、WebServer.parser(new String[]{“oa”});

    以上代码在服务器启动阶段解析每个 WebApp 的 web.xml 文件,其中 WebApp 的名字 oa 写死到服务器程序中了,其实对于 Web 服务器来说根本就不知道该 Web 服务器下有哪些 WebApp。这个问题怎么解决呢?我们可以规定一个目录,例如该目录的名字叫做 webapps,让所有的 WebApp 都放到我们所指定的 webapps 目录下,这样我们就可以在 Web 服务器中动态获取所有 WebApp 的名字了,这个功能大家自己完成,这里不再实现这个功能了。

    现在我们的角色还是 Web 服务器开发人员,web.xml 文件已经在服务器启动阶段解析了,用户的请求路径已经和对应的 Servlet 完整类名绑定在一起了,分析以下程序应该如何修改

(4)-我们在服务器端程序中可以获取到请求 URI,我们通过请求 URI 获取对应的 Servlet 完整类名

(5)再通过反射机制,调用该 Servlet 类的无参数构造方法,完成 Servlet对象的创建,代码如下所示

A、  在 HandlerRequest 类中 run 方法里,修改”/oa/login” .equals(servletPath)

//获取应用名称 webAppName

String webAppName = servletPath.split(“/”)[1];

//获取应用所对应的解析 web.xml 后的 Map 集合

MapservletMap = WebParser.servletMaps.get(webAppName);

//获取 servlet 的请求路径:/login

String urlPattern = servletPath.substring(webAppName.length()+1);

//获取 servlet 完整类名

String servletClassName = servletMap.get(urlPattern);

//通过 Class.forName()创建 servlet 对象

Class c = Class.forName(servletClassName);

Object obj = c.newInstance();

(6)Web 服务器的开发人员又遇到了新的问题

  A、虽然我们在服务器端根据请求 URI 找到了对应的 Servlet 完整类名,也通过反射机制

将 Servlet 对象创建成功了

  B、但是对于 Web 服务器的开发人员来说并不知道该 Servlet 对象中有什么方法

  C、这个时候只有 SUN 再次出面制定规范了

   a、接下来我们的角色发生了改变,我们现在是 SUN 公司,制定一个 Servlet 接口

   b、该接口的实现者是 WebApp,调用者 Web 服务器,以下是 SUN 公司制定的 Servlet规范的核心接口

   c、新建 javax.servlet 包,创建一个 Servlet 接口

   d、 该接口中包含:处理请求的核心方法 void service();

public interface Servlet{

void service();//处理请求的核心方法

}

(7)接下来我们的角色转变为 WebApp 的开发人员,让 LoginServlet 实

现 Servlet 接口

(8)接下来我们的角色转变为 Web 服务器的开发人员,

  A、在 HandlerRequest 类中面向 Servlet 接口调用 service 方法即可

  B、修改 HandlerRequest 方法,紧接着(5)继续编写代码

Servlet servlet = (Servlet)obj;

servlet.service();

(9)启动 httpserver,打开浏览器,输入 URL,发送请求

http://127.0.0.1:8008/oa/login?user=zhangsan&password=123