【JavaEE】Servlet常用的API

目录

前言

一、HttpServlet类

1、Servlet的生命周期

✨tomcat的两个端口

✨设置告诉浏览器使用那种字符集解析响应

✨Java中Unicode和utf8字符集的使用

二、HttpServletRequest类

1、获取请求的信息

2、 前端给后端传递数据的三种方式

2.1、通过query string传递

2.2、 发送Post请求通过form表单的格式传递数据

2.3、使用post请求的body以json的方式传递数据(最常用的写法)

三、HttpServletResponse类

1、设置响应状态码

 2、通过header实现自动刷新效果

 3、设置重定向


前言

Servlet API是tomcat提供的一组API,虽然提供了很多的API,但是这里我们只需要了解HttpServlet、HttpServletRequest、HttpServletResponse这里三个类中提供的API即可。


一、HttpServlet类

我们之前写的Servlet程序,是继承自HttpServlet,不仅仅我们之前写的代码需要继承自HttpServlet,写Servlet代码的时候,我们创建的类都需要继承httpServlet类,并且重写其中的某些方法,HttpServlet类的实例只是在Tomcat启动是创建一次,而不是每次收到HTTP请求都重新创建实例。

核心方法

方法名称 调用时机
init 在HttpServlet实例化之后被调用一次
destory 在HttpServlet实例不在使用的时候调用一次
service 收到Http请求的时候调用
doGet 收到GET请求的时候调用(由service方法调用)
doPost 收到POST请求的时候调用(由service方法调用)
doPut/doDelete/doOptions/... 收到请求的时候调用(由service方法调用)

1、Servlet的生命周期

其中init,destory,service这三个方法的调用时机,也就构成Servlet的生命周期。

1️⃣init方法:HttpServlet被实例化之后,首次收到匹配请求的时候,会调用到init方法,也就是请求在触发HelloServlet类的doGet的执行之前,会先执行init方法。但是这个方法在一个类的实例化对象中只会被调用一次,之后再通过URL发送请求,都不会再调用这个方法

通过在HelloServlet类中重写父类的init方法,然后我们通过URL多次访问HelloServlet这个类,来观察init方法的执行次数。

【JavaEE】Servlet常用的API_第1张图片

 【JavaEE】Servlet常用的API_第2张图片

2️⃣destroy方法这个方法是该webapp(前端+后端)被卸载(被销毁之前)执行一次,用来做一些收尾工作。这个方法的调用比较尴尬,如果是通过8005管理端口,来停止服务器,此时destroy能够被执行,但是如果是直接杀死进程的方式停止服务器,此时destroy执行不了。但是在现实开发中,停止服务器的方式大多都是直接杀死进程。

3️⃣service方法这个方法每次收到路径匹配的请求,都会执行。我们重写的doGet/doPost方法其实都是在service中被调用的,一半不会重写service,只是重写doXXX就行了。

img

✨tomcat的两个端口

Tomcat启动之后会使用两个端口8080(业务端口)和8005(管理端口)。8080端口上输出的数据就是服务器上收到那些业务上请求,然后给你返回一些相应。而8005是关注的你业务之外的一些东西,比如重新加载配置,重新启动,调整一些设置项等。

✨设置告诉浏览器使用那种字符集解析响应

我们在构造请求的时候,有的时候在doXXX方法中输入的是汉字,但是在浏览器页面中汉字显示的是乱码,这是因为我们使用idea编写程序的时候,使用的UTF8编码,而Windows系统自带的GBK编码方式,所以浏览器在解析相应的时候,就会按照GBK编码的方式解析,这就导致出现了乱码。我们可以在doXXX方法中调用setContentType方法来设置浏览器解析响应使用某种字符集。

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html: charset=utf8");
    }

✨Java中Unicode和utf8字符集的使用

Java中char类型是,Unicode编码的,Java中String类型默认是utf8编码的。如果使用Unicode编码字符串,则会出现粘包问题,不能区分开字符。而使用utf8就解决了这个问题。utf8在编码的时候,就自解释了自己这个字符表示的长度。


二、HttpServletRequest类

当Tomcat通过Socket API读取 HTTP请求(字符串),并且按照HTTP协议的格式把字符串解析成HttpServletRequest对象。

✨核心方法

方法 描述
String getProtocol() 返回请求协议的名称和版本
String getMethod() 返回请求的HTTP方法的名称,例如GET、POST或PUT
String getRequestURI() 从协议名称直到HTTP请求的第一行的查询字符串中,返回请求的URL的一部分
String getContextPath() 返回指示请求上下文的请求 URI 部分。
String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。
Enumeration getParameterNames() 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
String getParameter(String name) 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null.
String[] getParameterValues(String name) 返回一个字符串对象的数组,包含所有给定的请求参数的值,如 果参数不存在则返回 null。
Enumeration getHeaderNames() 返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String name) 以字符串形式返回指定的请求头的值
String getCharacterEncoding() 返回请求主体中使用的字符编码的名称。
String getContentType() 返回请求主体的 MIME 类型,如果不知道类型则返回 null。
int getContentLength() 以字节为单位返回请求主体的长度,并提供输入流,或者如果长 度未知则返回 -1。
InputStream getInputStream() 用于读取请求的 body 内容. 返回一个 InputStream 对象.

