16. Servlet入门 - request介绍以及使用

2022-01-14 17:46:37 浏览数 (1)

16. Servlet入门 - request介绍以及使用

request概述

什么是request

在Servlet API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求头和请求体三部分,因此,在HttpServletRequest接口中定义了获取请求行、请求头和请求消息体的相关方法.

Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。

request作用

  • 操作请求三部分(行,头,体)
  • 请求转发
  • 作为域对象存数据

获取客户端以及请求头信息(操作请求行和请求头)

上面我们已经知道了 request 的基本作用,下面我们来使用一下。

获取客户机信息(操作请求行)

请求方式 请求路径(URI) 协议版本

代码语言:javascript复制
GET  /requestDemo/register.htm?username=zs&password=123456   HTTP/1.1 
  • getMethod();获取请求方式
  • getRemoteAddr() ;获取客户机的IP地址(知道是谁请求的)
  • getContextPath(); 获得当前应用工程名(部署的路径);
  • getRequestURI();获得请求地址,不带主机名
  • getRequestURL();获得请求地址,带主机名
  • getServerPort();获得服务端的端口
  • getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)
1. 创建一个演示Servlet程序,如下:

image-20201228164510317

代码语言:javascript复制
@WebServlet("/requestDemo")
public class RequestServletDemo extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("访问 RequestServletDemo ....");
    }
}

启动 tomcat 测试服务如下:

image-20201228164610934

可以看到成功访问了,那么下面我们来逐个演示一下获取客户端信息的方法。

2. getMethod();获取请求方式

image-20201228165148365

代码语言:javascript复制
//**getMethod()**;获取请求方式
String method = request.getMethod();
System.out.println("获取请求方式 method: "   method);
3. getRemoteAddr() ;获取客户机的IP地址(知道是谁请求的)

image-20201228165349054

代码语言:javascript复制
// **getRemoteAddr()** ;获取客户机的IP地址(知道是谁请求的)
String remoteAddr = request.getRemoteAddr();
System.out.println("获取客户机的IP地址: "   remoteAddr);
4.getContextPath(); 获得当前应用工程名(部署的路径);

image-20201230234000886

代码语言:javascript复制
// **getContextPath()**;    获得当前应用工程名(部署的路径);
String contextPath = request.getContextPath();
System.out.println("获得当前应用工程名(部署的路径): "   contextPath);
5.getRequestURI();获得请求地址,不带主机名

image-20201230234255331

代码语言:javascript复制
// **getRequestURI();获得请求地址,不带主机名**
String requestURI = request.getRequestURI();
System.out.println("获得请求地址,不带主机名: "   requestURI);
6.getRequestURL();获得请求地址,带主机名

image-20201230234438317

代码语言:javascript复制
// **getRequestURL();获得请求地址,带主机名**
StringBuffer requestURL = request.getRequestURL();
System.out.println("获得请求地址,带主机名: "   requestURL);
7. getServerPort();获得服务端的端口

image-20201230234808764

代码语言:javascript复制
// getServerPort();获得服务端的端口
int serverPort = request.getServerPort();
System.out.println("获得服务端的端口: "   serverPort);
8. getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)

image-20201230235128191

代码语言:javascript复制
// getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)
String queryString = request.getQueryString();
System.out.println("获的请求参数: "   queryString);

获得请求头信息(操作请求头)

请求头: 浏览器告诉服务器自己的属性,配置的, 以key value存在, 可能一个key对应多个value

img

使用 getHeader(String name); 可以获取以下信息
  • User-Agent: 浏览器信息
  • Referer:来自哪个网站(防盗链)

image-20201231085654381

代码语言:javascript复制
//根据请求头的name获取value
//目标:获取name为user-agent的请求头的信息
// User-Agent: 浏览器信息
String header = request.getHeader("user-agent");
System.out.println("获取的请求头agent为:"   header);

// Referer:来自哪个网站(防盗链)
String referer = request.getHeader("referer");
System.out.println("来自哪个网站(防盗链) Referer:"   referer);

小结

  1. 操作请求行(获得客户机信息)
    • getMethod(); 获得请求方式
    • getRemoteAddr(); 获得客户机的IP地址
    • getContextPath(); 获得项目的部署的路径
    • getRequestURI(); 获得URI(不带http,主机,端口)
    • getRequestURL(); 获得URL(带http,主机,端口)
  2. 操作请求头
    • User-Agent: 浏览器信息
    • Referer:来自哪个网站(防盗链)
    • getHeader(String name);

获取请求参数以及乱码处理(操作请求体)

