Servlet API详解

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 本文我们主要介绍Servlet里的关键API,也就是HttpServlet、HttpServletRequest、HttpServletResponse这三个类中一些方法的使用。

1.HttpServlet


我们在写Servlet代码的时候,首先第一步就是先创建类,继承自HttpServlet,并重写其中的某些方法。


1.1 核心方法


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


在实际开发中主要重写doXXX方法,很少会重写init/destory/service.


这些方法的调用时机,就称为“Servlet生命周期”(也就是描述了一个Servlet实例从生到死的过程)


微信图片_20230111165928.png

注意:HttpServlet的实例只是在程序启动时创建一次,而不是每次收到HTTP请求都重新创建实例。


1.2 代码示例:处理GET请求


创建MethodServlet.java,创建doGet方法


@WebServlet("/method")
public class MethodServlet extends HelloServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("GET RESPONSE");
    }
}


我们知道,在浏览器中直接输入URL就可以构造一个GET请求,现在我们来测试服务器的处理:


微信图片_20230111165924.png

1.3 代码示例:处理POST请求


在MethodServlet.java中,新增doPost方法


@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("POST 响应");
    }


完成了服务器端的代码,我们需要构造一个POST请求来进行测试,并不能通过直接输入URL的方式来构造POST请求;构造POST请求的方法有两种,一种是基于form表单,另一种是通过ajax来构造,下边我们主要来看看通过ajax的方式来如何构造post请求。(该流程的详情也可见文章【构造HTTP请求与HTTPS加密1.2】)


首先我们需要先在webapp目录下创建一个HTML文件,用来构造POST请求。

微信图片_20230111165919.png

然后我们需要引入jQuery依赖(搜索jQuery mdn进行复制,也可本地导入)

微信图片_20230111165917.png

最后使用jQuery的ajax函数.


微信图片_20230111165908.png

注意:ajax请求中的URL不能加/,但是Servlet类的注解必须加上/.


我们访问http://localhost:8080/maven_1102/testMethod.html,出现如下图结果:


微信图片_20230111165905.png

也就是出现了乱码的情况,这是因为我们在编译器上,字体的默认编码方式为utf-8,而浏览器字体的默认编码方式为GBK,因为编码方式的不同,导致同一文件在不同地方的展示出现了乱码的情况;我们可以通过响应,显式的告诉浏览器通过utf8的方式进行编码,就可以避免乱码的情况了。

微信图片_20230111165902.png

上述红框中代码的含义为,响应的返回类型为html格式,编码方式为utf8.


重新打包部署并测试:


微信图片_20230111165857.png

2.HttpServletRequest


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


2.1 核心方法


方法 描述

String getProtocol() 返回请求协议的名称和版本

String getMethod() 返回请求的HTTP方法的名称,例如,GET、POST或PUT

String getRequestURI() 从协议名称直到HTTP请求的第一行的查询字符串中,返回该请求的URL的一部分。

String getContextPath() 返回指示请求上下文的请求URI部分

String getQueryString() 返回包含在路径后的请求URL中的查询字符串

Enumeration getParameterNames() 返回一个String 对象的枚举,包含在该请求中包含的参数的名称(即键值对中的Key)

String getParameter(String name) 以字符串形式返回请求参数的值,或者如果参数不存在则返回null(即通过键值对中的Key来拿到value)

String[] getParameterValues(String name) 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回null

Enumeration getHeaderNames() 返回一个枚举,包含在该请求中包含的所有的头名(请求报头也是键值对结构,此处活动Key)

String getHeader(String name) 以字符串形式返回指定的请求头的值(Value)

String getCharacterEncoding()返回请求主体中使用的字符编码的名称

String getContentType() 返回请求主体的MIME类型,如果不知道类型则返回null

int getContentLength() 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回-1.

InputStream getInputStream() 用于读取请求的body内容,返回一个InputStream对象


通过这些方法可以获取到一个请求中的各个方面的信息。


