javaweb视频笔记10
文章目录
一、response
1. response简介
response是响应对象,用来在Servlet的service()方法中向客户端响应数据
response的功能如下:
- 设置响应头
- 发送状态码
- 设置响应正文
- 重定向
2. response响应正文
* ServletOutputStream getOutputStream():用来向客户端响应字节数据;
* PrintWriter getWriter():用来向客户端响应字符数据;
response.getWriter().print("你好");//向客户端响应字符数据
byte[] bytes = ...;
response.getOutputStream().write(bytes);//向客户端响应字节数据
3. response字符编码
* Tomcat响应数据默认使用ISO-8859-1(tomcat8之后使用utf-8)
* 通常浏览器默认使用GBK编码
* response.setCharacterEncoding("utf-8");//设置response.getWriter()的字符编码
1 ) 设置字符编码
response.setCharacterEncoding("utf-8");
response.getWriter().print("大家好");
2 ) setContentType()方法有两个作用:
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("大家好");
- 设置字符流编码。等同与调用了response.setCharacterEncoding(“utf-8”);
- 设置Content-type响应头,即通知浏览器响应数据的编码为utf-8。
因为设置字符流的编码为utf-8,所以响应给客户端数据为utf-8编码
因为设置了Content-type头为utf-8,所以浏览器会使用utf-8来解析响应数据
没有乱码!
3 )
response.setHeader("Content-type", "text/html;charset=utf-8")
等同于
repsonse.setContentType("text/html;charset=utf-8")
4 )
response.getOutputStream().write("大家好".getBytes("utf-8"));
响应的数据是utf-8编码
客户端浏览器默认使用utf-8编码
所以没有乱码
4. response字符流缓冲区
response字符流缓冲区大小为8KB,当向字符流中写入数据后,数据可能只在缓冲区中,而没有发送到浏览器。
可以调用response.flushBuffer()或response.getWriter().flush()
方法刷新缓冲区,把数据发送到浏览器。
5. 设置响应头
response.setHeader("Content-type", "text/html;charset=utf-8");
等同与
response.setContentType("text/html;charset=utf-8");
response.setHeader("Refresh", "5; URL=http://www....");
6. 指定状态码
response.setStatus(200):设置状态码为200
response.sendError(404, “您要查找的资源不存在”):设置状态码为404
repsonse.sendError(500, “服务器出氏了”):设置状态码为500
在调用sendError()方法时,不只是设置了状态码,而且还会给浏览器一个显示错误的页面。
7. 重定向
重定向是服务器通知浏览器去访问另一个地址,即再发出另一个请求。
响应码为200表示响应成功,而响应码为302表示重定向
/*
1.设置Location
2.发送状态码
*/
repsonse.setHeader("Location", "http://www.baidu.com");
response.sendStatus(302);
快捷的方法重定向:
response.sendRedirect("http://www.baidu.com");
8.其他方法
总结重定向:
- 重定向是两次请求
- 重定向不局限与当前应用,也可以是其他应用,例如重定向到百度
- 重定向响应码为302,而且必须有Location响应头
- 重定向与response响应流同时使用。
定时刷新:
/**
* 定时刷新
* 是指一个Refresh 表示定时刷新
*/
@WebServlet(name = "DServlet", urlPatterns = "/DServlet")
public class DServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//发送响应体
PrintWriter writer = response.getWriter();
writer.println("欢迎登录!5秒之后跳转到主页!");
//设置响应头
response.setHeader("Refresh","5;URL=/day10_01/EServlet" );
}
}
禁用浏览器缓存:
/**
* 禁用浏览器缓存
*/
@WebServlet(name = "FServlet", urlPatterns = "/FServlet")
public class FServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* Cache-Control pragma expires
*/
response.setHeader("Cache-Control", "no-cache");
response.setHeader("pragma", "no-cache");
response.setDateHeader("expires", -1);
response.getWriter().println("hello");
}
}
字符流、字节流:
@WebServlet(name = "GServlet", urlPatterns = "/GServlet")
public class GServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 字符流
// String s = "Hello outputStream";
// byte[] bytes = s.getBytes();
// response.getOutputStream().write(bytes);
//演示相应字节数据,把一张图片读取到字节数组中
String path = "mys.jpg";
FileInputStream in = new FileInputStream(path);
byte[] bytes = IOUtils.toByteArray(in);
response.getOutputStream().write(bytes);
}
}
二、request
1. request功能介绍
- 获取请求头
- 获取请求参数
- Servlet三大域对象之一
- 请求包含和请求转发
2. request域方法
* void setAttribute(String name, Object value):添加或替换request域属性
* Object getAttribute(String name):获取request域指定名称的域属性
* void removeAttribute(String name):移除request域指定名称的域属性
* Enumeration getAttributeNames():获取所有request域的属性名称
3. request获取请求头
* String getHeader(String name):获取指定名称的请求头
* int getIntHeader(String name):获取指定名称的请求头,把值转换成int类型。
* Enumeration getHeaderNames():获取所有请求头名称
/**
* 获取客户端的IP地址、获取请求方式、获取User-Agent
* 得到客户端信息(操作系统、浏览器)
*/
@javax.servlet.annotation.WebServlet(name = "AServlet", urlPatterns = "/AServlet")
public class AServlet extends javax.servlet.http.HttpServlet {
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//获取客户端的IP地址
String addr = request.getRemoteAddr();
System.out.println("IP:" + addr);
//获取请求方式
System.out.println("请求方式:" + request.getMethod());
//获取User-Agent请求头
String userAgent = request.getHeader("User-Agent");
System.out.println("User-Agent:" + userAgent);
//IP:127.0.0.1
//请求方式:GET
//User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64)
//AppleWebKit/537.36 (KHTML, like Gecko)
// Chrome/70.0.3538.102 Safari/537.36
//是否包含某种类型的浏览器
if (userAgent.toLowerCase().contains("chrome")) {
System.out.println("您好:" + addr + "您使用的是谷歌浏览器");
} else if (userAgent.toLowerCase().contains("firefox")) {
System.out.println("您好:" + addr + "您使用的是火狐浏览器");
} else if (userAgent.toLowerCase().contains("edge")) {
System.out.println("您好:" + addr + "您使用的是IE浏览器");
}
}
}
@WebServlet(name = "BServlet", urlPatterns = "/BServlet")
public class BServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 使用Referer请求头防盗链
*/
String referer = request.getHeader("Referer");
System.out.println(referer);
if (referer == null || referer.contains("localhost")) {
response.sendRedirect("http://www.baidu.com");
} else {
System.out.println("hello");
}
}
}
4. request请求数据相关其他方法
重点:
* String getMethod():获取请求方式
* String getContextPath():获取上下文路径,即“/” + 应用名称,例如:/day05_1
* void setCharacterEncoding(String):设置请求体的编码
* String getRemoteAddr():获取客户端IP地址
非重点:
* int getContentLength():获取请求体字节数
* Locale getLocale():获取请求Locale,例如zh_CN表示中文,中国
* String getCharacterEncoding():获取请求体编码,在没有调用setCharacterEncoding()之前该方法返回null
* String getQueryString():获取参数列表,例如:username=zhangSan&password=123
* String getRequestURI():返回请求URI路径,从应用名称开始,到参数之前这一段,例如:/day05_1/AServlet
* StringBuffer getRequestURL():整个请求URL,不包含参数部分
* String getServletPath():返回Servlet路径,从应用名称后开始,到参数之前这一段,不包含应用名称。
* String getServerName():返回主机名,例如:localhost
* int getServerPort():返回服务器端口号,例如:8080
5. 请求参数
获取请求参数,即获取超链接上的参数和表单中的参数
- String getParameter(String name):获取指定名称的参数,如果存在同名参数,那么该方法只获取第一个参数值
- String[] getParameterValues(String name):获取指定名称的参数,因为同名参数的存在,所以返回值为String[]
- Enumeration getParameterNames():获取所有参数名称
- Map getParameterMap():获取所有参数,封装到Map中,key为参数名称,value为参数值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html" charset="UTF-8">
<title>a.html</title>
</head>
<body>
<h1>测试请求参数</h1>
<a href="/day10_03/AServlet?xxx=XXX&yyy=YYY">点击这里</a>
<hr/>
<form action="/day10_03/AServlet" method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="password" name="password"/><br/>
爱 好:<input type="checkbox" name="hobby" value="cf"/>吃饭
<input type="checkbox" name="hobby" value="sj"/>睡觉
<input type="checkbox" name="hobby" value="qdm"/>敲代码
<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
/**
* request获取请求参数
*/
@WebServlet(name = "AServlet", urlPatterns = "/AServlet")
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobby = request.getParameterValues("hobby");
System.out.println(username + "," + password + "," + Arrays.toString(hobby));
//测试所有请求参数名称
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
System.out.println(names.nextElement());
}
//获取所有请求参数,封装到map中
Map<String, String[]> map = request.getParameterMap();
for (String name : map.keySet()) {
String[] values = map.get(name);
System.out.println(name + " = " + Arrays.toString(values));
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("GET:" + request.getParameter("xxx"));
System.out.println("GET:" + request.getParameter("yyy"));
}
}
6. 请求包含和请求转发
请求包含和请求转发都是在一个请求中,访问两个Servlet。
请求包含和请求转发都是有一个Servlet去调用执行另一个Servlet
请求包含和请求转发都可以共享request中的数据,因为都是一个请求。
从AServlet请求转发到BServlet
在AServlet中可以设置响应头
在AServlet中不能使用响应流输出
如果在AServlet中执行了响应操作,那么有两种可能:
如果在AServlet中响应的数据导致response提交,那么在转发时抛出异常;
如果在AServlet中响应的数据没有导致response提交,那么response中的数据会被清空。
从AServlet请求包含BServlet
在AServlet可以设置响应头
在AServlet可以使用响应流输出
* 请求转发和请求包含都要使用RequestDispatcher对象:RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
* 请求转发执行RequestDispatcher的forward()方法:rd.forward(request,response);
* 请求包含执行RequestDispatcher的include()方法:rd.include(request,response);
* 请求转发和请求包含的路径都是服务器端路径,相对当前应用
演示请求转发
/**
* 演示请求转发
*/
@WebServlet(name = "OneServlet", urlPatterns = "/OneServlet")
public class OneServlet 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("OneServlet...");
//设置响应头
response.setHeader("aaa","AAA");
//设置响应体
response.getWriter().println("hello OneServlet");
//向request域中添加属性
request.setAttribute("username", "mys");
//请求转发 等同于调用TwoServlet的service()方法
request.getRequestDispatcher("/TwoServlet").forward(request, response);
}
}
@WebServlet(name = "TwoServlet", urlPatterns = "/TwoServlet")
public class TwoServlet 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("TwoServlet");
//设置响应体
response.getWriter().println("hello TwoServlet");
System.out.println(request.getAttribute("username"));
}
}
7. 请求转发与重定向
请求转发是一个请求,而重定向是两个请求
请求转发,是使用RequestDispatcher来完成,重定向使用response对象来完成
请求转发的路径都是服务器端路径,而重定向是客户端路径,需要给出应用名称
请求转发在浏览器地址栏中的地址是第一个Servlet的路径,而重定向在地址栏中的地址是第二个请求的Servlet的路径
请求转发中的两个Servlet是可以共享request数据的,而重定向因为是两个请求,所以不能共享request数据
请求转发只能转发到本应用的其他Servlet,而重定向可以重定向到其他应用中。
8. request.getParameter()和request.getAttribute()
* getParameter()是获取客户端参数,它是从客户端传递给服务器的数据。
* getAttribute()是获取服务器端自己设置的数据,而不是客户端的数据。
* request没有setParameter()方法,不能自己设置参数,参数都由客户端传递
* request有setAttribute()方法,在getAttribute()之前,需要先setAttribute()才能获取到。
* getAttribute()和setAttribute()是用来在请求转发和请求包含中的多个Servlet中共享数据。
9.路径
- 客户端路径和服务器端路径
客户端路径需要给出应用名称,例如:/day05_1/AServlet
服务器端路径无需给出应用名称,例如:/AServlet - 客户端路径
1)页面中都是客户端路径:
* 超链接的href
* 表单的action
* <img>的src
2) 重定向也是客户端路径:response.sendRedirect("/day05_1/BServlet");
3. 服务器端路径
* <url-pattern>
* 请求转发和请求包含
* ServletContext获取资源等
10.乱码
请求编码
客户端发送的数据编码:由浏览器来决定:
1). 如果是在地址栏中直接给出url,那么一般都是默认为GBK,但这个可能不太大。
2). 如果是通过页面上的表单或超链接发出请求,那么由当前页面的编码来决定发送的参数的编码。
无论浏览器发送过来的是什么编码的数据,Tomcat都默认使用ISO-8859-1来解码
1). POST:可以使用request.setCharacterEncoding()方法来设置请求体数据的编码,因为POST请求参数在请求体中,所以是可以设置编码的。在使用request.getParameter()方法获取参数之前,先使用request.setCharacterEncoding()方法来设置编码即可。
2). GET:没有方法可以设置它,因为参数在url中。所以使用request.getParameter()获取到的数据一定是错误的使用了iso-8859-1解码的。可以再使用iso-8859-1把字符串转回到byte[],再重新使用正确的编码来解码即可。
String s = request.getParameter(“s”);//使用iso-8859-1错误的解码了
byte[] bytes = s.getBytes(“iso-8859-1”);//退回错误的解码,让字符串通过iso-8859-1返回到字节数据,即还原字节数据
s = new String(bytes, “utf-8”);//重新使用正确的utf-8来解码。
@WebServlet(name = "AServlet", urlPatterns = "/AServlet")
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 1.在获取参数之前,需要先调用request.setCharacterEncoding("utf-8")
* 2.使用getParameter()来获取参数
*/
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println(username);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 1.先获取来使用的iso错误字符串
* 2.回退,使用(utf-8)重编
* 注意:tomcat8已经默认使用utf-8了,不是iso
*/
// String name = request.getParameter("username");
// byte[] bytes = name.getBytes("iso-8859-1"); //注意
// name = new String(bytes, "utf-8");
// System.out.println(name);
}
}
/**
* URL编码
*/
public class Demo {
@Test
public void fun1() throws UnsupportedEncodingException {
//[-27, -68, -96, -28, -72, -119]
//[%E5, %BC, %A0, ...] E5:(256-27)16
String name = "张三";
// byte[] bytes = name.getBytes("utf-8");
// System.out.println(Arrays.toString(bytes));
//%E5%BC%A0%E4%B8%89 编码
String s = URLEncoder.encode(name, "UTF-8");
System.out.println(s);
//解码
s = URLDecoder.decode(s, "utf-8");
System.out.println(s);
}
}
/**
* ClassLoader和Class获取类路径资源
*/
public class demo2 {
/**
* ClassLoader获取资源时,不能以/开头
* @throws IOException
*/
@Test
public void fun1() throws IOException {
//得到类加载器
ClassLoader cl = demo2.class.getClassLoader();
//让类加载器去类路径下查找资源
InputStream in = cl.getResourceAsStream("a.txt");
System.out.println(IOUtils.toString(in));
}
@Test
public void fun2() throws IOException {
Class c = demo2.class;
//与类加载器效果相同
InputStream in = c.getResourceAsStream("/a.txt");
System.out.println(IOUtils.toString(in));
}
@Test
public void fun3() throws IOException {
Class c = demo2.class;
//到当前Class对应的.class文件坐在目录下去加载
InputStream in = c.getResourceAsStream("a.txt");
System.out.println(IOUtils.toString(in));
}
}