最近面试,问了Servlet是什么,当时也没想那么多,感觉知道怎么用,用在那一层,用什么语言实现,说下与JSP的区别就可以了,但是从面试的结果来看,面试官好像不是很认可,我们不能改变别人,只能让自己无懈可击,所以在网上书上找了些资料总结一下,感觉自己写一下才是自己的东西。
一.什么是Servlet
简单的说Servlet使用Java语言实现的程序,运行于支持Java语言的Web服务器或者应用服务器中。Servlet先于JSP出现,提供和客户端动态交互的功能。Servlet可以处理来自客户端的HTTP请求,并生成响应返回给客户端。
Servlet对于Web服务器而言,就好像是Java Applet对于Web浏览器,Servlet需要加在到Web服务器并在Web服务器内执行。
使用Servlet的基本流程如下:
客户端通过HTTP提出请求。
Web服务器接受改请求并将其发给servlet。如果这个servlet尚未被加载,Web服务器将把它加载到Java虚拟机并且执行它。
Servlet将接收该HTTP请求执行某种处理。
Servlet将向Web服务器返回应答。
Web服务器将从servlet收到的应答发送给客户端。
Java Servlet API 是Servlet容器(tomcat)和Servlet之间的接口,它定义了一个Servlet的各种方法,还定义了Servlet容器传给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。所以我们在编写Servlet时,需要实现Servlet接口,按照其规定进行操作。
二.Servlet的优点:
1.可以移植性:
由于Servlet是用Java语言编写的,因此它可以在不同的操作系统和服务器上移植。
2.安全:
Servlet也具有类型检查特征,并利用Java的垃圾收集和没有指针的设计,使得Servlet避免了内存管理等问题。
3.高效:
Servlet加载执行后会常驻服务器内存中,当再次受到客户端的请求时,服务器会产生新的线程而不是进程为客户端服务,这样就提高了响应速度。


三.编写Servlet
在前面,我们已经知道了Servlet是什么,为什么需要Servlet?(为了实现动态网页,而不是显示静态网页),tomcat和Servlet的关系?等问题。现在手动编写一个Servlet。
  1.创建一个MyServlet继承HttpServlet,重写doGet和doPost方法,也就是看请求的方法是get还是post,然后不同的处理方式来处理请求:
            servlet2 - 图1
2.在Web.xml中配置MyServlet,为什么需要配置?让浏览器发出的请求知道到达那个servlet,也就是让tomcat将封装好的request找到对应的servlet让其使用。
配置四个东西:

               servlet2 - 图2 配置之后,浏览器是如何通过我们配置的信息来找到对应的servlet的。
                 servlet2 - 图3  

按照步骤,首先浏览器通过http://localhost:8080/test01/MyServlet来找到web.xml中的url-parttern,这就是第一步,匹配到了url-parttern后,就会找到第二步servlet的名字MyServlet,知道了名字,就可以通过Servlet-name找到第三步,到了第三步,也就能够知道Servlet的位置了。然后到其中找到对应的处理方式进行处理。
3.实验,验证上面配置成功。
                
 servlet2 - 图4   
            servlet2 - 图5

补充:
利用Eclipse创建MyServlet
1.右击项目,在new选项中有直接新建servlet的选项。
2.配置MyServlet类中的信息
                
 servlet2 - 图6

3.配置web.xml中的Servlet信息

servlet2 - 图7

4.查看MyServlet01类中的代码和Web.xml,其中的配置跟手动的配置是一样的,只是用图形化界面,让我们更方便的创建servlet而产生的。
四.Servlet的生命周期:
Servlet的生命周期可以概括为以下几个阶段:
1)当客户端第一次请求Servlet时,Servlet被加载到内存中,容器会创建Servlet实例,并调用其init()方法进行初始化工作。
2)容器创建请求对象和响应对象,然后调用Servlet的service()方法为客户端提供服务。
3)当Servlet不再被需要时,容器调用Servlet的destory()方法将Servlet实例销毁。
当客户端请求的Servlet已经存在于服务器内存时,容器会创建信的线程调用service()方法响应客户端请求。在Servlet的整个生命周期中,init()方法和destory()方法只会被调用一次。

五.四个重点对象。ServletConfig;ServletContext;request;response
讲解四大类:Servlet对象,ServletContext对象,request对象,response对象
ServletConfig对象
获取途径:getServletConfig();
功能:上面大概提及了下,能用到四个东西:
         
    servlet2 - 图8
getServletName();//获取servlet的名称,也就是我们在web.xml中配置的servlet-name
getServletContext();//获取ServletContext对象,该对象的作用看下面讲解;
getInitParameter(String);//获取在servlet中初始化参数的值。这里注意与全局初始化参数的区分。这个获取的知识在该servlet下的初始化参数。
                
  servlet2 - 图9
