Servlet简介

servlet是JavaEE的规范(接口)之一, 也是JavaWeb的三大组件之一;三大组件分别是Servlet程序、Filter过滤器、Listener监听器。

Servlet是运行在服务器上的一个Java小程序,它可以接收客户端发送过来的请求,并相应数据给客户端。

实现Servlet程序

  1. 编写一个类去实现servlet接口

    创建一个类然后implements Servlet并实现其方法(实际开发中不使用)

    创建一个类然后extends HttpServlet去继承已经实现好的Servlet子类(实际使用)

  2. 实现service方法处理请求并响应数据

  3. web.xml中去配置servlet程序的访问地址

    要在web.xml中配置两个标签servletservlet-mapping

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!--  servlet标签给Tomcat配置Servlet程序  -->
    <servlet>
    <!-- servlet-name标签:给Servlet程序其一个别名(一般设定为类名) -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- servlet-class是servlet程序的全类名 -->
    <servlet-class>com.example.tomcat_web.HelloServlet</servlet-class>
    </servlet>

    <!-- servlet-mapping标签给servlet程序配置访问地址 -->
    <servlet-mapping>
    <!-- servlet-name标签的作用是表明这个标签是为哪一个servlet程序配置的 -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- url-pattern标签配置访问地址表明在工程路径下的访问地址 -->
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>

Servlet的生命周期

  1. 执行Servlet构造方法
  2. 执行init()初始化
  3. 执行service()方法
  4. 执行destory()销毁方法

1~2步创建服务时调用,3步每次访问都会调用,4步结束服务时调用

获取访问类型

使用service()方法中类型为ServletRequest的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
super.service(req, res);

//强制类型转换 因为HttpServletRequest 是 ServletRequest 的一个子类
//但只有子类实现了getMethod()方法
HttpServletRequest httpServletRequest = (HttpServletRequest) req;

//获取请求的类型(GET/POST)
String method = httpServletRequest.getMethod();

if(method.equals("GET")){
doGet();
}
else if(method.equals("POST")){
doPost();
}
}

通过继承HTTPServlet实现Servlet程序

  1. 编写一个类去继承HttpServlet类
  2. 根据需要重写doGet()doPost()方法和其他
  3. 同样需要配置web.xml

直接使用IDEA创建Servlet程序

在需要创建servlet程序的包上New -> Servlet程序即可实现自动配置

一般取消创建Java EE6+ 注解类选项,完成后只需要在web.xml中配置servlet-mapping即可

Servlet类的继承体系

Servlet类的继承体系

ServletConfig类

从类名上看显然该类与Servlet程序的配置有关

ServletConfig类的三大作用:

  1. 获取Servlet程序的别名即web.xmlservlet-name的值

    1
    2
    3
    4
    5
    6
    7
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取Servlet别名
    String servletName = config.getServletName();
    }
  2. 获取初始化参数init-param

    初始化参数是在web.xml中配置的,需要在对应的servlet标签下配置,可以配置多组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!--  servlet标签给Tomcat配置Servlet程序  -->
    <servlet>
    <!-- servlet-name标签:给Servlet程序其一个别名(一般设定为类名) -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- servlet-class是servlet程序的全类名 -->
    <servlet-class>com.example.tomcat_web.HelloServlet</servlet-class>

    <!--init-param是初始化参数-->
    <init-param>
    <!--参数名-->
    <param-name>username</param-name>
    <!--参数值-->
    <param-value>root</param-value>
    </init-param>
    </servlet>

    然后在对应的类中就可获取这个初始化参数

    1
    2
    3
    4
    5
    6
    7
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取初始参数
    String initParameter = config.getInitParameter("username");
    }
  3. 获取ServletContext对象

    1
    2
    3
    4
    5
    6
    7
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取ServletContext对象
    ServletContext servletContext = config.getServletContext();
    }

注意:当我们需要重写继承自HTTPServlet的类的init()方法时,一定要在方法内加入这段代码super.init(config);,表示向父类传递类型为ServletConfig的servlet配置对象,原因是HttpServlet的父类GenericServlet需要使用到了这个参数并且保存了它的值

ServletContext类

  1. ServletContex是一个接口,表示Servlet上下文对象
  2. 一个Web工程只有一个ServletContext对象实例
  3. ServletContext对象是一个域对象
  4. ServletContext是在web工程部署启动的时候创建,在web工程停止的时候销毁的