上面我们已经理解了通过 request 获取客户端 以及 请求头 的信息,下面我们来看看如何获取请求参数,以及对应的中文乱码问题处理。

request 获得请求参数的方法

方法名

描述

String getParameter(String name)

获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack

String[] getParameterValues(String name)

获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码

Map<String,String[]> getParameterMap()

获得所有的请求参数。key为参数名,value为key对应的所有的值。

下面我们来用代码快速示例演示一下。

1.获取指定参数名对应的值 getParameter(String name)
1.1 首先我们创建一个 Servlet,如下:

image-20210107213514678

经过测试,我们已经知道了 Servlet 能够正常访问了。

1.2 使用 getParameter(String name) 来获取一个 username 的参数

image-20210107213833663

代码语言:javascript复制
// 使用 getParameter(String name) 来获取一个 username 的参数
String username = request.getParameter("username");
System.out.println("获取到的username参数: "   username);

那么这里带来一个疑问,如果是 post 请求呢?是否也可以获取参数呢?下面我们可以使用 postman 使用 form 表单的方式,快速测试一下,如下:

image-20210107214127912

我们使用 post 请求的方式,可以看到 Servlet 打印信息如下:

image-20210107214226773

2. 获得指定参数名对应的所有的值 getParameterValues(String name)。

获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码

2.1 测试使用 GET 的 query 请求方式

image-20210107220002203

代码语言:javascript复制
// 获得指定参数名对应的所有的值 getParameterValues(String name)。
String[] hobbies = request.getParameterValues("hobby");
for (String hobby : hobbies) {
    System.out.println("获取的hobby:"   hobby);
}

访问:http://localhost:8080/demo6?username=libai&hobby=basketball&hobby=football

可以看到正常获取到所有 hobby 参数。

2.2 测试用 POST 的 请求方式

image-20210107220150452

获取到参数如下:

image-20210107220249999

可以看到两种请求方式都可以获取参数。

3.获得所有的请求参数 getParameterMap()。key为参数名,value为key对应的所有的值。

image-20210107221251645

代码语言:javascript复制
// 获得所有的请求参数 getParameterMap()
System.out.println("获得所有的请求参数 getParameterMap(): ");
Map<String, String[]> parameterMap = request.getParameterMap();
// 遍历所有参数 map
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
    // 遍历参数的value
    for (String value : entry.getValue()) {
        System.out.println(entry.getKey()   ": "   value);
    }
}

中文乱码问题处理

上面我们设置请求参数的时候,都是采用英文,并没有使用中文内容,那么如果使用中文的话,会出现什么结果呢?

1.中文乱码问题
1.1 在 GET 请求参数中,设置中文内容

image-20210107222052303

访问 http://localhost:8080/demo6?username=肥子白&hobby=basketball&hobby=football&hobby=无情兴趣

1.2 在 POST 请求参数中,设置中文内容

image-20210107222405433

image-20210107222442030

可以看到当我们使用 POST 请求参数为中文的时候,服务端接收的内容为乱码,这是为什么么?

2.中文乱码的产生原因(客户端与服务端两者的编码格式不一致)

我们在输入一些中文数据提交给服务器的时候,服务器解析显示出来的一堆无意义的字符,就是乱码。那么这个乱码是如何出现的呢?如下图所示:

image-20191209100446323

基本的原因其实就是 客户端 与 服务端 两者的编码格式不一致,那么我们只要将两边都设置为 utf-8 编码格式即可。

而在上面的示例中,我们发现GET请求中文乱码不用处理,而 POST 请求需要处理,总结如下:

  1. get方式, 当 tomcat>=8.0, 乱码会由 tomcat 自动处理;而如果低于 8.0 ,也是需要自己设置一下编码格式。
  2. post方式, 目前的版本都需要自己设置编码格式。

所以,还是都自己设置一下编码格式就好了。

3.中文乱码的解决(设置服务端的解码格式为 utf-8)

image-20210107223051821

代码语言:javascript复制
// 设置服务端为 utf-8 解码格式,解决中文乱码问题
request.setCharacterEncoding("UTF-8");
4.设置编码格式的快速输入模板

在 IDEA 中,如果每次都要去记住如何输入,也是一个比较麻烦的事情,那么我们可以设置一个快捷输入方式,如下:

image-20210107233153227

代码语言:javascript复制
request.setCharacterEncoding("UTF-8");

image-20210107233232778

测试输入如下:

image-20210107233257945

获取请求参数使用 BeanUtils 封装好 POJO 对象中

现在我们已经可以使用request对象来获取请求参数,但是,如果参数过多,我们就需要将数据封装到对象。

