前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Servlet 详解

Servlet 详解

作者头像
wsuo
发布2020-07-31 15:19:56
6040
发布2020-07-31 15:19:56
举报
文章被收录于专栏:技术进阶之路技术进阶之路

文章目录
  • 一、Servlet 的定义
  • 二、Servlet 的生命周期
    • 1、Servlet 出生
    • 2、Servlet 服务
    • 3、Servlet 销毁
  • 三、Servlet 中的接口
    • 1、ServletRequest 和 ServletResponse
    • 2、ServletRequest
    • 3、ServletResponse
    • 4、ServletConfig
  • 四、Servlet 的实现
    • 1、实现Servlet有三种方式:
    • 2、GenericServlet
    • 3、HttpServlet
    • 4、启动创建 Servlet
    • 5、web.xml文件的继承
    • 6、ServletContext
      • 6.1、ServletContext概述
      • 6.2、获取ServletContext
      • 6.3、域对象的功能
      • 6.4、操作数据的方法
      • 6.5、初始化参数
  • 五、请求和响应
    • 1、Request
      • 1.1、概述
      • 1.2、常用方法
      • 1.3、实际应用
    • 2、Response
      • 2.1、概述
      • 2.2、响应正文
      • 2.3、设置响应头信息
      • 2.4、设置状态码及其他方法
      • 2.5、重定向
    • 3、GET 和 POST 的区别
    • 4、请求转发
    • 5、转发和重定向的区别

一、Servlet 的定义

Servlet 是 JavaWeb 的三大组件之一,它属于动态资源。Servlet 的作用是处理请求,服务器会把接收到的请求交给 Servlet 来处理,在 Servlet 中需要:

  • 接收请求数据;
  • 处理请求;
  • 完成响应;

二、Servlet 的生命周期

我们先创建一个实例来实现 Servlet 接口:

public class Servlet01 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

可以看到该实例默认实现了5个方法,我们主要讲解其中的3个。

方法:
  • void init(ServletConfig):出生之后(1次);
  • void service(ServletRequest request, ServletResponse response):每次处理请求时都会被调用;
  • void destroy():临死之前(1次);

特征:
  • 单例的,一个类只有一个对象;
  • 多线程的,不是线程安全的。

1、Servlet 出生

  • 默认情况下,服务器会在第一次访问 Servlet 时创建它,如果是在服务器启动时就创建 Servlet ,那么需要在 web.xml 中配置。
  • 对于一个 Servlet ,服务器只会创建一次,当访问 Servlet 时, 服务器会首先检查该 Servlet 是否创建过,如果创建过直接拿过来用,如果没有才会通过反射来创建该 Servlet 实例。
  • Servlet 出生后会立即调用 init() 方法,而且这个方法之后被调用一次,所以一些对 Servlet 的初始化操作可以放在该方法中。

2、Servlet 服务

当服务器每次接收到请求时,都会调用 service 方法,该方法是会被多次调用的。

3、Servlet 销毁

  • Servlet 是不会轻易消失的,通常在服务器关闭的时候才会销毁,在服务器关闭时,他会调用 destroy 方法,然后销毁 Servlet,我们可以将一些资源的释放放到该方法中。

三、Servlet 中的接口

在 Servlet 中有三个接口类型的参数:

  • ServletConfig:init()方法的参数,它表示Servlet配置对象,它对应Servlet的配置
  • ServletRequest:service() 方法的参数,它表示请求对象,它封装了所有与请求相关的数据,里面全是请求头之类get方法,它是由服务器创建的;
  • ServletResponse:service()方法的参数,它表示响应对象,里面很多响应的set方法,在 service() 方法中完成对客户端的响应需要使用这个对象;

1、ServletRequest 和 ServletResponse

ServletRequest 和 ServletResponse 是 Servlet 的service() 方法的两个参数:


一个是请求对象,可以从 ServletRequest 对象中获取请求数据; 一个是响应对象,可以使用 ServletResponse 对象完成响应。

  • ServletRequest 和 ServletResponse 的实例由服务器创建,然后传递给 service方法,如果要使用 HTTP 相关内容,那么需要将 ServletRequest 强转成 HttpServletRequest ,这很烦,因为我们经常要这么做,后面有一个类可以解决这个问题。

