请求

请求对象

关于请求

顾名思义,意思就是请求一个“对象”

请求不到的,别想了

请求,就是使用者希望从服务器端索取一些资源,向服务器发出询问。在B/S架构中,就是客户浏览器向服务器发出询问。在JavaEE工程中,客户浏览器发出询问,要遵循HTTP协议规定。

请求对象,就是在JavaEE工程中,用于发送请求的对象。我们常用的对象就是ServletRequest和HttpServletRequest,它们的区别就是是否和HTTP协议有关。

常用请求对象

常用请求方法

请求对象的使用示例

常用方法一:请求各种路径

/*
获取路径的相关方法
*/
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取虚拟目录名称 getContextPath()
String contextPath = req.getContextPath();
System.out.println(contextPath); //2.获取Servlet映射路径 getServletPath()
String servletPath = req.getServletPath();
System.out.println(servletPath); //3.获取访问者ip getRemoteAddr()
String ip = req.getRemoteAddr();
System.out.println(ip); //4.获取请求消息的数据 getQueryString()
String queryString = req.getQueryString();
System.out.println(queryString); //5.获取统一资源标识符 getRequestURI() /request/servletDemo01
String requestURI = req.getRequestURI();
System.out.println(requestURI); //6.获取统一资源定位符 getRequestURL() http://localhost:8080/request/servletDemo01
StringBuffer requestURL = req.getRequestURL();
System.out.println(requestURL); } @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

常用方法二:获取请求参数以及封装(非常重要)

我们常常会使用HttpServletRequest对象获取请求参数,然后将其封装到实体类中

/*
获取请求参数信息的相关方法
*/
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.根据名称获取数据 getParameter()
String username = req.getParameter("username");
System.out.println(username);
String password = req.getParameter("password");
System.out.println(password);
System.out.println("--------------------"); //2.根据名称获取所有数据 getParameterValues()
String[] hobbies = req.getParameterValues("hobby");
for(String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("--------------------"); //3.获取所有名称 getParameterNames()
Enumeration<String> names = req.getParameterNames();
while(names.hasMoreElements()) {
String name = names.nextElement();
System.out.println(name);
}
System.out.println("--------------------"); //4.获取所有参数的键值对 getParameterMap()
Map<String, String[]> map = req.getParameterMap();
for(String key : map.keySet()) {
String[] values = map.get(key);
System.out.print(key + ":");
for(String value : values) {
System.out.print(value + " ");
}
System.out.println();
}
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

下面通过实例说明几种封装方式

需求:我们要实现从网页填写学生注册信息,然后把获取请求参数并把相应的信息封装到每一个Student类中。

第一步:编写一个页面html程序


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/request/servletDemo08" method="post" autocomplete="off">
姓名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
爱好:<input type="checkbox" name="hobby" value="study">学习
<input type="checkbox" name="hobby" value="game">游戏 <br>
<button type="submit">注册</button>
</form>
</body>
</html>

第二步:编写Student的javabean类,注意其数据成员最好(必须)与html文件表单的name属性一致

public class Student {
private String username;
private String password;
private String[] hobby; public Student() {
} public Student(String username, String password, String[] hobby) {
this.username = username;
this.password = password;
this.hobby = 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[] getHobby() {
return hobby;
} public void setHobby(String[] hobby) {
this.hobby = hobby;
} @Override
public String toString() {
return "Student{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", hobby=" + Arrays.toString(hobby) +
'}';
}
}

第三步:获取参数信息,并封装数据

法一:直接手动封装(简单粗暴)

/*
封装对象-手动方式
*/
@WebServlet("/servletDemo04")
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取所有的数据
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby"); //2.封装学生对象
Student stu = new Student(username,password,hobbies); //3.输出对象
System.out.println(stu); } @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

法二:通过反射封装

PropertyDescriptor: Describes a Java Bean property hosting validation constraints

调用javabean类的有参构造函数创建对象

构造函数 PropertyDescriptor(String,class); 注意第一个参数是javabean构造函数的第一个形式参数,第二个参数是已经创建的实类的字节码。

/*
封装对象-反射方式
*/
@WebServlet("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取所有的数据
Map<String, String[]> map = req.getParameterMap(); //2.封装学生对象
Student stu = new Student();
//2.1遍历集合
for(String name : map.keySet()) {
String[] value = map.get(name);
try {
//2.2获取Student对象的属性描述器
PropertyDescriptor pd = new PropertyDescriptor(name,stu.getClass());
//2.3获取对应的setXxx方法
Method writeMethod = pd.getWriteMethod();
//2.4执行方法
if(value.length > 1) {
writeMethod.invoke(stu,(Object)value);
}else {
writeMethod.invoke(stu,value);
}
} catch (Exception e) {
e.printStackTrace();
}
} //3.输出对象
System.out.println(stu); } @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

法三:BeanUtils工具类封装

BeanUtils.populate(stu,map);(实类,参数map)

/*
封装对象-工具类方式
*/
@WebServlet("/servletDemo06")
public class ServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取所有的数据
Map<String, String[]> map = req.getParameterMap(); //2.封装学生对象
Student stu = new Student();
try {
BeanUtils.populate(stu,map);
} catch (Exception e) {
e.printStackTrace();
} //3.输出对象
System.out.println(stu); } @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

