详解 Servlet 及其常用 API

目录

一. Servlet运行原理

二. Servlet常用API

1. HttpServlet

1.1. Servlet的生命周期

1.2. Post请求的构造

2. HttpServletRequest

2.1. 获取请求信息

2.2. 前端给后端传输数据的三种方式

3. HttpServletResponse

3.1. 设置响应状态码

3.2. 自动页面刷新

3.3. 重定向


一. Servlet运行原理

二. Servlet常用API

1. HttpServlet

1.1. Servlet的生命周期

1.2. Post请求的构造

2. HttpServletRequest

Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成 HttpServletRequest 对象.我们就通过这个类来获取到请求的各个方面的信息,尤其是前端传过来的自定义数据,这个自定义数据的方式有三种,下面来介绍:

下面是获取请求信息的常用方法:

2.1. 获取请求信息

通过上面的API,我们就可以获取请求的各种信息,现在我们构造一个GET请求:在浏览器输入URL:localhost:8080/servlet-FirstHelloWorld/hello123?a=12313&t=777  

然后通过HttpServletRequest类的一系列API,我们就可以获取请求的协议版本,方法类型,URL,查询字符串,Header属性等等。其中Header信息的获取先要使用 getHeaderNames方法获取所有的头部信息的所有key值, 这s是一个枚举对象, 然后在根据 getHeader 方法通过key值遍历枚举对象获取value.

String Builder 的用法:  http://t.csdn.cn/yyGda

String,String Buffer,String Builder的区别:    http://t.csdn.cn/IfUwI

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("/hello123")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//      设置响应的body格式
        resp.setContentType("text/html;charset=utf8");

        StringBuilder stringBuilder = new StringBuilder();

//        返回请求协议的名称和版本。
        stringBuilder.append("协议版本:");
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("<br>");

//        返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
        stringBuilder.append("方法:");
        stringBuilder.append(req.getMethod());
        stringBuilder.append("<br>");


//        从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的层次路径部分。
        stringBuilder.append("URL:");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("<br>");

//        返回指示请求上下文的请求 URI 部分(一级路径)。
        stringBuilder.append("一级路径:");
        stringBuilder.append((req.getContextPath()));
        stringBuilder.append("<br>");

//        返回包含在路径后的请求 URL 中的查询字符串。
        stringBuilder.append("查询字符串:");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("<br>");

//        返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
        stringBuilder.append("<h3>获得头部的键值对</h3>");
        Enumeration<String> headerNames = req.getHeaderNames();
         while (headerNames.hasMoreElements()) {
             String headerName = headerNames.nextElement();
             String headerValue = req.getHeader(headerName);
             stringBuilder.append(headerName + ":" + headerValue + "<br>");
         }

//        在页面上输出信息
         resp.getWriter().write(stringBuilder.toString());

    }
}

2.2. 前端给后端传输数据的三种方式

2.2.1通过Query String的方式传递

构造GET请求的方法:在浏览器地址栏输入URL

构造Query String的方法:URL后 + ? + 键值对

如果只输入用户名,不输入密码的情况:

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("/methodOne")
public class getParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        if (username == null){
            System.out.println("username 不存在");
        }
        if (password == null){
            System.out.println("password 不存在");
        }

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

以上是基于程序员了解前端会返回什么样的key值(键值对的属性名)的情况

但 如果不知道value对应的key是什么,比如 不知道密码的 key 是 password 还是 number

也可以通过枚举获取所有的Query String的key与value再将它们一 一打印出来

注意要记得设置响应格式,不然<br>实现不了换行

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("/methodOne")
public class getParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //  设置好响应格式,浏览器才知道是html文本
        resp.setContentType("text/html;charset=utf8");
        StringBuilder stringBuilder = new StringBuilder();

        //  获取请求报头中所有的 key 值 赋值给 queryStringKeys
        Enumeration<String> queryStringKeys = req.getParameterNames();
        //  但枚举容器里还有 key 值 时,循环继续
        while (queryStringKeys.hasMoreElements()){
            // 拿到下一个 key 值  赋值给 key
            String key = queryStringKeys.nextElement();
            //  将key 及其所对应的 value 放到stringBuilder容器中
            stringBuilder.append(key + ": " + req.getParameter(key));
            stringBuilder.append("<br>");
        }
        resp.getWriter().write(stringBuilder.toString());
    }
}
2.2.2通过body,以form表单的格式传递