getInitParameterNames();//获取在Servlet中所有初始化参数的名字,也就是key值,可以通过key值,来找到各个初始化参数的value值。注意发挥的是枚举类型。
           
  servlet2 - 图10

  1. ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855066-acfa76c8-d3d2-49bf-8af2-979da2ba76a6.png#align=left&display=inline&height=251&margin=%5Bobject%20Object%5D&originHeight=474&originWidth=1512&size=0&status=done&style=none&width=801)<br />                ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855144-0198e91c-b54f-43d2-b13f-b9ae9cdc3e5f.png#align=left&display=inline&height=167&margin=%5Bobject%20Object%5D&originHeight=237&originWidth=690&size=0&status=done&style=none&width=486)<br /> <br /> 注意:在上面我们所分析的源码过程中,我们就知道,其实可以不用先获得ServletConfig,然后在获取各个参数,可以直接使用其它方法,比如上面我们用的ServletConfig().getServletName();可以直接写成getServletName();而不用在获取ServletConfig();了,原因就是在GenericServlet中,已经帮我们获取了这些数据,我哦们只需要直接拿就行了。<br /> <br /> ServletContext对象<br /> 获取途径:<br /> getServletContext();getServletConfig().getServletContext();//这两种获取方式的区别就跟上面的解释一样,第一种是直接拿,在GenericServlet中已经帮我们用getServletConfig.getServletContext();拿到了ServletContext。我们只需要直接获取就行了,第二种就相当于我们自己在获取一遍,两种读是一样的。<br /> 功能:tomcat为每个web项目都创建一个ServletContext实例,tomcat在启动时创建,服务器关闭时销毁,在一个web项目中共享数据,管理web项目资源,为整个web匹配公共信息等,通俗点讲,就是一个web项目,就存在一个ServletContext实例,每个Servlet读可以访问到它。<br /> 1.web项目中共享数据,getAttribute(String name),setAttribute(String name,Object obj),removeAttribute(String name)<br /> setAttribute(String name,Object obj)在web项目范围内存放内容,以便让在web项目中所有的servlet读能访问到。<br /> getAttribute(String name)通过制定名称获得内容<br /> removeAttribute(String name)通过制定名称移除内容<br /> <br />                 <br /> <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855214-08b6f22c-cb21-48a5-8c83-32fb6c43854e.png#align=left&display=inline&height=45&margin=%5Bobject%20Object%5D&originHeight=115&originWidth=1374&size=0&status=done&style=none&width=538)<br />          ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855331-0143135a-4c62-43f8-b1ae-932c12b6bf6c.png#align=left&display=inline&height=81&margin=%5Bobject%20Object%5D&originHeight=203&originWidth=1346&size=0&status=done&style=none&width=538)<br />                 <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855169-0226a90f-18e8-4383-bad2-ba0bdfc6569a.png#align=left&display=inline&height=77&margin=%5Bobject%20Object%5D&originHeight=125&originWidth=848&size=0&status=done&style=none&width=523)<br /> 2.整个web项目初始化参数//这个就是全局初始化参数,每个Servlet中都能获取到该初始化值。<br /> getInitParameter(String name) //通过指定名称获取初始化值<br /> getInitParameterNames() //获得枚举类型<br /> web.xml配置 整个web项目的初始化<br />                 <br />   ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855168-0001df69-3cbe-4d7d-a5ea-3460abb74abc.png#align=left&display=inline&height=79&margin=%5Bobject%20Object%5D&originHeight=151&originWidth=943&size=0&status=done&style=none&width=494)<br />         ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855105-569cb589-238b-4c05-a74d-e4f27b3460c2.png#align=left&display=inline&height=46&margin=%5Bobject%20Object%5D&originHeight=110&originWidth=1254&size=0&status=done&style=none&width=523)<br />        ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855181-a75df22e-a71d-4b04-a5e8-a20efa730e8d.png#align=left&display=inline&height=71&margin=%5Bobject%20Object%5D&originHeight=121&originWidth=762&size=0&status=done&style=none&width=448)<br /> 3.获取web项目资源<br /> 1)获取web项目下指定资源的路径:<br /> getServletContext().getRealPath("/WEB-INF/web.xml");<br />                 <br /> ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855153-5bcbaf1f-f707-4ea6-9f10-3d0e5214f143.png#align=left&display=inline&height=30&margin=%5Bobject%20Object%5D&originHeight=64&originWidth=1182&size=0&status=done&style=none&width=555)<br />        ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855167-a2a9ae81-a8b9-414d-8d62-2cd3dbc30d80.png#align=left&display=inline&height=19&margin=%5Bobject%20Object%5D&originHeight=44&originWidth=1326&size=0&status=done&style=none&width=583)<br /> 2)获取web项目下指定资源的内容,返回的是字节输入流。InputStream.getResourceAsStream(java.lang.String path)<br /> 前提知识:需要了解流。<br /> <br /> Request对象<br /> request对象就是将请求文本封装而成的对象,所以通过request能获得请求文本中的宿友内容,请求头,请求体,请求行。<br />                 <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855121-38991e9d-51b4-4cfe-b115-aa2c6fc85c3d.png#align=left&display=inline&height=259&margin=%5Bobject%20Object%5D&originHeight=374&originWidth=1025&size=0&status=done&style=none&width=710)<br /> <br /> 1.请求行内容的获取:<br />                 <br />   ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855175-0548d2a0-145c-4571-bd63-31a737511cd3.png#align=left&display=inline&height=107&margin=%5Bobject%20Object%5D&originHeight=158&originWidth=840&size=0&status=done&style=none&width=569) <br />             ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855143-174b6a5d-c392-4072-9b0d-1c6616cb7ad8.png#align=left&display=inline&height=628&margin=%5Bobject%20Object%5D&originHeight=758&originWidth=812&size=0&status=done&style=none&width=673)<br />                 <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855166-ae7aa047-4935-4805-9aee-a55859389f8d.png#align=left&display=inline&height=74&margin=%5Bobject%20Object%5D&originHeight=73&originWidth=450&size=0&status=done&style=none&width=454)<br /> 2.请求头的获取:<br /> 随便百度一个东西,然后查看的请求头,包括下面这些内容,稍作了解。<br />                 <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855147-84e9bc01-2a8d-4ad5-b3e1-fbc088f92359.png#align=left&display=inline&height=167&margin=%5Bobject%20Object%5D&originHeight=314&originWidth=1316&size=0&status=done&style=none&width=698)<br /> String getHeader(java.lang.String name)获得指定头内容String<br /> System.out.println(req.getHeader("Accept-Language"));<br /> 3.请求体的获取--请求参数的获取<br /> 分为两种,一种get请求,一种post请求<br /> get请求参数:http://localhost:8080/test01/MyServlet?username = jack & password = 1234<br /> post请求参数:<form method = "post"><input type="text" name="username"><br /> String request.getParameter(String)获得指定名称,一个请求参数值。<br /> String[] request.getParameterValues(String)获得指定名称,一个请求参数值。<br /> 4.请求转发<br /> request.getRequestDispatcher(String path).forward(request,response);<br /> //path:转发后跳转的页面,这里不管用不用“/”开头,都是以web项目根开始,因为这是请求转发,请求 //转发只局限与在同一个web项目下使用,所以这里一直都是从web项目根下开始的。<br /> web项目根就是从该web项目名开始,所以我们请求转发时,只需接着项目名后面需要访问的路径写就行了。<br /> 特点:浏览器中的URL不会改变,也就是浏览器不知道服务器做了什么,是服务器帮我们跳转页面的,并且 在转发后的页面,能够继续使用原先的request,因为是原先的request,所以request域中的属性都可 以继续获取到。<br /> <br /> response对象<br />                 <br />    ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855223-b91228d7-98cb-494c-a0dd-11579e94b624.png#align=left&display=inline&height=493&margin=%5Bobject%20Object%5D&originHeight=669&originWidth=971&size=0&status=done&style=none&width=715)<br /> <br /> 常用的一个方法:response.setHeader(java.lang.String name,java.lang.String value)<br /> 设置指定的头,一般常用。<br /> 例如:设置每隔3秒就自动刷新一次,<br /> response.setHeader("Refresh",3);<br />                 <br />  ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855241-e6f77eee-1dc3-46d8-9aec-37d2b8f932e6.png#align=left&display=inline&height=64&margin=%5Bobject%20Object%5D&originHeight=108&originWidth=1152&size=0&status=done&style=none&width=683)<br />         ![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855245-abcc49d5-cf31-4cd5-86a4-5d0d240bd9f3.png#align=left&display=inline&height=106&margin=%5Bobject%20Object%5D&originHeight=207&originWidth=412&size=0&status=done&style=none&width=211)![](https://cdn.nlark.com/yuque/0/2020/png/2332604/1599050855254-8417e39d-e9e8-4393-8f89-13f049bae9e1.png#align=left&display=inline&height=112&margin=%5Bobject%20Object%5D&originHeight=176&originWidth=322&size=0&status=done&style=none&width=205)<br /> <br /> 这样可以看到现在时间的秒数,会发现每隔三秒就会自动刷新一次页面。<br /> 这个最重要的一个就是重定向,其它的一些操作都被装到response对象中了<br /> 重定向(页面跳转)<br /> 方式一:手动方案<br /> response.setStatus(302); //状态码302就代表重定向<br /> response.setHeader("location","http://www.baidu.com");<br /> 方式二:使用封装好的,通过response.sendRedirect("http://www.baidu.com");<br /> 特点:<br /> 服务器告诉浏览器要跳转的页面,是浏览器主动跳转的页面,浏览器知道,浏览器中的地址栏url也会改变,是浏览 器重新发起一个请求到另外一个页面,所以request是重新发起的,跟请求转发不一样。<br /> 注意:response.sendRendirect(path);<br /> 第一种:response.sendRedirect("/test01/MyServlet01"); //使用了“/”开头,说明是从web站点根开始,所以需 要写test01/MyServlet01 <br /> 第二种:response.sendRedirect("MyServlet01"); //没有使用"/"开头,说明从web项目开始,那么就无需写 test01了。<br /> 重定向没有任何局限,可以重定向web项目内的任何路径,也可以访问别的web项目中的路径,并且这里就用"/"区分开来,如果使用了"/"开头,就说明我要重新开始定位了,不访问刚才的web项目,自己写项目名,如果没有使用"/ "开始,那么就知道是访问刚才那个web项目 下的servlet,就可以省略项目名了。就是这样来区别的。<br />