注:域对象是可以像Map一样存取数据的对象,这里的域是指存取数据的操作范围(整个Web工程)

存数据 取数据 删除数据
Map put() get() remove()
域对象 setAttribute() getAttribute() removeAttribute()

ServletContext类的作用:

  1. 获取web.xml中配置的上下文参数 context-param

    先在web.xml中配置上下文参数,同样可以根据需要配置多组但是这里配置的参数所有在该web工程下的类都能通过ServletContext访问即属于整个web工程

    1
    2
    3
    4
    5
    <!--  这里的context-param标签是上下文参数标签,属于整个web项目  -->
    <context-param>
    <param-name>username</param-name>
    <param-value>context</param-value>
    </context-param>

    然后就可以通过ServletContext类获取到这些参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取初始参数
    String initParameter1 = config.getInitParameter("username");

    //获取ServletContext对象
    ServletContext servletContext = config.getServletContext();

    //获取上下文参数
    String initParameter2 = servletContext.getInitParameter("username");
    }

    这里把通过ServletConfig对象实例获取得到的初始化参数与通过Servletcontext对象实例获取得到的初始化参数同时放在了一起,这里需要注意的是通过ServletConfig获取的初始化参数是在web.xml中专门为当前类配置的初始化参数,而通过ServletContext获取的是属于整个web工程的初始化参数

  2. 获取当前的工程路径(格式为:/工程路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取ServletContext对象
    ServletContext servletContext = config.getServletContext();

    //获取当前工程路径
    String contextPath = servletContext.getContextPath();
    }
  3. 获取工程部署后在服务器磁盘上的绝对路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取ServletContext对象
    ServletContext servletContext = config.getServletContext();

    //获取当前工程的绝对路径
    String realPath = servletContext.getRealPath("/");
    }

    这里的在函数中传入的参数/是被解析为当前工程工程路径,传入getRealPath()方法后获取得到了该web项目部署在服务器上是绝对路径

  4. 像Map一样存储数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    public void init(ServletConfig config) throws ServletException {
    super.init(config);

    //获取ServletContext对象
    ServletContext servletContext = config.getServletContext();

    //像Map一样存储数据
    servletContext.setAttribute("name", "Object");
    servletContext.getAttribute("name");
    }

Servlet处理Http请求

  1. Get请求

    请求行:

    (1) 请求方式 GET

    (2) 请求的资源路径

    (3) 请求的协议及其版本号

    请求头:

    (1) 由key : value 键值对组成,不同键值对代表不同的含义

    屏幕截图 2022-01-13 164551

  2. Post请求

请求行:

(1) 请求方式 POST

(2) 请求的资源路径

(3) 请求的协议及其版本号

请求头:

(1)同样是由key : value键值对组成,不同键值对由不同的含义

(2) 空行

请求体:

发给服务器的内容

Post请求

  1. http响应

    响应行:

    (1) 响应的协议和版本号

    (2) 响应状态码

    (3) 响应状态描述符

    响应头:

    (1) 还是由key : value键值对组成,不同键值对由不同的含义

    (2) 空行

    响应体:

    回传给用户的数据

    Http响应

MIME类型说明

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,用于支持非ASCLL编码的内容传输,其格式为“大类型/小类型”

用于WAP服务器的MIME类型有:

类型 描述 典型示例
text 表明文件是普通文本,理论上是人类可读 text/plain, text/html, text/css, text/javascript
image 表明是某种图像。不包括视频,但是动态图(比如动态gif)也使用image类型 image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon, image/vnd.microsoft.icon
audio 表明是某种音频文件 audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
video 表明是某种视频文件 video/webm, video/ogg
application 表明是某种二进制数据 application/octet-stream, application/pkcs12, application/vnd.mspowerpoint, application/xhtml+xml, application/xml, application/pdf

HttpServletRequest类

