Request(请求) :
Request:获取请求数据
Response:设置响应数据
Request继承体系:
使用request对象,查阅JavaEE API文档的HttpServeltRequest接口
Tomcat需要解析请求数据,封装为request对象,并且创建requests对象传递到service方法中,验证如下:
创建Servlet并输出HttpServletRequest的包名:
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("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
输出结果如下:
Request获取请求数据:
请求行:
GET/request-demo/req1?username=zhangsan HTTP/1.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("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求方式的获取方法:String getMethod()
String method=req.getMethod();
System.out.println(method);
//虚拟目录 (项目访问路径)的获取方法:StringgetContextPath()
String contextPath=req.getContextPath();
System.out.println(contextPath);
//URL(统一资源标识符)的获取方法:String getRequestURL()
StringBuffer url=req.getRequestURL();
System.out.println(url);
//访问路径的完整目录
String uri=req.getRequestURI();
System.out.println(uri);
//请求参数的获取方法:String getQueryString()
String queryString=req.getQueryString();
System.out.println(queryString);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
点击运行后在网页中输入请求参数以及访问路径:
输出如下:
请求头:
User-Agent:Mozilla/5.0 Chrome/91.0.4472.106
String getHeader(String name):根据请求头名称,获取值
举例:
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("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求头:user-agent:浏览器的版本信息
String agent=req.getHeader("user-agent");
System.out.println(agent);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
获取的信息如下:
请求体:
username=superbaby&password=123
ServletInputStream getInputStream():获取字节输入流
BufferedReader getReader():获取字符输入流
举例:
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;
@WebServlet("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取post 请求体:请求参数
//1.获取字符输入流
BufferedReader br=req.getReader();
//读取数据
String line=br.readLine();
System.out.println(line);
}
}
a.html文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/mymavenweb4/demo4" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>
</body>
</html>
在网页中,输入下述内容:
点击回车,我们发现此时的路径变为了demo4,表示将上述数据提交到了路径为demo4的文件中
输出内容如下所示:
通过上述的方法我们知道GET获取请求参数是通过getQueryString()方法,而POST方式获取请求参数是通过getReader()方法,那么是否存在一种统一获取请求参数的方式,从而统一doGet和doPOST方法内的代码呢?
如下所示:
当我们获取到请求方式后,首先对其进行判断,如果是GET,则使用GET方式获取请求参数,反之使用POST
获取到值之后,request会将字符串进行解析。如下所示:
得到上述这些键值对后,request会将其存放在一个集合中,很多情况下,一个键值对中的值不止有一个,针对这种情况,request对于键值部分是采用字符数组的形式
Map<String,String[]> getParameterMap():获取所有参数Map集合
举例:
创建servlet类:
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.Map;
@WebServlet("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//get请求逻辑
System.out.println("get.......");
//获取所有参数map的集合
Map<String,String[]> map=req.getParameterMap();
for(String key:map.keySet()){
//username:zhangsan lisi
System.out.println(key+":");
//获取值
String[] values=map.get(key);
for(String value:values){
System.out.println(value+" ");
}
System.out.println();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
创建web文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/mymavenweb4/demo4" method="get">
<input type="text" name="username">
<input type="password" name="password">
<input type="checkbox" name="hobby" value="1">游泳
<input type="checkbox" name="hobby" value="2">爬山
<input type="submit">
</form>
</body>
</html>
运行后在网页中输入以下内容:
点击回车后,出现以下内容:
控制台输出:
String[] getParameterValues(String name):根据名称获取参数值(数组)
在上述创建的servlet类的doGET方法中加入如下代码:
//根据key获取参数值,数组
String[] hobbies=req.getParameterValues("hobby");
for(String hobby:hobbies) {
System.out.println(hobby);
}
运行,在网页中输入如下内容:
回车后我们发现,未填写值的部分获取到的为空字符串
控制台输出:
String getParamter(String name):根据名称获取参数值(单个值)
在上述创建的servlet类的doGET方法中加入如下代码:
//根据key获取单个参数值
String username=req.getParameter("username");
String password=req.getParameter("password");
System.out.println("获取到的单个参数值为:");
System.out.println(username);
System.out.println(password);
运行,在网页中输入如下内容:
回车:
控制台输出:
那么上述的这些方法是否也可用用于POST请求方式呢?
验证如下:
1:将刚在doget方法中书写的获取值的核心部分代码复制至dopost方法中,代码如下所示
//post请求逻辑
System.out.println("post.......");
//获取所有参数map的集合
Map<String,String[]> map=req.getParameterMap();
for(String key:map.keySet()){
//username:zhangsan lisi
System.out.println(key+":");
//获取值
String[] values=map.get(key);
for(String value:values){
System.out.println(value+" ");
}
}
System.out.println();
//根据key获取参数值,数组
String[] hobbies=req.getParameterValues("hobby");
System.out.println("获取到的参数值为:");
for(String hobby:hobbies) {
System.out.println(hobby);
}
//根据key获取单个参数值
String username=req.getParameter("username");
String password=req.getParameter("password");
System.out.println("获取到的单个参数值为:");
System.out.println(username);
System.out.println(password);
第二步:将web文件中的method改为post
运行后在网页中输入如下内容:
点击回车,我们发现这里并没有显示我们刚输入的值,则证明为post请求方式:
控制台输出:
验证成功说明上述方法对于post请求和get请求均适用!
既然代码都是完全相同的,那么我们不必同样的代码书写两边,修改如下:
//当为post请求方式时,我们只需要调用doget方法
this.doGet(req,resp);
验证如下:
运行后在网页中输入如下内容:
回车,确实为post请求方式:
控制台输出:
这样也能够正确使用不同的请求方式,并且这种方式代码量更少!
解决中文乱码问题:
当我们在表单中填写的值为中文时,会出现乱码问题,而这种乱码问题与请求方式是没有关系的,无论是post还是get都会出现乱码问题
举例:
控制台输出:
解决POST请求方式出现的乱码问题:使用setCharacterEncoding设置字符输入流
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("/demo4")
public class Myservlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//一定要写在第一行!!!
req.setCharacterEncoding("UTF-8");//设置字符输入流的编码
String username=req.getParameter("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
乱码问题被解决:
如果还没有解决的小伙伴请检查自己web文件中的请求方式是不是错写成get了,或者可以试试设置为GBK
解决GET请求方式出现的乱码问题:
如下所示:
<configuration>
<uriEncoding>${project.build.sourceEncoding}</uriEncoding>
</configuration>
Request请求转发:
请求转发[forword]:一种在服务器内部的资源跳转方式
实现方式:req.getRequestDispatcher("资源B路径").forword(req,resp);
举例:
新创建Myservlet5类:
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("/demo5")
public class Myservlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo5.............");
//请求转发---我们所能改变的内容为转发的资源路径,也就是下一个要执行的servlet类
req.getRequestDispatcher("/demo6").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
新创建Myservlet6类:
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("/demo6")
public class Myservlet6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo6.............");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
打开浏览器访问demo5,控制台输出如下:
请求转发资源共享数据,使用Request对象:
void setAttribute(String name,Object o):存储数据到request域中
Object getAttribute(String name):根据key,获取值
void removeAttribute(String name):根据key,删除该键值对
在上述创建的Myservlet5和Myservlet6的基础上进行如下步骤:
举例:
1:在Myservlet5中添加数据
在Myservlet6中添加下述代码:
打开浏览器访问demo5,控制台输出:
请求转发特点:
浏览器地址栏路径不发生变化
只能转发到当前服务器的内部资源
一次请求,可以在转发的资源间使用request共享数据
Response(响应):
Response:设置响应数据功能介绍
响应数据分为3部分:
1:响应行:HTTP/1.1 200 OK
void setStatus(int sc):设置响应状态码
2:响应头:Content-Type:text/html
void setHeader(String name,String value):设置响应头键值对
3:响应体<html><head><head><body></body></html>
PrintWriter getWriter():获取字符输出流
ServeltOutputStream getOutputStream():获取字节输出流
重定向:一种资源跳转方式
实现方式:
resp.setStatus(302);
resp.setHeader("location","资源B的路径");
举例:
创建MyResponse1类:
package Response;
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("/res1")
public class MyResponse1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("res1..........");
//重定向
//1:设置响应状态码:302
resp.setStatus(302);
//设置响应头Location
resp.setHeader("Location","res2");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
创建MyResponse2类:
package Response;
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("/res2")
public class MyResponse2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("res2..........");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
当在浏览器访问res1:
回车,重定向至res2:
控制台输出:
如果有小伙伴的控制台只输出了res1,如下所示:
错误的原因为:响应头的路径书写错误,有可能是多加了“/”,有可能是忘记写虚拟路径,也就是项目的名称,我这里没写项目名称的原因是因为我的IDE为2021版本的,可以直接写另一个资源的名称
resp.setHeader("Location","res2");
除了上述方法可以进行重定向外,我们还可以使用下述这种简化的方式进行重定向,这种方法的输出结果上述完全相同
resp.sendRedirect("res2");
重定向的特点:
1:浏览器地址栏路径发生变化—>在上述案例中我们已经指出了
2:可以重定向到任意位置的资源(服务器内部,外部均可)
上述案例的资源即为服务器内部,我们也可以将其定位到服务器外部,如下所示,我们将重定向的路径定位至百度:
resp.sendRedirect("https://www.baidu.com/");
浏览器依然访问res1资源:
点击回车,浏览器地址栏路径发生不仅变为了百度的网址,而且页面也是跳转到了百度
3:两次请求,不能在多个资源使用request共享数据
由于浏览器发送了两次请求,是两个不同的request对象,就无法通过request对象进行共享数据
Resopnse响应字符数据:
使用:
1:通过Response对象获得字符输出流
PrintWriter writer=resp.getWriter();
2:写数据
writer.writer("aaa");
举例:
新建servlet类:
package Response;
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.io.PrintWriter;
@WebServlet("/res3")
public class MyResponse3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取字符输出流
//该流不需要关闭,当最后程序结束时,response对象被销毁的时候,该流自动关闭
PrintWriter writer=resp.getWriter();
writer.write("aaa");
writer.write("<h1>aaa</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
浏览器打开运行:
这样看似好像没什么问题,但仔细看,我们写入的<h1>aaa<h1>
的标签本质是想将其以标题的形式显示,但是这里并非如此,而是将其按照文本直接输出了,针对上述问题,解决方法如下:
//将其解析为html文件
resp.setHeader("content-type","text/html");
显示如下:
解决中文乱码问题:
上述实例中,我们所写的字符都是英文的,那么如果是中文的,会出现乱码问题吗?
测试如下:
writer.write("你好");
输出如下所示:
我们看到,你好此时被解析为了两个问号
针对上述问题的解决方法如下:
在doGET方法的第一行加入下述代码:
resp.setContentType("text/html;charset=utf-8");
输出如下:乱码被解决
Resopnse响应字节数据:
1:通过Response对象获取字符输出流
ServletOutputStream outputStream=resp.getOutputStream();
2:写数据
outputStream.write(字节数据);
举例:
package Response;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/res4")
public class MyResponse4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//读取文件
FileInputStream fileInputStream = new FileInputStream("E://开心的微笑.jpg");
//获取response字节输出流
ServletOutputStream os = resp.getOutputStream();
//完成流的copy
byte[] buff = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buff)) != -1) {
os.write(buff, 0, len);
}
fileInputStream.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
访问res4资源,显示如下:
上述流的copy只是为了巩固基础,为了简化代码,我们可以直接使用工具类,步骤如下:
首先在pom.xml文件中导入下述依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2:将上述中流copy的部分改为下述代码:
IOUtils.copy(fileInputStream,os);
在浏览器中再次访问res4资源,发现依然可以成功输出,但下述这种方式明显简单许多: