Servlet获取请求数据HttpServletRequest

Posted 一朵花花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet获取请求数据HttpServletRequest相关的知识,希望对你有一定的参考价值。

HttpServletRequest


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

方法了解

部分方法:

方法描述
String getProtocol()返回请求协议的名称和版本
String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT
String getRequestURI()从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分
String getContextPath()返回指示请求上下文的请求 URI 部分
String getQueryString()返回包含在路径后的请求 URL 中的查询字符串
String getParameter(Stringname)以字符串形式返回请求参数的值,或者如果参数不存在则返回null
String[] getParameterValues(Stringname)返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null

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

通过上述方法可以获取到一个请求中的各个方面的信息

举例:

@WebServlet("/request")
public class RequestServletStudy extends HttpServlet 
    // 访问路径: request?username=hh&password=123
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        // 此处是后台打印
        System.out.println("请求协议名:" + req.getProtocol());
        System.out.println("请求方法名:" + req.getMethod());
        System.out.println("应用上下文路径/应用名:" + req.getContextPath());
        System.out.println("资源路径/ServletPath:" + req.getServletPath());
        System.out.println("请求头中键为Host的值:" + req.getHeader("Host"));

        //响应给客户端的内容
        resp.getWriter().println("请求信息已获取,在idea后端控制台查看");
    

运行后:


点击链接跳转,此时弹出 404,需在 url 后补充 /request.html


点击 get 跳转:

重点方法介绍

1.getParamter 方法

1).获取url QueryString中的数据

@WebServlet("/request")
public class RequestServletStudy extends HttpServlet 
    // 访问路径: request?username=hh&password=123
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        // 此处是后台打印
        System.out.println("请求协议名:" + req.getProtocol());
        System.out.println("请求方法名:" + req.getMethod());
        System.out.println("应用上下文路径/应用名:" + req.getContextPath());
        System.out.println("资源路径/ServletPath:" + req.getServletPath());
        System.out.println("请求头中键为Host的值:" + req.getHeader("Host"));
       
        //重点
        //通过键获取值: 1.queryString;
        // 访问路径: request?username=hh&password=123
        System.out.println("username: " + req.getParameter("username"));
        System.out.println("password: " + req.getParameter("password"));

        //响应给客户端的内容
        resp.getWriter().println("请求信息已获取,在idea后端控制台查看");
        
    


可以在后端查看打印内容:


通过 fiddler 抓包查看:

注意: http 请求时,url 会进行编码,获取 queryString 中的中文,空格,特殊字符,就需要进行解码

举例 form 表单提交,没有设置请求方法,默认为 GET,会把 form 中的控件以name为键,用户输入/选择 的内容为值,设置到 queryString 中

<body>
    <h3>get with query string</h3>
    <form action="request">
        <input type="text" name="username" placeholder="请输入用户名">
        </br>
        <input type="password" name="password" placeholder="请输入密码">
        </br>
        <input type="submit" value="提交">
    </form>  
</body>

其他与上述例子保持一致

由于前端代码可以立即生效,所以不需要进行重启,直接对页面进行刷新即可:


查看后端打印内容:

2).获取body中表单格式

表单格式: body中的数据,格式和 queryString 是一样的

修改前端代码:

<h3>表单提交</h3>
<form action="request" method="post">
    <input type="text" name="username" placeholder="请输入用户名">
    </br>
    <input type="password" name="password" placeholder="请输入密码">
    </br>
    <input type="submit" value="提交">
</form>  

刷新页面,提交表单:


提交后会发现方法不允许,出现405错误
后端代码,是 GET 方法,而我们前端代码写的是 post

思考: 如何在不改 doGet方法的前提下,使其同时支持 post 方法??

// 既支持 get, 也支持 post
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
    doGet(req, resp);

重新启动,然后输入用户名和密码:

查看后端输出:


观察上图,会发现,出现了乱码的情况
注意: body 中的内容也是有编码格式的,需要设置一下才能正常显示:

req.setCharacterEncoding("utf-8"); //设置body解析的编码格式
System.out.println("username: " + req.getParameter("username"));
System.out.println("password: " + req.getParameter("password"));

重新启动,刷新页面查看:

此时不再出现乱码情况:

3).获取form-data中的简单数据类型的数据

修改前端代码:

<h3>fomr-data格式</h3>
<form action="request" enctype="multipart/form-data" method="post">
    <input type="text" name="username" placeholder="请输入用户名">
    </br>
    <input type="password" name="password" placeholder="请输入密码">
    </br>
    <input type="submit" value="提交">
</form> 

刷新页面:


查看后端输出:


通过抓包查看:


添加后端代码:

@WebServlet("/form-data")
@MultipartConfig //form-data 格式需要使用这个注解
public class FormDataServlet extends HttpServlet 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        // request.getParameter 也可以获取 form-data 中的简单类型数据
        req.setCharacterEncoding("utf-8"); // 设置body解析的编码格式
        System.out.println("username: " + req.getParameter("username"));
        System.out.println("password: " + req.getParameter("password"));
    

重新启动,刷新页面:


重点: http请求数据,存放的位置

  1. url queryString
  2. body(多种类型)

2.getPart 方法

获取form-data格式中,上传的文件
上传文件,若直接采用getParameter()来获取,是获取不到的

举例:

<h3>fomr-data格式 上传文件</h3>
<form action="form-data" enctype="multipart/form-data" method="post">
    <input type="text" name="username" placeholder="请输入用户名">
    </br>
    <input type="password" name="password" placeholder="请输入密码">
    </br>
    选择头像: <input type="file" name="head" accept="image/*">
    <input type="submit" value="提交">
