Web对象
一.请求的方式
1. 地址栏输入
在浏览器地址栏直接输入要访问的地址即可,此种方式可以看做是访问服务器的起始操作。
格式:http://ip:port/path
2. 超链接
使用超链接也可以向服务器发出请求
<a href="http://www.baidu.com">百度</a>
3. Form 表单
当需要向服务器发送请求,并且传输一些用户输入的数据时,我们优先选择form 表单的方式发起请求。
前后台连接时action="..."与
<servlet-mapping>中的<url-pattern>值一致
Servlet3.0 和注解一致
4. ajax
通过 ajax 发起的请求,属于异步请求,能实现局部刷新的效果,是一种比较常用的请求方式。
通过 jQuery 中的 ajax(),get(),post(),getJSON()等方法都能发送请求
5. 请求转发
通过服务器内部将请求进行一次转发,可以请求到其他资源
6. 重定向
服务器通过给定一个新资源的地址,响应会客户端后,客户端自动再次发送一个请求到新资源的地址处。
二.HttpServletRequest 对象
1. 介绍
HttpServletRequest 对象主要作用是用来接收客户端发送过来的请求信息
例如:请求的参数,发送的头信息等都属于客户端发来的信息,service()方法中形参接收的是 HttpServletRequest 接口的实例化对象,表示该对象主要应用在HTTP 协议上,该对象是由 Tomcat 封装好传递过来。
HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一个子接口,就是 HttpServletRequest。既然只有一个子接口为什么不将两个接口合并为一个?
从长远上讲:现在主要用的协议是 HTTP 协议,但以后可能出现更多新的协议。若以后想要支持这种新协议,只需要直接继承 ServletRequest 接口就行了。
在 HttpServletRequest 接口中,定义的方法很多,但都是围绕接收客户端参数的。但是怎么拿到该对象呢?不需要,直接在 Service 方法中由容器传入过来,而我们需要做的就是取出对象中的数据,进行分析、处理。
注:这里是重写service方法
2.常用形式
1). 常用方法
1.★获取请求的完整路径 (从http开始,到问号前面)
getRequestURL()完整url
2.★获取部分资源路径(从站点名开始,到问号前面)
getRequestURI()部分url
3.获取 请求的参数字符串 (从问号开始,到最后的字符串,不包含问号)
getQueryString()
4.获取请求的类型 (GET/POST)
getMethod()请求类型
5.获取请求协议版本
getProtocol()协议版本
6.获取站点名(项目的对外访问路径)
getContextPath()站点名
代码示例:
// 常用方法
// 获取请求的完整路径 (从http开始,到问号前面)
System.out.println("获取请求的完整路径: " + req.getRequestURL());
//获取请求的部分资源路径: /sr02/s01
// 获取部分资源路径(从站点名开始,到问号前面)
System.out.println("获取请求的部分资源路径: " + req.getRequestURI());
//获取请求的部分资源路径: /sr02/s01
// 获取 请求的参数字符串 (从问号开始,到最后的字符串,不包含问号)
System.out.println("获取 请求的参数字符串: " + req.getQueryString());
//获取 请求的参数字符串: uname=admin&upwd=123&hobby=sing&hobby=dance&hobby=rap
// 获取请求的类型 (GET/POST)
System.out.println("获取请求的类型: " + req.getMethod());
//获取请求的类型: GET
// 获取请求协议版本
System.out.println("获取请求协议版本: " + req.getProtocol());
//获取请求协议版本: HTTP/1.1
// 获取站点名(项目的对外访问路径)
System.out.println("获取站点名:" + req.getContextPath());
//获取站点名:/sr02
2). 获取请求头
获取单个请求头内容
getHeader(String)
获取单个请求头名称集合
Enumeration<String>getHeaderNames()
代码示例:
// 获取请求头 (键不区分大小写)
System.out.println("获取请求头:" + req.getHeader("host"));
// 获取所有的请求头名称
Enumeration<String> enumeration = req.getHeaderNames();
//获取请求头:localhost:8080
// 遍历枚举集合
while(enumeration.hasMoreElements()) { System.out.println(enumeration.nextElement());
}
//host
//connection
//upgrade-insecure-requests
//user-agent
//accept
//accept-encoding
//accept-language
3). 获取客户端请求参数(客户端提交的数据)
获取指定名称的参数★
getParameter(name)
获取指定名称参数的所有值
getParameter(String name)
获取一个包含请求消息中的所有参数名的Enumeration对象
getParameterNames()
返回一个保存了请求信息中的所有参数名称和值的Map对象
getParameterMap()
代码示例:
// ============获取客户端请求参数(客户端提交的数据)============
// 获取指定名称的参数值 字符串
String uname = req.getParameter("uname");
String upwd = req.getParameter("upwd");
System.out.println("姓名:" + uname + ",密码:" +upwd);
//姓名:admin,密码:123
// 获取指定名称的参数的所有值 数组
String[] hobbys = req.getParameterValues("hobby");
// 判断非空
if (hobbys != null && hobbys.length > 0) {
for (String string : hobbys) {
System.out.println(string);
}
}
//sing
//dance
//rap
// 获取所有请求参数的名称 枚举对象
Enumeration<String> enumeration2 = req.getParameterNames();
while(enumeration2.hasMoreElements()) {
System.out.println(enumeration2.nextElement());
}
//uname
//upwd
//hobby
// 获取包含参数名和参数值的map对象 map对象
Map<String,String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
System.out.println("参数名: " + key);
// 通过key获取值
String[] strings = map.get(key);
for (String string : strings) {
System.out.println(string);
}
}
参数名: uname
//admin
//参数名: upwd
//123
//参数名: hobby
//sing
//dance
//rap
3. 请求乱码解决 ★
1).乱码原因:
由于现在的 request 属于接收客户端的参数,所以必然有其默认的语言编码,主要是由于在解析过程中默认使用的编码方式为 ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码。
要想解决这种乱码问题,需要设置 request 中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数据以后,再通过相应的编码格式还原。
TomCat 8 及以上版本 | TomCat 7 及以下版本 | |
---|---|---|
POST | 乱码 | 乱码 |
GET | 不乱码(不需处理) | 乱码 |
2). 解决方式一:post
String uname = request.setCharacterEncoding("UTF-8");
这种方式只针对 POST 有效(必须在接收所有的数据之前设定)
不会对get造成影响
3). 解决方式二:get && post
String uname = new String(request.getParameter(name).getBytes("ISO-8859-1"));
借助了 String 对象的方法,该种方式对任何请求有效,是通用的。
Tomcat8 起,以后的 GET 方式请求是不会出现乱码的。
缺点: 本身不乱码的(例如:TomCat 8及以后 的get 会出现乱码),设置后会出现另一种乱码,而且一次只能处理一个参数
示例:
//tomcat容器默认采用了iso-8859-1的编码方法
//通过本为UTF-8编码却被tomcat用iso-8859-1解码的字进行恢复,
//其将解码后的字通过iso-8859-1反解码成二进制数组,再将该字节数组用 UTF-8解码。
//最终被new String成字符串。
value = new String(value.getBytes("iso8859-1"),"UTF-8");
这里的value是 String value = request.getParameter(name);
4). 额外知识点:
// 抑制警告
@SuppressWarnings("serial")
//添加序列号
private static final long serialVersionUID = 1L;
4. 请求转发 ★
1). 特点: 页面地址不改变 但页面跳转
2). 定义:
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出。
实现方式如下,达到多个资源协同响应的效果
3). 格式:
request.getRequestDispatcher().forward()
request.getRequestDispatcher("跳转的路径").forward(request, response);
4).与重定向区别:
- 服务端行为,由服务器控制跳转
- 跳转后地址栏不发生改变
- 从始至终只有一个请求发出,请求对象可以共享(request和response对象是同一个)
5. request作用域对象 ★
(还有Session会话 和ServletContext)
1). 作用:
一般用作前台提取数据,通过该对象可以在一个请求中传递数据
2). 作用范围:
在一次请求中有效,即服务器跳转有效。
3). 三大方法:
request.setAttribute()
:设置域对象内容;
request.getAttribute(String name)
:获取域对象内容;
request.removeAttribute(String name)
: 删除域对象内容。
4).示例:
// 设置域对象
request.setAttribute("uname", "zhangsan");
request.setAttribute("uage", 18);
// 请求转发跳转到servlet01
request.getRequestDispatcher("s01").forward(request, response);
request 域对象中的数据在一次请求中有效,则经过请求转发,request 域中的数据依然 存在,则在请求转发的过程中可以通过 request 来传输/共享数据。
三.HttpServletResponse 对象
HttpServletRequest request,HttpServletResponse` response
1. 介绍
Web 服务器收到客户端的 http 请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。
request 和 response 对象代表请求和响应:获取客户端数据,需要通过request 对象;向客户端输出数据,需要通过 response 对象。
HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将Web 服务器处理后的结果返回给客户端。 service()方法中形参接收的HttpServletResponse 接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
2. 常用方法
1).添加指定的键值到响应头信息中
addHeader(String name , String value)
2).判断响应的头部是否被设置
containsHeader(String name)
3).编码指定的URL
encodeURL(String url)
4).使用指定状态码发送一个错误到客户端
sendError(int sc)
5).设置指定响应头的值
setHeader(String name , String value)
6).给当前响应设置状态
setStatus(int sc)
7).设置数据的响应类型★
setContentType("text/html")
response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。
例如:web浏览器就是通过MIME类型来判断文件是GIF图片。通过MIME类型来处理json字符串。
示例:resp.setContentType("text/html;charset=UTF-8");
一般同时设置字符集
8).获取字符流(只能响应回字符);★
getWriter()
示例:
PrintWriter writer = resp.getWriter();
writer.write("Hello");
writer.write("<h2>Hello1</h2>");
writer.close();
9).获取字节输出流(能响应一切数据)。
getOutputStream()
=>响应的数据回到客户端被浏览器解析。
示例:
PrintWriter writer = resp.getWriter();
writer.write("<input type='text' value='123' />");
writer.close();
**注意:**上述两种流不能同时使用。异常:
java.lang.IllegalStateException:
getWriter() has already been called for this response
3.刷新和页面自动跳转
所有头信息都是随着请求和回应自动发送到服务器端(客户端),在response 中一个比较常用的头信息就是刷新的指令,可以完成定时刷新的功能。
resp.setHeader("refresh","2");
对于刷新的头信息,除了定时的功能外,还具备了定时跳转的功能,可以让一个页面定时跳转到一个指定的页面。(已经注册成功,两秒后跳转到登陆页面)
response.setHeader("refresh","3;URL=ok.html");
但是这种跳转不是万能的,有时候根本就无法进行跳转操作,返回后刷新不会跳转;对于这种定时跳转的头信息,也可以采用 HTML 的方式进行设置,HTML 本身也可以设置头信息。(客户端跳转)
//设置响应头
resp.addHeader("uname", "admin");
// 设置页面报错
resp.sendError(500);
resp.sendError(404, "无法访问!");
// 自动刷新 3秒钟刷新一次
resp.setHeader("refresh", "3");
// 跳转 3秒钟后跳转到百度
resp.setHeader("refresh", "3;http://www.baidu.com");
4. 数据响应★
接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流,有两种形式 getWriter()获取字符流(只能响应回字符);getOutputStream()获取字节流(能响应一切数据)。响应回的数据到客户端被浏览器解析。注意:两者不能同时使用。
5. 乱码解决响应乱码问题
1).乱码原因:
1.服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。
2.注:如果服务端和客户端编码一致,但编码不支持中文,也会乱码。
2).乱码情况:
1. getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-8859-1 格式的编码,该编码方式并不支持中文。
设置服务端的编码
resp.setCharacterEncoding("UTF-8");
2. getOutputStream()字节乱码
对于 getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节, 所以此时可能出现乱码,也可能正确显示。
★同时设置服务端和客户端的编码及响应类型
resp.setContentType("text/html;charset=UTF-8");
3).总结:
要想解决响应的乱码,只需要保证使用支持中文的编码格式。并且保证服务器端 和客户端使用相同的编码方式即可。
setContentType()
设置数据的响应类型及编码
6. 响应图片 ★
在学习 HTML 的时候我们知道使用的方式可以显示图片。但有的时候我们并不知道(或不能确定)图片的路径,需要通过请求服务器资源动态地响应图片给客户端。这种方式和文件拷贝的理念是一致的,客户端请求服务器的资源,在服务端获取到真实的图片资源,通过输入流读取到内存,然后通过输出流写出到客户端即可。
值得注意的是,在客户端解析资源时默认是以文本(text/html)的形式,当响应图片时 需要指定响应头信息,告知客户端响应内容为图片形式,使用一种叫做 MIME 类型的东西来指定。MIME 类型见 Tomcat 的 web.xml 文件。
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型
定义某一个扩展名和某一个 MIME Type 做对应,包含两个子元素:
<extension></extension>
扩展名的名称
<mime-type></mime-type>
MIME 格式
代码:
@SuppressWarnings("serial")
public class Servlet04 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet04....");
// 获取项目在服务器中的真实路径
String realPath = req.getServletContext().getRealPath("/");
System.out.println(realPath);
// 得到图片的存放路径
String filePath = realPath + "/WEB-INF/images/jay.jpg";
// 通过路径得到file对象
File file = new File(filePath);
// 判断文件是否存在,且是一个标准文件
if (file.exists() && file.isFile()) {
// 设置响应类型
resp.setContentType("image/jpeg");
// 得到文件的输入流
InputStream in = new FileInputStream(file);
// 得到字节输出流
ServletOutputStream out = resp.getOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
while((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
} else {
// 设置响应类型及编码
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("<h2>文件不存在!</h2>");
resp.getWriter().close();
}
}
7. 重定向跳转 ★
重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收,经过处理服务器进行响应,与此同时,服务器给客户端一个地址(下次请求的地址 resp.sendRedirect(“url”);),当客户端接收到响应后,立刻、马上、自动根据服务器 给的地址进行请求的发送第二个请求,服务器接收请求并作出响应,重定向完成。从描述中可以看出重定向当中有两个请求存在,并且属于客户端行为。实现方式如下:
通过观察浏览器我们发现第一次请求获得的响应码为 302,并且含有一个location 头信息。并且地址栏最终看到的地址是和第一次请求地址不同的,地址栏已经发生了变化。
请求转发和重定向比较:
重定向
response.sendRedirect()
请求转发
request.getRequestDispatcher().forward()
两者都可进行跳转,根据实际需求选取即可。
请求转发和重定向区别:
1).请求转发
1、地址栏不发生改变
2、服务端跳转
3、只有一次请求
4、request作用域共享 (一次请求中有效)
5、跳转的地址定位到站点名后 (请求转发到当前项目的资源路径)
2).重定向
1、地址栏发生改变
2、客户端跳转
3、存在两次请求
4、request作用域不共享
5、跳转的地址定位到http (可以重定向到任意地址)
四、请求时的路径问题 ★
1.相对路径
相对于当前资源的路径
2.绝对路径
资源的完整路径
1).完整绝对路径
以 http://
开头的,该种绝对路径已经跨域,即任何地方的资源都能访问
2).部分绝对路径
以/
开头,从当前域名|IP|主机后的端口号开始的,不能跨域
/
的含义:
请求转发:
代表的是 http://localhost:8080/站点名/
重定向(客户端跳转):
代表的是 http://localhost:8080/
代码:
// ================请求转发================
// (OK)相对路径
req.getRequestDispatcher("index.html").forward(req, resp);
// (OK)在请求转发时,"/"代表的是到站点名后
//http://loaclhost:8080/sr03 /index.html
req.getRequestDispatcher("/index.html").forward(req, resp);
// (404)地址定位在站点名
//http://loaclhost:8080/sr03 sr03/index.html
req.getRequestDispatcher("sr03/index.html").forward(req, resp);
// (404)地址定位在站点名
//http://loaclhost:8080/sr03 sr03/index.html
req.getRequestDispatcher("/sr03/index.html").forward(req, resp);
// (404)地址定位在站点名
//http://loaclhost:8080/sr03 http://loaclhost:8080/sr03/index.html
req.getRequestDispatcher("http://localhost:8080/sr03/index.html").forward(req, resp);
// ================重定向================
// (OK)相对路径
resp.sendRedirect("index.html");
// (404)绝对路径定位到端口后,http://loaclhost:8080 /index.html
resp.sendRedirect("/index.html");
// (404)相对路径,http://loaclhost:8080/sr03 sr03/index.html
resp.sendRedirect("sr03/index.html");
// (OK)绝对路径定位到端口后,http://loaclhost:8080 /sr03/index.html
resp.sendRedirect("/sr03/index.html");
// (OK)完整的绝对地址,从http开始
resp.sendRedirect("http://localhost:8080/sr03/index.html");
五、Cookie(储存在用户本地终端上的数据)
定义:
Cookie 是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的。例如常见的记住密码则可以通过 Cookie 来实现。
cookie的大小在4kb左右,每个浏览器在同一域名下能存放cookie数量是有限的,谷歌浏览器大概是50个。
Cookie不跨浏览器,换电脑也无效。
有一个专门操作 Cookie 的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存在浏览器。当下次再访问服务器时把 Cookie 再带回服务器。
Cookie 的格式:键值对用 =
链接,多个键值对间通过 “;” 隔开
优缺点:
提高网页的效率,减轻服务器的负载。
安全性较差。
1.创建Cookie 对象
new Cookie("key","value");
通过 new Cookie(“key”,“value”);来创建一个 cookie对象
Cookie cookie = new Cookie("cookie的名称","cookie的值");
注:键和值都是字符串,不支持中文
2.发送Cookie 对象
response.addCookie(cookie);
要想将 Cookie 随响应发送到客户端,需要先添加到 response 对象中,resp.addCookie(cookie);此时该 cookie 对象则随着响应发送至了客户端。在浏览器上可以看见。
F12 查看
3. Cookie 的获取
request.getCookies();
返回的是所有的cookie的数组
在服务器端只提供了一个 getCookies()的方法用来获取客户端回传的所有cookie 组成的一个数组,如果需要获取单个 cookie 则需要通过遍历,getName()获取 Cookie 的名称,getValue()获取 Cookie 的值。
4. Cookie 到期时间的设定
注:Cookie是浏览器技术,关闭服务器不会影响cookie的变化
到期时间,到期时间用来指定该 cookie 何时失效。
默认为当前浏览器关闭即失效。
手动设定 cookie 的有效时间(通过到期时间计算)
通过 setMaxAge(int time);方法设定 cookie 的最大有效时间,以秒为单位。
大于 0 的整数,表示存储的秒数;若为负数,则表示不存储该 cookie;若为 0,则删 除该 cookie。
负整数:cookie 的 maxAge 属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么 cookie 就会消失。
正整数:表示 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie 也
会存活相应的时间。
零:cookie 生命等于 0 是一个特殊的值,它表示 cookie 被作废!也就是说,如果原来浏览器已经保存了这个 Cookie,那么可以通过 Cookie 的setMaxAge(0)来删除这个 Cookie。 无论是在浏览器内存中,还是在客户端硬盘上都会删除这个 Cookie。
5. Cookie 的注意不能存中文
(encode 编码 decode解码)
在一般的站点中常常有记住用户名这样一个操作,该操作只是将信息保存在本机上,换电脑以后这些信息就无效了。而且 cookie 还不能跨浏览器。
Cookie 中不能出现中文,如果有中文则通过
URLEncoder.encode()
来进行编码,
获取时通过
URLDecoder.decode()
来进行解码。
不同的浏览器对 Cookie 也有限定,Cookie 的存储有是上限的。Cookie 是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合 Session来实现回话跟踪。
6. Cookie 的覆盖
如果服务器端发送重复的 Cookie 那么会覆盖原有的 Cookie。
7. Cookie 的路径path
浏览器在访问 BServlet 时,是否会带上 AServlet 保存的 Cookie,这取决于Cookie 的 path。
在项目中的配置文件 web.xml
在 Cookie01.java 中添加一个 cookie
在 Cookie02.java 中获取 cookie01.java 中添加的 cookie
在 Cookie.java 中获取 cookie01.java 中添加的 cookie
在 Servlet 中保存的 Cookie 如果没有设置 path,那么它的 path 默认为当前 Servlet 的所在路径;
当访问的路径包含了 cookie 的路径时,则该请求将带上该 cookie;如果访问路径不包含 cookie 路径,则该请求不会携带该 cookie
// 创建cookie
Cookie cookie = new Cookie("uname","admin");
// 设置path (当前服务器下任意资源都可访问)
cookie.setPath("/");
// 发送cookie
resp.addCookie(cookie);
// 创建cookie
Cookie cookie2 = new Cookie("userName","zhangsan");
// 设置path
cookie2.setPath("/sc04/test/aa");
// 发送cookie
resp.addCookie(cookie2);