用流的形式读取请求信息

/*
流对象获取数据
*/
@WebServlet("/servletDemo07")
public class ServletDemo07 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//字符流(必须是post方式)
/*BufferedReader br = req.getReader();
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}*/
//br.close(); //字节流
ServletInputStream is = req.getInputStream();
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1) {
System.out.println(new String(arr,0,len));
}
//is.close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

请求正文中中文编码问题

1.POST方式请求

问题:获取请求正文,会有乱码问题。是在获取的时候就已经乱码了。

解决:是request对象的编码出问题了。设置request对象的字符集

request.setCharacterEncoding("编码方式")它只能解决POST的请求方式,GET方式解决不了

/*
中文乱码
*/
@WebServlet("/servletDemo08")
public class ServletDemo08 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 {
doGet(req,resp);
}
}

2.GET方式请求

问题:GET方式:正文在地址栏username=%D5%C5%C8%FD%D5%C5%C8%FD是已经被编过一次码了

GET方式请求的正文是在地址栏中,在Tomcat8.5版本及以后,Tomcat服务器已经帮我们解决了,所以不会有乱码问题了。

而如果我们使用的不是Tomcat服务器,或者Tomcat的版本是8.5以前,那么GET方式仍然会有乱码问题,解决方式如下:

使用正确的码表对已经编过码的数据进行解码。就是把取出的内容转成一个字节数组,但是要使用正确的码表。(ISO-8859-1)再使用正确的码表进行编码,把字节数组再转成一个字符串,需要使用正确的码表,是看浏览器当时用的是什么码表。

