javaEE初阶 — Servlet API 详解

HttpServlet


在 HttpServlet 中 有三个核心的方法,是 init、destory、service

init 方法

@WebServlet("/method")
public class servletMethond extends HttpServlet {

    @Override
    public void init() throws ServletException {
        // 重写 inti 方法
        System.out.println("init");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doGet");
    }
}


init 方法与 doGet 都是 HttpServlet 类里的方法,也是 tomcat 调用的, 同样都是可以重写的。

tomcat 收到了 /method 这样的路径的请求,就会调用到 servletMethond
于是就需要先对 servletMethond 进行实例化,这个实例化只进行一次。
后续再收到 /method 此时就不必在重复实例化了,直接复用之前的 servletMethond 实例即可。

这个方法在 HttpServlet 实例化之后只会被调用一次
也就是说,即使是多次请求也只会出现一个init。
\



开启服务器,可以看到此时只有一个 init,下面来多次刷新页面观察效果。



可以看到 doGet 会随着刷新次数增加,但是 init 只会在最开始的时候出现一次。



destroy 方法

在服务器终止的时候就会调用这个方法。

下面重写这个来演示一下。

 @Override
 public void destroy() {
     System.out.println("destroy");
 }



可以看到启动服务器的时候,并没有调用 destroy 这个方法,所以就没有显示出这个方法里的内容。

点击红色的矩形终止服务器。



可以看到终止服务器之后,就成功的调用了这个方法。


会不会出现 destroy 是不确定的。

如果是通过 smart tomcat 停止按钮,这个操作本质上是通过 tomcat 的 8005 端口主动停止,
是能够调用 destroy 这个方法,触发 destroy 的。
如果是直接杀进程,此时就可能来不及执行,此时 destroy 就没了。


service 方法

在收到路径匹配的 http 请求就会调用这个方法。

service 这个方法里包含了一个 doGet 方法,也就是说 doGet 方法就是在 service 方法中调用的。

接下来重写 service 方法观看底层代码。

 @Override
 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     super.service(req, resp);
 }




可以看到有一个 diGet 方法。

1 Servlet 的生命周期


这是一个比较频繁的面试题,生命周期就是在什么阶段,做什么事了。

比如一个人的生命周期:

1.小时候,要做的就是上学。
2.长大了之后,要参加工作。
3.再大一点,要结婚生娃。
4.年纪再大,娃要上学了。
5.年纪再大,娃娃要结婚了。
6.年纪再大一点,帮娃带娃。
7.ji了。


Servlet 的生命周期就是:

1.开始的时候,执行 init。
2.每次收到请求,执行 service。
3.销毁之前,执行 destroy。

2 代码示例


先来重写 doGet、doPost、doPut、doDelete 方法。

@WebServlet("/methods")
public class MyMethod extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doGet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
        resp.getWriter().write("doPost");
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPut");
        resp.getWriter().write("doPut");
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doDelete");
    }
}




可以看到此时只显示出了一个 doGet,那其他的请求怎么办呢?
这个时候就可以使用 postmanajax 来构造请求。

3 使用 postman 构造请求


输入路径,选择 GET 请求,点击 send 就构造好了一个 GET 请求,就出现了一个 doGet。



如果要构造其他的请求,可以更改即可。

4 使用 ajax 构造请求


在 webapp 目录下创建一个 .html 的文件。

绝对路径的写法:

<!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>ajax</title>
</head>
<body>
    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
    <script>
        $.ajax({
            type: 'get',
            url: 'methods',
           success: function(body, status) {
               console.log(body);
           }
        });
    </script>
</body>
</html>


此处所写的 methods 就相当于是在 http://127.0.0.1:8080/Servlet 基础上再拼上一个 methods。
也就是 http://127.0.0.1:8080/Servlet/methods




在地址栏输入路径,打开控制台就可以看到构造好的 GET 请求了。


相对路径的写法:

 url: '/Servlet/methods',


接下来使用 ajax 构造 POST 请求。

<body>
    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
    <script>
        $.ajax({
            type: 'post',
            url: 'methods',
            success: function(body, status) {
               console.log(body);
           }
        });
    </script>
</body>
</html>




Put、Delete…和上面的是一样的构造方法。

HttpServletRequest


Request 表示的是 HTTP 请求,HttpServlet 这个对象是 tomcat 自动创造的。
tomcat 其实会实现监听端口,接受连接,读取请求,解析请求,构造请求对象等一系列的工作。

核心方法

  • 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

1 代码示例

@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用 StringBuilder 把这些 api 结果拼接起来,统一写响应中
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(req.getProtocol());
        stringBuilder.append(req.getMethod());
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append(req.getContextPath());
        stringBuilder.append(req.getQueryString());
        
        // 写回到响应中
        resp.getWriter().write(stringBuilder.toString());
    }
}




getProtocol 得到的是 HTTP/1.1、getMethod 得到的是 GET
getRequestURI 得到的是 /Servlet/showRequest、getContextPath 得到的是 /Servlet
getQueryString 得到的是 null

前端如何给后端传参

1 通过 GET 里的 query string 传参


