目录
定义
二、HttpServletRequest基本功能
1.重要性
2.功能分类
3.获取请求头数据
方法
示例
结果:
4.其他请求相关方法
e.g
示例
结果:
三、HttpServletRequest获取参数
1.传递参数的方式
示例1
示例2(功能极为类似示例1)
2.获取参数的方法
单值参数接收
多值参数接收
3.中文乱码处理
四、请求转发重定向示例
1.向客户端响应数据(基础)
2.请求转发
3.利用重定向实现向客户端相应数据(两种方式:临时重定向&重定向)
五、高频面试题
转发和重定向的区别
1. 定义
请求转发(Forward)
重定向(Redirect)
2. 处理流程
3. 路径使用
相对路径
绝对路径
4. 其他区别
先前已经对请求转发和重定向(参见博客:请求转发和重定向_请求转发和重定向的代码-CSDN博客)有了核心基础的理解,而无论是请求转发还是重定向,它们都是基于请求响应模型的,所以这篇文章着重于请求对象和响应对象来做系统的梳理和示例演示。
一、Tomcat 请求与响应
定义
Web服务器收到客户端的HTTP请求后,会为每次请求创建一个request
对象和一个response
对象。
request
对象用于获取客户端提交的数据,response
对象用于向客户端输出数据。
二、HttpServletRequest基本功能
1.重要性
HttpServletRequest
是JavaWeb中非常重要的类,是Servlet的service()
方法的参数之一。
2.功能分类
作为域对象,可以存储和获取数据。
支持请求转发和重定向。
3.获取请求头数据
方法
getHeader(String name)
:获取指定名称的请求头。
getHeaderNames()
:获取所有请求头名称。
示例
通过getHeaderNames()
和getHeader()
遍历并输出所有请求头。
【注意:这里的项目用的是普通JavaWeb项目(不含maven的基础款),在这里我用的idea版本是2021版本,配置普通版本的JavaWeb项目需要创建普通Java项目后配置成JavaWeb项目(具体操作可以搜索相关文章),如果是用的2017版本的idea,那么配置JavaWeb基础项目有相关的选项,相较更为简单,但是2017版本的idea并没有自动导包的功能。】
java">package com.qcby.test;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;
/*** request对象的相关方法*/
@WebServlet(name = "Demo1Servlet",urlPatterns ="/demo1Servlet")
public class Demo1Servlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("doget.....");//获得请求头信息String accept = request.getHeader("Accept");System.out.println("Accept:"+accept );String ua = request.getHeader("User-Agent");System.out.println("User-Agent:"+ua);System.out.println("=====================================");//获取所有头信息Enumeration<String> names = request.getHeaderNames();while(names.hasMoreElements()){String name = names.nextElement();String value = request.getHeader(name);System.out.println(name+":"+value);}}
}
结果:
其实这里的结果就是请求标头里的内容:
4.其他请求相关方法
方法 | 描述 | 返回类型 |
---|---|---|
getContentLength() | 获取请求正文的字节数(GET请求无正文,返回-1)。 | int |
getContentType() | 获取请求的类型(如application/x-www-form-urlencoded )。 | String |
getMethod() | 获取请求方法(如GET 、POST 、PUT 、DELETE 等)。 | String |
getLocale() | 获取客户端浏览器支持的语言环境(java.util.Locale 对象)。 | Locale |
getCharacterEncoding() | 获取请求的编码(默认为ISO-8859-1 ,未设置时返回null )。 | String |
setCharacterEncoding(String code) | 设置请求的编码(仅对POST请求的正文有效)。 | void |
getContextPath() | 获取上下文路径(如/项目名称 )。 | String |
getQueryString() | 获取请求URL中的参数部分(如name=zhangSan )。 | String |
getRequestURI() | 获取请求的URI路径(如/hello/oneServlet )。 | String |
getRequestURL() | 获取完整的请求URL路径(不包括参数部分)。 | StringBuffer |
getServletPath() | 获取Servlet的路径(如/oneServlet )。 | String |
getRemoteAddr() | 获取客户端的IP地址。 | String |
getRemoteHost() | 获取客户端的主机名(通常返回IP地址)。 | String |
getRemotePort() | 获取客户端的端口号。 | int |
getScheme() | 获取请求协议(如http 或https )。 | String |
getServerName() | 获取服务器的主机名(如localhost )。 | String |
getServerPort() | 获取服务器的端口号(如80 或8080 )。 | int |
e.g
示例
获取HTTP请求的各种信息
java">package com.qcby.test;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(name = "Demo2Servlet",urlPatterns = "/demo2Servlet")
public class Demo2Servlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().write("request.getContentLength(): " + request.getContentLength());response.getWriter().write("request.getContentType(): " + request.getContentType());response.getWriter().write("request.getContextPath(): " + request.getContextPath());response.getWriter().write("request.getMethod(): " + request.getMethod());response.getWriter().write("request.getLocale(): " + request.getLocale());response.getWriter().write("request.getQueryString(): " + request.getQueryString());response.getWriter().write("request.getRequestURI(): " + request.getRequestURI());response.getWriter().write("request.getRequestURL(): " + request.getRequestURL());response.getWriter().write("request.getServletPath(): " + request.getServletPath());response.getWriter().write("request.getRemoteAddr(): " + request.getRemoteAddr());response.getWriter().write("request.getRemoteHost(): " + request.getRemoteHost());response.getWriter().write("request.getRemotePort(): " + request.getRemotePort());response.getWriter().write("request.getScheme(): " + request.getScheme());response.getWriter().write("request.getServerName(): " + request.getServerName());response.getWriter().write("request.getServerPort(): " + request.getServerPort());}
}
结果:
三、HttpServletRequest获取参数
1.传递参数的方式
GET请求:
-
地址栏传递参数。
-
超链接传递参数。
-
表单传递参数。
POST请求:
-
表单传递参数。
示例1
获取和打印通过GET和POST方法发送的HTTP请求参数
java">package com.qcby.test;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.Arrays;
import java.util.Enumeration;
import java.util.Map;/*** request对象获取请求参数*/
@WebServlet(name = "Demo3Servlet",urlPatterns = "/demo3Servlet")
public class Demo3Servlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取get请求的参数String username = request.getParameter("username");String passsword = request.getParameter("password");System.out.println(username+" : "+passsword);Enumeration<String> names = request.getParameterNames();while(names.hasMoreElements()){String name = names.nextElement();String value = request.getParameter(name);System.out.println(name+":"+value);}}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");//前端传过来的都是String类型0String password = request.getParameter("password");System.out.println(username+" : "+password);String[] happy = request.getParameterValues("happy");System.out.println("happy:"+ Arrays.toString(happy));//第二种方式 获得到请求参数k和vMap<String, String[]> map = request.getParameterMap();//遍历所有键值对的键keyfor (String key : map.keySet()) {String[] values = map.get(key);System.out.println(key+":"+Arrays.toString(values));}}
}
假设有一个表单(可以将它写在JavaWeb项目运行后默认打开的index.jsp文件的<body>部分):
<form action="/项目名/demo3Servlet" method="post"><input type="text" name="username" value="user1"><input type="password" name="password" value="pass123"><input type="checkbox" name="happy" value="yes">Happy<input type="checkbox" name="happy" value="no">No Happy<input type="submit" value="Submit">
</form>
即:
当用户填写表单并提交时,
doPost方法会被触发,打印出以下内容:
但是普通情况下输入“localhost:8080/requestDemo/demo3Servlet?username=user1&password=pass123”(即走doGet()方法实现)
得到结果:
示例2(功能极为类似示例1)
java">package com.qcby.test;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.Arrays;
import java.util.Enumeration;
import java.util.Map;/*** request对象获取请求参数*/
@WebServlet(name = "Demo4Servlet",urlPatterns = "/demo4Servlet")
public class Demo4Servlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//post请求解决乱码request.setCharacterEncoding("UTF-8");String username = request.getParameter("username");//传统解决乱码问题//username=new String(username.getBytes("ISO-8859-1"),"UTF-8");System.out.println(username);System.out.println("================================================");//第二种方式 获得到请求参数k和vMap<String, String[]> map = request.getParameterMap();//遍历所有键值对的键keyfor (String key : map.keySet()) {String[] values = map.get(key);System.out.println(key+":"+Arrays.toString(values));}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取get请求的参数//get请求在tomcat8.5以上不会乱码,7.0以下需要使用传统方式解码String username = request.getParameter("username");System.out.println(username);System.out.println("=====================================");Enumeration<String> names = request.getParameterNames();while(names.hasMoreElements()){String name = names.nextElement();String value = request.getParameter(name);System.out.println(name+":"+value);}}
}
结果:
2.获取参数的方法
getParameter(String name)
:获取单个参数值。
getParameterValues(String name)
:获取多个参数值。
getParameterNames()
:获取所有参数名称。
getParameterMap()
:获取所有参数的Map。
单值参数接收
通过getParameter()
获取表单提交的单值参数。
多值参数接收
通过getParameterValues()
获取表单提交的多值参数(如复选框)。
3.中文乱码处理
POST请求:
-
手动转码:先使用
ISO-8859-1
获取字节数组,再用UTF-8
解码。 -
设置编码:调用
setCharacterEncoding("UTF-8")
。
GET请求:
-
手动转码:与POST请求类似。
-
服务器配置:在Tomcat的
server.xml
中设置URIEncoding="UTF-8"
。 -
注意:Tomcat 8.5及以上版本默认支持URL传递中文。
四、请求转发重定向示例
1.向客户端响应数据(基础)
java">package com.qcby.test;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(name = "RedpondrServlet1",urlPatterns = "/redpondrServlet1")
public class RedpondrServlet1 extends HttpServlet {//父类HttpServlet是抽象类并且包含抽象方法,那么继承该抽象类的子类必须实现父类中的所有抽象方法,否则子类也必须被声明为抽象类。protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");//用字符的方式响应数据 字符流 中文出现乱码response.getWriter().write("<h3>你好,世界!!</h3>"); //响应附带格式response.getWriter().write("你好,世界!!");}
}
得到结果:
2.请求转发
java">package com.qcby.test;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;/*** request对象获取请求参数*/
@WebServlet(name = "Demo5Servlet",urlPatterns = "/demo5Servlet")
public class Demo5Servlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");System.out.println(username);request.setAttribute("username","haha");request.getRequestDispatcher("/index.jsp").forward(request,response);System.out.println("========================================");}
}
请求转发可以转发到任意的内部类(具体转发到哪里可以自行更改选择一个内部界面或其他)。
3.利用重定向实现向客户端相应数据(两种方式:临时重定向&重定向)
java">package com.qcby.test;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(name = "RedpondrServlet2",urlPatterns = "/redpondrServlet2")
public class RedpondrServlet2 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/*** 第一种原理方式* 1,设置状态码 setStatus(302);* 2,设置响应头,重定向的请求地址 setHeader(location,/success.html)* 注意:地址的写法与请求转发不同因为重定向可以跨项目 地址两种写法1,绝对路径2,相对路径* 第二种方法* 重定向方式第二种自动设置状态码和头* response.sendRedirect("/success.html");*/response.setStatus(302); //状态码 302:告诉客户端这是一个临时重定向。response.setHeader("location","http://www.chaoxing.com"); //响应头 Location:告诉客户端跳转到 http://www.chaoxing.com。//重定向方式第二种自动设置状态码和头//response.sendRedirect("/success.html");
// response.sendRedirect("http://www.chaoxing.com"); //普通重定向}
}
结果(跳转超星平台):
五、高频面试题
转发和重定向的区别
1. 定义
请求转发(Forward)
-
在服务器内部将请求从一个Servlet转发到另一个Servlet或JSP页面。
-
是服务器端的跳转,客户端浏览器地址栏不会发生变化。
重定向(Redirect)
-
服务器通知客户端浏览器访问另一个地址,客户端浏览器重新发起请求。
-
是客户端的跳转,地址栏会显示新的地址。
2. 处理流程
流程 | 请求转发 | 重定向 |
---|---|---|
客户端发送请求 | 客户端发送请求到Servlet A | 客户端发送请求到Servlet A |
Servlet处理 | Servlet A 调用request.getRequestDispatcher().forward(request, response) | Servlet A 调用response.sendRedirect("目标地址") |
服务器操作 | 服务器内部将请求转发到目标资源(Servlet B或JSP页面) | 服务器返回一个302状态码和目标地址给客户端 |
客户端操作 | 客户端浏览器地址栏不变,显示目标资源内容 | 客户端浏览器根据目标地址重新发起请求,地址栏更新为新地址 |
3. 路径使用
相对路径
-
转发和重定向中,相对路径的使用没有区别。
绝对路径
重定向
-
/
表示服务器的根目录(如Tomcat的根目录)。 -
示例:
response.sendRedirect("/WebModule/login.jsp")
,表示访问http://[hostname]:[port]/WebModule/login.jsp
。
请求转发
-
/
表示当前Web应用程序的根目录。 -
示例:
request.getRequestDispatcher("/login.jsp").forward(request, response)
,表示访问当前应用下的/login.jsp
。
4. 其他区别
区别点 | 请求转发 | 重定向 |
---|---|---|
地址栏变化 | 地址栏不变 | 地址栏更新为新地址 |
请求次数 | 整个过程属于同一个请求 | 客户端会向服务器发送两个请求 |
数据共享 | 可以通过request 作用域传递数据(request.setAttribute() ) | 无法使用request 作用域,只能通过session 或cookie 传递数据 |
效率 | 更高效,因为只涉及一次请求 | 相对低效,因为需要两次请求 |
跨域访问 | 不能跨域,仅限于当前Web服务器内部 | 可以跨域访问,客户端可以访问其他服务器 |
方法调用 | 使用RequestDispatcher.forward() ,属于HttpServletRequest | 使用response.sendRedirect() ,属于HttpServletResponse |
同源策略 | 不涉及同源策略问题 | 可能涉及同源策略问题(如跨域访问) |