/**
* 在Servlet的doGet方法中添加如下代码
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { String username = request.getParameter("username");
byte[] by = username.getBytes("ISO-8859-1");
username = new String(by,"GBK"); //输出到浏览器:注意响应的乱码问题已经解决了
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write(username);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

请求转发(与重定向的区别)

重定向特点:两次请求,浏览器行为,地址栏改变,请求域中的数据会丢失

请求转发:一次请求,服务器行为,地址栏不变,请求域中的数据不丢失

请求域的作用范围:当前请求(一次请求),和当前请求的转发之中

请求发送方:

/*
请求转发
*/
@WebServlet("/servletDemo09")
public class ServletDemo09 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置共享数据
req.setAttribute("encoding","gbk"); //获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/servletDemo10");
//实现转发功能
rd.forward(req,resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

请求接收方:

/*
请求转发
*/
@WebServlet("/servletDemo10")
public class ServletDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取共享数据
Object encoding = req.getAttribute("encoding");
System.out.println(encoding); System.out.println("servletDemo10执行了...");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

开启服务器后进入/servletDemo09之后会在控制台输出

encoding
servletDemo10执行了...

而此时浏览器的url依然是/servletDemo09,不会跳转

请求重定向

resp.sendRedirect(req.getContextPath() + "/servletDemo07");

请求发送方:

/*
请求重定向
*/
@WebServlet("/servletDemo06")
public class ServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求域数据
req.setAttribute("username","zhangsan"); //设置重定向
resp.sendRedirect(req.getContextPath() + "/servletDemo07"); // resp.sendRedirect("https://www.baidu.com");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

请求接收方:

/*
请求重定向
*/
@WebServlet("/servletDemo07")
public class ServletDemo07 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo07执行了...");
Object username = req.getAttribute("username");
System.out.println(username);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

请求包含

需求:把两个Servlet的内容合并到一起来响应浏览器

问题:HTTP协议的特点是一请求,一响应的方式。所以绝对不可能出现有两个Servlet同时响应方式。

解决:把两个Servlet的响应内容合并输出。

/*
请求包含
*/
@WebServlet("/servletDemo11")
public class ServletDemo11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo11执行了..."); //获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/servletDemo12");
//实现包含功能
rd.include(req,resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
/*
请求包含
*/
@WebServlet("/servletDemo12")
public class ServletDemo12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo12执行了...");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

控制台输出

servletDemo11执行了...

servletDemo12执行了...

而且浏览器的url依然是/servletDemo11,不会跳转

细节

请求转发的注意事项:负责转发的Servlet,转发前后的响应正文丢失,由转发目的地来响应浏览器。

请求包含的注意事项:被包含者的响应消息头丢失。因为它被包含起来了。

响应

响应对象

关于响应

服务器端收到请求,同时也已经处理完成,把处理的结果告知用户。

在B/S架构中,响应就是把结果带回浏览器。

常用响应对象

协议无关的对象标准是:ServletResponse接口

协议相关的对象标准是:HttpServletResponse接口

常用方法介绍

常用状态码:

状态码 说明
200 执行成功
302 它和307一样,都是用于重定向的状态码。只是307目前已不再使用
304 请求资源未改变,使用缓存。
400 请求错误。最常见的就是请求参数有问题
404 请求资源未找到
405 请求方式不被支持
500 服务器运行内部错误

状态码首位含义:

状态码 说明
1xx 消息
2xx 成功
3xx 重定向
4xx 客户端错误
5xx 服务器错误

响应对象的使用示例

字节流输出中文问题

项目中常用的编码格式是u8,而浏览器默认使用的编码是gbk。导致乱码!

解决方式一:修改浏览器的编码格式(不推荐,不能让用户做修改的动作)

解决方式二:通过输出流写出一个标签:response.getOutputStream().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>")

解决方式三:response.setHeader("Content-Type","text/html;charset=UTF-8"); 指定响应头信息

解决方式四:response.setContentType("text/html;charset=UTF-8"); (常用)

/*
字节流响应消息及乱码的解决
*/
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = "你好"; resp.setContentType("text/html;charset=UTF-8"); sos.write(str.getBytes("UTF-8"));
sos.close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

字符流输出中文问题

/*
字符流响应消息及乱码的解决
*/
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = "你好"; //解决中文乱码
resp.setContentType("text/html;charset=UTF-8"); //获取字符流对象
PrintWriter pw = resp.getWriter();
//pw.println(str);
pw.write(str);
pw.close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

响应图片到浏览器

/*
响应图片到浏览器
*/
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过文件的相对路径来获取文件的绝对路径
String realPath = getServletContext().getRealPath("/img/hm.png");
System.out.println(realPath);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath)); //获取字节输出流对象
ServletOutputStream sos = resp.getOutputStream(); //循环读写
byte[] arr = new byte[1024];
int len;
while((len = bis.read(arr)) != -1) {
sos.write(arr,0,len);
} bis.close();
sos.close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