上述的方法中有一个getRequestURI(),这个方法名中写到了URI。这里URI和URL表示的含义为,URI表示唯一资源标识符、URL表示唯一资源定位符。这两个概念非常的形似。

1、获取请求的信息

通过下面这个类,将获取到客户端的请求报文中的一些属性作为响应的body返回给客户端,来了解这些api的用法。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        StringBuilder result = new StringBuilder();
        //向字符串对象中拼接HTTP请求的名称和版本。
        result.append(req.getProtocol());
        result.append("
"); //拼接HTTP请求的HTTP方法 result.append(req.getMethod()); result.append("
"); //拼接URL中的一部分 result.append(req.getRequestURI()); result.append("
"); //拼接查询字符串 result.append(req.getQueryString()); result.append("
"); //拼接一级路径 result.append(req.getContextPath()); result.append("
"); result.append("

获取请求的header中的键值对

"); //这里获取getHeaderNames方法的返回值是一个枚举类型的值,所以使用枚举来接收 Enumeration headerNames = req.getHeaderNames(); while(headerNames.hasMoreElements()){ String headerName = headerNames.nextElement(); String headerValue = req.getHeader(headerName); result.append(headerName + ": "+headerValue + "
"); } //设置返回的响应的body的类型,方便浏览器进行解析 resp.setContentType("text/html;charset=utf8"); resp.getWriter().write(result.toString()); } }

 客户端将响应进行解析之后显示在页面上。

【JavaEE】Servlet常用的API_第3张图片

2、 前端给后端传递数据的三种方式

前端给后端传输数据,是非常常见的需求,常见的有以下三种方式:

  1. 通过query string传递,在浏览器的query string中直接编写
  2. 发送Post 请求通过form提交数据
  3. 发送Post请求通过json格式提交数据

2.1、通过query string传递

我们约定,前端通过query string传递username和password。这里我们可以使用getParamenter方法来获取服务器获取的请求中的username的值,如果这个值存在返回username所对应的值,如果不存在返回null.

public class GetParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //前端通过url的query string传递 username和password两个属性
        String username = req.getParameter("username");
        if(username == null){
            System.out.println("username 这个 key 在query string中不存在!");
        }
        String password = req.getParameter("password");
        if(password == null){
            System.out.println("password 这个 key 在query string中不存在!");
        }
        System.out.println("username" + username+", password"+password);
        resp.getWriter().write("ok");
    }
}

2.2、 发送Post请求通过form表单的格式传递数据

通过post请求的body以form表单的格式传递数据,body中的数据就和之前的query string一样,但是Content-type是application/x-www-form-urlencoded.我们这里还是使用getParament来获取键值对。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //前端通过body,以form表单的格式,把username和password传给服务器
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null){
            System.out.println("username 这个 key 在query string中不存在!");
        }
        if(password == null) {
            System.out.println("password 这个 key 在query string中不存在!");
        }
        System.out.println("username : " + username+", password : "+password);
        resp.getWriter().write("ok");

    }
}

这里我们直接使用Postman软件创建post请求,在body中格式选为x-www-form-urlencoded,这个格式就是form表单构造的body的格式。

【JavaEE】Servlet常用的API_第4张图片

 

✨注意:

第一种数据传输方式通过query string传输,URL中每个键的值,不能直接使用中文 ,如果想要在URL中的query string中包含中文或者特殊字符,就需要使用urlencode的方式进行转码,如果直接使用中文或者特殊字符,就存在乱码。

第一种数据传输的方式小编的电脑上没有办法演示,因为小编电脑的浏览器对中文的支持比较好。但是如果使用第一种数据传输的方式,query string中有中文或者特殊字符就需要使用urlencode进行转码,服务器使用urlecode进行解码。

第二种传输数据的方式,将键值对中的值改为中文,服务器解析的时候就出现了乱码。这是因为我们没有将前端的编码格式告诉后端,所以在写后端代码的时候,我们使用setCharacterEncoding方法,给请求设置编码方式,这个时候服务器就知道使用这种编码方式进行解析,显示的结果就不会乱码了。

【JavaEE】Servlet常用的API_第5张图片

【JavaEE】Servlet常用的API_第6张图片

【JavaEE】Servlet常用的API_第7张图片

2.3、使用post请求的body以json的方式传递数据(最常用的写法)

 json也是键值对格式的数据,但是Servlet自身并没有内置json解析功能,所以我们就可以借助第三方库来处理json。我们这里使用Jackson第三方库来解析json,Jackson属于spring官方指定的软件

✨下载Jackson

进入中央仓库,查找Jackson,找到之后,点击