以POST请求为例,代码格式与GET请求相似,数据此时是在 HTTP 格式中的 body 部分的, 使用 from 表单进行构造, 此时 body 中的请求内容的格式 (Content-Type) 是 application/x-www-form-urlencode 格式, 在形式上和 query string 是一样的, 后端仍然使用 getParameter 来获取.

    @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");
        }
        if (password == null){
            System.out.println("不存在 password");
        }
        resp.getWriter().write("ok");
        System.out.println("username =" + username + "; password =" + password);
    }

然后我们通过postman构造post请求      postman的用法:http://t.csdn.cn/q9mu4

这里的代码要注意, 需要设置拿到请求的编码格式, 显式的告诉后端代码, 请求使用的是 utf8 编码, 要不然Tomcat 服务器在进行 urldecode 解码时可能会由于编码问题解析错误, 尤其是请求内容中有中文存在的情况下, 也就是说, 我们在写后端代码时, 最好将请求和响应的编码格式都进行设置, 保证前后端解析的统一.

如图,数据含有中文,传递到后端就变成了乱码了

加上这一行代码,即可正常解析

2.2.3通过body,以json的格式传递

实际中,使用json是最常见的,要重点掌握。需要下载第三方库  jackson

下载地址:  Maven Repository: com.fasterxml.jackson.core » jackson-databind » 2.14.2 (mvnrepository.com)

将代码复制到pom.xml再刷新maven即可

先贴整体代码:

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("/getJsonServlet")
public class getJsonServlet extends HttpServlet {

    //  使用jackson 最核心的对象就是ObjectMapper
    //  通过这个对象,就可以把json字符串解析成 java对象
    //  也可以把一个java对象转换成一个 json格式的字符串
    ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //  通过POST请求的body 传递过来一个json格式的字符串
        User user = objectMapper.readValue(req.getInputStream(),User.class);
        System.out.println("username = " + user.username + "; password = " + user.password);

        resp.getWriter().write("ok");
    }
}

详解代码:

首先我们要构造一个ObjectMapper对象,这是使用Json最核心的对象

然后使用这个对象的  readValue()方法

第一个参数用来表示请求的来源, 可以是路径字符串, 也可以是InputSream对象,

 第二个参数表示接收 json 数据的实体类对象.

readValue()方法详解:

1.通过第一个参数,解析 json 字符串,转换成若干个键值对

2.根据第二个参数 User.class 去找到 User里所有的public属性,并依次遍历

                        .class是类对象,可以理解为这个类的图纸 ~ ~运用了反射的机制,

                         将这个类中所有的public的属性都展现出来

3.遍历属性,根据属性的名字去上述准备好的键值对里查询,如果这个属性的名字存在对应的value值,就把value赋值到该属性

意思是:如果找到 key == 属性名,就把 属性名 = value (赋值)。

写完后,通过postman构造POST请求,且body是json格式

发送后收到响应 ok ,同时服务器也获取到了信息

3. HttpServletResponse

HttpServletResponse表示一个响应

关键API:

3.1. 设置响应状态码

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.setContentType("text/html;charset=utf8");
        //设置状态码
        resp.setStatus(404);
        resp.getWriter().write("<h1>404 没找到</h1>");
    }
}

3.2. 自动页面刷新

通过header实现自动刷新效果

给HTTP响应中,设置  Refresh:时间

@WebServlet("/refresh")
public class refreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //  每隔一秒时,刷新一次
        resp.setHeader("Refresh","1");
        resp.getWriter().write("time = " + System.currentTimeMillis());
    }
}

抓包效果:

响应效果:

也可以设置成格式化的时钟刷新:

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.text.SimpleDateFormat;