控制缓存

resp.setDateHeader("Expires",(System.currentTimeMillis()+时间));

/*
缓存
*/
@WebServlet("/servletDemo04")
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String news = "这是一条很火爆的新闻~~"; //设置缓存时间
resp.setDateHeader("Expires",(System.currentTimeMillis()+1*60*60*1000L)); //设置编码格式
resp.setContentType("text/html;charset=UTF-8");
//写出数据
resp.getWriter().write(news);
System.out.println("aaa");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

定时刷新

resp.setHeader("Refresh","定时时间(秒);URL=/虚拟路径/页面路径");

/*
定时刷新
*/
@WebServlet("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String news = "您的用户名或密码错误,3秒后自动跳转到登录页面..."; //设置编码格式
resp.setContentType("text/html;charset=UTF-8");
//写出数据
resp.getWriter().write(news); //设置响应消息头定时刷新
resp.setHeader("Refresh","3;URL=/虚拟路径/login.html");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

文件下载

/*
文件下载
*/
@WebServlet("/servletDemo08")
public class ServletDemo08 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.创建字节输入流,关联读取的文件
//获取文件的绝对路径
String realPath = getServletContext().getRealPath("/img/hm.png");
//创建字节输出流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath)); //2.设置响应头支持的类型 应用支持的类型为字节流
/*
Content-Type 消息头名称 支持的类型
application/octet-stream 消息头参数 应用类型为字节流
*/
resp.setHeader("Content-Type","application/octet-stream"); //3.设置响应头以下载方式打开 以附件形式处理内容
/*
Content-Disposition 消息头名称 处理的形式
attachment;filename= 消息头参数 附件形式进行处理
*/
resp.setHeader("Content-Disposition","attachment;filename=" + System.currentTimeMillis() + ".png"); //4.获取字节输出流对象
ServletOutputStream sos = resp.getOutputStream(); //5.循环读写文件
byte[] arr = new byte[1024];
int len;
while((len = bis.read(arr)) != -1) {
sos.write(arr,0,len);
} //6.释放资源
bis.close();
sos.close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

最新文章

  1. 【中文分词】二阶隐马尔可夫模型2-HMM
  2. Jq基础简介
  3. spring源码学习之路---AOP初探(六)
  4. Windows下获取本机IP地址方法介绍
  5. hdu 2111 Saving HDU
  6. 用宏 x y z,找出最大值最小值
  7. java的nio之:java的nio的服务器实现模型
  8. 基于Cordova5.0开发自己定义插件(android)
  9. 魔兽世界---屠夫(Just a Hook)
  10. struts2获得提交是get还是post方法提交
  11. Java基础之IO流学习总结
  12. Spring 学习——Spring注解——Autowiring(自动装配)
  13. ELK学习博客
  14. 849. Maximize Distance to Closest Person
  15. InputStream流无法重复读取的解决办法
  16. Masonry应用【美图秀秀首页界面自动布局】
  17. String对象中的正则表达式
  18. Centos7 配置ssh 免秘钥登陆
  19. CodeForces 803A Maximal Binary Matrix
  20. codeforces 869A The Artful Expedient【暴力枚举/亦或性质】

热门文章

  1. 激光雷达Lidar Architecture and Lidar Design(上)
  2. JUC 并发编程--08,线程池,三大方法,七大参数,4种拒绝策略,代码演示
  3. Qt中的布局浅析与弹簧的使用,以及Qt居中的两种方法
  4. Mac下安装及配置Appium环境
  5. webpack 快速入门 系列 - 自定义 wepack 上
  6. 【dog与lxy】8.25题解-land
  7. linux常用命令及一些静态动态库相关知识
  8. 使用CI/CD工具Github Action发布jar到Maven中央仓库
  9. COURSES 赤裸裸的二分匹配大水题
  10. 13.9示例:有理数Rational类