web开发学习笔记:web容器、JSP简述和编写设置第一个Servlet

本篇文章是对自己学习的一个总结,主要学习资料是JSP&Servlet学习笔记(第三版),林信良著,清华大学出版社出版。


Web容器

  • 容器简述

对于Java程序而言,JVM是操作系统。.java文件会被编译成.class文件,.class文件对于JVM而言,就是可执行文件。Java程序基本上只认得一种操作系统,就是JVM。

一开始编写Servlet/JSP程序时就要认识到容器的概念。List,Set这类Collection也是一种容器,用来持有保存对象的集合对象。对于Servlet/JSP来说,容器的概念更广,它不仅持有对象,还负责对象的生命周期和相关服务的连接。

具体来说,容器就是一个写在JVM上的程序,不同类型的容器负责不同的工作。在编写Servlet时,会接触到HttpServletRequest和HttpServletResponse等对象,这些对象就是Java对象。想想看,HTTP这样的文本通信协议,其携带的信息是String类型的。这些信息是不会自己变成各种Java对象,其中的这些剖析和转换是容器帮我们完成的。

抽象来说,web容器可以看成是运行Servlet/JSP的HTTP服务器。没有Web容器的话,我们就是用HTTP服务器来交互信息。但HTTP服务器传来的只是String类型的信息,我们想要使用Java语言来开发网页,还要自己用JavaSE处理原始的HTTP数据的话,那也太麻烦了。Java为了方便,就制定了web容器规范,也就是接口。各大厂商负责实现这些接口,而我们不需要知道怎么实现的,由哪些厂商实现的,我们只需要调用接口就能得到我们想要的东西来进行网页开发。

所以啊,web容器本质上就是加了一层处理的HTTP服务器。

从请求到Servlet的处理过程如下(省略网络物理层和数据链路层的协议)

  1. 浏览器对服务器发送请求,服务器收到请求,使用HTTP协议将请求内容发送给容器。
  2. web容器会接卸HTTP请求内容,创建各种对象(比如HttpServletRequest、HttpServletResponse、HttpSession等)。
  3. 一个web容器内有多个Servlet,web容器根据请求的URI决定使用哪个Servlet来处理请求(开发人员定义Servet和URI的映射关系)。
  4. Servlet根据请求对象(HttpServletRequest)的信息来决定做什么,然后通过创建(HttpServletResponse)来响应。
  5. 服务器再根据HttpServletResponse转换成HTTP响应传回给浏览器。

以上就是一个请求的简要流程,我们能看出,真正负责处理请求和创建响应信息的是Servlet

最后再整理一下。web容器是JVM上的一个程序,当请求到来时,web容器会为每个请求分配一个线程来处理每个线程就是一个Servlet。

  • Web容器具体做了什么

我们已经知道Web容器会将String的HTTP信息转换成Java对象,下面就讲讲到底是如何转换的。

浏览器发出请求来到HTTP服务器,HTTP服务器会将请求交给容器来处理。容器会创建一个代表着这次请求的HttpServletRequest对象,并将请求的相关信息存储在这个对象中,比如请求的来源地址,请求用的浏览器是什么浏览器,浏览器是版本等等。

同时,容器还会创建一个HttpServletResponse对象,里面存放着对本次请求的响应信息,稍后是要对浏览器进行响应的。因为HTTP是无状态的协议,所以每次请求都会创建新的HttpServletRequest和HttpServletResponse对象,请求完成后都会销毁他们。当然,这些都是由Web容器帮我们完成的,我们可以不用关心。

如果我们在Java文档中查询HttpServletResquest和HttpServletResponse两个对象的话,会发现他们都是接口。就像我上面说的,Java只制订规范,实现交给厂商。想要知道HttpServletResponse的具体实现,我们现在使用Tomcat的话,就应该去看Tomcat的文档。

关于HttpServletRequest的具体用法可以看这篇文章,

关于HttpServletResponse的具体用法可以看这文章


Servlet和JSP

上面一直在讨论Servlet,没说涉及到JSP。实际上,Servlet和JSP是一体两面的,JSP最终还是会被web容器转换成Servlet的.java源文件,再编译成.class文件,然后再加载容器。所以JSP最终还是以Servlet的形式在运转。所以上面一直在说Servlet,因为要了解JSP,就必须对Servlet有一定的了解。

Servlet和JSP本质上是用一种东西,JSP能写出来的东西,使用Servlet也能达到同样的效果,那为什么还弄一个JSP呢?那是因为JSP的写法在比较适合写页面。相信使用过Servlet写页面和JSP写页面的之后,这点就会有很深的体会

但是现在处于商业性考虑和前端技术的兴起,JSP已经不是写页面的主要选择。尽管如此,现在还是有很多应用程序是基于JSP编写的,有JSP的基础的话,使用其他的页面技术就会变得容易上手。


使用Idea创建第一个Servlet

这次使用的web容器是Tomcat 8。操作系统是mac os。

在tomcat的官网https://tomcat.apache.org/download-80.cgi下载core下的tar.gz,然后将压缩文件解压后放在/Library目录之下。

打开idea,file->new->project,然后选择左侧栏的maven,然后从maven中选择maven-arthetype-webapp

