开始时间:2021-07-03
http状态码
1.介绍:
由三位数字组成的一个符号。
- Http服务器在推送响应包之前,根据本次请求处理情况,将Http状态码写入到响应包中【状态行】上
- 如果Http服务器针对本次请求,返回了对应的资源文件。通过Http状态码通知浏览器应该如何处理这个结果
- 如果Http服务器针对本次请求,无法返回对应的资源文件、通过Http状态码向浏览器解释不能提供服务的原因工
2.分类:
100-599 分为五个大类
比较有代表性的
-
100:通知浏览器本次返回的资源文件并不是一个独立的资源文件,需要浏览器在接收
响应包之后,继续向Http服务器所要依赖的其他资源文件(比如索要图片等其他资源) -
200:通知浏览器本次返回的资源文件是一个完整独立资源文件,浏览器在接收到之后不需要所要其他关联文件,注意与100进行比较
-
302:通知浏览器本次返回的不是一个资源文件内容而是一个资源文件地址,需要浏览器根据这个地址自动发起请求来索要这个资源文件。比较典型的就是resp.sendRedirect(address) 之前我们就写过登录验证此时Tomcat将302状态码写入到状态行,在浏览器接收到响应包之后,因为302状态码,浏览器不会读取响应体内容,自动根据响应头中location的地址发起第二次请求。
-
404:通知浏览器,由于在服务端没有定位到被访问的资源文件,因此无法提供帮助
-
405:通知浏览器,在服务端已经定位到被访问的资源文件(servlet)
但是这个servlet对于浏览器采用的请求方式不能处理,比如只能处理post,但是用的是get,就会出这种错误 -
500:通知浏览器,在服务端已经定位到被访问的资源文件(servlet),这个servlet可以接收浏览器采用请求方式,但是servlet在处理请求期间(Servlet调用自己的方法时报了异常),由于Java异常导致处理失败
补充一个小点
int num=(int)map.get("key');
报空指针异常
但是
Integer num=(Integer)map.get("key");
就可以避免这个异常
多个Servlet的调用
1.前提条件:
某些来自于浏览器发送请求,往往需要服务端中多个servlet协同处理。但是浏览器一次只能访问一个servlet,导致用户需要手动通过浏览器发起多次请求才能得到服务。
这样增加用户获得服务难度,导致用户放弃访问当前网站I
2.提高用户使用感受规则:
无论本次请求涉及到多少个servlet,用户只需要【手动】通知浏览器发起一次请求即可
3.多个servlet之间调用规则:
1)重定向解决方案
2)请求转发解决方案
重定向解决方案
服务端有多个Servlet的情况下,用户手动通知浏览器访问其中一个Servlet
服务端完成一个Servlet请求后,Tomcat将第二个Servlet地址写入到响应头location中,交给浏览器,此时携带的信息里就是状态码302以及第二个Servlet的地址。然后浏览器接收到响应包,得到了302状态码,立即自动根据location发起第二次请求
这种解决方案浏览器至少要发两次请求
resp.sendRedirect(address)
重定向后用的请求方式是get
浏览器地址栏命令浏览器发起的请求,为get
缺点:重定向解决方案需要在浏览器与服务器之间进行多次往返,大量时间消耗在往返次数上,增加用户等待服务时间。
请求转发解决方案
用户第一次通过手动方式要求浏览器访问oneservlet.
oneservlet工作完毕后,通过当前的请求对象直接向Tomcat发送请求,申请调用Twoservlet.
Tomcat在接收到这个请求之后,自动调用Twoservlet来完成剩余任务。也就是说,不需要经过返回浏览器,再让浏览器发请求来启动第二个Servlet的过程了。直接就内部完成了。完成所有Servlet之后才推回浏览器
举个例子:
第一个Servlet
package com.example.TestSystem;
import java.io.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("use the firstServlet");
//通过当前请求对象生成资源文件申请报告对象
RequestDispatcher report = request.getRequestDispatcher("/My");
try {
//将报告对象发送到Tomcat
report.forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
}
}
}
第二个Servlet
package com.example.TestSystem;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("use the second Servlet");
}
}
关键语句就在于
//通过当前请求对象生成资源文件申请报告对象
RequestDispatcher report = request.getRequestDispatcher("/My");
//将报告对象发送到Tomcat
report.forward(request, response);
-
无论本次请求涉及到多少个servlet,用户只需要手动通过浏览器发送一次请求
-
servlet之间调用发生在服务端计算机上,节省服务端与浏览器之间往返次数,增加处理服务速度
-
如果有五个Servlet做请求转发,那么每一次的都是靠上一次Servlet发起请求,交给Tomcat处理
-
这种方式所有的请求方式和浏览器发过来的保持一致,浏览器用post/get那么Servlet这边也是对应的
-
并且只能向Tomcat服务器申请调用当前网站下资源文件地址
request.getRequestDispathcer("/资源文件名")//不要写网站名
多个servlet之间数据共享实现方案:
数据共享:oneservlet工作完毕后,将产生数据交给Twoservlet来使用servlet规范中提供四种数据共享方案
- servletcontext接口
- cookie类
- Httpsession接口
- HttpservletRequest接口
ServletContext接口
ServletContext实例对象,也称为【全局作用域】对象
其中一个Servlet对象里面的数据,添加到全局作用域对象中,此时全局作用域相当于一个【map】
可以用来共享数据相当于公共的留言板,另一个Servlet通过键值对的方式,可以拿到第一个Servlet中的value
全局作用域对象生命周期:贯穿网站整个运行期间
- 在Http服务器启动过程中,自动为当前网站在内存中创建一个全局作用域对象
- 在Http服务器运行期间时,一个网站只有一个全局作用域对象
- 在Http服务器运行期间,全局作用域对象一直处于存活状态
- 在Http服务器准备关闭时,负责将当前网站中全局作用域对象进行销毁处理
第一个Servlet获取全局对象,再传一个map过去
第二个Servlet获取全局对象,再把map用key取出来
package com.example.TestSystem;
import java.io.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//建立ServletContext请求对象获得当前网站全局作用域对象
ServletContext application = request.getServletContext();
//将100作为value传回去
application.setAttribute("key", 100);
}
}
package com.example.TestSystem;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
建立ServletContext请求对象获得当前网站全局作用域对象
ServletContext application = req.getServletContext();
//收到的参数是一个对象,用Integer来接收
Integer value = (Integer) application.getAttribute("key");
System.out.println(value.toString());
}
}
cookie
- Cookie来自于servlet规范中一个工具类,存在于Tomcat提供servlet-api.jar中
- 如果两个servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于cookie对象进行数据共享
- cookie存放当前用户的私人数据,在共享数据过程中提高服务质量4)在现实生活场景中,cookie相当于用户在服务端得到【会员卡】
可以把浏览器端看做消费者,cookie是第一次发送请求时办理的会员卡,记录了消费信息。去消费的店是连锁店,去了北京的店消费,消费完后商家从银行卡里扣钱,并在卡中记录消费情况,再把卡给消费者。消费者下次去上海的连锁店消费,可以直接读取上次的消费情况信息。此时Twoservlet在运行时,就可以通过读取请求头中cookie中信息,得到oneServlet提供的共享数据
这一段给的案例代码写的不是很清晰
第一个Servlet
package com.example.TestSystem;
import java.io.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String userName;
String money;
//调用请求对象读取【请求头】参数信息
userName = request.getParameter("userName");
money = request.getParameter("money");
//cookie也相当于一个map,存放的key和value只能是String类型的
//且不能为中文
//办卡
Cookie cookie = new Cookie("userName", userName);
Cookie cookie1 = new Cookie("money", money);
//发卡,将cookie写入响应头交给浏览器
response.addCookie(cookie);
response.addCookie(cookie1);
//通知Tomcat将点餐内容写入到响应体中返回浏览器(请求转发)
try {
request.getRequestDispatcher("/OrderMenu.html").forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
}
}
}
第二个Servlet
package com.example.TestSystem;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int gaifan_money = 15;
int miantiao_money = 10;
int jiaozi_money = 12;
//调用请求对象
String food;
Cookie[] cookies = null;
//读取请求头参数,得到点餐食物类型
food = req.getParameter("food");
//读取请求中的cookie
cookies = req.getCookies();
//刷卡消费
for (Cookie MyCookie : cookies
) {
String key = MyCookie.getName();
String value = MyCookie.getValue();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<font style="color: red;font-size: 40px">新会员开卡</font>
<form action="/Hello">
<table border="2">
<tr>
<td>用户名</td>
<td><input type="text" name="userName"></td>
</tr>
<tr>
<td>预存金额</td>
<td><input type="text" name="money"></td>
</tr>
<tr>
<td><input type="submit" value="申请办卡">注册</td>
<td><input type="reset"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
初始页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<font style="color: red;font-size: 40px">新会员开卡</font>
<form action="/TestSystem/Hello">
<table border="2">
<tr>
<td>用户名</td>
<td><input type="text" name="userName"></td>
</tr>
<tr>
<td>预存金额</td>
<td><input type="text" name="money"></td>
</tr>
<tr>
<td><input type="submit" value="申请办卡"></td>
<td><input type="reset"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
跳转页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<font style="color: red;font-size: 50px">点餐页面</font>
<form action="/TestSystem/My">
食物类型:<input type="radio" name="food" value="饺子"/>饺子(30元)
<input type="radio" name="food" value="面条"/>面条(20元)
<input type="radio" name="food" value="盖饭"/>盖饭(15元)<br/>
<input type="submit" value="划卡消费">
</form>
</center>
</body>
</html>
上述代码跑出来有点bug,暂时不清楚如何解决
显示的是cookie为空,但是控制台输出测试的时候是有值的。
但是我查看F12里面
从index界面跳转到index_2界面,显示的Cookie并不是我想要的那个样子?
教程上查看就是比较正常的样子
用谷歌浏览器虽然得到的结果像是理想结果
但跳转后使用,还是报500的错误
Cookie生命周期
在默认情况下,cookie对象存放在浏览器的缓存中。
因此只要浏览器关闭,cookie对象就被销毁掉
在手动设置情况下,可以要求浏览器将接收的cookie
存放在客户端计算机上硬盘上,同时需要指定cookie在硬盘上存活时间。
在存活时间范围内,关闭浏览器关闭客户端计算机,关闭服务器,都不会导致cookie被销毁。
在存活时间到达时,cookie自动从硬盘上被删除
设置card2的生存周期为60秒
Cookie card1 = new Cookie("userName", userName);
Cookie card2 = new Cookie("money", money);
//3.发卡,将Cookie写入到响应头交给浏览器
card2.setMaxAge(60);
response.addCookie(card1);
response.addCookie(card2);
可以看到显示了生命周期
跳转到新的页面,也标记了此时的cookie情况
过了一分钟后就没了
HttpSession接口
- httpsession接口来自于Servlet规范下一个接口。存在于Tomcat中servlet-api.jar其实现类由Http服务器提供。Tomcat提供实现类存在于servlet-api.jar
- 如果两个servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于Httpsession对象进行数据共享
- 开发人员习惯于将Httpsession接口修饰对象称为【会话作用域对象】
HttpSession和Cookie的区别
名称 | Cookie | HttpSession |
---|---|---|
存储位置 | 存放在客户端计算机(浏览器内存/硬盘) | 存放在服务端计算机内存 |
数据类型 | 存储共享数据类型只能是String | 可以存储任意类型的共享数据object |
数据数量 | 一个cookie对象只能存储一个共享数据 | 使用map集合存储共享数据,可以存储任意数量共享数据 |
参照物 | 相当于客户在服务端【会员卡】 | Httpsession相当于客户在服务端【私人保险柜】 |
命令实现
HttpSession类似于一个即时的小型数据库
写一个简单的购物模拟
描述一下流程:
浏览器端的静态界面,列有一些商品参数以及加入购物车功能
点击加入购物车,将此时的商品参数携带上,发出第一次请求。
OneServlet调用请求对象读取请求参数,得到本次选购商品名
调用请求对象向Tomcat索要当前用户在服务端的【储物柜】
并将商品添加到当前用户的私人储物柜【HttpSession】中。
TwoServlet调用请求对象向Tomcat索要当前用户在服务端的储物柜,得到所有存放的商品信息【放到枚举里面】
调用相应对象,将得到的商品信息结合Table标签写入到响应体中,交给浏览器。
配置一下前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="2" align="center">
<tr>
<td>商品名称</td>
<td>商品价格</td>
<td>商品评价</td>
<td>加入购物车</td>
</tr>
<tr>
<td>小米手机</td>
<td>1699</td>
<td>好</td>
<td><a href="/myWeb/one?goodsName=Xiaomi">加入购物车</a></td>
</tr>
<tr>
<td>华为手机</td>
<td>2599</td>
<td>很好</td>
<td><a href="/myWeb/one?goodsName=Huawei">加入购物车</a></td>
</tr>
<tr>
<td>苹果手机</td>
<td>6599</td>
<td>贵</td>
<td><a href="/myWeb/one?goodsName=Apple">加入购物车</a></td>
</tr>
<tr align="center">
<td colspan="4">
<a href="/myWeb/two">查看我的购物车</a>
</td>
</tr>
</table>
</body>
</html>
配置第一个Servlet
package com.example.MyCart;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String goodsName;
//1.调用请求对象,读取请求头参数,得到用户选择商品名
goodsName = request.getParameter("goodsName");
//2.调用请求对象,向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession();
//session.setMaxInactiveInterval(5);
//3.将用户选购商品添加到当前用户私人储物柜
Integer goodsNum = (Integer) session.getAttribute(goodsName);
if (goodsNum == null) {
session.setAttribute(goodsName, 1);
} else {
session.setAttribute(goodsName, goodsNum + 1);
}
}
}
配置第二个Servlet
package com.example.MyCart;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Enumeration;
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.调用请求对象,向Tomcat索要当前用户在服务端私人储物柜
HttpSession session = request.getSession();
//2.将session中所有的key读取出来,存放一个枚举对象
Enumeration<String> goodsNames =session.getAttributeNames();
while(goodsNames.hasMoreElements()){
String goodsName = goodsNames.nextElement();
int goodsNum = (int)session.getAttribute(goodsName);
System.out.println("商品名称 "+goodsName+" 商品数量 "+goodsNum);
}
}
}
进行测试
单击加入购物车就会送到服务端
点击查看购物车,可以看到输出信息
打开第二个浏览器(同一款浏览器或者不同浏览器),再次键入这个地址,发现两边的浏览器购物车结果不同,是因为一个浏览器代表一个客户。如果是一个浏览器开的多个页面,那么还是算一个用户
Tomcat在创建一个HttpSession对象时,自动为这个HttpSession对象生成一个为一个编号(箱号)
Tomcat将箱号保存到Cookie对象,推送到当前浏览器缓存
等到用户第二次来访时,Tomcat根据请求头JSESSIONID确认用户是否有HttpSession以及哪一个HttpSession是当前用户
getsession()与getsession (false)
- getSession():如果当前用户在服务端已经拥有了自己的私人储物柜.
要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜要求Tomcat为当前用户创建一个全新的私人储物柜
2)getSession(false):如果当前用户在服务端已经拥有了自己的私人储物柜.
要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜此时Tomcat将返回null
根据需求选择用哪个
HttpSession销毁时间
- 用户与Httpsession关联时使用的cookie只能存放在浏览器缓存中.
- 在浏览器关闭时,意味着用户与他的Httpsession关系被切断
- 由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的Httpsession进行销毁
- 为了解决这个问题,Tomcat为每一个Httpsession对象设置【空闲时间】这个空闲时间默认30分钟,如果当前Httpsession对象空闲时间达到30分钟此时Tomcat认为用户已经放弃了自己的Httpsession,此时Tomcat就会销毁掉这个Httpsession
<!--session空闲时间-->
<session-config>
<session-timeout>5</session-timeout><!--当前网站中每一个session最大空闲时间5分钟-->
</session-config>
HttpServletRequest接口
- 在同一个网站中,如果两个servlet之间通过【请求转发】方式进行调用,彼此之间共享同一个请求协议包。而一个请求协议包只对应一个请求对象因此servlet之间共享同一个请求对象,此时可以利用这个请求对象在两个servlet之间实现数据共享
- 在请求对象实现servlet之间数据共享功能时,开发人员将请求对象称为【请求作用域对象】
OneServlet里面上传数据 Hello Java
package com.example.HttpServletRequestTest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将数据添加到请求作用域对象,作为共享数据
req.setAttribute("key1", "Hello Java");
//代替浏览器,向Tomcat索要TwoServlet来完成任务
req.getRequestDispatcher("/two").forward(req, resp);
}
}
TwoServlet得到数据并打印在控制台中
package com.example.HttpServletRequestTest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从同一个请求作用域中得到TwoServlet写入到共享数据
String value = (String) req.getAttribute("key1");
System.out.println("TwoServlet gets the sharing data is :" + value);
}
}
结束时间:2021-07-08