注意:请求对象是服务器收到的内容,不应该修改。因此上面的方法也都只是“读”方法,而不是“写”方法。


2.2 代码示例:打印请求信息


创建ShowRequestServlet类,调用一下在2.1中涉及到的几个关键API,并把得到的结果组织到一个html中,并作为响应的body.


@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //把API执行的结果,放到stringBuilder中
        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append("<h3>首行部分</h3>");
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getMethod());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getContextPath());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("<br>");
        stringBuilder.append("<h3>header部分</h3>");
        Enumeration<String> headerNames=req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName= headerNames.nextElement();
            String headerValue=req.getHeader(headerName);
            stringBuilder.append(headerName+":"+headerValue+"<br>");
        }
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write(stringBuilder.toString());
    }
}

微信图片_20230111165851.png

2.3 代码示例:获取GET请求中的参数


最常用的其实是getParameter这个方法,能够获取到query string中的详细内容。创建一个GetParameterServlet类来获取Get请求中的参数。


@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userId=req.getParameter("userId");
        String classId=req.getParameter("classId");
        resp.getWriter().write("userId="+userId+",classId="+classId);
    }
}


浏览器构造如下请求。


微信图片_20230111165847.png

2.4 代码示例:获取POST请求中的参数


POST请求的body格式主要有以下三种:


1.x-www-form-urlencoded

2.form-data

3.json


最为常见的是第一种和第三种,我们可以通过form表单或者ajax的方式来构造出这样的POST请求。


1)基于form表单构造x-www-form-urlencoded这种格式的请求。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="postParameter" method="post" accept-charset="utf-8">
        <span>userId</span>
        <input type="text" name="userId">
        <span>classId</span>
        <input type="text" name="classId">
        <input type="submit" value="提交">
    </form>
</body>
</html>


服务器获取参数的方式和GET方法一样,也是getParameter。


@WebServlet("/postParameter")
public class PostGetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求与响应中的编码格式
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html; charset=utf8");
        //获取post请求中的参数
        String userId=req.getParameter("userId");
        String classId=req.getParameter("classId");
        resp.getWriter().write("userId="+userId+",classId="+classId);
    }
}


测试效果演示:

微信图片_20230111165842.gif

2)基于ajax构造json这种格式的请求.


1.在浏览器的前端代码中,通过js构造出body为json格式的请求


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 前端HTML部分内容 -->
    <input type="text" id="userId">
    <input type="text" id="classId">
    <input type="button" id="submit" value="提交">
    <!-- 导入jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
    <script>
        let userIdInput=document.querySelector('#userId');
        let classIdInput=document.querySelector('#classId');
        let button=document.querySelector('#submit');
        button.onclik=function() {
            $.ajax({
                type:'post',
                url:'postJson',
                contentType:'application/json',
                data:JSON.stringify({
                    userId:userIdInput.value,
                    classId:classIdInput.value
                }),
                success:function(body) {
                    console.log(body);
                }
            })
        }
    </script>
</body>
</html>


微信图片_20230111165837.png

2.因为json格式的数据,不便于手动解析,所以在Java后端代码中,通过Jackson来进行处理(在maven中央仓库引入Jackson依赖)

微信图片_20230111165834.png


微信图片_20230111165829.png

微信图片_20230111165826.png

微信图片_20230111165822.png


后端代码:


class User {
    public int userId;
    public int classId;
}
@WebServlet("/postJson")
public class PostJsonServlet extends HttpServlet {
    //1.创建一个jackson的核心对象
    private ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //2.读取body中的请求,然后使用ObjectMapper来解析成需要的对象
        //readValue就是把JSON格式的字符串,转成Java的对象
        //第一个参数,表示对哪个字符串进行转换(这个参数可以是一个String,也可以是
        // 一个InputStream对象,还可以是一个File对象)
        //第二个参数,表示要把这个JSON格式的字符串,转换成哪个Java对象
        User user=objectMapper.readValue(req.getInputStream(),User.class);
        resp.getWriter().write("userId:"+user.userId+",classId:"+user.classId);
    }
}