之后再新的新的选择框中填上下图的信息,然后一直选择next直到finish

然后再下图的位置选择add configuration对项目配置

点击新弹出的页面的左上角的加号,选择tamcat server -> local。

之后选择配置Application server,之后配置tomcat home。找到刚才安装的tomcat位置,选择tomcat即可

之后在deployment下点击左下角的加号,选择Aritifact,选择冒号后为war exploded的。

点击完成。

然后在主页面选择file -> project structure,在module模块选择模块的java版本,选择java8,如下图所示

接下来就可以开始写一个简单的Servlet。

项目建立以后,项目的目录结构如左图所示在此基础上我们的java代码一般是写在main下的java包下,所以我们就新建一个java包,然后右键点击java包,mark directory as -> source root。最后结果如右图所示

              

在java包下建立如下的包,然后点击demo右键,new -> create new servlet,name设为Hello,Hello就是我们的Servlet,实际效果如下所示

这一步可能会遇到两个问题

  • new的时候没有create new servlet这个选项:那是因为项目还没有引进相关的包。解决方法是pom.xml文件中加入HttpServlet的依赖包

                                


关于HttpServlet架构的简单介绍

大部分的Servlet就像上面的Hello结构一样。继承了HttpServlet后,需要实现doPost和doGet两个方法。网页使用Get方式请求这个Servlet就调用doGet方法,使用Post方式请求即调用doPost方法。想要知道为什么会得到这样的效果,就要从HttpServlet的架构说起。下图是相关API的架构图(图片了来自于JSP&Servlet学习笔记)

首先是Servlet接口。这个接口定义了Servlet的基本行为,看看它的方法,与生命周期相关的init(),destroy();提供服务时要调用的service()方法等。

GenericServlet先不介绍。然后我们看HttpServlet,那些doGet,doPost方法分别对应着请求方式是Get,Post时的处理方式。当请求来到这个Servlet,Servlet是调用service方法,service方法的大致流程如下。

//获得本次请求的请求方式
String method = req.getMethod
if(method.equals(METHOD_GET)){
    //略
    doGet();
    //略
}
if(method.equals(METHOD_POST)){
    //略
    doPost();
    //略
}
···

所以,判断浏览器的请求方式是在service()这个方法里进行判断,这也基本上就是service()做的所有事情。我们要想根据不同的请求方式定义不同的逻辑,只需要复写对应的doXXX()方法即可,不要轻易复写service()方法,会打乱原有逻辑。


Servlet和请求地址的映射方式

  • 使用@WebServlet

一个web容器里有多个servlet,不同的servlet有不同的功能。浏览器输入地址就是一次请求,就要有一个servlet来处理这个请求。那如何确定这个请求是由哪个servlet处理就是servlet如何与地址进行映射。

假如浏览器输入的地址是localhost:8080/servletlearning_war_exploded/Hello,

localhost:8080是主机名和端口号,servletlearning_war_exploded是上下文,可以在idea中的Edit Configurations中的deployment中设置Application Context即可

然后剩下/Hello。我们就是靠最后的这个/Hello来确定哪个Servlet处理这个请求。

在上面的Hello类中,有一个注解@WebServlet。改变该注解的name值,就可以改变地址的映射关系。

或者省略name,写成@WebServlet("/Hello)也有同样的效果,注意要加上斜杠,并且区分大小写。

@WebServlet有很多的设置方式,这些方式有很强大的效果。

  1. 以" / "开头,以" /* "结尾的URI。比如@WebServlet("/guest/*")。请求除去环境路径的部分,所有以"/guest"开头的地址都交给该Servlet处理。比如/guest/text.view和/guest/test/t/a.view。
  2. 以" *. " + 类型名的URI,比如@WebServlet("*.view"),这代表所有的以.view结尾的请求,都交给该Servlet处理。
  3. 空字符串,比如@WebServlet(""),这就相当于根目录

当一个请求发送到服务器,可能有多个Servlet都可以处理这个请求。比如Servlet A设置成@WebServlet("/guest/text.view"),Servlet B设置成@WebServlet("/guest/*"),请求的地址是"/guest/text.view",这时候A和B都可以处理该请求,但是一个请求只能被一个Servlet处理。面对这种冲突,服务器的处理方式是将请求交给映射范围最具体的,范围最小的Servlet处理。在上面的例子中,请求会交给A处理,因为B的范围更大。

  • 使用web.xml

Servlet 3.0之后才可以使用注解来映射Servlet,在此之前都是使用web.xml文件来写映射。新建项目后,系统会为我们自动见一个web.xml文件,文件位置如下图

我们可以将里面的内容写成下面的样子,能达到使用注解的效果

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>Hello</servlet-name>
        <servlet-class>servletlearning.demo.Hello</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Hello</servlet-name>
        <url-pattern>/Hello</url-pattern>
    </servlet-mapping>
</web-app>

servlet的类和地址通过servlet-name确定映射关系。

web.xml的优先级是高于注解的,当web.xml和注解的映射有冲突时,以web.xml的为准。

猜你喜欢

转载自blog.csdn.net/sinat_38393872/article/details/103669621