详解 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");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值