【JavaEE】Servlet常用的API_第8张图片

 随便找一个版本,点击进入之后复制Maven中的代码

【JavaEE】Servlet常用的API_第9张图片

 然后将复制的代码放在pom.xml中的即可,如果没有下载,我们点击刷新,触发下载。下载完成,我们也就将Jackson引入到了我们的代码中了。

【JavaEE】Servlet常用的API_第10张图片

 我们先编写后端的Java代码,使用Jackson处理请求内容

  1. 创建Jackson核心对象ObjectMapper对象
  2. 创建用来接收json数据的实体类
  3. 读取请求中的body信息,该过程通过ObjectMapper对象的readValue方法实现,这个方法的参数有两个,第一个参数用来表示要对谁进行解析,将服务器接收到的请求,通过字节流的形式读取。第二个参数表示要将请求的josn格式数据转换成哪一个Java类对象。
  4. 处理响应请求
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//创建一个类表示要解析出来的对象
class User{
    public String username;
    public String password;
}
@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    //使用jackson,最核心的对象就是ObjectMapper
    //通过这个对象,就可以把json字符串解析成Java对象;也可以把一个Java对象转换成一个json格式字符串
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过post请求的body传递过来一个json格式的字符串
        //第一个参数表示要对谁进行解析,第二个参数表示要将请求的json格式数据转换成哪一个Java对象
       User user = objectMapper.readValue(req.getInputStream(),User.class);

       System.out.println("username="+user.username+", password="+user.password);
       resp.getWriter().write("username="+user.username+", password="+user.password);
    }
}

客户端的请求我们使用postman软件进行编写

【JavaEE】Servlet常用的API_第11张图片

 ✨readValue的工作原理

  1. 解析json字符串,转换成若干个键值对
  2. 根据第二个参数User.class,去找User里的所有public的属性或者有public getter setter的属性,依次遍历。这里User.class表示的是反射,.class表示的类对象。
  3. 遍历属性,根据属性的名字,去上述准备好的键值对里,查询,看看这个属性名字是否存在对应的value,如果存在就把value赋值到该属性中。遍历反射就是根据反射完成的。


三、HttpServletResponse类

httpServletResponse表示一个HTTP响应,Servlet中的doXXX方法的目的就是根据请求计算得到响应,然后把响应的数据设置到HttpServletResponse对象中。

然后Tomcat就会把这个HttpServletResponse对象按照HTTP协议的格式,转成一个字符串,并通过Socket写回到浏览器。

✨核心方法

方法 描述
void setStatus(int sc) 为该响应设置状态码
void setHeader(String name, String value) 设置一个带有给定的名称和值的header,如果name已经存在,则覆盖旧的值。
void addHeader(String name, String value) 添加一个带有给定的名称和值的 header. 如果 name 已经存在, 不覆盖旧的值, 并列添加新的键值对
void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME 字符集)例如, UTF-8。
void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter() 用于往 body 中写入文本格式数据.
OutputStream getOutputStream() 用于往 body 中写入二进制格式数据.
void setContentType(String type) 设置被发送到客户端的响应的内容类型。

1、设置响应状态码

使用HttpServletResponse类的setStatus方法,就可以设置响应的状态码,直接使用HttpServletResponse类的对象调用这个方法即可,给这个方法的参数中设置什么样的状态码,我们通过抓包就可以看见响应中是什么状态码。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(200);
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write("返回 200 响应!");
    }
}

【JavaEE】Servlet常用的API_第12张图片

现在将setStatus方法的参数设置为404,抓取的包中的显示的状态码就为404.

【JavaEE】Servlet常用的API_第13张图片

 2、通过header实现自动刷新效果

自动页面刷新只要在响应报头(header)中设置一个Refresh字段就能实现页面的定时刷新了,给header中设置字段和值,我们可以使用HttpServletResponse类的addHeader方法来设置,这个方法的第一个参数表示header中的字段,第二个参数表示的是这个字段的值。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/refresh")
public class RefreshServlet extends HelloServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //每隔1s自动刷新一次
        resp.setHeader("Refresh","1");
        resp.getWriter().write("time=" + System.currentTimeMillis());

    }
}

【JavaEE】Servlet常用的API_第14张图片

 3、设置重定向

实现一个程序,返回一个重定向HTTP响应,自动跳转到另外一个页面。

  1. 先将状态码设置为302,302表示资源临时重定向。
  2. 然后设置响应header中的Location字段,设置header,所以我们还是要使用setHeader方法,第一个参数填写Location,表示在header中设置字段Location,第二个参数为重定向的目标地址。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //用户访问这个路径的时候,自动重定向到百度主页
        resp.setStatus(302);
        resp.setHeader("Location","https://www.baidu.com");
    }
}

【JavaEE】Servlet常用的API_第15张图片

我们也可以使用sendRedirect方法简化上述的代码,只需要给这个方法给一个临时重定向的位置,也就是域名。

你可能感兴趣的:(JavaEE,java-ee,java)