@WebServlet("/refresh")
public class refreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset = utf8");
        //设置Refresh, 第二个参数表示刷新频率, 单位是秒, 每隔 1s 刷新一次
        resp.setHeader("Refresh", "1");
        //响应                                获取毫秒级别的时间戳
        // resp.getWriter().write("时间戳:" + System.currentTimeMillis());
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        resp.getWriter().write("格式化时间戳 = " + format.format(System.currentTimeMillis()));
    }
}

3.3. 重定向

使用 HttpServletResponse 类中的 sendRedirect 方法, 参数传入重定向的 URL 即可,

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 Redirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.sendRedirect("https://www.sogou.com");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux是一种流行的操作系统,广泛应用于服务器、嵌入式设备和个人电脑等领域。为了能够有效地使用Linux系统,我们需要学习Linux常用命令。《Linux常用命令大全及其详解》是一本非常实用的电子书,它详细介绍了Linux系统中的各种命令,并提供了丰富的例子和详细的解释。 这本电子书包括了Linux中常用的命令、文件管理、用户管理、软件包管理、系统管理、网络管理等方面的内容。对于初学者来说,这本书可以帮助他们迅速掌握Linux系统的基本命令,了解Linux系统的基本概念和操作方法。对于更有经验的用户来说,它也是一本很好的参考书,可以帮助他们深入了解Linux系统的高级命令和管理技术。 这本电子书的特点在于它提供了丰富的图例和示例代码,这些例子可以帮助读者更好地理解每个命令的用法。它还提供了详细的解释,这些解释可以帮助读者理解每个命令的作用和使用条件等。此外,这本书还附带了一些实用的技巧和建议,这些技巧可以帮助读者更好地管理他们自己的Linux系统,并防止发生安全问题和故障。 总之,《Linux常用命令大全及其详解》是一本非常实用的电子书,它可以帮助Linux用户更好地掌握Linux系统的基本命令和管理技巧,为他们的管理工作提供更好的基础和工具。如果你是Linux用户,我强烈推荐你阅读这本电子书。 ### 回答2: Linux 是一种开源操作系统,被广泛应用于服务器和个人电脑上。在学习和使用 Linux 时,熟练掌握常用命令是必不可少的技能。因此,有一份详细的 Linux 常用命令大全及其详解 PDF 文件对学习者和使用者来说非常有用和实用。 这份 PDF 文件包括了大量的常用 Linux 命令,如文件和目录管理命令、系统管理命令、网络命令、安全命令等,每个命令都附带了详细的用法解释和示例。例如,对于文件和目录管理命令,这份 PDF 文件详细介绍了如何创建、删除、复制、移动、重命名、查看、编辑和打包等操作。对于系统管理命令,这份 PDF 文件介绍了如何显示系统信息、查看进程、配置系统设置和定时任务等。对于网络命令,这份 PDF 文件介绍了如何测试网络连接、配置 IP 地址、查询网络状态和端口等。 此外,这份 PDF 文件还提供了常见的 Linux 命令快速查找表,使得用户能够更快地找到所需的命令和选项。同时,这份 PDF 文件还提供了一些常见问题的解决方法和一些实用的技巧,帮助用户更好地理解和掌握 Linux 命令。 总之,这份 Linux 常用命令大全及其详解 PDF 文件是 Linux 学习者和使用者必备的资料之一。通过学习和掌握这些命令,用户可以更加高效地使用 Linux 操作系统,在工作和生活中更加方便快捷地处理各种任务和问题。 ### 回答3: “Linux常用命令大全及其详解”是一本介绍Linux命令的电子书,该书内容详实,并且讲解通俗易懂,是学习Linux语言和操作系统的新手必备工具。 这本电子书中包含了Linux系统中常用的命令,包括文件管理、用户管理、进程管理和网络管理等多个方面,每个命令都有如何使用以及使用场景的介绍,适合初学者快速掌握Linux命令行的使用方式。 此外,“Linux常用命令大全及其详解”还提供了丰富的实例、操作步骤、技巧和注意事项,帮助读者更好地理解和掌握命令的使用方法。此书覆盖面广,内容详尽,是学习Linux命令行的高效工具。 最后,这本电子书的格式是PDF,具有方便阅读和打印的优点,学习者可以通过打印或电子阅读等方式来使用此书进行学习,非常方便实用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值