在前端给后端传两个数字,一个是同学的 studentId,一个是 classId
发送一个 ?studentId=10&classId=20 这样的请求。

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 预期浏览器会发一个形如 /getParameter?studentId=10&classId=20 请求
        // 借出 req 里的 getParameter 方法就能拿到 query string 中的键值对内容了
        // getParameter 得到的是 string 类型的结果
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("studentId = " + studentId + "classId = " + classId);
    }
}


在地址栏中输入路径访问。
我这里的路径是 127.0.0.1:8080/Servlet/getParameter?studentId=10&classId=20



通过 getParameter 方法,?studentId=10&classId=20 这个键值对会自动被 tomcat 处理成
形如 Map 这样的结构,后续就可以直接通过 key 获取 value 了。

如果 key 在 query string 中不存在,此时返回的就是 null。

2 通过 POST 借助 form 表单传参


如果前端是 form 表单格式的数据,后端还是使用 getParameter 来获取。

这里的 form 表单格式的数据也是键值对,和 query string 的格式是一样的,只是这部分内容在 body 中。

 <form action="postParameter" method="post">
     <input type="text" name="studentId">
     <input type="text" name="classId">
     <input type="submit" value="提交">
 </form>



在输入框中输入以下的数据。





当前显示 404 是因为 postParameter 还没有实现,但是不影响,打开 fiddler 抓包观察即可。



当前代码中的 action 属性里的 postParameter 得到的就是抓包结果中的 postParameter 这个路径。
method 属性 得到的就是抓包结果中的 POST 。

input 标签里的 name 属性里的 studentId 和 classId 实现的就是最下方的 studentId=10&classId=20。
而在输入框中输入的内容及决定了它们两个的值。


使用 getParameter 既可以获取到 query string 中的键值对,也可以获取到 form 表单构造的 body 中的键值对。

@WebServlet("/getparameter")
public class PostGetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("studentId = " + studentId + "classId = " + classId);
    }
}


抓包即可得到与之前相同的结果。



3 通过 json 格式传参


json 是一种非常主流的数据格式,也是键值对结构。

{
  classId: 20,
  studentId: 10
}


可以把 body 按照上面的格式来组织。

前段可以通过 ajax 的方式来构造出这个内容,也可以使用更简单的 postman 的方式。



打开 postman,勾选上述的选项,之后点击发送即可,由于还没有实现 getparameter2 的代码,
所以此时发送后,会报一个 404 错误。




接下来实现 getparameter2 的代码。

@WebServlet("/getparameter2")
public class PostParameter2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过 getInputStream 把 req 对象里的 body 完整读取出来
        // 在流对象中读取多少个字节,取决于 Content-Length
        int length = req.getContentLength(); // 这是 body 实际的长度
        // 创建一个相同长度的字节数组
        byte[] buffer = new byte[length];
        // 借出 inputStream 来读取 body 的内容
        InputStream inputStream = req.getInputStream();
        inputStream.read(buffer);

        // 把这个字节数组转成 String,然后打印出来
        String body = new String(buffer, 0, length, "utf8");
        System.out.println("body =" + body);
        resp.getWriter().write(body);
    }
}


通过 Content-Length 得到 body 的长度,然后再按照这个长度从请求对象中读取数据,
于是就把 body 给读取出来了。





可以看到服务器与客户端都有了结果。

服务器这里打印的结果就是,从 请求 body 里读取的内容。


接下来使用 fiddler 抓包观察结果



理解它的流程



json 与 form 的区别:

json 格式代码的执行流程与上面通过 form表单传参的流程是类似的,只不过是传参的数据格式不同。

form 表单是形如 classId=20&studentId=10

json 格式则是形如:

{
  classId: 20,
  studentId: 10
}



当前通过 json 传递数据,服务器只是把整个 body 读出来了,但是没有按照键值对的的方式来处理,
也就是说,目前还不能根据 key 获取 value。

此时建议使用 第三方库 —— jackson

1、通过 https://releases.jquery.com/ 打开 maven 仓库


2、搜索 jackson,点击第一个


3、选择 2.14.1 版本


4、将 Maven 里的代码复制到 pom.xml 文件里的 dependency 标签里




接下来尝试更改代码的写法。

class Student {
    public int studentId;
    public int classId;
}

@WebServlet("/getparameter2")
public class PostParameter2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用 jackson 涉及到的核心对象
        ObjectMapper objectMapper = new ObjectMapper();
        // readValue 可以把一个 jackson 格式的字符串转成 java 对象
        Student student = objectMapper.readValue(req.getInputStream(), Student.class);
        System.out.println(student.studentId + "," + student.classId);
    }
}


Student student = objectMapper.readValue(req.getInputStream(), Student.class);

这条语句中的 readValue 方法,会执行下面的流程。

1、从 body 中读取 json 格式的字符串

{
  classId: 20,
  studentId: 10
}



2、根据第二个参数类对象,创建 Student 实例


3、解析上述的 json 格式的字符串,处理成 map 键值对结构


4、遍历所有的键值对,看键的名字和 Student 实例的哪个属性名字匹配,
就把对应的 value 设置到该属性中



5、返回该 Student 实例