作用:将对Tomcat服务器的Http请求封装到HttpServletRequest对象中,然后传递给service方法(doGet和doPost),我们通过这个对象的访问就可以实现获取请求中的信息的功能。

  1. 获取请求的统一资源标识符(URI)和统一资源定位符(URL)getRequestURI()getRequestURL()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html");

    // Hello
    PrintWriter out = response.getWriter();
    out.println("<html><body>");
    out.println("<h1>"+ "URI\t:" + request.getRequestURI() + "</h1>");
    out.println("<h1>"+ "URL\t:" + request.getRequestURL() + "</h1>");
    out.println("</body></html>");
    }
  2. 获取请求发送的IP地址getRemoteHost()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html");

    // Hello
    PrintWriter out = response.getWriter();
    out.println("<html><body>");
    out.println("<h1>"+ "IP_Host\t:" + request.getRemoteHost() + "</h1>");
    out.println("</body></html>");
    }
  3. 获取请求头getHeader(String s)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html");

    // Hello
    PrintWriter out = response.getWriter();
    out.println("<html><body>");
    //获取请求头中的用户代理信息
    out.println("<h1>"+ "User-Agent\t:" + request.getHeader("User-Agent") + "</h1>");
    out.println("</body></html>");
    }
  4. 获取请求类型(前面有提到)getMethod()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html");

    // Hello
    PrintWriter out = response.getWriter();
    out.println("<html><body>");
    out.println("<h3>"+ "Method\t:" + request.getMethod() + "</h3>");
    out.println("</body></html>");
    }
  5. 获取请求参数getParameter(String s)getParameterValues(String s)

    先写一个简单的HTML表单文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <body>
    <!--action:填写你的表单需要提交到的地址 也就是你服务器页面的访问地址-->
    <form action="http://localhost:8080/Tomcat_web_war/hello" method="get">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    兴趣爱好:<input type="checkbox" name="hobby" value="cpp">C++
    <input type="checkbox" name="hobby" value="java">Java
    <input type="checkbox" name="hobby" value="js">JavaScript<br/>
    <input type="submit">
    </form>
    </body>

    然后在接受到请求参数的文件中就可以获取到请求参数啦

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html");

    // Hello
    PrintWriter out = response.getWriter();
    out.println("<html><body>");
    //获取请求参数
    out.println("<h3>"+ "username\t:" + request.getParameter("username") + "</h3>");
    out.println("<h3>"+ "password\t:" + request.getParameter("password") + "</h3>");
    out.println("<h3>"+ "hobby\t:" + request.getParameter("hobby") + "</h3>");
    out.println("<h3>"+ "hobbys\t:" + Arrays.asList(request.getParameterValues("hobby"))+ "</h3>");
    out.println("</body></html>");
    }
  6. 设置请求参数的编码(解析)格式为UTF-8避免中文乱码

    1
    request.setCharacterEncoding("UTF-8");

    注意这个函数必须在使用这个对象前就调用,否则是不会生效的

请求的转发

请求转发简单说就是一个servlet程序调用另一个servlet程序共同完成一项请求

屏幕截图 2022-01-18 154211

  1. 在本程序中处理请求数据

    1
    out.println("<h2>"+ "Hello1" + "</h2>");
  2. 可以在原有的请求中添加一些请求参数,例如标识这个请求是经过本程序处理过的(从降低耦合的角度上来看这个例子似乎不太合适)

    1
    request.setAttribute("httpResponse", out);
  3. 创建请求的调度对象(另一个程序的入口),然后传参并在另一个程序中对请求进行进一步的处理

    1
    2
    RequestDispatcher requestDispatcher =  request.getRequestDispatcher("/hello2");
    requestDispatcher.forward(request, response);

    同样的这里的getRequestDispatcher中传的参数仍然是工程路径

  4. 可以通过请求转发到WEB_INF目录下的程序进行处理

HttpServletResponse类

作用:返回给客户端的信息可以通过HttpServletResponse实例来进行设置

两种输出流:

类型 方法 作用
字节流 getOutputStream() 常用于下载(传递二进制数据)
字符流 getWriter() 常用于回传字符串信息

两个流只能同时使用一个,否则会抛出异常

例如我们在前面就用到了的out对象就是一个字符流对象

1
2
3
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();

这里先设置了响应的字符编码(需要浏览器也支持)和响应头的相应的内容类型(MIME)

也可以这样直接修改相应头修改相应内容的编码形式

1
2
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();

同样需要注意的是要在使用这个response对象之前调用

请求重定向

请求重定向

方法1:

  1. 设置相应状态码302表示重定向

    1
    response.setStatus(302);
  2. 设置响应头说明重定向的目的地址

    1
    response.setHeader("Location", "http://localhost:8080");

方法2:(推荐)

1
response.sendRedirect("http://localhost:8080");