2、ServletRequest

  • String getHeader(String var1):获取指定请求头的值;
  • String getMethod():获取请求方法,例如GET或POST;
  • String getParameter(String paramName):获取指定请求参数的值;
  • void setCharacterEncoding(String encoding):设置请求体的编码!

request.setCharacterEncoding(“utf-8”)之后,再通过getParameter()方法获取参数值时,那么参数值都已经通过了转码,即转换成了UTF-8编码。所以,这个方法必须在调用 getParameter() 方法之前调用!

3、ServletResponse

  • PrintWriter getWriter():获取字符响应流,使用该流可以向客户端输出响应信息。
  • ServletOutputStream getOutputStream():获取字节响应流,当需要向客户端响应字节数据时,需要使用这个流;
  • void setCharacterEncoding(String encoding):用来设置字符响应流的编码;
  • void setHeader(String name, String value):向客户端添加响应头信息。 例如setHeader(“Refresh”, “5;url=http://www.baidu.cn”),表示 5 秒后自动刷新到http://www.baidu.cn;
  • void setContentType(String contentType):该方法是 setHeader(“content-type”, “xxx”) 的简便方法,即用来添加名为content-type响应头的方法。content-type响应头用来设置响应数据的MIME类型。 -例如要向客户端响应 jpg 的图片,那么可以 setContentType(“image/jepg”) ,如果响应数据为文本类型,那么还要同时设置编码 -例如setContentType(“text/html;chartset=utf-8”)表示响应数据类型为文本类型中的html类型,并且该方法会调用 setCharacterEncoding(“utf-8”) 方法;

4、ServletConfig

Servlet 的配置信息,即web.xml文件中的<servlet>元素。

  • 一个 ServletConfig 对象对应着一个 servlet 元素的配置信息(servlet-name,servlet-class)
  • getServletName():获取的是<servlet-name>
  • getServletContext():获取的是 Servlet 上下文对象

四、Servlet 的实现

1、实现Servlet有三种方式:

  • 实现 javax.servlet.Servlet 接口;
  • 继承 javax.servlet.GenericServlet 类;
  • 继承 javax.servlet.http.HttpServlet 类;

通常我们会去继承 HttpServlet 类来完成我们的 Servlet

2、GenericServlet

GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。

GenericServlet 还实现了ServletConfig 接口,所以可以直接调用getInitParameter()、getServletContext() 等 ServletConfig 的方法。

源代码:

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;

    public GenericServlet() {
    }

    public void destroy() {
    }

    public String getInitParameter(String name) {
        return this.getServletConfig().getInitParameter(name);
    }

    public Enumeration<String> getInitParameterNames() {
        return this.getServletConfig().getInitParameterNames();
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public ServletContext getServletContext() {
        return this.getServletConfig().getServletContext();
    }

    public String getServletInfo() {
        return "";
    }

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public void log(String msg) {
        this.getServletContext().log(this.getServletName() + ": " + msg);
    }

    public void log(String message, Throwable t) {
        this.getServletContext().log(this.getServletName() + ": " + message, t);
    }

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    public String getServletName() {
        return this.config.getServletName();
    }
}

3、HttpServlet

HttpServlet 类是 GenericServlet 的子类,它提供了对 HTTP 请求的特殊支持,所以通常我们都会通过继承 HttpServlet 来完成自定义的 Servlet 。

  • HttpServlet 覆盖了 service() 方法 HttpServlet类中提供了 service(HttpServletRequest,HttpServletResponse) 方法,这个方法是 HttpServlet 自己的方法,不是从 Servlet 继承来的。在 HttpServlet的service(ServletRequest,ServletResponse) 方法中会把ServletRequest和ServletResponse 强转成 HttpServletRequest 和 HttpServletResponse ,然后调用,所以这样一来就不用我们自己强转了。
  • doGet() 和 doPost() 在 HttpServlet 的 service(HttpServletRequest,HttpServletResponse) 方法会去判断当前请求是 GET 还是 POST ,如果是 GET 请求,那么会去调用本类的doGet() 方法,如果是 POST 请求会去调用 doPost() 方法,这说明我们在子类中去覆盖 doGet() 或 doPost() 方法即可。

4、启动创建 Servlet

1、< load-on-startup >

<servlet>
	<servlet-name>hello</servlet-name>
	<servlet-class>cn.lsu.servlet.HelloServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet>元素中配置<load-on-startup>元素可以让服务器在启动时就创建该Servlet,其中<load-on-startup>元素的值必须是大于等于的整数,它的使用是服务器启动时创建 Servlet 的顺序。

2、< url-pattern >

<servlet-mapping>
	<servlet-name>hello</servlet-name>
	<url-pattern>/hello</url-pattern>
</servlet-mapping>

<url-pattern><servlet-mapping>的子元素,用来指定Servlet的访问路径,即URL。

可以在<servlet-mapping>中给出多个<url-pattern>,这样它所绑定的所有的 URL 都是指向这个 Servlet 的。

还可以使用通配符:

<url-pattern>.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配

<url-pattern>/*<url-pattern>:匹配所有URL;

5、web.xml文件的继承

在 Tomcat 的conf/web.xml路径下有一个所有的 web.xml 共同的父文件。

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>
    
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    
    <!-- 这里省略了大概4000多行的MIME类型的定义,这里只给出两种MIME类型的定义 -->
    <mime-mapping>
        <extension>bmp</extension>
        <mime-type>image/bmp</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>htm</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

6、ServletContext

6.1、ServletContext概述

服务器会为每个应用创建一个 ServletContext 对象:

  • ServletContext对象的创建是在服务器启动时完成的;
  • ServletContext对象的销毁是在服务器关闭时完成的。

ServletContext 对象的作用 是在整个Web应用动态资源之间共享数据

6.2、获取ServletContext
  • ServletConfig 下的 getServletContext();
  • GenericServlet 下的 getServletContext();(包括子类 HttpServlet )
  • HttpSession 下的 getServletContext();
  • ServletContextEvent 下的 getServletContext();

在 Servlet 中获取 ServletContext 对象:

  • 在void init(ServletConfig config)中: ServletContext context = config.getServletContext(); ServletConfig类的getServletContext()方法可以用来获取ServletContext对象;
  • GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;
public class MyServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) {
    	ServletContext context = this.getServletContext();
	}
}
6.3、域对象的功能

ServletContext是JavaWeb四大域对象之一:

  • PageContext;
  • ServletRequest;
  • HttpSession;
  • ServletContext;

所有域对象都有存取数据的功能,因为域对象内部有一个`Map`,用来存储数据
6.4、操作数据的方法
  • void setAttribute(String name, Object value):用来存储一个对象;
  • Object getAttribute(String name):用来获取ServletContext中的数据;
  • void removeAttribute(String name):用来移除ServletContext中的域属性;
  • Enumeration getAttributeNames():获取所有域属性的名称;
6.5、初始化参数

1、应用初始化参数

该参数是每个 Servlet 独有的,是局部参数。

2、公共初始化参数

该参数为所有 Servlet 都可用。

可以在 web.xml 中配置:

<web-app ...>
  ...
  <context-param>(为ServletContext设置的公共初始化参数)
	<param-name>paramName1</param-name>
	<param-value>paramValue1</param-value>  	
  </context-param>
  <context-param>
	<param-name>paramName2</param-name>
	<param-value>paramValue2</param-value>  	
  </context-param>
</web-app>

使用域对象获取:

ServletContext context = this.getServletContext();
String value1 = context.getInitParameter("paramName1");
String value2 = context.getInitParameter("paramName2");

五、请求和响应

服务器每次收到请求时,都会为这个请求开辟一个新的线程。

1、Request

1.1、概述

request 是 Servlet.service() 方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用 Servlet.service() 方法时传递给 service() 方法,这说明在 service() 方法中可以通过 request 对象来获取请求数据。


request的功能可以分为以下几种:

  • 封装了请求头数据;
  • 封装了请求正文数据,如果是GET请求,那么就没有正文;
  • request是一个域对象,可以把它当成Map来添加获取数据;
  • request提供了请求转发和请求包含功能。

一个请求会创建一个request对象,如果在一个请求中经历了多个 Servlet ,那么多个 Servlet 就可以使用 request 来共享数据

request 的域方法同 ServletContext 的域方法。

  • void setAttribute(String name, Object value):用来存储一个对象;
  • Object getAttribute(String name):用来获取ServletContext中的数据;
  • void removeAttribute(String name):用来移除ServletContext中的域属性;
  • Enumeration getAttributeNames():获取所有域属性的名称;

1.2、常用方法

1、获取请求头数据:

  • String getHeader(String name):获取指定名称的请求头;

2、获取请求相关的其它方法:

  • String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded,表示请求体内容使用了URL编码;
  • String getMethod():返回请求方法,例如:GET/POST
  • String getCharacterEncoding():获取请求编码;默认ISO-8859-1编码;
  • void setCharacterEncoding(String code):设置请求编码,只对请求体有效;
  • String getContextPath():返回上下文路径(/项目名),例如:/hello
  • String getQueryString():返回请求URL中的参数,例如:name=zhangSan
  • String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
  • StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
  • String getServletPath():返回Servlet路径,例如:/oneServlet
  • String getRemoteAddr():返回当前客户端的IP地址;
  • String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
  • String getScheme():返回请求协议,例如:http;
  • String getServerName():返回主机名,例如:localhost
  • int getServerPort():返回服务器端口号,例如:8080
1.3、实际应用

防盗链的应用:

可以使用request.getAttribute(“Referer”)如果不是当前页面,那么属于盗链,则跳转到当前页面如果是从地址栏直接输入URL,那么Referee返回的是null。

2、Response

2.1、概述

response 是 Servlet # service 方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个 response 对象,并传入给 Servlet.service() 方法。response 对象是用来对客户端进行响应的,这说明在 service() 方法中使用 response 对象可以完成对客户端的响应工作。

response对象的功能分为以下四种:

  • 设置响应头信息;
  • 发送状态码;
  • 设置响应正文;
  • 重定向。
2.2、响应正文

response是响应对象,向客户端输出响应正文(响应体) 可以使用response的响应流:

  • PrintWriter out = response.getWriter():获取字符流;
  • ServletOutputStream out = response.getOutputStream():获取字节流;

如果响应正文内容为字符(html),那么使用response.getWriter(),如果响应内容是字节(图片等),例如下载时,那么可以使用response.getOutputStream()

在一个请求中,不能同时使用这两个流!
  • 在使用 response.getWriter() 时需要注意默认字符编码为 ISO-8859-1,如果希望设置字符流的字符编码为utf-8,可以使用response.setCharaceterEncoding(“utf-8”) 来设置。这样可以保证输出给客户端的字符都是使用UTF-8编码的!
  • 但客户端浏览器并不知道响应数据是什么编码的!如果希望通知客户端使用UTF-8来解读响应数据,那么还是使用response.setContentType(“text/html;charset=utf-8”)方法比较好,因为这个方法不只会调用response.setCharaceterEncoding(“utf-8”),还会设置content-type响应头,客户端浏览器会使用 content-type 头来解读响应数据。

缓冲区:

  • response.getWriter() 是 PrintWriter 类型,所以它有缓冲区,缓冲区的默认大小为8KB。也就是说,在响应数据没有输出8KB之前,数据都是存放在缓冲区中,而不会立刻发送到客户端。当 Servlet 执行结束后,服务器才会去刷新流,使缓冲区中的数据发送到客户端。
  • 可以使用 response.flushBuffer() 方法手动刷新缓冲区。

字节响应流:

将一张图片转为字节流写入到response中

//读取图片,使用commons-io包的方法。
byte[] image = IOUtils.toByteArray(new FileInputStream(this.getServletContext().getRealPath("/images/cat.jpeg")));

response.getOutputStream().write(image);
2.3、设置响应头信息

可以使用 response 对象的setHeader()方法来设置响应头!使用该方法设置的响应头最终会发送给客户端浏览器!

response.setHeader("Refresh","5; URL=http://www.baidu.cn"):5秒后自动跳转到百度主页。
2.4、设置状态码及其他方法
  • response.setContentType(“text/html;charset=utf-8”)
  • response.setCharacterEncoding(“utf-8”)
  • response.setStatus(200)
  • response.sendError(404, “您要查找的资源不存在”)
2.5、重定向

当你访问http://www.sun.com时,你会发现浏览器地址栏中的URL会变成http://www.oracle.com/us/sun/index.html,这就是重定向了。

重定向是服务器通知浏览器去访问另一个地址,即再发出另一个请求。

1、设置响应码

  • 响应码为302表示重定向。所以完成重定向的第一步就是设置响应码为302。

2、设置Location头

  • 因为重定向是通知浏览器发出第二个请求,所以浏览器需要知道第二个请求的URL,所以完成重定向的第二步是设置Location头,指定第二个请求的URL地址。
public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setStatus(302);
		response.setHeader("Location", "http://www.baidu.cn");
	}
}

当访问 AServlet 后,会通知浏览器重定向到百度主页。客户端浏览器解析到响应码为302后,就知道服务器让它重定向,所以它会马上获取响应头Location,然发出第二个请求。

不过有更方便的方法:

response.sendRedirect()方法会设置响应头为302,以设置Location响应头。

如果要重定向的URL是在同一个服务器内,那么可以使用相对路径,例如:

public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
		response.sendRedirect("/hello/BServlet");
                              //注意是-/项目名/路径(请求URI)
	}
}

3、GET 和 POST 的区别

GET请求和POST请求的区别:

GET请求:

  • 请求参数会在浏览器的地址栏中显示,所以不安全;
  • 请求参数长度限制长度在1K之内;
  • GET请求没有请求体,无法通过 request.setCharacterEncoding() 来设置参数的编码;

POST请求:

  • 请求参数不会显示浏览器的地址栏,相对安全;
  • 请求参数长度没有限制;
  • 无论是GET|POST请求,都可以使用相同的API来获取请求参数。
  • 请求参数有一个key一个value的,也有一个key多个value的。

4、请求转发

无论是请求转发还是请求包含,都表示由多个 Servlet 共同来处理一个请求。例如 Servlet1 来处理请求,然后 Servlet1 又转发给 Servlet2 来继续处理这个请求。

在AServlet中,把请求转发到BServlet:

参数是Servlet路径(servlet-mapping中的url-pattern)—相当于/项目名

public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
	rd.forward(request, response);
}

5、转发和重定向的区别

转发是由服务端进行的页面跳转:

重定向是由客户端进行的页面跳转:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、Servlet 的定义
  • 二、Servlet 的生命周期
    • 1、Servlet 出生
      • 2、Servlet 服务
        • 3、Servlet 销毁
        • 三、Servlet 中的接口
          • 1、ServletRequest 和 ServletResponse
            • 2、ServletRequest
              • 3、ServletResponse
                • 4、ServletConfig
                • 四、Servlet 的实现
                  • 1、实现Servlet有三种方式:
                    • 2、GenericServlet
                      • 3、HttpServlet
                        • 4、启动创建 Servlet
                          • 5、web.xml文件的继承
                            • 6、ServletContext
                              • 6.1、ServletContext概述
                              • 6.2、获取ServletContext
                              • 6.3、域对象的功能
                              • 6.4、操作数据的方法
                              • 6.5、初始化参数
                          • 五、请求和响应
                            • 1、Request
                              • 1.1、概述
                              • 1.2、常用方法
                              • 1.3、实际应用
                            • 2、Response
                              • 2.1、概述
                              • 2.2、响应正文
                              • 2.3、设置响应头信息
                              • 2.4、设置状态码及其他方法
                              • 2.5、重定向
                            • 3、GET 和 POST 的区别
                              • 4、请求转发
                                • 5、转发和重定向的区别
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档