启动服务器再点击发送,会在服务器上得到下面这样的结果。

HttpServletResponse


1 代码示例

1.1 设置字符集


如果想让下面的代码显示出中文,此时就需要设置字符集 为 utf-8

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 预期浏览器会发一个形如 /getParameter?studentId=10&classId=20 请求
        // 借出 req 里的 getParameter 方法就能拿到 query string 中的键值对内容了
        // getParameter 得到的是 string 类型的结果
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("学生Id = " + studentId + "班级Id = " + classId);
    }
}




在设置之前会出现以上的结果。



接下来开始调用 setCharacterEncoding 设置字符集。

 resp.setCharacterEncoding("utf-8");


将上述的代码中添加上这条语句即可。


刷新页面可以看到正确的显示出来了。

需要注意的是 设置字符集那条语句必须是在 getWriter().write() 的上面。
如果写在了下面是不会生效的。


也可以把字符集和 ContentType 一起设置

 resp.setContentType("text/html; charset = utf-8");

1.2 重定向


以 3 开头的状态码,浏览器会自动跳转到指定的新地址。

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


在地址栏中输入地址后,会跳转到指定的新地址。以上就是会跳转到搜狗的页面。


打开 fiddler 抓包并观察结果。




代码实现的第二种方式

 resp.setStatus(302);
 resp.setHeader("Location", "https://www.sogou.com/");


将代码修改为以上两句即可,这种写法是将上面的步骤给拆分成两步了。


下期来介绍服务器版本的表白墙案例!!!




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java EE 5 Platform Packages javax.activation The JavaBeans(TM) Activation Framework is used by the JavaMail(TM) API to manage MIME data. javax.annotation javax.annotation.security javax.ejb The javax.ejb package contains the Enterprise JavaBeans classes and interfaces that define the contracts between the enterprise bean and its clients and between the enterprise bean and the EJB container. javax.ejb.spi The javax.ejb.spi package defines interfaces that are implemented by the EJB container. javax.el Provides the API for the Unified Expression Language shared by the JSP 2.1 and JSF 1.2 technologies. javax.enterprise.deploy.model Provides Tool Vendor implementation classes. javax.enterprise.deploy.model.exceptions Provides Tool Vendor exception implementation classes. javax.enterprise.deploy.shared Provides shared objects for Tool Vendor and Product Vendor implementation classes. javax.enterprise.deploy.shared.factories Provides shared factory manager object for Tool Vendor and Product Vendor implementation classes. javax.enterprise.deploy.spi Provides J2EE Product Vendor implementation classes. javax.enterprise.deploy.spi.exceptions Provides J2EE Product Vendor deployment exception implementation classes. javax.enterprise.deploy.spi.factories Provides J2EE Product Vendor deployment factory implementation classes. javax.enterprise.deploy.spi.status Provides J2EE Product Vendor deployment status implementation classes. javax.faces Top level classes for the JavaServer(tm) Faces API. javax.faces.application APIs that are used to link an application's business logic objects to JavaServer Faces, as well as convenient pluggable mechanisms to manage the execution of an application that is based on JavaServer Faces. javax.faces.component Fundamental APIs for user interface components. javax.faces.component.html Specialized user interface component classes for HTML. javax.faces.context Classes and interfaces defining per-request state information. javax.faces.convert Contains classes and interfaces defining converters. javax.faces.el DEPRECATED Classes and interfaces for evaluating and processing reference expressions. javax.faces.event Interfaces describing events and event listeners, and concrete event implementation classes. javax.faces.lifecycle Classes and interfaces defining lifecycle management for the JavaServer Faces implementation. javax.faces.model Standard model data beans for JavaServer Faces. javax.faces.render Classes and interfaces defining the rendering model. javax.faces.validator Interface defining the validator model, and concrete validator implementation classes. javax.faces.webapp Classes required for integration of JavaServer Faces into web applications, including a standard servlet, base classes for JSP custom component tags, and concrete tag implementations for core tags. javax.interceptor The javax.interceptor package contains classes and interfaces for use with EJB interceptors. javax.jms The Java Message Service (JMS) API provides a common way for Java programs to create, send, receive and read an enterprise messaging system's messages. javax.jws javax.jws.soap javax.mail The JavaMailTM API provides classes that model a mail system. javax.mail.event Listeners and events for the JavaMail API. javax.mail.internet Classes specific to Internet mail systems. javax.mail.search Message search terms for the JavaMail API. javax.mail.util Utility classes. javax.management.j2ee Provides the J2EE Management Enterprise Bean component (MEJB) interfaces. javax.management.j2ee.statistics Provides the standard interfaces for accessing performance data from J2EE managed objects Package Specification JSR 77, J2EE Management Related Documentation For overviews, tutorials, examples, guides, and tool documentation, please see: J2EE Tools javax.persistence The javax.persistence package contains the classes and interfaces that define the contracts between a persistence provider and the managed classes and the clients of the Java Persistence API. javax.persistence.spi The javax.persistence.spi package defines the classes and interfaces that are implemented by the persistence provider and the Java EE container for use by the container, provider, and/or Persistence bootstrap class in deployment and bootstrapping.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与大师约会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值