Servlet处理请求的流程:

  1. 1) 客户端在浏览器的地址栏中输入一个请求的URL,按回车后就向服务器端发起一个http request(由浏览器生成)。<br /> 2) 服务器端的Web Server首先接受到请求,并将请求转交给容器,容器会根据请求的URL去调用客户端要访问的Servlet。<br /> 3) 容器会根据web.xml中对Servlet的描述去查找要访问的Servlet,若找到,将此Servlet<br />装载进虚拟机并实例化(第一次访问),然后调用Servlet实例中的service方法处理请求,并分配一个线程去执行。<br />注: 当第二次去访问同一个Servlet时,若容器判断到该Servlet已经被装载并实例化,<br />那么容器就不会再去创建一个新的Servlet实例,直接调用原来那个Servlet实例中的service方法<br />来处理请求。<br /> 4) 若没有查找到,直接返回一个404的错误代码到客户端,表示访问的资源不存在。<br /> <br /> <br />

Servlet处理响应:

设置HTTP状态码

设置HTTP响应头

HttpServletResponse对象用于操纵响应的HTTP头
目的用于告诉客户端
–发送回来的内容的类型
–有多少内容正被发送
常用的方法:
setContentType(String mimetype);
addCookie(Cookie c);

发送内容的服务器的类型