readValue方法解析:


微信图片_20230111165817.png

1.先把getInputStream对应的流对象里面的数据读取出来。

2.针对这个json字符串进行解析,从字符串转换成键值对

3.遍历键值对,依次获取到每一个Key,根据这个Key的名字,和类对象Uer里面的属性名字对比(利用反射获取到内部属性),如果匹配就进行赋值,不匹配就跳过

4.当把所有的键值对都遍历过后,此时User对象就被构造好了。


测试效果演示:


微信图片_20230111165812.gif

3.HttpServletResponse


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


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


3.1 核心方法


方法 描述

void setStatus(int sc) 为该响应设置状态码

void setHeader(String name,String value) 设置一个带有给定的名称和值的header,如果name已经存在,则覆盖掉旧的值,可以实现页面的刷新

void addHeader(String name,String value) 添加一个带有给定的名称和值的header,如果name已经存在,不覆盖旧的值,并列添加新的键值对

void setContentType(String type) 设置被发送到客户端的响应的内容类型

void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME字符集)例如,UTF-8

void sendRedirect(String location) 设置指定的重定向位置URL,发送临时重定向响应到客户端

PrintWriter getWriter() 用于往body中写入文本格式数据

OutputStream getOutputStream() 用于往body中写入二进制格式数据


注意:响应对象是服务器要返回给浏览器的内容,这里的重要信息都是程序猿设置的。因此上面的方法都是“写”方法

对于状态码/响应头的设置,要放到getWriter/getOutputStream之前,否则可能设置失效


3.2 代码示例:设置状态码

代码:


@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(404);
        resp.getWriter().write("hello");
    }
}


效果预览:

微信图片_20230111165804.png

状态码虽然是404,但页面仍然能够显示出内容,就像b站的404页面一样


微信图片_20230111165759.png

3.3 代码示例:自动刷新

代码:


@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Refresh","1");
        resp.getWriter().write("timeStamp:"+System.currentTimeMillis());
    }
}


效果预览:


微信图片_20230111165755.gif

3.4 代码示例:重定向

代码:


@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("https://www.bilibili.com");
    }
}


效果预览:

微信图片_20230111165747.gif

相关文章
|
API
05JavaWeb基础 - Servlet的相关API
05JavaWeb基础 - Servlet的相关API
47 0
|
7月前
|
API
获得servlet相关API,获得请求头和cookie-spring23
获得servlet相关API,获得请求头和cookie-spring23
|
JSON 应用服务中间件 API
【计算机网络】Servlet API重点知识汇总
【计算机网络】Servlet API重点知识汇总
|
8月前
|
JSON Java 应用服务中间件
Servlet API 详解
Servlet API 详解
|
网络协议 应用服务中间件 API
Servlet的常用Api—HttpServletResponse
Servlet的常用Api—HttpServletResponse
143 0
Servlet的常用Api—HttpServletResponse
|
JSON 编解码 前端开发
【JavaEE】Servlet的API详解
【JavaEE】Servlet的API详解
113 0
|
API
java202304java学习笔记第六十二天-ssm-获取servlet相关api
java202304java学习笔记第六十二天-ssm-获取servlet相关api
88 0
|
API
java202304java学习笔记第六十二天-ssm-获取servlet相关api
java202304java学习笔记第六十二天-ssm-获取servlet相关api
99 0
|
应用服务中间件 API
Servlet API 详解
Servlet API 详解
262 0
Servlet API 详解
|
应用服务中间件 API 容器
Servlet入门案例(三)Servlet的生命周期、api和请求方式、工作原理、注解开发
Servlet入门案例(三)Servlet的生命周期、api和请求方式、工作原理、注解开发
130 0
Servlet入门案例(三)Servlet的生命周期、api和请求方式、工作原理、注解开发