JavaWeb核心篇(2)——Request和Response
JavaWeb核心篇(2)——Request和Response
上篇文章中提及到了Servlet,在Servlet中我们主要继承了HTTPServlet类,在HTTPServlet类中我们会接触到两个对象
这篇文章主要介绍Servlet中使用的Request和Respnse对象
简单介绍
首先我们先了解一下客户端与服务端之间信息如何传递:
从上图,我们可以看到:
- 客户端发送请求,而请求是以HTTP请求数据格式进行发送,因而Servlet就创建了一个Request类来封装这些接收数据
- 服务端给出响应,而响应是以HTTP响应数据格式进行发送,因而Servlet就创建了一个Response类来封装这些返回数据
简单来说:
- Request对象:获得请求数据
- Response对象:设置响应数据
Request介绍
我们在介绍Request之前,应当先了解一下Request的继承体系:
我们可以看到HttpServletRequest是基于ServletRequest接口创建的针对Http协议的请求对象接口
我们在使用Request对象时,也常常使用HttpServletRequest接口
Request获得请求数据
Request对象被创建的主要目的就是获得请求数据
我们将根据HTTP请求数据对象的三种格式分开介绍获得请求数据方法
- 请求行:
请求行格式:
GET/request-demo/req1?username=zhangsan HTTP/1.1
请求行获得代码:
函数 | 解释 |
---|---|
String getMethod() | 获得请求方式(GET/POST) |
String getContextPath() | 获得虚拟目录(项目访问路径):/request-demo |
StringBuffer getRequestURL() | 获得URL(统一资源定位符):http://localhost:8080/request-demo/req1 |
String getRequestURI() | 获得URI(统一资源标识符):/request-demo/req1 |
String getQueryString | 获得请求参数(GET方法):username=zhangsan HTTP/1.1 |
- 请求头:
请求头格式:
User-Agent: Mozilla/5.0 Chrome/91.0.4472.106
请求头获得代码:
函数 | 解释 |
---|---|
String getHeader(String name) | 根据请求头名称,获得值 |
- 请求体:
请求体格式:
username=superbaby&password=123456
请求体获得代码:
函数 | 解释 |
---|---|
ServletInputStream getInputStream() | 获得字节输入流 |
BufferedReader getReader() | 获得字符输入流 |
最后给出代码展示:
package com.itheima.web.request;
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.BufferedReader;
import java.io.IOException;
/**
* request 获取请求数据
*/
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// String getMethod():获取请求方式: GET
String method = req.getMethod();
System.out.println(method);//GET
// String getContextPath():获取虚拟目录(项目访问路径):/request-demo
String contextPath = req.getContextPath();
System.out.println(contextPath);
// StringBuffer getRequestURL(): 获取URL(统一资源定位符):http://localhost:8080/request-demo/req1
StringBuffer url = req.getRequestURL();
System.out.println(url.toString());
// String getRequestURI():获取URI(统一资源标识符): /request-demo/req1
String uri = req.getRequestURI();
System.out.println(uri);
// String getQueryString():获取请求参数(GET方式): username=zhangsan
String queryString = req.getQueryString();
System.out.println(queryString);
//------------
// 获取请求头:user-agent: 浏览器的版本信息
String agent = req.getHeader("user-agent");
System.out.println(agent);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取post 请求体:请求参数
//1. 获取字符输入流
BufferedReader br = req.getReader();
//2. 读取数据
String line = br.readLine();
System.out.println(line);
}
}
Request通用方式获得请求参数
在请求参数的获取方法上GET与POST有所不同:
- GET:String getQueryString()
- POST: BufferedReader getReader()
那么如果我们能够采用一种方法同时使GET和POST获得参数,就可以实现两者的通用
Request对此提供了一下方法:
函数 | 解释 |
---|---|
Map<String,String[]> getParameterMap() | 获得所有参数Map的集合 |
String[] getParametervalues(String name) | 根据名称获得参数值(数组) |
String getParameter(String name) | 根据名称获得参数值 |
我们给出通用方法,并做出解释:
package com.itheima.web.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Map;
/**
* request 通用方式获取请求参数
*/
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求逻辑
//System.out.println("get....");
//1. 获取所有参数的Map集合
Map<String, String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
// username:zhangsan lisi
System.out.print(key+":");
//获取值
String[] values = map.get(key);
for (String value : values) {
System.out.print(value + " ");
}
System.out.println();
}
System.out.println("------------");
//2. 根据key获取参数值,数组(我们希望查询参数为hobby的值,在查询中hobby的值为1,2)
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3. 根据key 获取单个参数值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//POST请求逻辑
// 因为两者可以共用一个方法,所以doPost直接调用doGet即可
this.doGet(req,resp);
/*System.out.println("post....");
//1. 获取所有参数的Map集合
Map<String, String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
// username:zhangsan lisi
System.out.print(key+":");
//获取值
String[] values = map.get(key);
for (String value : values) {
System.out.print(value + " ");
}
System.out.println();
}
System.out.println("------------");
//2. 根据key获取参数值,数组
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3. 根据key 获取单个参数值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);*/
}
}
请求参数中文化导致乱码问题
当我们的请求参数中如果存在中文数据,可能会出现乱码(Tomcat8以下版本)
我们分别介绍POST和GET的中文乱码解决方案
- POST:
首先我们从根本上解释一下为什么会出现乱码:
- POST底层以getReader()的方式以ISO-8859-1的形式获得输入流
//1. 解决乱码:POST,getReader()
// 默认情况下POST以ISO-8859-1的形式获取流
// POST中可以直接设置字符输入流的编码
// request.setCharacterEncoding() 改变字符输入流的获得格式
request.setCharacterEncoding("UTF-8");
- GET:
首先我们从根本上解释一下为什么会出现乱码:
- 当HTML识别到内容后,会以UTF-8的形式进行编码,并发送给服务端
- 但服务端在接收到数据后,会以ISO-8859-1的形式进行解码
- 编码解码方式不同,对中文的处理方式不同,导致中文数据出现乱码
// 我们以一个例子来模拟GET乱码的解决过程
package com.itheima.web.request;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class URLDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String username = "张三";
// 1.2步模拟了乱码过程;3,4步解决乱码过程
//1. URL编码(HTML传递)
//URLEncoder.encode(username, "utf-8");表示对username进行utf-8形式的编码,形成code
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);
//2. URL解码
//URLDecoder.decode(encode, "ISO-8859-1");表示对encode进行ISO-8859-1形式的解码,形成decode
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode);
//3. 转换为字节数据,编码
byte[] bytes = decode.getBytes("ISO-8859-1");
//4. 将字节数组转为字符串,解码
String s = new String(bytes, "utf-8");
System.out.println(s);
}
}
因为GET的方法属于通用方法,所以在整个项目中可以直接通过第二种方法来进行GET和POST的中文乱码修改问题
package com.itheima.web.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* 中文乱码问题解决方案
*/
@WebServlet("/req4")
public class RequestDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 解决乱码:POST,getReader()
//request.setCharacterEncoding("UTF-8");//设置字符输入流的编码
//2. 获取username
String username = request.getParameter("username");
System.out.println("解决乱码前:"+username);
//3. GET,获取参数的方式:getQueryString
// 乱码原因:tomcat进行URL解码,默认的字符集ISO-8859-1
/* //3.1 先对乱码数据进行编码:转为字节数组
byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
//3.2 字节数组解码
username = new String(bytes, StandardCharsets.UTF_8);*/
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
System.out.println("解决乱码后:"+username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
Request请求转发
首先讲解一下请求转发的概念:
- 请求转发:一种在服务器内部的资源跳转方法
- 当客户端发送请求后,服务端可以选择把这个请求转发出去或者说是共享出去
实现方式:
req.getRequestDispatcher("资源B地址").forward(req,resp)
实现所需函数:
函数 | 解释 |
---|---|
void setAttribute(String name,Object o) | 存储数据到request域(一般在资源A地址存储) |
Object getAttribute(String name) | 根据key,获得value(一般在资源B地址存储) |
void removeAttribute(String name) | 根据key,删除该键值对 |
请求转发特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器的内部资源
- 一次请求,可以在转发的资源间使用request共享数据
我们给出两个/demo服务器端进行模拟:
// 客户端资源A
package com.itheima.web.request;
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.nio.charset.StandardCharsets;
/**
* 请求转发
*/
@WebServlet("/req5")
public class RequestDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo5...");
System.out.println(request);
//存储数据
request.setAttribute("msg","hello");
//请求转发
request.getRequestDispatcher("/req6").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
// 客户端资源B
package com.itheima.web.request;
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("/req6")
public class RequestDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo6...");
System.out.println(request);
//获取数据
Object msg = request.getAttribute("msg");
System.out.println(msg);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
Response介绍
同样,我们也来介绍一下Response的体系结构:
我们在使用Response时,也以HttpServletResponse为主
设置响应数据
和获取数据相同,我们把函数根据响应数据的三部分分别展示:
- 响应行:
响应行格式:
HTTP/1.1 200 OK
响应行设置函数:
函数 | 解释 |
---|---|
void setStatus(int sc) | 设置响应状态码 |
- 响应头:
响应头格式:
Content-Type:text/html
响应头设置函数:
函数 | 解释 |
---|---|
void setHeader(String name,String value) | 设置响应头键值对 |
- 响应体:
响应体格式:
<html><head></head><body></body></html>
响应体设置函数:
函数 | 解释 |
---|---|
PrintWriter getWriter() | 获得字符输出流 |
ServletOutputStream getOutputStream() | 获得字节输出流 |
下面给出代码示例:
package com.itheima.web.response;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1....");
//1.设置响应状态码 302
response.setStatus(302);
//2. 设置响应头 Location
response.setHeader("Location","/request-demo/resp2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
重定位
首先我们介绍一下重定位:
- 重定位:一种资源跳转方式
- 客户端向服务器A发出请求,当该资源A无法满足客户端发出的请求,资源A返回响应(响应码302表示无法处理,并给出响应头location:xxx告诉客户端应该去哪个资源B解决问题),然后客户端再向资源B发送请求,由资源B来设置响应数据
实现方式:
resp.setStatus(302);
resp.setHeader("location","资源B的路径")
resp.sendRedirect("资源B的路径")
重定位特点:
- 浏览器地址栏路径发生变化
- 可以重定位到任意位置的资源(服务器内部,外部均可以)
- 两次请求,不能在多个资源使用request共享数据
下面给出代码示例:
package com.itheima.web.response;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1....");
//重定向
/*//1.设置响应状态码 302
response.setStatus(302);
//2. 设置响应头 Location
response.setHeader("Location","/request-demo/resp2");*/
//简化方式完成重定向
//动态获取虚拟目录
String contextPath = request.getContextPath();
// 这里资源B的路径是虚拟目录+设置名
response.sendRedirect(contextPath+"/resp2");
//response.sendRedirect("https://www.itcast.cn");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
资源路径问题:
浏览器使用:需要加虚拟目录(项目访问路径)
服务端使用:不需要加虚拟目录
目前已学习内容:
resp.sendRedirect("路径") : 加虚拟目录
req.getRequestDispatcher("路径") : 不加虚拟目录
这里附上链接:01-Request和Response介绍&Request继承体系_哔哩哔哩_bilibili
JavaWeb核心篇(2)——Request和Response的更多相关文章
- JavaWeb核心篇(3)——JSP,MVC,三层架构
JavaWeb核心篇(3)--JSP,MVC,三层架构 在本篇文章中我们会学习到JSP,MVC,三层架构 虽然JSP已经快被时代所淘汰,但是在一些老旧的工作场所还是有在使用,所以了解一下也不为过 至于 ...
- javaWeb中 servlet 、request 、response
1.Servlet (1)Servlet是JavaEE的一个动态web资源开发技 术,就是在服务器上运行的小程序,这个小程序是由服务器调用的,服务器为了能调用这个小程序,就要求这样的程序必须实现一个S ...
- Servlet第三篇【request和response简介、response的常见应用】
response.request对象 Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象.和代表响应的response对象 既然request对象代表ht ...
- 第十五节:HttpContext五大核心对象的使用(Request、Response、Application、Server、Session)
一. 基本认识 1. 简介:HttpContext用于保持单个用户.单个请求的数据,并且数据只在该请求期间保持: 也可以用于保持需要在不同的HttpModules和HttpHandlers之间传递的值 ...
- JavaWeb学习总结(三)response与request
一.response response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse.在客户端发出每个请求时,服务器 ...
- JavaWeb学习篇之----容器Request详解
前篇说到了Response容器对象,这篇我们就来看一下Request容器对象,之前也说过了,这个两个容器对象是相对应的,每次用户请求服务器的时候web容器就会给创建这对容器对象,他们是共存亡的,当然R ...
- JavaWeb(一)Servlet中的request与response
一.HttpServletRequest概述 1.1.HttpServletRequest简介 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP ...
- JavaWeb学习笔记四 request&response
HttpServletResponse 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应res ...
- JavaWeb Request和Response
1. Request与Response 1.1. Web应用运行机制 到目前为止,我们已经掌握了Web应用程序的运行机制,现在学习的就是Web应用程序运行机制中很重要的内容 —— Request与Re ...
随机推荐
- RPA应用场景-报税机器人
场景概述 报税机器人 所涉系统名称 税务网站 人工操作(时间/次) 53分钟 所涉人工数量 60 操作频率 每月 场景流程 1.通过RPA自动将财税信息从对应系统中导出 2.RPA根据不同的税务报表规 ...
- centos通过日志查入侵
1. Linux查看/var/log/wtmp文件查看可疑IP登陆 last -f /var/log/wtmp 该日志文件永久记录每个用户登录.注销及系统的启动.停机的事件.因此随着系统正常运行时间的 ...
- rhel6下eth1恢复eth0
问题:VMware 虚拟机中,从模板克隆出来的虚拟机的网卡名都会变成为eth1,而程序或者脚本,默认网卡是eth0,这时需要将eth1改为eth0. 原因:/etc/udev/rules.d/70-p ...
- python小题目练习(13)
题目:封装用户的上网行为 实现代码: """Author:mllContent:封装用户的上网行为Date:2020-01-19"""def ...
- python常见的错误提示处理
python常见的错误有 NameError变量名错误 IndentationError代码缩进错误 AttributeError对象属性错误 TypeError类型错误 IOError输入输出错误 ...
- Docker部署jar包运行
1.上传jar包到服务器 2.在该目录下创建Dockerfile 文件 vi Dockerfile 3.然后将下面的内容复制到Dockerfile文件中 FROM java:8 MAINTAINER ...
- antd vue 折叠面板 v-for 循环点击无效
问题描述 实现一个折叠面板点击展开,但是必须点击两次才能展开,第一次无效 <a-collapse-panel v-for="(item, index) in dataMap" ...
- C++对象的应用
本篇文章将介绍对象数组,对象的动态分配以及对象在函数中的应用. 一.对象数组 1.对象数组的定义和初始化 定义对象数组与定义普通数组的语法形式基本相同.如定义一个Square obj[3]:表示一个正 ...
- WPS前骨干历时10年打造新型软件,Excel用户:我为此改用WPS
办公软件本质是降本增效,我们常见的金山WPS软件.微软office Excel.仓库管理WMS.生产管理MES等都是如此,但是有一款软件却让人变得更"懒惰",而且还是针对于有进取心 ...
- fpga中的存储器
fpga中的存储器三种:RAM,ROM,FIFO. RAM和ROM已经比较熟悉了,记录一下FIFO. FIFO:first in first out ,顺序存取,先入先出.是一种数据缓存器,用来作不同 ...