设置HTTP消息体

HttpServletResponse对象负责将信息返回给客户端

HttpServletResponse对象只产生一个空的HTTP响应

传回自定义的内容需要使用getWriter()或者getOutputStream()方法

–传送普通文本

–传送二进制内容

请求重定向和自动刷新页面

重定向的原理:

  1. ![](https://cdn.nlark.com/yuque/0/2020/jpeg/2332604/1599050855272-9c22118c-f124-4659-afc3-3de9f64c17d4.jpeg#align=left&display=inline&height=193&margin=%5Bobject%20Object%5D&originHeight=193&originWidth=530&size=0&status=done&style=none&width=530)<br /> ![](https://cdn.nlark.com/yuque/0/2020/jpeg/2332604/1599050855252-e8c93f99-9104-4c69-a6f7-4e5f0e9dad18.jpeg#align=left&display=inline&height=303&margin=%5Bobject%20Object%5D&originHeight=303&originWidth=585&size=0&status=done&style=none&width=585) <br /> ![](https://cdn.nlark.com/yuque/0/2020/jpeg/2332604/1599050855395-cf314c26-cf12-4bc1-935c-3a574635aa11.jpeg#align=left&display=inline&height=248&margin=%5Bobject%20Object%5D&originHeight=248&originWidth=532&size=0&status=done&style=none&width=532)<br />使用sendRedirect(String URL)方法实现重定向,<br /> <br />在指定时间内自动刷新当前页或到一个新的页面<br />根据时间来控制响应<br />想在响应中有一个短时间的暂停 <br />response.setHeader("Refresh", "time; URL=url" );<br /> 总结:<br />请求URL时HTTP发出了多个请求<br />状态码告诉浏览器发送的内容及格式状态<br />Servlet API与容器进行通讯<br />HttpServletResponse定义的常量来避免直接使用整数<br />在通过PrintWriter对象发送任何内容之前先调用 HttpServletResponse的setStatus()方法<br />为了让Servlet发挥最大的效能,HttpServletResponse对象用于操纵响应的HTTP头<br />getWrite()或者getOutputStream()方法传送文本或者二进制内容给客户端<br />sendRedirect方法实现重定向<br />HTTP响应头“Refresh”会根据时间来控制响应