以前封装数据的时候,实体类有多少个字段,我们就需要手动编码调用多少次setXXX方法,因此,我们需要BeanUtils来解决这个问题。

BeanUtils是Apache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。

使用步骤:

  1. 导入jar
  2. 使用BeanUtils.populate(user,map)

1.使用 Maven 导入 BeanUtils 的 jar 包依赖

1.1 访问 Maven 仓库,搜索 BeanUtils 的依赖

访问 https://mvnrepository.com 搜索 BeanUtils 如下:

image-20210107225030048

image-20210107225128037

image-20210107225235531

代码语言:javascript复制
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>
1.2 在项目的 pom.xml 导入 BeanUtils 坐标依赖

image-20210107225418529

2.创建 POJO 包的 User 类

image-20210107225758825

代码语言:javascript复制
package com.pojo;

import java.util.Arrays;

/**
 * @author Aron.li
 * @date 2021/1/7 22:56
 */
public class User {
    private String username;
    private String password;
    private String gender;
    private String[] hobby;

    public User() {
    }

    public User(String username, String password, String gender, String[] hobby) {
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "User{"  
                "username='"   username   '''  
                ", password='"   password   '''  
                ", gender='"   gender   '''  
                ", hobby="   Arrays.toString(hobby)  
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }
}

3.使用 BeanUtils 将 与 User 类属性同名的 请求参数 进行自动批量赋值

image-20210107230727283

代码语言:javascript复制
@WebServlet("/BeanUtilsDemo")
public class BeanUtilsDemo extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置请求参数的编码格式,解决中文乱码问题
        request.setCharacterEncoding("UTF-8");
        //1. 获取所有的请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //2. 将请求参数封装到User对象中
        User user = new User();
        //3. 使用BeanUtils框架自动将map中的数据封装到对象中
        try {
            BeanUtils.populate(user, parameterMap);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 4. 打印封装好的user对象
        System.out.println(user);

    }
}

4.使用 post 请求 Servlet,每个请求参数都与 User 类中的属性同名

image-20210107230847532

请求之后,Servlet 程序打印封装好的 user 对象如下:

image-20210107230927807

那么如果缺少 或者 请求的参数 与 User 类属性不同名称 呢?

image-20210107231023378

image-20210107231040429

可以发现,如果请求的参数不同命,那么 BeanUtils 就无法对应赋值了。

request 的请求转发

在上面我们基本清楚了 request 如何获取请求头、请求参数等功能了,那么下面继续介绍 request 的请求转发功能。

1. 请求转发的格式

代码语言:javascript复制
request.getRequestDispatcher(url).forward(request, response);//转发

2.请求转发的作用

当我们需要将 request 对象同时交给两个或者多个 Servlet 程序处理的时候,那么就可以使用请求转发。

request 请求转发不会修改浏览器的路径,也不需要浏览器跳转至其他路径,由服务端执行跳转。

更加重要的是,request 请求转发还可以访问 WEB-INF 中受保护的资源。

3.设置 请求转发的 forward 快捷输入模板

我们可以看到输入一个请求转发要写好多内容,为了方便,我们可以自己设置一下快捷方式,如下:

File | Settings | Editor | Live Templates

image-20210107232036814

代码语言:javascript复制
request.getRequestDispatcher(url).forward(request, response);

image-20210107232718248

image-20210107232752324

下面在代码输入 forward 尝试快捷输入,如下:

image-20210107232829032

image-20210107232846420

4.请求转发的效果是跳转: 跳转到其它页面,跳转到其它的servlet

4.1 首先创建一个 Servlet 程序 forwardDemo1

image-20210108075753836

代码语言:javascript复制
@WebServlet("/ForwardDemo1")
public class ForwardDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("this is ForwardDemo1....");
    }
}
4.2 再创建一个 Servlet 程序 forwardDemo2

image-20210108075933510

代码语言:javascript复制
@WebServlet("/ForwardDemo2")
public class ForwardDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("this is ForwardDemo2....");
    }
}
4.3 在 forwardDemo1 中设置请求转发至 forwardDemo2

image-20210108080421057

代码语言:javascript复制
@WebServlet("/ForwardDemo1")
public class ForwardDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("this is ForwardDemo1....");

        System.out.println("访问到 ForwardDemo1...");

        // 请求转发至 forwardDemo2
        request.getRequestDispatcher("/ForwardDemo2").forward(request, response);
    }
}

我们从执行的效果来看,请求的确到了 demo1 的 Servlet 程序中,并且浏览器又直接显示 demo2 返回的结果,没有进行二次请求。

5.请求转发的跳转,只能是跳转到本项目的资源,无法访问项目外的资源

5.1 创建一个项目的 index.html ,用于演示请求转发

image-20210108080827164

5.2 在forwardDemo2中,再次设置请求转发至 index.html

image-20210108081024136

代码语言:javascript复制
// 请求转发项目中的 index.html
request.getRequestDispatcher("/index.html").forward(request, response);
5.3 接着上面的示例,首先请求 demo1,然后demo1 转发至 demo2,然后 demo2 转发至 index.html

image-20210108081159370

5.4 测试能否访问项目外的资源,例如:百度

image-20210108081337556

代码语言:javascript复制
// 测试访问项目外的资源
request.getRequestDispatcher("https://www.baidu.com/").forward(request, response);

可以看到请求失败了,无法请求转发无法访问项目外的资源。

6. 请求转发到WEB-INF中的资源

6.1 将上面写的 index.html 移动到 WEB-INF 中

image-20210108081547303

一般来说,WEB-INF的资源是受保护的,在浏览器无法访问。但是使用请求转发的话,就可以访问到了。

6.2 使用请求转发,访问 WEB-INF 中的 index.html

image-20210108081813515

代码语言:javascript复制
// 请求转发至 WEB-INF 中的 index.html
request.getRequestDispatcher("/WEB-INF/index.html").forward(request, response);

request 作为域对象存取值

在上面我们已经理解了 request 请求转发的功能,而伴随着 请求转发的 当然就是可以携带 request 对象的存储值了。

当然 Servlet 的域对象有四种,而 request 只是其中的一种。

ServletContext: 范围 整个应用(无论多少次请求,只要是这个应用里面的都是可以共享的)

request范围: 一次请求有效 (所以要结合请求转发使用)

域对象是一个容器,这种容器主要用于Servlet与Servlet/JSP之间的数据传输使用的。

  • Object getAttribute(String name) ;
  • void setAttribute(String name,Object object) ;
  • void removeAttribute(String name) ;

下面编写两个Servlet,进行 request 传值看看。

1.接着在上面的 forwardDemo1 中存储一个 name 值在 request 域对象中

image-20210108084315439

代码语言:javascript复制
@WebServlet("/ForwardDemo1")
public class ForwardDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("this is ForwardDemo1....");

        System.out.println("访问到 ForwardDemo1...");

        // 目标: 在ForwardDemo2中获取ForwardDemo1中的变量username的值
        // 要求只能是由ForwardDemo1跳转到ForwardDemo2的时候才能获取
        String username = "周杰棍";
        //将username存储到request域对象中
        request.setAttribute("name",username);

        // 请求转发至 forwardDemo2
        request.getRequestDispatcher("/ForwardDemo2").forward(request, response);
    }
}

2.在 forwardDemo2 中取 request 的 name 值

image-20210108084406991

代码语言:javascript复制
@WebServlet("/ForwardDemo2")
public class ForwardDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("this is ForwardDemo2....");

        System.out.println("访问到 ForwardDemo2....");

        // 获取request中的值
        Object name = request.getAttribute("name");
        System.out.println("从 ForwardDemo1 传递过来的 name: "   name);

    }
}

3.测试请求

image-20210108084500341

可以看到,通过上面的示例,成功将 demo1 存储的值 转发到 demo2 上了。

4.小结

  1. request 作为域对象存取数据
    • Object getAttribute(String name) ; 取
    • void setAttribute(String name,Object object) ; 存
    • void removeAttribute(String name) ; 移除
  2. 范围: 一次请求有效(转发可以使用)

image-20191209110018952

Request部分的小结

  1. 获取请求行的信息
    1. 获取请求方式:getMethod()
    2. 获取请求的客户端的ip地址:getRemoteAddr()
    3. 获取项目部署的路径:getContextPath()
    4. 获取uri:统一资源标识符
    5. 获取url:统一资源定位符
    6. 获取服务器的端口号
    7. 获取请求参数的字符串:getQueryString()
  2. 获取请求头的信息:getHeader(name)
  3. 获取请求参数
    1. getParameter(name)
    2. getParameterValues(name)
    3. getParameterMap()
  4. 使用BeanUtils将map中的数据存储到JavaBean对象中
    1. map的key要和JavaBean的属性名保持一致,如果不一致那么该字段的值就无法存储
    2. BeanUtils中默认内置一些基本类型的转换器(如果map中的数据是string类型,JavaBean的属性还是int类型那么会自动转换)
  5. 使用request做请求转发: request.getRequestDispatcher("跳转路径").forward(request,response);
  6. request对象作为域对象向存取数据,它的作用范围是一次请求中,和请求转发一起使用

0 人点赞