</form> 
@WebServlet("/form-data")
@MultipartConfig //form-data 格式需要使用这个注解
public class FormDataServlet extends HttpServlet 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        // request.getParameter 也可以获取 form-data 中的简单类型数据
        req.setCharacterEncoding("utf-8"); // 设置body解析的编码格式
        System.out.println("username: " + req.getParameter("username"));
        System.out.println("password: " + req.getParameter("password"));
        System.out.println("head[文件无法通过getParameter获取]: " + req.getParameter("head"));
    


通过 fiddler 抓包:


form-data 中上传的文件必须需要通过 getPart 来获取,getParameter 无法获取到
简单类型的数据其实也可以使用getPart获取,但还需要调用 part 对象api来获取内容,比较复杂

  1. 获取上传文件的二进制数据,转换为字符串打印
    (通过 part 对象的输入流读取)
Part head = req.getPart("head");
// 获取上传文件的二进制数据,转换为字符串打印
InputStream is = head.getInputStream(); // 获取输入流(里边包含了数据)
// 输入流.available 返回包含的数据长度
byte[] bytes = new byte[is.available()];
// 从输入流中把数据读取到 byte[]中,字节数组对象就有了这些数据
is.read(bytes);
System.out.println(new String(bytes,"utf-8"));

后台打印出来的二进制数据,部分截图:

  1. 直接将客户端上传的文件,保存在服务端本地 (不读取,直接保存)
    注意要将上述代码注释掉,否则不能用
// 直接把客户端上传的文件,保存在服务器本地
head.write("D://"+head.getSubmittedFileName());

注意: 若这个路径已经有这个文件,那么就会报错

重新启动,刷新页面,输入用户名和密码,选择图片,进行提交,成功之后就会在对应的目录下找到刚才保存的图片

3.getInputStream 方法

获取请求正文body的数据(输入流中包含了这些数据),不管什么格式,只要是在body中,都可以获取到;只是表单格式没有必要使用这个方式来获取(比较麻烦,还要自己解析里边的多组键值对)
常用的场景:json格式

前端代码:

<body>
    <h3>ajax提交json格式</h3>
    <input type="text" id="ajax_username" placeholder="请输入用户名">
    </br>
    <input type="password" id="ajax_password" placeholder="请输入密码">
    </br>
    <button onclick="ajax_submit()">提交</button>
</body>

<script>
    function ajax_submit()
        let username = document.querySelector("#ajax_username");
        let password = document.querySelector("#ajax_password");
        let json = 
            username: username.value, // 键为username,值为对象的value属性
            password: password.value,
        ;
        ajax(
            url: "ajax-json-servlet",
            method: "post",
            //body上为 json格式的字符串
            contentType: "application/json",
            // JSON.stringify(json) 是将一个json对象序列化成一个字符串,格式是json格式
            body: JSON.stringify(json),
            callback: function(status,resp)
                alert("后端返回的内容: " + resp)
            
        );
    
    function ajax(args)//var ajax = function()
        let xhr = new XMLHttpRequest();
        // 设置回调函数
        xhr.onreadystatechange = function()
            // 4: 客户端接收到响应后回调
            if(xhr.readyState == 4)
                // 回调函数可能需要使用响应的内容,作为传入参数
                args.callback(xhr.status, xhr.responseText);
            
        
        xhr.open(args.method, args.url);
        //如果args中,contentType属性有内容,就设置Content-Type请求头
        if(args.contentType)//js中,if判断,除了判断boolean值,还可以判断字符串,对象等,有值就为true
            xhr.setRequestHeader("Content-Type", args.contentType);
        
        //如果args中,设置了body请求正文,调用send(body)
        if(args.body)
            xhr.send(args.body);
        else//如果没有设置,调用send()
            xhr.send();
        
    
</script>

后端代码:

@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
        // request.getInputStream 获取请求正文的数据 (不管Content-Type是什么类型,都可以获取)
        // 表单格式也可以使用此 API 获取,比较复杂
        // json是使用这个 api 比较典型的场景
        InputStream is = req.getInputStream();
        //先定义一个 byte 数组
        int len = req.getContentLength(); //也可以通过getHeader("Content-Length")获取,只是返回的是字符串相对麻烦一点
        byte[] bytes = new byte[len];
        is.read(bytes);
        System.out.println("获取的json数据:" + new String(bytes,"utf-8"));
    

重新启动,刷新页面:


输入用户名密码,提交:

后端打印内容:

可以抓包检查:

其实,拿到整个 json 字符串也不方便使用,如: 要判断账号密码是否正确
即:到目前为止,服务器拿到的 JSON 数据仍然是一个整体的 String 类型,若要想获取到 username 和 password 的具体值,还需要搭配 JSON 库进一步解析

常用的方式:使用第三方库
可以把 json字符串,转换为一个java对象;
还可以把一个java对象,转换为json字符串(响应的时候就有用)

引入 Jackson 这个库,进行 JSON 解析

  1. 在中央仓库中搜索 JackSon Databind

  1. 把中央仓库中的依赖配置添加到 pom.xml 中
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

修改后端代码:

@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
        InputStream is = req.getInputStream();
        ObjectMapper mapper = new ObjectMapper();
        // 简单暴力 直接转换为 map对象
        Map json = mapper.readValue(is, Map.class);
        System.out.println("获取的json字符串转换的map:" + json);
    

重新启动,刷新页面,提交数据,查看打印结果:


Map 使用其实也不太方便,若要使用指定的字符串键来获取值,再修改后端代码:

@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
        InputStream is = req.getInputStream();
        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.readValue(is,User.class)在Myeclipse buildpath 加server lib (server runtime)/项目导入时报错:The import javax.servlet.http.HttpServletR

Servlet中使用注解@Resource注入service,该怎么办

获取访问者的IP

Serverlet程序

天网恢恢Filter 窃听风云Listener

HttpServletRequest